Summary
Your code runs as expected when I execute it through the geth
console. If it does not work for you, try increase the gas you send with your transactions.
As @Taylor Gerring
has stated in his answer, you may not be able to get the results from your vote()
function, but your code seems to work OK.
If you want the result from your vote()
function, which in your example is a check as to whether a person has voted before, you already have this data in your voters
data.
The Details
I've taken your source code and just changed the class name from answer
to Answer
, and converted your comment from //
to /*...*/
:
contract Answer {
mapping(address => mapping(string => bool)) voters;
struct qList {
uint count; /* The number of respondents */
mapping(address => mapping(uint => uint)) answer;
}
mapping(string => qList) questionnaires;
function vote(string ID, uint qNum, uint ans) returns (bool) {
if (voters[msg.sender][ID]) throw;
voters[msg.sender][ID] = true;
questionnaires[ID].count += 1;
questionnaires[ID].answer[msg.sender][qNum] = ans;
return true;
}
function getNumResult(string ID) constant returns (uint res) {
return questionnaires[ID].count;
}
}
I've stripped out the CR-LF from the code and collapsed the spaces, and executed the following statement in geth
:
> var answerSource='contract Answer { mapping(address => mapping(string => bool)) voters; struct qList { uint count; /* The number of respondents */ mapping(address => mapping(uint => uint)) answer; } mapping(string => qList) questionnaires; function vote(string ID, uint qNum, uint ans) returns (bool) { if(voters[msg.sender][ID]) throw; voters[msg.sender][ID] = true; questionnaires[ID].count += 1; questionnaires[ID].answer[msg.sender][qNum] = ans; return true; } function getNumResult(string ID) constant returns (uint res) { return questionnaires[ID].count; }}'
undefined
I then compiled your code and inserted it into my dev blockchain:
> var answerCompiled = web3.eth.compile.solidity(answerSource);
undefined
> var answerContract = web3.eth.contract(answerCompiled.Answer.info.abiDefinition);
undefined
> var answer = answerContract.new({
from:web3.eth.accounts[0],
data: answerCompiled.Answer.code, gas: 2000000},
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);
}
}
})
Contract transaction send: TransactionHash: 0x5b5eb3c6d2a4b43eff4444b71b762911ddc72e239d1d495b6bec7b2e6a738df0 waiting to be mined...
I waited for the contract to be mined and got the following message:
Contract mined! Address: 0xe51ac93e4c28206f0f0296e5b6d66daf0a917bc3
[object Object]
Checked getNumResult()
:
> answer.getNumResult("idOne")
0
Voted:
> answer.vote("idOne", 1, 1, eth.accounts[0], {
from:web3.eth.accounts[0],
data: answerCompiled.Answer.code,
gas: 1000000
});
"0xfcbf47472733c0922552aa617fc7cb1226c346edc022fbe09ea521dfb75f7699"
Waited for the transaction to be mined and checked the transaction:
> eth.getTransaction("0xfcbf47472733c0922552aa617fc7cb1226c346edc022fbe09ea521dfb75f7699")
{
...
blockNumber: 6567,
...
}
Checked getNumResult()
:
> answer.getNumResult("idOne")
1
Sent another vote with a different ID:
> answer.vote("idTwo", 2, 1, eth.accounts[0], {
from:web3.eth.accounts[0],
data: answerCompiled.Answer.code,
gas: 1000000
});
Checked the results:
> answer.getNumResult("idTwo")
1
Sent another vote from the same account with the same ID:
> answer.vote("idOne", 2, 1, eth.accounts[0], {
from:web3.eth.accounts[0],
data: answerCompiled.Answer.code,
gas: 1000000
});
"0xbbf9db6eb7c02571948002f56e3a7c56b6c7f55c2a4bbc70a244bb2afbf44e1f"
And I noticed the following error:
PC 00000366: JUMP GAS: 976744 COST: 8 ERROR: invalid jump destination (PUSH1) 2
The error above must have been generated from the throw
statement in your code if the same ID is voted from the same account:
if (voters[msg.sender][ID]) throw;
I then sent another vote from my second account:
> answer.vote("idOne", 2, 1, eth.accounts[1], {
from:web3.eth.accounts[1],
data: answerCompiled.Answer.code,
gas: 1000000
});
And the results were updated as expected:
> answer.getNumResult("idOne")
2
Best Answer
The return-value of a non-constant (neither
pure
norview
) function is available only when the function is called on-chain (i.e., from this contract or from another contract).When you call such function from the off-chain (e.g., from an ethers.js script), you need to execute it within a transaction, and the return-value is the hash of that transaction.
This is because it is unknown when the transaction will be mined and added to the blockchain.
Moreover, even when the transaction is added to the blockchain, it can be removed from it later.
The longer it stays on the blockchain, the smaller the chances are that it will be removed from it later in the future.
It is custom to confirm 12 blocks before assuming that it will remain in the blockchain forever.
In order to obtain the return-value of a non-constant function when you call it from the off-chain, you can emit an event which contains the value which you are about to return.
The contents of this event will then be available to you within the transaction receipt, which you may obtain via the transaction hash.