Mysterious Behavior in Logs in Recipts on Failed Transactions

Hello everyone,

I’ve encountered a peculiar issue with different instances of our indexer that I hope some of you might shed some light on.

Context:

I have deployed an orderbook contract, and the code can be found here. This contract includes custom events that are logged and recorded by my indexer. The code for the indexer is available here.

Issue:

I’ve observed a strange behavior related to the logging of receipts. Specifically, my indexer still logs an event as if an order was created, even when the transaction has failed. Below are some details and screenshots:

Order Creation Error: Here’s the error for out-of-gas during the order creation process:

{
  "doc": "https://docs.rs/fuel-asm/latest/fuel_asm/enum.PanicReason.html#variant.OutOfGas",
  "reason": "OutOfGas"
}

Logs:
[
  {
    "order_id": "0x478c2031a1adedb6f657cb65f284e808816830f18df817c0d22fe2224700278e",
    "sender": {
      "Address": {
        "value": "0x0f9b6829c0fc83206ad6c62f863aec5c09bd643c1904ed3edfe0644322f1cb76"
      }
    },
    "timestamp": "0x400000006627ef28",
    "identifier": "OrderOpenEvent",
    "tx_id": "0xc3a0120245d2a5ad466165eb2df950a3471796e8b32b6dbe8a742c717cee3416",
    "order": {
      "id": "0x478c2031a1adedb6f657cb65f284e808816830f18df817c0d22fe2224700278e",
      "trader": {
        "value": "0x0f9b6829c0fc83206ad6c62f863aec5c09bd643c1904ed3edfe0644322f1cb76"
      },
      "base_token": {
        "value": "0x593b117a05f5ea64b39ba1f9bc3fb7e7a791c9be130e28376ad552eacdb3b746"
      },
      "base_size": {
        "value": "0x1426a5e",
        "negative": true
      },
      "base_price": "0x3ca5d8870e00"
    }
  }
]

Receipts:
[
  {
    "type": "Call",
    "from": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "to": "0x0f0c1065a7b82d026069c5cf070b21ee65713fd1ac92ec1d25eacc3100187f78",
    "amount": "0x1426a5e",
    "assetId": "0x593b117a05f5ea64b39ba1f9bc3fb7e7a791c9be130e28376ad552eacdb3b746",
    "gas": "0xab3b8",
    "param1": "0xe1d5749d",
    "param2": "0x28d0",
    "pc": "0x3000",
    "is": "0x3000"
  },
  {
    "type": "LogData",
    "id": "0x0f0c1065a7b82d026069c5cf070b21ee65713fd1ac92ec1d25eacc3100187f78",
    "val0": "0x0",
    "val1": "0x2e",
    "ptr": "0x23f30",
    "len": "0xf8",
    "digest": "0xee81d5aae0b12a40c8bbf492384a03da09505fd9532d31539d132d2164678cf0",
    "pc": "0x1d698",
    "is": "0x3000",
    "data": "0x478c2031a1adedb6f657cb65f284e808816830f18df817c0d22fe2224700278e00000000000000000f9b6829c0fc83206ad6c62f863aec5c09bd643c1904ed3edfe0644322f1cb76400000006627ef280000000000000000c3a0120245d2a5ad466165eb2df950a3471796e8b32b6dbe8a742c717cee34160000000000000001478c2031a1adedb6f657cb65f284e808816830f18df817c0d22fe2224700278e0f9b6829c0fc83206ad6c62f863aec5c09bd643c1904ed3edfe0644322f1cb76593b117a05f5ea64b39ba1f9bc3fb7e7a791c9be130e28376ad552eacdb3b7460000000001426a5e010000000000000000003ca5d8870e00"
  },
  {
    "type": "Panic",
    "id": "0x0f0c1065a7b82d026069c5cf070b21ee65713fd1ac92ec1d25eacc3100187f78",
    "reason": "0x225550000000000",
    "pc": "0x1d6b0",
    "is": "0x3000",
    "contractId": "0x0000000000000000000000000000000000000000000000000000000000000000"
  },
  {
    "type": "ScriptResult",
    "result": "0x2",
    "gasUsed": "0xb79a3"
  }
]
    at decodeCallResult (script-request.ts:119:1)
    at decodeContractCallScriptResult (contract-call-script.ts:174:1)
    at FunctionInvocationResult.getDecodedValue (invocation-results.ts:100:1)
    at new InvocationResult (invocation-results.ts:60:1)
    at new FunctionInvocationResult (invocation-results.ts:163:1)
    at FunctionInvocationResult.build (invocation-results.ts:187:1)
    at async WriteActions.createSpotOrder (TokenAbi__factory.ts:432:1)
    at async CreateOrderVM.createOrder (CreateOrderVM.tsx:404:1)

Indexer Log: Despite the failure, my indexer logs the creation of the order:

Storage Check: I sent a request to the node to verify if the order was actually stored and found no records:


Screenshot of the storage check

Let’s fix this—it is 100% incorrect logic, because the log event happens at the end of my function, after all checks have been made.

1 Like

Hi!

After reading through the indexer code, it seems like you only look for data logs, but completely ignore that the transaction panicked (in the decodeReceipt function). Note that transactions are atomic, meaning that a panicking transaction is completely reverted and e.g. storage writes do not cause any effects. In this case I suspect your code runs out of gas after emitting the logs, and the receipts support that conclusion.

All events are emites after whole logic

Open order

Cancel order

Match orders

I will edit match orders to put all logs together
But how do you think what would be the easiest way to ​​to skip events from any txs that also contain a panic or revert status?

A way to fetch receipts from all successful transactions belonging to a given wallet:

    let fetch_txs = |from_tx_id| {
        wallet.get_transactions(PaginationRequest {
            cursor: from_tx_id,
            results: 1000,
            direction: PageDirection::Forward,
        })
    };

    let receipts = futures::stream::unfold(None, |last_tx_id| async {
        let txs = fetch_txs(last_tx_id).await.ok()?;
        let next_cursor = txs.cursor;
        if txs.results.is_empty() {
            None
        } else {
            Some((futures::stream::iter(txs.results), next_cursor))
        }
    })
    .flatten()
    .filter_map(|tx| async {
        match tx.status {
            TxStatus::Success { receipts } => Some(futures::stream::iter(receipts)),
            _ => None,
        }
    })
    .flatten()
    .collect::<Vec<_>>()
    .await;

In any case you whatever you can of the Provider to fetch the transaction you’re interested in, then filter it based on its status.

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.