Может ли событие watch() перейти от последнего номера блока (хвоста) к голове?

В общем, я предполагаю, что события проходят от меньшего к большему номеру блока.

Пример:

contractDeployedBlockNumber = 10000
fromBlock: contractDeployedBlockNumber, toBlock: 'latest'

[В] Можно ли event watch()перейти от 'latest'номера блока к блоку с номером 0 (или блоку с меньшим номером)? это в основном операция обратного обхода, чтобы eventсначала поймать самое последнее и сломать, это поможет как можно быстрее получить последнее сгенерированное событие.


Функция смарт-контракта хранит информацию о зарегистрированных пользователях и обновляет ее с помощью registerUser()функции.

contract Example {
   mapping(address => uint) userLatestEmittedBlocNum;
   function registerUser(string memory userEmail,
                         string memory name,
                         string memory githubUserName) public
       returns (bool success)
   {
       userLatestEmittedBlocNum[msg.sender] = block.number;
       emit LogUser(msg.sender, userEmail, name, githubUserName);
       return true;
   }

   function getUserLatestEmittedBlocNum(address userAddress) public view
    returns(uint)
  {
      if (userLatestEmittedBlocNum[userAddress] != 0)
          return (userLatestEmittedBlocNum[userAddress]);
   }
   event LogUser(address userAddress, string userEmail, string name, string githubUserName);
 }

Я могу сохранить номер блока, в котором обновляется информация о пользователе, userLatestEmittedBlocNum[msg.sender]и получить созданный журнал непосредственно из этого номера блока, но это будет стоить дополнительного хранилища и использования газа.

blockReadFrom = Example.functions. getUserLatestEmittedBlocNum(userAddress).call()
my_filter = Example.eventFilter('LogUser',{'fromBlock':int(blockReadFrom),'toBlock':int(blockReadFrom) + 1})

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

Может быть неэффективно выполнять итерацию от меньшего номера блока к последнему номеру блока (который также получит предыдущие обновленные события), а диапазон диапазона может быть очень большим. Вместо этого, если бы мы могли сканировать от последнего номера блока к маленькому номеру блока и прерывать итерацию при перехвате события, возможно, было бы быстрее найти последний сгенерированный журнал.

В смарт-контракте некоторая информация регистрируется и со временем может обновляться, поэтому latestсобытие является действительным. Поэтому я хочу получить последнее событие в моем смарт-контракте, не запуская сканирование с гораздо меньшего номера блока, что занимает много времени и неэффективно. Таким образом, в основном, начиная с «последнего» номера блока до меньшего блока, и прерывайте эту итерацию, если я поймаю событие. В противном случае, если я начну с меньшего номера блока, несмотря ни на что, мне придется повторять до последнего номера блока.


Цель :fromBlock: latest, toBlock: 0

blockNum = 0;
var contract = myContract.LogJob({}, { fromBlock: blockNum, toBlock: 'latest' });
var i = 0;
contract.watch(function (error, result) {
    console.log(i++ + ": " + JSON.stringify(result));
});
Вы бы знали, когда ваш контракт был заминирован. Итак, в основном, вам нужно выполнить итерацию от latestк этому mindedBlockNumber. Надеюсь, мне удалось дать вам некоторое представление. Пожалуйста, дайте мне знать, если мое понимание неверно.
Но я не могу перейти от последнего к меньшему номеру блока, он ничего не возвращает. fromBlock: latest, toBlock: 0@ Раджеш

Ответы (1)

Я постараюсь, потому что щедрости. :-)

Технически нет, но вы можете создать подобный эффект.

Я говорю «нет», потому что блокчейн — это упорядоченный набор блоков, каждый из которых содержит упорядоченный набор транзакций. В более широком смысле блокчейн представляет собой хорошо упорядоченный набор транзакций, начиная с первой транзакции в или после блока 0.

Вот кикер.

Он предназначен для просмотра по порядку из-за того, что блоки после блока генезиса не могут быть проверены независимо без ссылки на предыдущий блок. Другими словами, чтобы знать, что вы смотрите на подлинный 50-й блок (согласно консенсусу), вы должны знать блок 49. Если вы начнете с конца, вы, как правило, будете либо рекурсивно применять логику вплоть до блока 0 или доверьтесь чему-то другому, кроме собственной независимой оценки.

Кроме того, вы никогда не узнаете, что у вас есть последний блок. Самое большее, что вы можете знать, это то, что у вас есть последний блок, о котором вы знаете (и, возможно, еще более новый на подходе). Что, будет первым в списке событий, начиная с самого нового? Это не продлится очень долго.

Чтобы выполнить что-то похожее на ваш вариант использования, похоже, подразумевается прослушивание всех известных событий и постоянная вставка новых «самых последних» блоков в начале списка. Или (вероятно, более эффективно) добавить самые новые в конец вашего собственного списка, а затем прочитать его в обратном порядке, когда вам нужно. Это, вероятно, будет связано с проблемами вне сети (пользовательский интерфейс, кеш, что-то еще ...) - возможно, моментальные снимки «на момент времени» или оперативные обновления по мере появления новых «самых последних» записей журнала.

Совершенно справедливо поддерживать свои собственные источники данных вне сети для повышения производительности и по другим причинам. Вы по-прежнему можете пользоваться преимуществами блокчейна, когда пользователи/клиенты могут проверять факты , если захотят , подтверждая факты своей собственной копией цепочки. Это примерно то, что происходит, когда вы используете онлайн-обозреватели блоков и другие приложения, которым требуется большая производительность, чем может обеспечить обычный узел. Вы можете сортировать такие вещи как угодно.

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

ОБНОВИТЬ

Существует шаблон для эффективного выполнения этого , если вы разрабатываете контракт для его поддержки. Он использует очень простые хлебные крошки:

pragma solidity 0.5.1;

contract ReverseOrderEvents {

    uint lastEventBlock;

    event LogEvent(address sender, uint previousEvent);

    function doSomething() public {
        emit LogEvent(msg.sender, lastEventBlock);
        lastEventBlock = block.number;
    }
}

На стороне клиента, когда lastEvent != 0затем перейти к этому блоку и «прослушать» интересующие события. Это событие будет включать указатель на блок, содержащий предыдущее событие. Промыть и повторить. Когда вы нажимаете 0, предыдущих событий нет.

Этот метод прост, и вы можете использовать отдельные указатели для отдельных журналов, отдельных пользователей и т. д., если это необходимо, чтобы клиенты могли быстро находить наиболее важную последнюю информацию.

Это позволяет клиенту начать с самого последнего и вернуться назад, насколько это необходимо. Шаблон можно использовать в проектах без сохранения состояния, когда данные находятся в журнале событий и, возможно, важна только самая последняя запись.

На всякий случай, если это не ясно, watch()не идет в обратном направлении. Чтобы использовать это, вы должны watch()только один блок (что было бы быстро), найти то, что вам нужно, а затем watch()следующий отдельный блок интересов, следуя подсказкам в обратном порядке, которые вы составили для себя.

ТЫ. Я понял вашу точку зрения, но я не пытаюсь следить за событиями. Это должен быть очень простой алгоритм. Я просто хочу получить события из последнего номера блока в меньший. Я могу зарегистрировать их на своей локальной машине, но я не хочу этого делать. Почему мы не можем получить их от последнего к меньшему, если мы можем получить их от меньшего к большему. Я все еще считаю, что это может быть реализовано на стороне web3, что на самом деле может быть полезной функцией. @Роб Хитченс
Кажется, я объяснил, почему его нет. Знаете ли вы, что вы можете расширить web3библиотеку самостоятельно?
Не могли бы вы помочь мне с расширением web3, могу ли я написать код на их github? Мое лучшее решение — хранить развернутые функции blockNumber и обновлять его, если есть обновление, которое будет указывать на точный номер блока обновленного события. @Роб Хитченс
@RobHitchens Я думаю, что модель полностью на стороне клиента будет работать, поскольку вы можете получить самый последний известный номер блока на клиенте, а затем программно, используя этот номер блока, проверить наличие события, используя getвместо watch, для опроса, и если не получить уменьшите номер блока на единицу и повторите процесс, это увеличит затрачиваемое время, но избавит вас от необходимости добавлять что-либо в смарт-контракт. @alper Вам потребуются сложности либо на стороне клиента, либо намеренно структурированный контракт, чтобы достичь этого, афаик.
Ваш обновленный ответ - это решение, которое я объяснил на свой вопрос... uint lastEventBlockвызовет дополнительное хранилище памяти. Я пытаюсь найти решение, при котором в контракте не будет дополнительного использования хранилища. @РобХитченс