nibiru icon indicating copy to clipboard operation
nibiru copied to clipboard

feat(evm): failed wasm precompile transaction don't propagate error message

Open matthiasmatt opened this issue 1 year ago • 5 comments

I had an error when creating a transaction for the wasm pre-compile (which came to a contract error in wasm). When querying the evm transaction, i just get failed true with no logs attached.

❯ curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"debug_traceTransaction","params":["0xd7371d317b2b62591225ecbb852e6a9206a60078f946cdc4311ab04d54f99b10"],"id":1}' http://localhost:8545
{"jsonrpc":"2.0","id":1,"result":{"failed":true,"gas":30000000,"returnValue":"","structLogs":[]}}

The only way i was able to see the error was with this debug print:

	data, err := p.Wasm.Execute(ctx, wasmContract, nibiruCaller, msgArgsBz, funds)
	if err != nil {
		fmt.Printf("Wasm execution failed: %v\n", err)
		return
	}

matthiasmatt avatar Mar 16 '25 14:03 matthiasmatt

Here's the erorr message from the receipt (wasmcaller)

error: transaction execution reverted (action="sendTransaction", data=null, reason=null, invocation=null, revert=null, transaction={ "data": "", "from": "0xC0f4b45712670cf7865A14816bE9Af9091EDdA1d", "to": "0x0000000000000000000000000000000000000802" }, receipt={ "_type": "TransactionReceipt", "blobGasPrice": null, "blobGasUsed": null, "blockHash": "0x52a038f4bf72b1564cb2f314521a376f5c89423ffa20cd94befb4f32904371d7", "blockNumber": 78, "contractAddress": "0x0000000000000000000000000000000000000000", "cumulativeGasUsed": "609662", "from": "0xC0f4b45712670cf7865A14816bE9Af9091EDdA1d", "gasPrice": "1000000000000", "gasUsed": "609662", "hash": "0xb91c43da8fe370bcffeee969bf8376953a702fb09924959b9c4c54d64b4019b9", "index": 0, "logs": [  ], "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "root": null, "status": 0, "to": "0x0000000000000000000000000000000000000802" }, code=CALL_EXCEPTION, version=6.13.5)
     action: "sendTransaction",
       data: null,
     reason: null,
 invocation: null,
     revert: null,
 transaction: {
  to: "0x0000000000000000000000000000000000000802",
  from: "0xC0f4b45712670cf7865A14816bE9Af9091EDdA1d",
  data: "",
},
    receipt: TransactionReceipt {
  provider: [Object ...],
  to: "0x0000000000000000000000000000000000000802",
  from: "0xC0f4b45712670cf7865A14816bE9Af9091EDdA1d",
  contractAddress: "0x0000000000000000000000000000000000000000",
  hash: "0xb91c43da8fe370bcffeee969bf8376953a702fb09924959b9c4c54d64b4019b9",
  index: 0,
  blockHash: "0x52a038f4bf72b1564cb2f314521a376f5c89423ffa20cd94befb4f32904371d7",
  blockNumber: 78,
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  gasUsed: 609662n,
  blobGasUsed: null,
  cumulativeGasUsed: 609662n,
  gasPrice: 1000000000000n,
  blobGasPrice: null,
  type: 2,
  status: 0,
  root: undefined,
  logs: [Getter],
  toJSON: [Function: toJSON],
  length: [Getter],
  fee: [Getter],
  getBlock: [AsyncFunction: getBlock],
  getTransaction: [AsyncFunction: getTransaction],
  getResult: [AsyncFunction: getResult],
  confirmations: [AsyncFunction: confirmations],
  removedEvent: [Function: removedEvent],
  reorderedEvent: [Function: reorderedEvent],
  [Symbol(Symbol.iterator)]: [Function],
},
 shortMessage: "transaction execution reverted",
       code: "CALL_EXCEPTION"

      at makeError (/Users/mdarblade/code/sai/scripts/node_modules/ethers/lib.esm/utils/errors.js:124:21)
      at assert (/Users/mdarblade/code/sai/scripts/node_modules/ethers/lib.esm/utils/errors.js:143:15)
      at checkReceipt (/Users/mdarblade/code/sai/scripts/node_modules/ethers/lib.esm/providers/provider.js:1119:13)
      at <anonymous> (/Users/mdarblade/code/sai/scripts/node_modules/ethers/lib.esm/providers/provider.js:1165:33)

matthiasmatt avatar Mar 16 '25 14:03 matthiasmatt

Can be replicated on SAI by setting the value on this branch from 2_000_000 to 200_000 for the gas limit.

https://github.com/NibiruChain/sai-perps/blob/3e2aa3a1711ad06a5b8b2d3c93f2df28f09e11ac/scripts/localnet_test/test_simple_evm.ts#L18

matthiasmatt avatar Mar 21 '25 19:03 matthiasmatt

TLDR; works as expected

Use debug_traceTransaction call to get error details.

Working example of debug_traceTransaction on testnet-2 (wasm precompile)

Sent wrong message to sai oracle contract via EVM:

curl -s -X POST --data '{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0x5644c4e9d47a896bc4660a615146cca3a5db39fc3d22b04c48c8df78665aa8f1", {"tracer": "callTracer"}],
  "id": 1
}' -H "Content-Type: application/json" https://evm-rpc.testnet-2.nibiru.fi/ | jq

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "error": "precompile error: failed to run precompileWasm: execute method called: Error parsing into type oracle::state::OraclesExecuteMsg: unknown variant `increment1`, expected one of `set_price`, `update_expiration_time`, `create_token`, `delete_token`, `create_permission_group`, `update_permission_group`, `delete_permission_group`, `update_ownership`: execute wasm contract failed [CosmWasm/[email protected]/x/wasm/keeper/keeper.go:395]",
    "from": "0xc0f4b45712670cf7865a14816be9af9091edda1d",
    "gas": "0xee770",
    "gasUsed": "0xee770",
    "input": "0x61ffaee4000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000003f6e696269316b61716471796a38737364757534747672736570756b34677565726a396871666b7a38337870726a61737a7563396b706b637473347a776b35710000000000000000000000000000000000000000000000000000000000000000127b22696e6372656d656e7431223a207b7d7d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
    "to": "0x0000000000000000000000000000000000000802",
    "type": "CALL",
    "value": "0x0"
  }
}

Working example of debug_traceTransaction on testnet-2 (funtoken precompile)

Here the tx tries to send more ERC20 than user has.

curl -s -X POST --data '{
  "jsonrpc": "2.0",
  "method": "debug_traceTransaction",
  "params": ["0xd67ca72bbea14d6a60f4e6895e6a2ed41db05a0d5fde5030255ca446d214d43f", {"tracer": "callTracer"}],
  "id": 1
}' -H "Content-Type: application/json" https://evm-rpc.testnet-2.nibiru.fi | jq

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "error": "precompile error: failed to run precompileFunToken: error in ERC20.transfer from caller to EVM account: CallContractError: VMError: execution reverted with reason \"ERC20: transfer amount exceeds balance\"",
    "from": "0xc0f4b45712670cf7865a14816be9af9091edda1d",
    "gas": "0x2b8d8",
    "gasUsed": "0x1e2bfc",
    "input": "0xa9059cbb000000000000000000000000603871c2ddd41c26ee77495e2e31e6de7f9957e000000000000000000000000000000000000000000000000000000002540be400",
    "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002645524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e63650000000000000000000000000000000000000000000000000000",
    "to": "0x7d4b7b8ca7e1a24928bb96d59249c7a5bd1dfbe6",
    "type": "CALL",
    "value": "0x0"
  }
}

ethers.js script to debug tx

const trace = await provider.send(
    'debug_traceTransaction', [
        tx.hash,
        {
            // Use callTracer for better visibility into the call stack
            tracer: 'callTracer',
            // Include return data to see error messages
            enableReturnData: true
        }
    ]);
console.log(JSON.stringify(trace, null, 2));

Proper flow (for apps):

  1. Send tx (eth_sendRawTransaction) -> returns tx hash
  2. Wait for tx (eth_getTransactionReceipt )
  3. If tx failed, call debug_traceTransaction to get error details.

onikonychev avatar Mar 28 '25 18:03 onikonychev

debug_traceTransaction was empty for me when running out of gas during wasm precompile operation:

❯ curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"debug_traceTransaction","params":["0xd7371d317b2b62591225ecbb852e6a9206a60078f946cdc4311ab04d54f99b10"],"id":1}' http://localhost:8545


{"jsonrpc":"2.0","id":1,"result":{"failed":true,"gas":30000000,"returnValue":"","structLogs":[]}}

matthiasmatt avatar Mar 28 '25 18:03 matthiasmatt

This is the log from 2 different txs from my local node:

  • First, a tx with not enough gas
  • Second, a tx with wrong msg

Image

expertdicer avatar Jun 13 '25 08:06 expertdicer