Создавать и подписывать необработанные транзакции OFFLINE?

Я хочу создать необработанную транзакцию, подписать ее и передать ее с помощью eth.sendRawTransactionметода RPC.

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

Не существует ни метода RPC для создания/подписания необработанной транзакции, ни каких-либо библиотек для этого (в автономном режиме).

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

Вопрос может быть разным, но ответы похожи/одинаковы. Я связываю это здесь для дальнейшего использования. Как отправить с холодного кошелька: ethereum.stackexchange.com/questions/1019/…

Ответы (6)

ethereumjs-tx — это библиотека с таким примером:

npm install ethereumjs-tx

const Tx = require('ethereumjs-tx').Transaction
var privateKey = new Buffer('e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', 'hex')

var rawTx = {
  nonce: '0x00',
  gasPrice: '0x09184e72a000', 
  gasLimit: '0x2710',
  to: '0x0000000000000000000000000000000000000000', 
  value: '0x00', 
  data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057'
}

var tx = new Tx(rawTx)
tx.sign(privateKey)

var serializedTx = tx.serialize()
console.log(serializedTx.toString('hex'))
ethereumjs-tx действительно великолепен. Вы также можете проверить этот инструмент, который я сделал для примера использования графического интерфейса для подписи транзакций на автономной машине: github.com/kobigurk/frozeth
@kobigurk К вашему сведению, если вы используете ethereumjs-utils для генерации закрытого/открытого ключа, вам необходимо как можно скорее обновить эту библиотеку. Была неприятная ошибка заполнения, которая иногда приводила к неправильному получению открытого ключа из закрытого ключа.
@eth Знаете ли вы какие-либо библиотеки Python для этого?
Есть github.com/ethereum/pyethereum/blob/develop/ethereum/… , но в настоящее время у меня нет примеров; Я могу отредактировать ответ, если что-то найду.
Существует ли какая-либо версия автономного подписывающего лица C#?
@Denis Денис, я не знаю, но я бы начал с github.com/Nethereum/Nethereum , а затем спросил бы их дальше в соответствии с их файлами readme.
Могу ли я запустить этот код на стороне веб-клиента? Или я должен использовать чистый код JS?
@eth, как я могу использовать этот код в json rpc.
@YogeshKarodiya Возьмите то, что выводит код, и это данные дляsendRawTransaction
@eth Я использую json rpc + curl, пожалуйста, обратитесь к этому вопросу ethereum.stackexchange.com/questions/29904/…
Правильный импорт в версии 2.1.2:const Tx = require('ethereumjs-tx').Transaction
@KirillBulgakov Спасибо, также обновил ответ на ваш комментарий.

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

transaction := types.NewTransaction(nonce, recipient, value, gasLimit, gasPrice, input)
signature, _ := crypto.Sign(transaction.SigHash().Bytes(), key)
signed, _ := tx.WithSignature(signature)

где ключ является равниной *ecdsa.PrivateKey. Если вы хотите использовать зашифрованные учетные записи Ethereum, вы можете взглянуть на AccountManager, который сделает за вас все причудливые криптографические вещи, и вы можете просто вызвать Signметод с входной транзакцией, чтобы подписать ее.

После того, как он будет подписан, вам все равно нужно объявить об этом через RPC в сети. Это уже реализовано для привязок Native DApp здесь: https://github.com/ethereum/go-ethereum/blob/develop/accounts/abi/bind/backends/remote.go#L202 , которые вы можете скопировать и вставить или, альтернативно, подождать немного, пока Феликс не закончит свой клиент RPC Go.

вы используете какую-либо библиотеку? Не поделитесь ссылкой на эту библиотеку? Знаете ли вы, есть ли реализация Python?
Это реализация go-ethereum. По сути, внутренности Гета. Мы стремимся к тому, чтобы Geth (в целом или по частям) использовался как библиотека в других проектах. Что касается Python, я не могу помочь. Без понятия.
Спасибо, Питер. Я хотел сделать простой исполняемый файл, чтобы сделать это. Это будет моей отправной точкой.
О какой cryptoбиблиотеке вы здесь говорите? А можно ссылку на ваш typesфайл?

Вы можете использовать Web3 .

var Accounts = require('web3-eth-accounts');

// Passing in the eth or web3 package is necessary to allow retrieving chainId, gasPrice and nonce automatically
// for accounts.signTransaction().
// var accounts = new Accounts('ws://localhost:8546');
var accounts = new Accounts();
// if nonce, chainId, gas and gasPrice is given it returns synchronous
accounts.signTransaction({
    to: '0xF0109fC8DF283027b6285cc889F5aA624EaC1F55',
    value: '1000000000',
    gas: 2000000,
    gasPrice: '234567897654321',
    nonce: 0,
    chainId: 1
}, '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318')

Выход:

{
    messageHash: '0x6893a6ee8df79b0f5d64a180cd1ef35d030f3e296a5361cf04d02ce720d32ec5',
    r: '0x09ebb6ca057a0535d6186462bc0b465b561c94a295bdb0621fc19208ab149a9c',
    s: '0x440ffd775ce91a833ab410777204d5341a6f9fa91216a6f3ee2c051fea6a0428',
    v: '0x25',
    rawTransaction: '0xf86a8086d55698372431831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca008025a009ebb6ca057a0535d6186462bc0b465b561c94a295bdb0621fc19208ab149a9ca0440ffd775ce91a833ab410777204d5341a6f9fa91216a6f3ee2c051fea6a0428'
}

Просто используйте rawTransaction.

Исходный код

Ваш ответ вдохновил меня написать для этого небольшой скрипт, который декодирует файл хранилища ключей. Это на gist.github.com/neuhaus/7387edf411513a9f11f1242dcec8d62e.

Я нашел способ, используя pyethereum lib.

Кстати, эта библиотека требует минимального обслуживания и не встраивается в большинство ОС.

Вот пример кода для этого:

from libs.pyethereum.ethereum import transactions
from libs.pyethereum.ethereum import utils

# Create the priv keys and addresses. Addresses are returned in bytearray
key = utils.sha3("this is an insecure passphrase")
key2 = utils.sha3("37Dhsg17e92dfghKa Th!s i$ mUcH better r920167dfghjiHFGJsbcm")
addr = utils.privtoaddr(key)
addr2 = utils.privtoaddr(key2)

# Bytearray addresses
addr
'\xb8\xa1\xe7\x0b\x90\xb2\x8c\xde\x1e\xf7@+\xc2\x80\xc5\xb5\xa3W\xb4\x99'
addr2
'R~\xde {\x07"\xde\xfd\x981\x84\xcdA\x81\xbe\x82b\xdf\x01'

# Encoding the addresses in hex
addr_hex = utils.decode_addr(addr)
addr_hex
'b8a1e70b90b28cde1ef7402bc280c5b5a357b499'
addr2_hex = utils.decode_addr(addr2)
addr2_hex
'527ede207b0722defd983184cd4181be8262df01'
# These addresses are better represented with a '0x' prefix


# Create a transaction using key (address 1 priv key) and addr2 in bytearray
tx = transactions.Transaction(0, 1000, 100000, addr2, 56789000, "").sign(key)
tx.to_dict()
{'nonce': 0,
'hash': '648f97b1127bd26e5aa2f9b19d711648cb42509f105fd1ac4c90314c60bb06b1',
'sender': '\xb8\xa1\xe7\x0b\x90\xb2\x8c\xde\x1e\xf7@+\xc2\x80\xc5\xb5\xa3W\xb4\x99',
'startgas': 100000, 'value': 56789000, 'to': 'R~\xde {\x07"\xde\xfd\x981\x84\xcdA\x81\xbe\x82b\xdf\x01',
's': 27174000365690764914673576881913711980121871729925928151256478086834586258233L,
'r': 38109765815193709364550029305417348322702924861956728590268128554533127943524L,
'v': 28L, 'data': '', 'gasprice': 1000
}
Как будет выглядеть транзакция, если я хочу составить транзакцию для вызова функции изменения состояния контракта? Как и где указать аргументы функции контракта.

Я написал полный код Python. Не стесняйтесь использовать:

def signTransaction(to, value, privkey, nonce=0, gasPrice=20000000000, gas=21000, data=""):
    from ethereum import transactions
    import rlp
    try:
        return { 'error':False, 'sign':rlp.encode(transactions.Transaction(nonce, gasPrice, gas, to, value, data).sign(privkey)).encode('hex') }
    except Exception as msg:
        return { 'error':True, 'message':msg }

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

  • В автономном режиме, как и в вашем личном ключе, никогда не покидает ваш компьютер

  • Он использует сервис etherscan.io, чтобы получить последний одноразовый номер и цену на газ.

  • Вы можете дополнительно предоставить вызов функции контракта и аргументы

Код:

  /**
   * Sign an Ethereum transaction offline.
   *
   *
   * To run:
   *
   *   nvm use 7.2.1
   *   ./node_modules/babel-cli/bin/babel-node.js --presets es2015 --plugins transform-async-to-generator ./src/offlinetx.js --private-key 0xaaaaaaaaaaaaaaaaaaa --value 0.95 --to 0xAaF2ac6b800398F671b0D24cb8FccC3897B6aE49 --api-key HHHHHHHHHHHHHHHHHHHHHH

   *
   */

  import Web3 from 'web3'; // https://www.npmjs.com/package/web3
  import argv from 'optimist';
  import {buildTx, getAddressFromPrivateKey} from './txbuilder';
  import {API} from './etherscan';

  let web3 = new Web3();

  let _argv = argv.usage("offlinetx $0 --api-key 0x0000000 --private-key 0x00000000000000 --value 1.20 --to 0x1231231231")
    .describe("value", "Transaction amount in ETH")
    .describe("private-key", "32 bytes private key has hexadecimal format")
    .describe("to", "Ethereum 0x address where to send")
    .describe("nonce", "Nonce as hexacimal format, like 0x1")
    .describe("api-key", "etherscan.io API key used to get network status")
    .describe("gas-limt", "Maximum gas limit for the transaction as a hexadecmial")
    .default("gas-limit", web3.toHex(200000))
    .string("private-key")  // Heurestics is number by default which doesn't work for bigints
    .string("to")
    .string("api-key")
    .string("value")
    .string("nonce")
    .string("gas-limit")
    .demand(["private-key", "value", "to"]);

  async function run(argv) {

    // Parse command line
    let apiKey = argv["api-key"];
    let privateKey = argv["private-key"];
    let value = argv["value"];
    let to = argv["to"];
    let nonce = argv["nonce"];
    let gasLimit = argv["gas-limit"];

    if(!privateKey) {
      console.error("No private key given");
      process.exit(1);
    }

    if(!apiKey) {
      console.error("No EtherScan.io API key given");
      process.exit(1);
    }

    // Build EtherScan.io API wrapper object
    const api = new API("https://api.etherscan.io/api", apiKey);

    let fromAddress = getAddressFromPrivateKey(privateKey);

    // If nonce is not given get it usig Etherscan
    if(!nonce) {
      nonce = await api.getTransactionCount(fromAddress);
    }

    let gasPrice = await api.getGasPrice();

    value = web3.toHex(web3.toWei(value, "ether"));

    // What goes into our transaction
    let txData = {
      contractAddress: to,
      privateKey: privateKey,
      nonce: nonce,
      functionSignature: null, // TODO: Add contract call support here
      functionParameters: null,
      value: value,
      gasLimit: gasLimit,
      gasPrice: gasPrice,
    };

    // User readable output
    let info = Object.assign({}, txData);
    info.fromAddress = fromAddress;
    info.gasLimitInt = parseInt(txData.gasLimit, 16);
    info.gasPriceInt = parseInt(txData.gasPrice, 16);
    info.weiValueInt = parseInt(txData.value, 16);
    console.log("Building transaction with parameters\n", info);

    let tx = buildTx(txData);

    console.log("Your raw transaction is: ", tx);
    console.log("Visit at https://etherscan.io/pushTx to broadcast your transaction.");

  }

  run(_argv.argv)
    .catch(function(e) {
      console.error(e);
    });