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.
Based on my Debug observation:
I have tested that:
- Firstly I insert data into my map data-structure as I explained in my question.
- Secondly, I have returned the address of first mapped index, which is 0, this could be done for other indexes as well (0:10).
- Without a delete operation I can retrieve the data perfectly fine from the address of mapped Foo[]. But if I did the delete operation, Solidity gives an error.
This debug result: leads me to conclude that memory is freed or address does not contain any valid information.
Test code:
set_txn_hash = my_contract.transact().map_insert();
contract_address = unmigrated_chain.wait.for_receipt(set_txn_hash)
for x in range(0, 9):
for y in range(0, 9):
output = my_contract.call().get_(x, y);
print(output); //returns correct value.
set_txn_hash = my_contract.transact().map_remove_map();
contract_address = unmigrated_chain.wait.for_receipt(set_txn_hash)
set_txn_hash = my_contract.transact().get_map_address(0);
contract_address = unmigrated_chain.wait.for_receipt(set_txn_hash)
output = my_contract.call().get_map();
print(output);
output = my_contract.call().try_();
print(output); //Solidity gives error if delete map_remove_map() is called
Additional functions inside my Contract:
function map_insert(){
for(uint i = 0; i < 10; i++)
for(uint j = 0; j < 10; j++)
add(i, i*10 + j);
}
function map_remove_map(){
for(uint i = 0; i < 10; i++)
delete_(i);
}
function map_remove_map_item(){
for(uint i = 0; i < 10; i++)
for(uint j = 0; j < 10; j++)
delete_items(i, j);
}
function get_map_address(uint id) {
uint addr;
Foo[] a = foo[id];
assembly{
addr := a
}
map_address = addr;
}
function get_map() constant returns (uint){
return map_address;
}
function try_() constant returns (uint ){
uint addr = map_address;
Foo[] a;
assembly{
a := addr
}
return a[1].x;
}
Best Answer
The issue is that you can't
push
to arrays that are located in memory. (Such arrays are not resizable.)One possible fix is to just do the changes in storage: