Инициирование события до фактической установки данных

Допустим, это мой смарт-контракт:

  event NewUser(
    address userAddress,
    uint amount
  );
  function addUser() public payable{
    require(msg.value <= maxValue && msg.value > 0);
    require(allowedValues[msg.value]);
    require(accountAmount() < 5);

    if (users[msg.sender] > 0) {
        userPullout(); //Remove senders data
    }

    userAddresses.push(msg.sender);
    partAmounts.push(msg.value);// This value doesn't get pushed before the event is finished
    users[msg.sender] = msg.value;

    emit NewUser(msg.sender, msg.value);//This is called to soon
}

Это мой файл nodeJS:

app.contract.events.NewUser({}, function(error, event){})
.on('data', function(event){
  io.emit('new user', event.returnValues);
}).on('change', function(event){
  io.emit('new user', event.returnValues);
})
.on('error', console.error);

Если я зарегистрирую partAmountмассив в web3 с помощью .callфункции, старые значения до события все равно будут возвращены. Это говорит мне о том, что событие запущено слишком рано.

Есть ли способ вызвать событие после установки данных?

РЕДАКТИРОВАТЬ: еще немного кода.

const socket = openSocket('http://localhost:3000'); // subscribed to the socket server firing the events from node back-end
socket.on('new user', (event) => {
  console.log(event) // returns for example 7 which is CORRECT
  this.props.contract.methods.getCertainArray().call(this.props.contractObject, (err, res) => {
    console.log(res); // old data from before the event so if the previous array was [0, 6 , 6], this would still be returned NOTICE: no 7 in the array yet.
  });
})

ПРИМЕЧАНИЕ. Если я установлю тайм-аут для функции вызова следующим образом:

setTimeout(() => {
    this.props.contract.methods.getCertainArray().call(this.props.contractObject, (err, res) => {
      console.log(res); // old data from before the event so if the previous array was [0, 6 , 6], this would still be returned NOTICE: no 7 in the array yet.
    });
}, 5000);

Он возвращает правильный массив, но это не так, как я хочу, чтобы скрипт работал.

Ответы (3)

Проблема в том, что вы не ждете, пока транзакция будет добыта, прежде чем .callпроверять результат.

Это идет:

  1. Подпишите и отправьте транзакцию. Получите квитанцию ​​об операции.
  2. Транзакция добывается, и контракт выполняет инструкции по порядку.
  3. Блок приходит с подтвержденной транзакцией.
  4. Теперь вы можете callиспользовать функцию, чтобы увидеть эффект.

Или следите за событием, как выглядит ваш пример JS. События не поступают до тех пор, пока транзакция не будет включена в блок.

Надеюсь, поможет.

Видите, это ожидаемое поведение, может быть, это как-то связано с тем, что я использую трюфель и ганаш? Что из-за этого событие запускается, потому что оно не в реальном блокчейне?
Да, это ожидаемо, но нет, события не запускаются перед майнингом. Очень маловероятно какое-либо другое объяснение. Вы делаете callдо того, как транзакция будет добыта. Первый обратный вызов дает хэш транзакции. Это не подтверждение "заминировано". Это просто подтверждение запроса. Это часто ошибочно принимают за подтверждение майнинга. Посмотрите здесь: gist.github.com/xavierlepretre/88682e871f4ad07be4534ae560692ee6
Итак, мне до сих пор не удалось решить проблему, поэтому давайте попытаемся объяснить еще кое-что.. Данные, которые выходят из события, ПРАВИЛЬНЫ, проблема в том, что функция вызова (которая запускается событием) после этого по-прежнему извлекает СТАРЫЕ данные. Я загружу еще немного кода
Вы понимаете ожидаемую механику, и я понимаю ваше разочарование. Я не думаю, что трюфель является вероятным виновником, но вы, возможно, обнаружили что-то о ганаше, сообщающем о событии до того, как он полностью переварил состояние, или, может быть, даже предостережение, связанное с передачей массивов. Это относительно новая функция и обычно не очень хорошая идея, учитывая избыточность. Если подумать, когда клиенты информируются о строках пошагово, нет причин запрашивать весь массив залпом. Это не объясняет, почему это кажется неудачным, но может объяснить, почему проблема существует.
Может быть, кто-то может поделиться информацией, чтобы подтвердить, что вы гарантированно получите последний динамический массив немедленно, с ганашем. Я бы подумал о создании частного узла с помощью geth, просто чтобы посмотреть, соответствует ли поведение ожидаемому. В случае разногласий побеждает гет.
Возможно, вы правы, во всяком случае, я нашел решение. Смотрите мой ответ.

Как отметил Роб, вы, скорее всего, не ждете, пока транзакция будет полностью проанализирована, прежде чем извлекать данные. Я не уверен насчет web3js, но Golang предоставляет возможность считывать данные об ожидающем состоянии до того, как транзакция будет добыта. Лично я предпочитаю golang для написания внутреннего кода, взаимодействующего со смарт-контрактами, и буду использовать web3 только в случае необходимости (т.е. интерфейсный код).

Предупреждение, однако, я бы рекомендовал не читать ожидающие данные состояния, поскольку они могут измениться в зависимости от того, какие транзакции вставлены в мемпул.

Настоятельно рекомендуется дождаться обработки транзакции, прежде чем обрабатывать какие-либо данные, и я бы лично рекомендовал использовать golang вместо web3 для взаимодействия со смарт-контрактами и использовать web3 только в том случае, если мне нужно написать код внешнего интерфейса.

У меня есть функция, которая вызывается всякий раз, когда конкретная транзакция отправляется из блокчейна, и автоматически завершает обработку и завершает работу после получения события.

https://github.com/RTradeLtd/Temporal/blob/2dd19bd950e2864e2cbad904c3b7c94958499048/server/payments.go#L55

Теперь, когда я подключен к тестовой сети Ropsten, она работает, как и ожидалось (если сервер WebSocket работает).

Я не знаю точно, в чем проблема, но я знаю, что проблема заключается в Ganache, который запускал события до того, как следующий блок был фактически завершен, и все переменные были обновлены.

Исправление: либо работайте со своего локального сервера Geth, либо загружайте свой контракт в одну из тестовых сетей.

Привет @jasper, похоже, ты решил свою проблему. Было бы идеально, если бы вы могли разработать его подробно, чтобы это принесло пользу сообществу. Если вам помог какой-либо из других ответов, было бы лучше, если бы вы могли принять его и отредактировать, если вы выполнили какой-либо дополнительный шаг.
Привет, Ачала, ты прав!
Отлично, было бы неплохо получить принятый ответ, даже ваш собственный ответ :).
Я отмечу это как правильный ответ, когда смогу через 23 часа :)
Замечательно :)