Двоичные данные журнала программы

Проблема

В Solidity нет поддержки регистрации двоичных данных.

События в Solidity

В Solidity можно сообщать о событиях. Они выглядят как структуры с нулем или более полей и могут быть испущены с определенными значениями. Например:

event PaymentReceived {
    address sender;
    uint amount;
}

contract c {
    function pay() public payable {
        emit PaymentReceived(msg.sender, msg.value);
    }
}

События доступны только для записи с точки зрения Solidity/VM и записываются в блоки в записях tx.

Некоторые из этих полей могут быть помечены как «индексированные», что влияет на способ кодирования данных. Все неиндексированные поля кодируются eth abi в массив байтов переменной длины. Все проиндексированные поля входят в так называемые темы.

Темы представляют собой поля фиксированной длины в 32 байта. Максимум 4 темы; если тип не всегда умещается в 32 байта (например, строковые типы), то топик хешируется keccak256.

Первая тема — это хэш keccak256 подписи события, в данном случае keccak256('PaymentReceived(address,uint)'). Четыре оставшихся доступны для «индексированных» полей. Событие может быть объявлено «анонимным», и в этом случае первое поле не является хэшем подписи, и разрешено иметь 4 проиндексированных поля.

Прослушивание событий в клиенте

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

const Web3 = require('web3');
const url = 'ws://127.0.0.1:8546';
const web3 = new Web3(url);

var options = {
    address: '0xfbBE8f06FAda977Ea1E177da391C370EFbEE3D25',
    topics: [
        '0xdf50c7bb3b25f812aedef81bc334454040e7b27e27de95a79451d663013b7e17',
        //'0x0000000000000000000000000d8a3f5e71560982fb0eb5959ecf84412be6ae3e'
      ]
};

var subscription = web3.eth.subscribe('logs', options, function(error, result){
    if (!error) console.log('got result');
    else console.log(error);
}).on("data", function(log){
    console.log('got data', log);
}).on("changed", function(log){
    console.log('changed');
});

Для декодирования неиндексированных полей (данных) необходим abi контракта. Таким образом, тема сначала используется для обнаружения того, какое событие было использовано, а затем данные могут быть декодированы.

Ethereum Tx в блоке

Транзакция вызывает журналы событий. Вот tx с одним событием, с 3 темами и некоторыми данными.

{
  "tx": {
    "nonce": "0x2",
    "gasPrice": "0xf224d4a00",
    "gas": "0xc350",
    "to": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
    "value": "0x0",
    "input": "0xa9059cbb000000000000000000000000a12431d0b9db640034b0cdfceef9cce161e62be40000000000000000000000000000000000000000000000a030dcebbd2f4c0000",
    "hash": "0x98a67f0a35ebc0ac068acf0885d38419c632ffa4354e96641d6d5103a7681910",
    "blockNumber": "0xc96431",
    "from": "0x82f890D638478d211eF2208f3c1466B5Abf83551",
    "transactionIndex": "0xe1"
  },
  "receipt": {
    "gasUsed": "0x74d2",
    "status": "0x1",
    "logs": [
      {
        "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
        "topics": [
          "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
          "0x00000000000000000000000082f890d638478d211ef2208f3c1466b5abf83551",
          "0x000000000000000000000000a12431d0b9db640034b0cdfceef9cce161e62be4"
        ],
        "data": "0x0000000000000000000000000000000000000000000000a030dcebbd2f4c0000"
      }
    ]
  }
}

Дополнительные соображения

В Ethereum события хранятся в блоках. События отмечают определенные изменения состояния в смарт-контрактах. Это служит двум целям:

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

Предложенное решение

Двоичное ведение журнала должно быть добавлено в журнал программы. Журнал программы должен включать данные в кодировке base64 (разрешено ноль или более единиц).

Итак, если мы сначала закодируем темы, а затем данные, то событие в tx выше будет выглядеть так:

program data: 3fJSrRviyJtpwrBo/DeNqpUrpFjxKEWKPVaTfUjs8AAAAAAAAAAAAAAACC+JDWOEeNIR7yII88FGa1q/g1UQAAAAAAAAAAAAAAAKEkMdC522QANLDN/O75zOFh5ivk AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgMNzrvS9MAAA=

Для этого требуется новый системный вызов:

void sol_log_data(SolBytes *fields, uint64_t length);

Соображения