есть ли простой способ получить полное состояние контракта?

Я разрабатываю довольно сложный контракт со многими переменными состояния всех видов. (сопоставления, массивы, uint, строки, байты и т. д.).

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

Я хотел бы знать, есть ли простой способ получить это состояние из geth или web3.

Что-то типа:

var currentState = web3.eth.getFullState([Contract address]);

Было бы очень хорошо, если бы этот метод работал для любого контракта любого рода.

Состояние хранится как одно отображение из 256-битных целых чисел в 256-битные целые числа. Если вас устраивает это внутреннее представление, его можно получить (хотя, возможно, и не через JSON API), но если вам нужно что-то более полезное, например, имена переменных, это... немного сложнее.
Вы проверили test.ether.camp и live.ether.camp — я связал оба URL-адреса с примерами контрактов.

Ответы (3)

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

function getContractState(abi_object, contract_instance)
{
    "use strict";
    for (let i=0; i<abi_object.length;i++)
    {
        if (abi_object[i].constant==true &&
            abi_object[i].inputs.length==0&&
            abi_object[i].payable==false &&
            abi_object[i].type=="function")
        {
            console.log(abi_object[i].name+"="+contract_instance[abi_object[i].name].call());
        }
    }
}

Пример контракта:

contract StateTest
{
    uint public u;
    bool public  b;
    int  public  i;
    string public  s;
    byte   public  by;
    bytes  public  bs;
    address public  a;

    function StateTest()
    {
        u=1;
        b=true;
        i=-1;
        s="abc";
        by = 0x13;

        bs=new bytes(2);
        bs[0]=0x11;
        bs[1]=0xff;

        a = msg.sender;
    }
}

Выход:

a=0xa90fa13d754131a31cde816fa8ce7ad222d4a246
b=true
bs=0x11ff
by=0x13
s=abc
u=1
i=-1

Скопируйте ответ отсюда: Получение полного состояния смарт-контракта

Я создал репозиторий на Github с примером, показывающим, как читать все записи Patricia trie в блоке и в любом хранилище контрактов, используя nodejs https://github.com/medvedev1088/ethereum-merkle-patricia-trie-example .

var Trie = require('merkle-patricia-tree');
var rlp = require('rlp');
var levelup = require('levelup');
var leveldown = require('leveldown');
var db = levelup(leveldown('/your_home_dir/Library/Ethereum/rinkeby/geth/chaindata'));
var keccak256 = require('js-sha3').keccak256;

// the block state root, rinkeby, block number 1775804
// the block state root can be obtained by invoking web3.eth.getBlock(<blockNumber>) in `stateRoot` field
var root = '0xe4a6ff741ec2e0d0cd274a745756028df27312161bdb4557b6da434349f716a9';
var trie = new Trie(db, root);

trie.checkRoot(root, function (err, val) {
  console.log('Root exists:', val);
});

var address = '398A7A69f3c59181A1ffe34bed11DCb5DF863A8a';
var addressHash = keccak256(new Buffer(address, 'hex'));

trie.get('0x' + addressHash, function (err, val) {
  var decodedVal = rlp.decode(val);
  console.log(decodedVal);

  if (!decodedVal || decodedVal.length < 4) {
    console.log('The value for the address must be an array of 4 elements');
    return;
  }

  // 3rd element in the array is storage root, 1st - nonce, 2nd - balance, 4th - codeHash
  var storageRoot = decodedVal[2];
  console.log('storageRoot', storageRoot);

  trie.root = storageRoot;

  trie.checkRoot(storageRoot, function (err, val) {
    console.log('Storage root exists:', val);
  });

  // Read storage slot with index 0

  var slotZeroHash = keccak256(new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'));
  trie.get('0x' + slotZeroHash, function (err, val) {
    var decodedVal = rlp.decode(val);
    console.log('Value at slot 0: ', decodedVal);
  });

  // Read all entries from contract storage

  var stream = trie.createReadStream();

  stream.on('data', function (data) {
    console.log('key:' + data.key.toString('hex'));

    // values are rlp encoded
    var decodedVal = rlp.decode(data.value);
    console.log(decodedVal);
  });

  stream.on('end', function (val) {
    console.log('done reading!');
  });
});

Пример вывода:

Root exists: true
Account data: 398A7A69f3c59181A1ffe34bed11DCb5DF863A8a [ <Buffer 01>,
  <Buffer >,
  <Buffer 24 21 83 63 90 de b4 32 ce 0e ac fe 5f 49 be 88 99 17 bf 8a fa 07 72 24 1c 30 9e 61 e0 4a 0d 42>,
  <Buffer 61 60 55 49 c9 7c 3e 7a d6 68 63 3b 72 b2 60 d3 00 5e ab be f3 22 a2 d6 33 2a 49 76 80 89 77 7a> ]
Storage root: <Buffer 24 21 83 63 90 de b4 32 ce 0e ac fe 5f 49 be 88 99 17 bf 8a fa 07 72 24 1c 30 9e 61 e0 4a 0d 42>
Storage root exists: true
Value at slot 0 - key: 290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563
<Buffer 40 9f 9c d8 52 a3 ba e9 52 5d 2a aa>
key:0205d9ce8b4a26409d40486b0ac7b8dc356714e840016b19cc5c0f2c8adbcd74
<Buffer 36 35 c9 ad c5 de a0 00 00>
key:0249d346d51fad5ef0b6fae89b4907e63c831f4f8af088d602baef47cda4eab7
<Buffer 0a 07 64 07 d3 f7 44 00 00>

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

Вы должны взглянуть на эту ветку форума: http://forum.ethereum.org/discussion/2340/is-there-a-way-to-access-ethereum-smart-contracts-variables-by-name-in- javascript , где вы можете найти ссылки на Truffle и Pudding, два инструмента для абстрагирования контрактов и, таким образом, манипулирования ими и просмотра их состояния:

Трюфель: https://github.com/ConsenSys/truffle

Пудинг: https://github.com/ConsenSys/ether-pudding

Хотя теоретически это может ответить на вопрос, было бы предпочтительнее включить сюда основные части ответа и предоставить ссылку для справки.
Я не могу, так как сам ответ представляет собой код этих инструментов, как указано в моем ответе. Я не буду пропускать весь исходный код в ответе. Я уже абстрагировался от содержимого связанной ветки форума, так как две ссылки на github важны в этой ветке. Поэтому я думаю, что мой ответ соответствует правилам обмена стеками как есть.
При всем уважении, я думаю, вы неправильно поняли его вопрос. Он не спрашивает, как получить доступ к отдельным переменным (как спрашивает этот старый пост на форуме), а скорее, как получить полное состояние контракта за один раз. Ответ @NickJohnson ближе всего к тому, что он ищет. Я почти уверен, что такой разработчик, как jbaylina, уже хорошо знает такие инструменты, как Truffle и Embark.
@iurimatias, наверное, ты прав. Однако у меня нет лучшего ответа, поэтому не стесняйтесь отвечать, если можете.