Как вызвать метод контракта с использованием API-интерфейса eth_call JSON-RPC

Хорошо, поэтому я пытаюсь вызвать метод контракта, используя методы, предоставляемые интерфейсом RPC Ethereum JSON. JSON RPC работает на машине Ubuntu. К сожалению, я не могу получить результат от тестового контракта, который я создал.

Первое, что я сделал, это запустить Go Ethereum в Testnet с помощью:

geth --rpc --testnet

Затем я открою другую консоль и откройте консоль JS с помощью

geth attach

Затем я скомпилировал свой контракт с использованием Browser Solidity, где мой код:

 contract test { function double(int a) returns(int) {   return 2*a;   } }

Что дает мне следующий байтовый код:

606060405260728060106000396000f360606040526000357c0100000000000000000000000000000000000000000000000000000000900480636ffa1caa146037576035565b005b604b60048080359060200190919050506061565b6040518082815260200191505060405180910390f35b6000816002029050606d565b91905056

Затем я создал контракт с:

curl localhost:8545 -X POST --data '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{"from": "0x8aff0a12f3e8d55cc718d36f84e002c335df2f4a", "data": "606060405260728060106000396000f360606040526000357c0100000000000000000000000000000000000000000000000000000000900480636ffa1caa146037576035565b005b604b60048080359060200190919050506061565b6040518082815260200191505060405180910390f35b6000816002029050606d565b91905056"}],"id":1}

Что возвращает мне хеш транзакции, который я использую для получения адреса контракта:

curl localhost:8545 -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["0x8290c22bd9b4d61bc57222698799edd7bbc8df5214be44e239a95f679249c59c"],"id":1}'

Что возвращает мне следующее:

{"id":1,"jsonrpc":"2.0","result":{"transactionHash":"0x8290c22bd9b4d61bc57222698799edd7bbc8df5214be44e239a95f679249c59c","transactionIndex":"0x0","blockNumber":"0xd32da","blockHash":"0xf13f185f0eb1e4797885400e3b371c972eedebcf3eef27815a45b649283ec669","cumulativeGasUsed":"0x14293","gasUsed":"0x14293","contractAddress":"0x5c7687810ce3eae6cda44d0e6c896245cd4f97c6","logs":[]}}

Затем мне захотелось вызвать метод «double» с номером «5». В документации по контракту ABI говорится, что вам нужно взять первые 4 байта хеша Keccak.
Подпись метода

double(int)

Что дает хэш с web3.sha3 ("double (int)":

6740d36c7d42fba12b8eb3b047193c9761224c267d7a2e96dc50949860652317

Первые четыре байта с префиксом «0x»:

0x6740d36c

Документация затем сообщает, чтобы взять параметр, закодировать его в шестнадцатеричном виде и оставить его до 32 байтов. Который будет следующим, используя число «5»:

0x0000000000000000000000000000000000000000000000000000000000000005

В общем случае закодированная строка должна выглядеть так:

0x6740d36c0000000000000000000000000000000000000000000000000000000000000005

Итак, используя это для вызова метода:

 curl localhost:8545 -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"from": "0x8aff0a12f3e8d55cc718d36f84e002c335df2f4a", "to": "0x5c7687810ce3eae6cda44d0e6c896245cd4f97c6", "data": "0x6740d36c0000000000000000000000000000000000000000000000000000000000000005"}, "latest"],"id":1}'

Что дает мне этот результат:

{"id":1,"jsonrpc":"2.0","result":"0x"}

Я делаю что-то неправильно здесь или забываю о важном шаге?

Кроме того, есть ли способ получить доступ к уже существующим методам в библиотеке Go Ethereum, которая избавит меня от необходимости реализовывать, например, методы, которые могут быть заполнены самим?

Спасибо вам большое заблаговременно!

35 голосов | спросил MethDamon 2 Maypm16 2016, 22:16:34

3 ответа


52

Резюме

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

  • Мне пришлось использовать сигнатуру метода double(int256) вместо double(int), чтобы получить код eth_call JSON -RPC для работы.



Подробности

Запустите свой geth Экземпляр

Вы можете использовать цепочку Testnet , синхронизированную с другими одноранговыми узлами через Интернет, или вы можете использовать целую цепочку Dev , которая доступна только на вашем компьютере и быстрее развивать с. Параметр --rpc позволит вам использовать curl для связи с вашим экземпляром geth.

Блок тестовой блокировки

Вам нужно будет создать учетную запись и мои монеты, так как вам нужны монеты, чтобы вставить ваш код в блок-цепочку или отправить транзакции в блок-цепочку:

geth --testnet account new
Your new account is locked with a password. Please give a password. Do not forget this password.
Passphrase: 
Repeat Passphrase: 
Address: {aaaa725f2f36a28c01bc47f883534990c9c8bbbb}

Ваш экземпляр geth должен будет синхронизировать цепочку цепочек Testnet с другими одноранговыми узлами в Интернете. Это может занять и час или больше. После синхронизации ваша операция по добыче начнется, и вы должны раздобыть несколько монет за 10 или 20 минут. Запустите geth с параметрами интеллектуального анализа:

geth --testnet --rpc --mine --minerthreads 1 console

Чтобы проверить, есть ли у вас монеты, выполните команду:

> web3.fromWei(eth.getBalance(eth.accounts[0]), "ether");
25

Если вы хотите выйти из geth, нажмите Control-D.

Если вы хотите, вы можете запустить экземпляр geth без параметров интеллектуального анализа данных, так как другой экземпляр geth где-то в Интернете будет обрабатывать ваши транзакции. Используйте следующую команду, чтобы удалить параметр интеллектуального поиска или просто использовать предыдущую команду geth:

geth --testnet --rpc console

Dev Blockchain

Вам нужно будет создать учетную запись и мои монеты:

geth --dev account new
Your new account is locked with a password. Please give a password. Do not forget this password.
Passphrase: 
Repeat Passphrase: 
Address: {cccc725f2f36a28c01bc47f883534990c9c8dddd}

Запустите geth с параметрами --miner и --minerthreads, так как ваш экземпляр geth мой собственный блокчейн:

geth --dev --rpc --mine --minerthreads 1 console


Сгладьте свой код и назначьте переменную

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

В вашем примере ваш код обычно будет отформатирован для удобства чтения:

contract Test { 
    function double(int a) constant returns(int) {
        return 2*a;
    } 
}

Вы можете использовать такую ​​услугу, как Инструмент для удаления строк> или перейдите в Как загрузить исходный файл Solidity в geth для некоторых альтернатив.

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

contract Test { function double(int a) constant returns(int) { return 2*a; } }

Вам нужно будет присвоить свой код строковой переменной:

var testSource='contract Test {  function double(int a) constant returns(int) { return 2*a; } }'

Обратите внимание, что комментарии // вызовут некоторые проблемы, если ваш код будет сглажен, поскольку весь текст после комментария // будет рассматриваться как комментарий. Используйте /* ... */, если вам нужно добавить комментарии к вашему коду.


Скомпилируйте свой код

В вашем экземпляре geth введите свой сплющенный код с присвоением переменной. Не беспокойтесь о результатах undefined, так как это нормальный ответ от geth:

> var testSource='contract Test {  function double(int a) constant returns(int) { return 2*a; } }'
undefined

Скомпилируйте свой код:

> var testCompiled = web3.eth.compile.solidity(testSource);
I0503 09:04:15.907715    3190 solidity.go:114] solc, the solidity compiler commandline interface
Version: 0.3.2-0/Release-Linux/g++/Interpreter

path: /usr/bin/solc
undefined

Если вы хотите увидеть двоичную форму своегокод:

testCompiled
{
  Test: {
    code: "0x6060604052602a8060106000396000f3606060405260e060020a60003504636ffa1caa8114601a575b005b6002600435026060908152602090f3",
    info: {
      abiDefinition: [{...}],
      compilerOptions: "--bin --abi --userdoc --devdoc --add-std --optimize -o /tmp/solc497335011",
      compilerVersion: "0.3.2",
      developerDoc: {
        methods: {}
      },
      language: "Solidity",
      languageVersion: "0.3.2",
      source: "contract Test {  function double(int a) constant returns(int) { return 2*a; } }",
      userDoc: {
        methods: {}
      }
    }
  }
}

Для вашего контракта вам понадобится подпись Application Binary Interface (ABI), если вы хотите получить доступ к своей функции вне этого сеанса geth:

> testCompiled.Test.info.abiDefinition
[{
    constant: true,
    inputs: [{
        name: "a",
        type: "int256"
    }],
    name: "double",
    outputs: [{
        name: "",
        type: "int256"
    }],
    type: "function"
}]

Примечание . Это второй намек на то, почему ваш JSON-вызов RPC не работал - подпись метода имеет int256 для a вместо int.


Вставьте свой код в блок-цепочку

Запустите следующие команды, чтобы вставить код в цепочку:

> var testContract = web3.eth.contract(testCompiled.Test.info.abiDefinition);
undefined
> var test = testContract.new({
    from:web3.eth.accounts[0], 
    data: testCompiled.Test.code, gas: 2000000}, 
    function(e, contract) {
      if (!e) {
        if (!contract.address) {
          console.log("Contract transaction send: TransactionHash: " +
            contract.transactionHash + " waiting to be mined...");
        } else {
          console.log("Contract mined! Address: " + contract.address);
          console.log(contract);
        }
    }
})
I0503 09:09:39.632499    3190 xeth.go:1026] Tx(0x8c15e8b8bb593d4a680b084a455ba82b103e60204638a3674ef1fb90ca0ad4f0) created: 0x7a2d8fa11aa28097135eb514f6a23ba12501191e
Contract transaction send: TransactionHash: 0x8c15e8b8bb593d4a680b084a455ba82b103e60204638a3674ef1fb90ca0ad4f0 waiting to be mined...
undefined

Подождите несколько минут, и вы увидите следующий вывод:

I0503 09:10:34.319772    3190 worker.go:569] commit new work on block 11122 with 0 txs & 0 uncles. Took 431.081µs
Contract mined! Address: 0x7a2d8fa11aa28097135eb514f6a23ba12501191e
[object Object]

Вы должны сохранить адрес, если хотите выполнить этот контракт вне своего сеанса geth.


Используйте свой контракт внутри одного сеанса geth

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

> test.double(5)
invalid address

Примечание . Это первый намек на то, почему ваш JSON-вызов RPC не удался.

Чтобы использовать свой контракт в рамках сеанса geth, ПОСЛЕ добавления constant к функции double:

> test.double(5)
10
> test.double(55)
110


Используйте свой контракт, используя curl И JSON-RPC

И теперь мы попадаем в сложную часть.

Ваша функция double(int) действительно double(int256). Из Solidity-Types :

  

intâ € ¢ /uintâ € ¢: Целочисленные и неподписанные целые числа разных размеров. Ключевые слова от uint8 до uint256 с шагом 8 (без знака от 8 до 256 бит) и от int8 до int256. uint и int - псевдонимы для uint256 и int256 соответственно.

В geth, мы запускаем следующую команду, чтобы найти подпись функции double(...):

> web3.sha3('double(int256)')
"6ffa1caacdbca40c71e3787a33872771f2864c218eaf6f1b2f862d9323ba1640"

И возьмите первые 4 байта, чтобы создать параметр data

0x6ffa1caa0000000000000000000000000000000000000000000000000000000000000005

И используя адрес из параметра «Подключенный контракт», мы создаем следующую команду curl:

curl localhost:8545 -X POST --data '{"jsonrpc":"2.0", "method":"eth_call", "params":[{"from": "eth.accounts[0]", "to": "0x65da172d668fbaeb1f60e206204c2327400665fd", "data": "0x6ffa1caa0000000000000000000000000000000000000000000000000000000000000005"}], "id":1}'

И запустите эту команду из командной строки:

[email protected]:~$ curl localhost:8545 -X POST --data '{"jsonrpc":"2.0", "method":"eth_call", "params":[{"from": "eth.accounts[0]", "to": "0x65da172d668fbaeb1f60e206204c2327400665fd", "data": "0x6ffa1caa0000000000000000000000000000000000000000000000000000000000000005"}], "id":1}'
{"id":1,"jsonrpc":"2.0","result":"0x000000000000000000000000000000000000000000000000000000000000000a"}

Результатом 0x0000...000a является значение 10.


Обновление от 18 октября 2016 г.

Как указано в ошибке RPC "недопустимое или отсутствующее значение для параметров" при вызове константы контракта void , вам может потребоваться добавить параметр блока в список params. Ваша команда с параметром блока будет:

[email protected]:~$ curl localhost:8545 -X POST --data '{"jsonrpc":"2.0", "method":"eth_call", "params":[{"from": "eth.accounts[0]", "to": "0x65da172d668fbaeb1f60e206204c2327400665fd", "data": "0x6ffa1caa0000000000000000000000000000000000000000000000000000000000000005"}, "latest"], "id":1}'
{"id":1,"jsonrpc":"2.0","result":"0x000000000000000000000000000000000000000000000000000000000000000a"}

Вам также может потребоваться оставить параметр from.

Литература:


Другой вопрос

  

Кроме того, есть ли способ получить доступ к уже существующим методам в библиотеке Go Ethereum, которая избавит меня от необходимости реализовывать, например, методы, которые могут быть заполнены самим?

Не могли бы вы спросить об этом в другом вопросе, поскольку этот ответ уже слишком длинный.

ответил The Officious BokkyPooBah 3 Mayam16 2016, 01:22:41
4

Чтобы использовать eth_call, сложная часть предоставляет данные data, которая

Закладки и динамические типы должен быть указан правильно. В этом примере аргумент double(int256) > web3.sha3('double(int256)').substr(0, 8) "6ffa1caa" просто дополняется:

int256

Объединение приведенного выше дает:

0x6ffa1caa0000000000000000000000000000000000000000000000000000000000000005

, который эффективно означает 5 и указывает его как 0000000000000000000000000000000000000000000000000000000000000005 :

  

curl localhost: 8545 -X POST --data '{"jsonrpc": "2.0",   "method": "eth_call", "params": [{"from": "0xsenderAccount", "to":   «0xcontractAddress», «data»:   "0x6ffa1caa0000000000000000000000000000000000000000000000000000000000000005"}],   "Идентификатор": 1} '

double(5) - это адрес вызываемого контракта, а data - это учетная запись отправителя (обычно to)) .


EDIT: больше информации о «сложной части предоставляет from»:

web3.js можно настроить и eth.accounts[0] , например:

  

var myCallData = myContractInstance.myMethod.getData (param1 [, param2,   ...]);

(В этом случае можно также рассмотреть возможность включения web3.js для вызова data вместо использования getData JSON-RPC.)

ответил eth 16 Mayam16 2016, 01:37:18
4

Рассмотрите возможность разблокировки учетной записи перед отправкой транзакции:

personal.unlockAccount(eth.accounts[0], 'your password goes here', 9000)

или вызов RPC:

curl your_ethereum_node_address:port -X POST --data '{"jsonrpc":"2.0","method":"personal_unlockAccount","params": ["your account address","password of your account",null],"id":1}'

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

ответил Michail Gede 29 Maypm16 2016, 23:13:34

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132