Estoy escribiendo a continuación un contrato simple que almacena todos los resultados de los cuestionarios para cada identificación.
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;
}
}
La función vote
se puede llamar y extraer con éxito, sin embargo, no puedo obtener el valor de retorno de vote
.
Agradecería que alguien aconsejara la causa de esto y la solución para obtener el valor de retorno de la función con argumentos.
Su código se ejecuta como se esperaba cuando lo ejecuto a través de la geth
consola. Si no te funciona, prueba a aumentar la gasolina que envías con tus transacciones.
Como @Taylor Gerring
ha dicho en su respuesta, es posible que no pueda obtener los resultados de su vote()
función, pero su código parece funcionar bien.
Si desea el resultado de su vote()
función, que en su ejemplo es una verificación de si una persona ha votado antes, ya tiene estos datos en sus voters
datos.
Tomé su código fuente y simplemente cambié el nombre de la clase de answer
a Answer
, y convertí su comentario de //
a /*...*/
:
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;
}
}
Eliminé el CR-LF del código, colapsé los espacios y ejecuté la siguiente declaración en 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
Luego compilé su código y lo inserté en mi cadena de bloques de desarrollo:
> 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...
Esperé a que se extrajera el contrato y recibí el siguiente mensaje:
Contract mined! Address: 0xe51ac93e4c28206f0f0296e5b6d66daf0a917bc3
[object Object]
Comprobado getNumResult()
:
> answer.getNumResult("idOne")
0
Votado:
> answer.vote("idOne", 1, 1, eth.accounts[0], {
from:web3.eth.accounts[0],
data: answerCompiled.Answer.code,
gas: 1000000
});
"0xfcbf47472733c0922552aa617fc7cb1226c346edc022fbe09ea521dfb75f7699"
Esperé a que se extrajera la transacción y verifiqué la transacción:
> eth.getTransaction("0xfcbf47472733c0922552aa617fc7cb1226c346edc022fbe09ea521dfb75f7699")
{
...
blockNumber: 6567,
...
}
Comprobado getNumResult()
:
> answer.getNumResult("idOne")
1
Envió otro voto con una identificación diferente:
> answer.vote("idTwo", 2, 1, eth.accounts[0], {
from:web3.eth.accounts[0],
data: answerCompiled.Answer.code,
gas: 1000000
});
Comprueba los resultados:
> answer.getNumResult("idTwo")
1
Enviado otro voto desde la misma cuenta con el mismo ID:
> answer.vote("idOne", 2, 1, eth.accounts[0], {
from:web3.eth.accounts[0],
data: answerCompiled.Answer.code,
gas: 1000000
});
"0xbbf9db6eb7c02571948002f56e3a7c56b6c7f55c2a4bbc70a244bb2afbf44e1f"
Y noté el siguiente error:
PC 00000366: JUMP GAS: 976744 COST: 8 ERROR: invalid jump destination (PUSH1) 2
El error anterior debe haberse generado a partir de la throw
declaración en su código si se vota la misma ID desde la misma cuenta:
if (voters[msg.sender][ID]) throw;
Luego envié otro voto desde mi segunda cuenta:
> answer.vote("idOne", 2, 1, eth.accounts[1], {
from:web3.eth.accounts[1],
data: answerCompiled.Answer.code,
gas: 1000000
});
Y los resultados se actualizaron como se esperaba:
> answer.getNumResult("idOne")
2
Actualmente no es posible devolver valores de funciones que modifican la cadena de bloques. Para recibir un valor de retorno, puede marcar las funciones como "pure" o "view" .
Para las funciones de cambio de estado, la única forma de "devolver" información es mediante el uso de Solidity Events, que se fusionan como códigos de operación LOG en la máquina virtual Ethereum.
Con la función no constante vote
, solo puede recuperar el hash de la transacción inmediatamente porque es posible que la transacción nunca se extraiga. O podría tomar varios bloques como se indica en "Esperando que se extraiga la transacción..." Se recomienda comprobar: ¿ Cuál es la diferencia entre una transacción y una llamada?
Se necesitan eventos para obtener el "valor de retorno" de vote
.
Ejemplo de cómo agregar y activar un event
:
contract answer{
// ...
event VoteEvent(string ID, bool returnValue);
function vote(string ID, uint qNum, uint ans) returns (bool) {
// ...
VoteEvent(ID, true);
return true;
}
}
Consulte Eventos de contrato para conocer las diferentes formas de observar y obtener datos de eventos mediante web3.js.
vote
pudiera return false
, por ejemplo, si ya votó, el valor de retorno podría ser útil para que otros contratos puedan hacer cosas como if (!someContract.vote("ak", 7, 2)) {...}
. Los valores de retorno pueden ser usados por otros contratos, pero web3.js solo puede usar eventos. Si siempre es return true
, entonces probablemente se pueda eliminar el booleano y simplificar el evento a algo como UserVoted(string ID)
.
Ahmed Ajtar
require
con la condición negada por!
el operador en lugar dethrow
.