Проблема при попытке получить данные из контракта с помощью Web3 1.0

Я чувствую, что я должен пропустить что-то тривиальное здесь. У меня есть смарт-контракт, который заполняет массив структур, показанных ниже. При попытке вызова addNewQuestion('0x12345')или getQuestionListSize()кажется, что он никогда не добавляет новую структуру Вопроса в questionList. При вызове getQuestionListSize()он должен возвращать счетчик, который я назвал questionId, но он всегда просто возвращает «1». Любая помощь очень ценится.

Договор:

pragma solidity ^0.4.11;

contract EthUpVoting {

  struct Question {
    bytes32 ipfsHash;
    uint upvotes;
    address user;
  }

  uint private questionId;
  mapping (uint => Question) public questionList;

  event AddedQuestion(bytes32 ipfs_hash, uint qId);

  function EthUpVoting() public {
    questionId = 1;
    questionList[questionId] = Question({
        ipfsHash: "Hello, World!",
        upvotes: 0,
        user: msg.sender
    });
  }

  function addNewQuestion(bytes32 questionHash) public {
      questionId += 1;
      questionList[questionId] = Question({
          ipfsHash: questionHash,
          upvotes: 0,
          user: msg.sender
      });
      AddedQuestion(questionHash, questionId);
  }

  function voteForQuestion(uint qId) public {    
    questionList[qId].upvotes += 1;
    questionId += 1;
  }

  function getQuestionTextAtIndex(uint qId) public constant returns (bytes32 ipfsHashReturn) {
      return questionList[qId].ipfsHash;
  }

   function getQuestionListSize() public constant returns (uint size) {
      return questionId;
  }

}

NodeJS:

const web3 = new Web3(Web3.givenProvider || "ws://127.0.0.1:8546")
const ethUpVotingContract = new web3.eth.Contract(config.eth.abi, config.eth.contractAddr);

ethUpVotingContract.methods.addNewQuestion('foo').send(ethOptions, (err, resp) => {
    if (err) {
      console.log(err) 
    } else {
      // successfully returns transaction hash 
      console.log(resp);
    }
}).then(resp => {
    // successfully returns transaction receipt
    console.log(resp);
});

ethUpVotingContract.methods.getQuestionListSize().call().then(function (resp) {
    // this always returns "1"
    console.log(resp);
});
почему вы используете ethUpVotingContract.methods. не только ethUpVotingContract
Я просто следил за документацией: web3js.readthedocs.io/en/1.0/…
В предыдущей версии провайдер «ws» не работал, я бы попробовал «http» и/или «ipc», чтобы проверить, работают ли они, web3 v1.0 все еще находится в стадии бета-тестирования, поэтому некоторые вещи не будут работать, а в других есть ошибки.
@Ismael, так что эти методы являются частью web3js 1.0 в качестве новых функций?
@Etherkimist Да, web3 v1.0 — это рефакторинг старой стабильной версии v0.20. Я бы посоветовал изучить web3 v1.0, потому что он больше рассчитан на будущее, но если вам нужно что-то готовое к производству, я бы пока остановился на v0.20. Надеюсь скоро выйдет версия 1.0.
Пробовал через httpпровайдера, те же симптомы.

Ответы (1)

Я попробовал ваш контракт и обнаружил пару проблем:

ethUpVotingContract.methods.addNewQuestion('foo')
.send(ethOptions, (err, resp) => {

потерпит неудачу с

throw new Error('Данный параметр не является байтом: "'+ значение + '"');

Ошибка: данный параметр не является байтом: «foo» в SolidityTypeBytes.formatInputBytes [как _inputFormatter]

Преобразование в байты заставит его работать

const question = web3.utils.asciiToHex('foo');

ethUpVotingContract.methods.addNewQuestion(question)
.send(options, (err, hash) => {

Другая проблема заключается в том, что теперь sendи callвернуть обещание. Что случилось? Если callобещание начнет выполняться до sendзавершения, оно отобразит предыдущие данные, как будто sendони никогда не выполнялись.

Чтобы исправить это, вы должны сделать callвнутри предложение then, sendчтобы убедиться, что оно завершено.

const message = web3.utils.asciiToHex('foo');

ethUpVotingContract.methods.addNewQuestion(message)
.send(options, (err, hash) => {
  if (err) {
    console.log(err);
  }
  console.log(`TxHash: ${hash}`);
})
.then((result) => {
  console.log('Send has completed');
  // Here we are guarantee `send` has finished
  // and we can query the data
  ethUpVotingContract.methods.getQuestionListSize().call()
  .then((result) => {
    console.log('Call has returned');
    console.log(result);
  });
});

// If we call here perhaps `send` didn't finish yet
console.log('Send was called');
Спасибо, что нашли время, чтобы найти ошибку и объяснить все, очень полезно.