Я новичок, пытаюсь взаимодействовать с простым контрактом через web3, и у меня возникли некоторые проблемы, которые я не могу понять.
Я написал базовый контракт со структурой и двумя функциями. Это в основном скопировано отсюда: Возврат структуры и чтение через Web3
contract MyContract {
struct MyStruct {
address a;
uint b;
}
MyStruct[] public MyStructs;
function getStruct(uint index) public constant returns (address, uint) {
return (MyStructs[index].a, MyStructs[index].b);
}
function addStruct(address _a, uint _b) public returns (uint){
MyStruct memory a = MyStruct(_a, _b);
MyStructs.length++;
MyStructs.push(a);
return MyStructs.length;
}
}
У меня есть две тестовые функции, которые я вызываю с помощью тестовой функции трюфеля. Они в основном скопированы с http://truffleframework.com/docs/getting_started/javascript-tests.
var MyContract = artifacts.require("MyContract");
contract('MyContract', function() {
it("should create a stuct", function() {
return MyContract.deployed().then(function(instance) {
return instance.addStruct.call(0xf17f52151EbEF6C7334FAD080c5704D77216b732, 1000);
}).then(function(length) {
console.log(length);
assert.equal(length, 1, "length is not 1");
});
});
it("get the struct that was previously created", function() {
return MyContract.deployed().then(function(instance) {
return instance.getStruct.call(0);
}).then(function(values) {
console.log(values);
assert.equal(values, (0xf17f52151EbEF6C7334FAD080c5704D77216b732, 1000));
});
});
});
Когда я запускаю это, я получаю следующее:
Contract: MyContract { [String: '2'] s: 1, e: 0, c: [ 2 ] }
1) should create a stuct
> No events were emitted
2) get the struct that was previously created
> No events were emitted
0 passing (190ms) 2 failing
1) Contract: MyContract should create a stuct:
AssertionError: length is not 1: expected { Object (s, e, ...) } to equal 1
at test/mycontract.js:10:15
at process._tickCallback (internal/process/next_tick.js:103:7)
2) Contract: MyContract get the struct that was previously created:
Error: Invalid JSON RPC response: {"id":21,"jsonrpc":"2.0"}
at Object.InvalidResponse (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:41483:16)
at /usr/local/lib/node_modules/truffle/build/cli.bundled.js:330353:36
at /usr/local/lib/node_modules/truffle/build/cli.bundled.js:326008:9
at XMLHttpRequest.request.onreadystatechange (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:329052:7)
at XMLHttpRequestEventTarget.dispatchEvent (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:176427:18)
at XMLHttpRequest._setReadyState (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:176717:12)
at XMLHttpRequest._onHttpResponseEnd (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:176872:12)
at IncomingMessage.<anonymous> (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:176832:24)
Другими словами, когда он попадает в console.log(length), который должен быть ответом функции addStruct, вместо этого он получает { [String: '2'] s: 1, e: 0, c: [ 2 ] }
, а затем получает ошибки getStruct сError: Invalid JSON RPC response: {"id":21,"jsonrpc":"2.0"}
Любая идея, почему это происходит? Обе эти вещи для меня ничего не значат, поэтому я даже не знаю, что гуглить. Я просмотрел документацию по Truffle и Solidity и, насколько я могу судить, я все делаю правильно.
Возможно, это не связано, но я включаю на всякий случай, если это не так - ранее я успешно развернул это в Ganache и играл в консоли браузера. Я смог вызвать web3.eth.contract(abi) и получить ответ, который кажется правильным, но когда я добавил адрес в качестве аргумента, он отказался дать мне что-либо, кроме «неверный адрес». Я подтвердил в документации web3 и ganache, что делал это правильно примерно 10 раз, поэтому я думаю, что, возможно, что-то еще не так. А может и нет — не стесняйтесь игнорировать эту часть.
В первом сценарии ваш результат — BigNumber , поэтому вам просто нужно .toNumber()
добавить length
:
it("should create a stuct", function() {
return MyContract.deployed().then(function(instance) {
return instance.addStruct.call(0xf17f52151EbEF6C7334FAD080c5704D77216b732, 1000);
}).then(function(length) {
console.log(length.toNumber());
assert.equal(length.toNumber(), 1, "length is not 1");
});
});
Связано: что такое свойства C , E и S в объекте возврата вызова сообщения?
Во втором сценарии я немного переработал ваш тест:
it("get the struct that was previously created", function() {
return MyContract.deployed().then(function(instance) {
instance.addStruct.sendTransaction("0xf17f52151ebef6c7334fad080c5704d77216b732", 1000);
return instance.getStruct.call(1);
}).then(function(values) {
console.log(values[0].toString(), values[1].toNumber());
assert.equal(values[0].toString(), "0xf17f52151ebef6c7334fad080c5704d77216b732", 'blah-blah');
assert.equal(values[1].toNumber(), 1000, 'blah-blah');
});
});
Мы выполним sendTransaction
, чтобы фактически добавить новую структуру в массив. Затем мы сделаем call
это, и возвращаемый массив будет прочитан с помощью .toString()
и .toNumber()
для нормализации вывода.
Также хорошо отметить, что если мы call
getStruct
с 0, он возвращает 0x0000000000000000000000000000000000000000 0
.
function addStruct(address _a, uint _b) public returns (uint){
MyStruct memory a = MyStruct(_a, _b);
MyStructs.push(a);
// delete this line (MyStructs.length++;)
return MyStructs.length;
}
После этого редактирования вы можете изменить call
значение с 0 обратно на 1 здесь:
return instance.getStruct.call(0);
@roman-frolov справился с первым выпуском.
Что касается второй проблемы, я считаю, что проблема в том, что вы использовали call
вместо того sendTransaction
, когда вызывали addStruct
. Вызовы фактически не отправляют транзакции в сеть; они просто запускают функцию локально, а затем отбрасывают побочные эффекты. Таким образом, на самом деле никакая структура не была добавлена в MyStructs
. Последующий вызов getStruct
завершится ошибкой, поскольку он использует недопустимый индекс в массиве. (Он пытается использовать индекс 0, но длина массива по-прежнему равна 0.)