Проблемы с взаимодействием с простым контрактом

Я новичок, пытаюсь взаимодействовать с простым контрактом через 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 раз, поэтому я думаю, что, возможно, что-то еще не так. А может и нет — не стесняйтесь игнорировать эту часть.

Ответы (2)

В первом сценарии ваш результат — 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.)