Solidity – Solving Push Not Working for Mapped Structs with Address Array

arraysmappingsoliditystruct

Can someone help me understand why the function add in the contract one is not working and in the contract two is?

Both are mined and are inserted into the blockchain.

Thanks.

Not working contract

contract one {
    struct A {
        address[] count;
    }
    struct B {
        uint8[] count;
    }

    mapping (address => A) a;
    mapping (address => B) b;

    function add(address c, uint8 g) {
        a[msg.sender].count.push(c);
        b[msg.sender].count.push(g);
    }
}

Working contract

contract two {
    struct A {
        address[] count;
    }

    mapping (address => A) a;

    function add(address c) {
        a[msg.sender].count.push(c);
    }
}

Best Answer

Summary

Works perfectly. I do get the ["0x", 0] message if I call the functions get1() and get2() immediately after the I send the add(...) transaction. But after waiting a while more, the get1() and get2() functions return the expected values.



Details

Modification To Your Code

I've modified your code to add some functions to view the inserted data:

contract TwoStructs {
    struct A {
        address[] count;
    }
    struct B {
        uint8[] count;
    }

    mapping (address => A) a;
    mapping (address => B) b;

    function add(address c, uint8 g) {
        a[msg.sender].count.push(c);
        b[msg.sender].count.push(g);
    }

    function get1(address sender) constant returns (address, uint8) {
        return (a[sender].count[0], b[sender].count[0]);
    }

    function get2() constant returns (address, uint8) {
        return (a[msg.sender].count[0], b[msg.sender].count[0]);
    }

    function getMsgSender() constant returns (address) {
        return msg.sender;
    }
}

Running geth

I'm running the Dev blockchain using the following parameters:

geth --datadir /home/user/DevData --dev --nodiscover \
  --mine --minerthreads 1 --port 30301 --maxpeers 0  \
  --verbosity 3 --rpc console


Flattened Your Code And Assigned To A Variable

You can use a service like Line Break Removal Tool to strip out your line breaks, or see How to load Solidity source file into geth for some alternatives.

I flattened your code, assigned it to a variable and pasted it into geth:

> var twoStructsSource='contract TwoStructs { struct A { address[] count; } struct B { uint8[] count; } mapping (address => A) a; mapping (address => B) b; function add(address c, uint8 g) { a[msg.sender].count.push(c); b[msg.sender].count.push(g); } function get1(address sender) constant returns (address, uint8) { return (a[sender].count[0], b[sender].count[0]); } function get2() constant returns (address, uint8) { return (a[msg.sender].count[0], b[msg.sender].count[0]); } function getMsgSender() constant returns (address) { return msg.sender; }}'


Compiled Your Code

I compiled your code using the following command:

> var twoStructsCompiled = web3.eth.compile.solidity(twoStructsSource);


Inserted Your Code Into The Blockchain

I used the following commands to insert your code into the blockchain:

> var twoStructsContract = web3.eth.contract(twoStructsCompiled.TwoStructs.info.abiDefinition);
> var twoStructs = twoStructsContract.new({from:web3.eth.accounts[0], data: twoStructsCompiled.TwoStructs.code, gas: 1000000}, 
  function(e, contract) {
    if (!e) {
      if (!contract.address) {
        console.log("Contract transaction send: TransactionHash: " + 
          contract.transactionHash + " waiting to be mined...");
      } else {
        console.log("Contract mined! Address: " + contract.address);
        console.log(contract);
      }
    }
  }
)

And waited for the following message:

Contract mined! Address: 0xe924f5c2240bfb2a78d46a8ebfb2bc149cfeeff0


Sent Transaction To Add Data

I inserted some sample data into the blockchain using the following command:

> twoStructs.add(eth.accounts[0], 123, {
  from:web3.eth.accounts[0], 
  data: twoStructsCompiled.TwoStructs.code,
  gas: 1000000
});

And waited for the transaction to be mined.

"0xe4966cb845f5e929eb554c772e9982a2e1c5f3da3190a13cca5994a4f11f4143"


Check Data Inserted

If I immediately run twoStructs.get1(eth.accounts[0]), I get the following results:

> twoStructs.get1(eth.accounts[0])
...
PC 00000104: JUMPI GAS: 49977033 COST: 10 ERROR: invalid jump destination (PUSH1) 2
...
["0x", 0]

If I want a few more seconds:

> twoStructs.get1(eth.accounts[0])
["0xa485ab3ad17cd9aca6fd5343a53a513685c7e0ed", 123]

> twoStructs.get2()
["0xa485ab3ad17cd9aca6fd5343a53a513685c7e0ed", 123]

> twoStructs.getMsgSender()
"0xa485ab3ad17cd9aca6fd5343a53a513685c7e0ed"

as expected. If you get the ["0x", 0], wait for some time then try again.