Tengo un ABI y el input
valor de la transacción y quiero saber qué función se ha llamado en un contrato y con qué argumentos (uno o varios de diferentes tipos), preferiblemente usando geth
, JSON-RPC
y algún pseudocódigo que luego pueda traducir a Ruby.
Hay un par de preguntas similares sobre SO, pero ninguna de ellas realmente respondió la pregunta de una manera que sea comprensible para alguien nuevo en Ethereum.
Como ejemplo, uso el MetaCoin
contrato generado por Truffle . Llamo al método getBalance('0xfd46f749f9d916122fe958d7f8d5ad033b187472')
y obtengo la entrada 0xf8b2cb4f000000000000000000000000fd46f749f9d916122fe958d7f8d5ad033b187472
.
trufa(desarrollo)> web3.eth.getTransaction('0x5d7a91c9f068d723ac52480c0ef61b9bf3f7b52dc726046e0b47f1beaa2f44ff') { hash: '0x5d7a91c9f068d723ac52480c0ef61b9bf3f7b52dc726046e0b47f1beaa2f44ff', una vez: 5, bloqueHash: '0xd150b520eb69a621a7218722c0de5b270c9abc499a90a81ca96340e274599c28', número de bloque: 6, índice de transacción: 0, de: '0xfd46f749f9d916122fe958d7f8d5ad033b187472', a: '0x8dec2f9cccbe718c7c51e9154f223eb226bb7942', valor: { [Cadena: '0'] s: 1, e: 0, c: [ 0 ] }, gasolina: 4712388, preciogas: { [String: '100000000000'] s: 1, e: 11, c: [ 100000000000 ] }, entrada: '0xf8b2cb4f0000000000000000000000000fd46f749f9d916122fe958d7f8d5ad033b187472' }
El ABI es el siguiente:
[ { "constante": falso, "entradas": [ { "nombre": "dirección", "tipo": "dirección" } ], "nombre": "obtenerBalanceInEth", "salidas": [ { "nombre": "", "tipo": "uint256" } ], "a pagar": falso, "tipo": "función" }, { "constante": falso, "entradas": [ { "nombre": "receptor", "tipo": "dirección" }, { "nombre": "cantidad", "tipo": "uint256" } ], "nombre": "enviarCoin", "salidas": [ { "nombre": "suficiente", "tipo": "bool" } ], "a pagar": falso, "tipo": "función" }, { "constante": falso, "entradas": [ { "nombre": "dirección", "tipo": "dirección" } ], "nombre": "obtener Saldo", "salidas": [ { "nombre": "", "tipo": "uint256" } ], "a pagar": falso, "tipo": "función" }, { "entradas": [], "a pagar": falso, "tipo": "constructor" }, { "anónimo": falso, "entradas": [ { "indexado": cierto, "nombre": "_de", "tipo": "dirección" }, { "indexado": cierto, "nombre": "_a", "tipo": "dirección" }, { "indexado": falso, "nombre": "_valor", "tipo": "uint256" } ], "nombre": "Transferir", "tipo": "evento" } ]
¿Cómo puedo decodificar cualquier entrada para saber qué método se llamó y qué argumentos se pasaron?
Actualizar
He agregado todos los datos del bloque con el campo de entrada en la parte inferior de los registros.
{"number"=>"0x09",
"hash"=>"0xf543eba0c80d49beea1f934c0f0ad9f0babe272a8318312545d43e6b612e4006",
"parentHash"=>
"0xde7a61e8dd84b5e080da8e16430951f7f138347c77ed263d0093e367c9d30775",
"nonce"=>"0x0",
"sha3Uncles"=>
"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"logsBloom"=>
"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"transactionsRoot"=>
"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot"=>
"0x269cfa04ca1fe73202f788397ece62c520c64d5da7225ba2af2d673a2e9892f2",
"receiptRoot"=>
"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"miner"=>"0x0000000000000000000000000000000000000000",
"difficulty"=>"0x0",
"totalDifficulty"=>"0x0",
"extraData"=>"0x0",
"size"=>"0x03e8",
"gasLimit"=>"0x47e7c4",
"gasUsed"=>"0x5a3e",
"timestamp"=>"0x58c83fda",
"transactions"=>
[{"hash"=>
"0xce1eaf03dd1dfa5898243711ebcc1dc5c6357701f5a6c19f0b1f84130cb651fa",
"nonce"=>"0x08",
"blockHash"=>
"0xf543eba0c80d49beea1f934c0f0ad9f0babe272a8318312545d43e6b612e4006",
"blockNumber"=>"0x09",
"transactionIndex"=>"0x0",
"from"=>"0xfd46f749f9d916122fe958d7f8d5ad033b187472",
"to"=>"0x8dec2f9cccbe718c7c51e9154f223eb226bb7942",
"value"=>"0x0",
"gas"=>"0x47e7c4",
"gasPrice"=>"0x174876e800",
"input"=>
"0xf8b2cb4f000000000000000000000000fd46f749f9d916122fe958d7f8d5ad033b187472"}],
"uncles"=>[]}
Puede consultar un paquete desarrollado por Consensys https://github.com/ConsenSys/abi-decoder
getBalance
), el nombre de cada argumento pasado en ( receiver
) y el valor pasado en ( 0xfd46f749f9d916122fe958d7f8d5ad033b187472
) para cada argumento. Sin embargo, ¿no devuelve el tipo de argumento?Ah ok, entiendo lo que preguntas. Puede hacer esto web3.toAscii(transactionID.input)
para obtener un formato legible por humanos.
Consulte web3.toAscii
https://github.com/ethereum/wiki/wiki/JavaScript-API#web3toascii
Así que con tu código sería:
transaction = web3.eth.getTransaction('0x5d7a91c9f068d723ac52480c0ef61b9bf3f7b52dc726046e0b47f1beaa2f44ff')
input = web3.toAscii(transaction.input)
console.log(input)
'ø²ËO\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000ýF÷IùÙ\u0016\u0012/éX×øÕ\u0003;\u0018tr'
da No estoy familiarizado con Ascii y no sé cómo podría deducir de esta cadena que getBalance(address)
se llamó al método con el argumento 0xfd46f749f9d916122fe958d7f8d5ad033b187472
.Ahora puede utilizar la web3.eth.abi.decodeLog
función (web3 1.0).
Ejemplo de la documentación:
web3.eth.abi.decodeLog([{
type: 'string',
name: 'myString'
},{
type: 'uint256',
name: 'myNumber',
indexed: true
},{
type: 'uint8',
name: 'mySmallNumber',
indexed: true
}],
'0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000748656c6c6f252100000000000000000000000000000000000000000000000000',
['0x000000000000000000000000000000000000000000000000000000000000f310', '0x0000000000000000000000000000000000000000000000000000000000000010']);
> Result {
'0': 'Hello%!',
'1': '62224',
'2': '16',
myString: 'Hello%!',
myNumber: '62224',
mySmallNumber: '16'
}
Puede usar la herramienta ethereum-input-data-decoder para decodificar datos de entrada de transacciones dada la ABI.
Ejemplo:
const InputDataDecoder = require('ethereum-input-data-decoder');
const decoder = new InputDataDecoder(`${__dirname}/abi.json`);
const data = `0x67043cae0000000000000000000000005a9dac9315fdd1c3d13ef8af7fdfeb522db08f020000000000000000000000000000000000000000000000000000000058a20230000000000000000000000000000000000000000000000000000000000040293400000000000000000000000000000000000000000000000000000000000000a0f3df64775a2dfb6bc9e09dced96d0816ff5055bf95da13ce5b6c3f53b97071c800000000000000000000000000000000000000000000000000000000000000034254430000000000000000000000000000000000000000000000000000000000`;
const result = decoder.decodeData(data);
console.log(result);
{
"name": "registerOffChainDonation",
"types": [
"address",
"uint256",
"uint256",
"string",
"bytes32"
],
"inputs": [
<BN: 5a9dac9315fdd1c3d13ef8af7fdfeb522db08f02>,
<BN: 58a20230>,
<BN: 402934>,
"BTC",
<Buffer f3 df ... 71 c8>
]
}
En el nuevo web3.js 1.0 debe usar: web3.utils.toAscii(transaction.input)
.
Algunas veces debe hacer una let input = transaction.input.replace(/^0x/, ``);
para eliminar estos caracteres inútiles desde el inicio de la cadena.
Ver documentos .
Samuel Hawksby-Robinson
migu