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;
        }
}
  • 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 8 '17 at 0:34
  • @Malone if it returned false the transaction would fail, right? it does not fail in remix – Z Jones Nov 8 '17 at 0:41
  • Require is currently INVALID opcode up until the release of Metropolis, if this is the case the transaction will not refund gas etc.. ethereum.stackexchange.com/questions/13502/… – Malone Nov 8 '17 at 1: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 8 '17 at 4:59
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;
    }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.