¿Crear y firmar transacciones sin procesar SIN CONEXIÓN?

Estoy buscando crear una transacción sin procesar, firmarla y transmitirla usando el eth.sendRawTransactionmétodo RPC.

Me gustaría hacer esto fuera de línea usando un código o una biblioteca de código abierto O en línea pero sin la necesidad de usar una billetera o software específico.

No hay un método RPC para crear/firmar la transacción sin procesar, ni puedo encontrar ninguna biblioteca para hacer esto (sin conexión).

Cualquier ayuda u orientación sobre cómo se podría lograr esto sería muy agradecida. Si hay una implementación de python, sería increíble.

La pregunta puede ser diferente pero las respuestas son similares/iguales. Estoy vinculando esto aquí para futuras referencias. Cómo enviar desde una billetera fría: ethereum.stackexchange.com/questions/1019/…

Respuestas (6)

ethereumjs-tx es una biblioteca con este ejemplo:

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 es realmente genial. También puede consultar esta herramienta que hice para ver un ejemplo de GUI de su uso para firmar transacciones en una máquina fuera de línea: github.com/kobigurk/frozeth
@kobigurk FYI, si está utilizando ethereumjs-utils para la generación de claves públicas/privadas, debe actualizar esa biblioteca lo antes posible. Hubo un error de relleno desagradable que daría lugar a que la clave pública incorrecta se derivara de la clave privada de vez en cuando.
@eth ¿Conoce alguna biblioteca de Python para hacer esto?
Hay github.com/ethereum/pyethereum/blob/develop/ethereum/… pero no tengo ejemplos actualmente; Puedo editar la respuesta si encuentro algo.
¿Hay alguna versión C# del firmante fuera de línea?
@Denis No lo sé, pero comenzaría con github.com/Nethereum/Nethereum y luego les preguntaría más según su archivo Léame.
¿Puedo ejecutar este código en un lado del cliente web? ¿O debería usar código JS puro?
@eth, ¿cómo puedo usar este código en json rpc?
@YogeshKarodiya Tome lo que genera el código y son los datos parasendRawTransaction
@eth Estoy usando json rpc + curl, consulte esta pregunta ethereum.stackexchange.com/questions/29904/…
Importación correcta en la versión 2.1.2:const Tx = require('ethereumjs-tx').Transaction
@KirillBulgakov Gracias, también actualicé la respuesta a tu comentario.

En Go, la creación de una transacción firmada se vería así:

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

donde la clave es un plano *ecdsa.PrivateKey. Si desea utilizar cuentas cifradas de Ethereum, puede echar un vistazo a AccountManager, que hace todas las funciones criptográficas sofisticadas por usted y simplemente puede llamar a un Signmétodo con una transacción de entrada para firmarlo.

Después de haberlo firmado, aún deberá anunciarlo a través de RPC a la red. Eso ya está implementado para los enlaces Native DApp aquí: https://github.com/ethereum/go-ethereum/blob/develop/accounts/abi/bind/backends/remote.go#L202 que puede copiar y pegar o, alternativamente, esperar un bit hasta que Felix termine su cliente RPC Go.

estas usando alguna libreria? ¿Puedes compartir el enlace a esa biblioteca? ¿Sabes si hay una implementación de python?
Esta es la implementación de go-ethereum. Esencialmente las partes internas de Geth. Nos esforzamos para que Geth (en su totalidad o en partes) se utilice como biblioteca en otros proyectos. Con respecto a Python, realmente no puedo ayudar. Ni idea.
Gracias Pedro. Estaba buscando hacer un ejecutable simple en go para hacer eso. Este será mi punto de partida.
¿ A qué cryptobiblioteca te refieres aquí? ¿También puede vincular a su typesarchivo?

Puedes usar 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')

Producción:

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

Solo rawTransactionusa

Código fuente

Su respuesta me inspiró a escribir un pequeño script para esto que decodifica un archivo de almacén de claves. Está en gist.github.com/neuhaus/7387edf411513a9f11f1242dcec8d62e

Encontré una manera de usar pyethereum lib.

Por cierto, esta biblioteca tiene poco mantenimiento y no se integra en la mayoría de los sistemas operativos.

Aquí está el código de muestra para eso:

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
}
¿Cómo se vería la transacción si quiero componer la transacción para llamar a una función de cambio de estado de un contrato? Cómo y dónde especificaría los argumentos a la función del contrato.

Escribí un código Python completo. Siéntete libre de usar:

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 }

Aquí hay una aplicación JavaScript de línea de comando para crear transacciones fuera de línea. También puede leer la entrada de blog del tutorial completo .

  • Fuera de línea como en su clave privada nunca sale de su computadora

  • Utiliza el servicio etherscan.io para obtener el último nonce y el precio del gas.

  • Además, puede proporcionar una llamada de función de contrato y argumentos

Código:

  /**
   * 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);
    });