0

I'm having trouble getting the array of "watchers" to persist after I:

  1. Deploy the contract
  2. Create Magic with name "test1"
  3. Execute watchMagic (with test1's magic id)
  4. Execute watchMagic (with test1's magic id from a different account)
  5. Call getMagicWatchers which returns an empty array

Any ideas?

contract WTF {

        struct Magic {
            bytes32 id;
            string name;
            address[] watchers;
        }

        uint _nonce;

        mapping (bytes32 => Magic) public allMagic;

        uint private _numWatchersMax = 16;

        function countWatchers(Magic magic) internal returns(uint) {
            uint count;
            uint i;
            for (i = 0; i < magic.watchers.length; i++) {
                if (address(0) != magic.watchers[i]) {
                    count++;
                }
            }
            return count;
        }

        function registerMagicWatcher(Magic magic, address watcher) internal returns(bool success) {
            magic.watchers[countWatchers(magic)] = watcher;
            return true;
        }

        function createMagic(string name) public returns(bytes32 magicId) {
            Magic memory magic = Magic({
                id: keccak256(msg.sender, name, _nonce++),
                name: name,
                watchers: new address[](_numWatchersMax)
            });

            require(registerMagicWatcher(magic, msg.sender));

            return magic.id;
        }

        function getMagicWatchers(bytes32 magicId) returns(address[] watchers) {
            return allMagic[magicId].watchers;
        }

        function watchMagic(bytes32 magicId) returns(bool success) {
            require(allMagic[magicId].id == magicId); // ensure magic with this id exists
            require(countWatchers(allMagic[magicId]) < _numWatchersMax);

            bool alreadyWatcher = false;
            uint i;
            for (i = 0; i < allMagic[magicId].watchers.length; i++) {
                if (msg.sender == allMagic[magicId].watchers[i]) {
                    alreadyWatcher = true;
                    break;
                }
            }
            require(alreadyWatcher == false);

            require(registerMagicWatcher(allMagic[magicId], msg.sender));
            return true;
        }
}
Z Jones
  • 101
  • 2
  • Have you debugged 'require(registerMagicWatcher(magic, msg.sender));'? This is potentially your problem. You may be having a require-style exception generated by it returning false. – Malone Nov 08 '17 at 00:34
  • @Malone if it returned false the transaction would fail, right? it does not fail in remix – Z Jones Nov 08 '17 at 00:41
  • Require is currently INVALID opcode up until the release of Metropolis, if this is the case the transaction will not refund gas etc.. https://ethereum.stackexchange.com/questions/13502/difference-between-stop-and-invalid-opcode/13504#13504 – Malone Nov 08 '17 at 01:15
  • @Malone thanks for the heads up - found more info here in case anyone is wondering. My understanding is that even now require() should be used. Am I mistaken? – Z Jones Nov 08 '17 at 04:59
  • https://ethereum.stackexchange.com/questions/15166/difference-between-require-and-assert-and-the-difference-between-revert-and-thro – Z Jones Nov 08 '17 at 04:59
  • Put require(false) below it so we can rule it out if it fails. – Malone Nov 08 '17 at 10:26

1 Answers1

2

Your createMagic function creates a Magic instance but never stores

    function createMagic(string name) public returns(bytes32 magicId) {

        // Allocates magic inmemory
        Magic memory magic = Magic({
            id: keccak256(msg.sender, name, _nonce++),
            name: name,
            watchers: new address[](_numWatchersMax)
        });

        // Add msg.sender as watcher
        require(registerMagicWatcher(magic, msg.sender));

        // Save magic in storage
        allMagic[magic.id] = magic;             // <------- Missing part

        // return id
        return magic.id;
    }
Ismael
  • 30,570
  • 21
  • 53
  • 96