graphprotocol / graph-node

Graph Node indexes data from blockchains such as Ethereum and serves it over GraphQL
https://thegraph.com
Apache License 2.0
2.91k stars 966 forks source link

[Bug] ethereum.decode function misinterprets the value #5378

Closed Pafaul closed 5 months ago

Pafaul commented 5 months ago

Bug report

I've been trying to decode some raw encoded data (encoded with abi.encode) to use it later, but encountered an error. What i've been doing:

    const decodedTuple = ethereum
        .decode('(bool, bool, uint256, uint256, uint256, bool)', args)!
        .toTuple();

After it the decoded data will be used this way:

    createOrUpdateNominationConfig(
        address,
        decodedTuple.at(0).toBoolean(),
        decodedTuple.at(1).toBoolean(),
        decodedTuple.at(2).toBigInt(),
        decodedTuple.at(3).toBigInt(),
        decodedTuple.at(4).toBigInt(),
        decodedTuple.at(5).toBoolean(),
    );

With some log output for debugging:

    log.info('decoding: {}', [args.toHexString()]);
    for (let id = 0; id < 6; id++) {
        log.info('Decoded value type: {}', [decodedTuple.at(id).kind.toString()]);
    }

Data to decode: 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

The decoding was able to successfully decode encoded values when it was just two addresses or two uint256 values (encoded with abi.encode):

// Works fine with two addresses
function decodeTwoAddresses(calldata: Bytes): Address[] {
    // Decoding two addresses from RLP
    const decodedTuple = ethereum
        .decode('(address,address)', Bytes.fromUint8Array(calldata.slice(4)))!
        .toTuple();

    return [decodedTuple.at(0).toAddress(), decodedTuple.at(1).toAddress()];
}
// Works fine with two uint256
    const decodedTuple = ethereum.decode('(uint256, uint256)', args)!.toTuple();
    return createOrUpdateSignatureCollectionConfig(
        address,
        decodedTuple.at(0).toBigInt(),
        decodedTuple.at(1).toBigInt(),
    );

Setup:

Relevant log output

2024-04-26 14:00:43 Apr 26 11:00:43.068 INFO NOMINATION_PROCESS, data_source: SpawnerFactory, sgd: 39, subgraph_id: QmVXGsTsp6FKTvDQJfV8WhCk3yK9VtUHyQ5dq5dz1yw73y, component: SubgraphInstanceManager > UserMapping
2024-04-26 14:00:43 Apr 26 11:00:43.069 INFO decoding: 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, data_source: SpawnerFactory, sgd: 39, subgraph_id: QmVXGsTsp6FKTvDQJfV8WhCk3yK9VtUHyQ5dq5dz1yw73y, component: SubgraphInstanceManager > UserMapping
2024-04-26 14:00:43 Apr 26 11:00:43.069 INFO Decoded value type: 5, data_source: SpawnerFactory, sgd: 39, subgraph_id: QmVXGsTsp6FKTvDQJfV8WhCk3yK9VtUHyQ5dq5dz1yw73y, component: SubgraphInstanceManager > UserMapping
2024-04-26 14:00:43 Apr 26 11:00:43.069 INFO Decoded value type: 4, data_source: SpawnerFactory, sgd: 39, subgraph_id: QmVXGsTsp6FKTvDQJfV8WhCk3yK9VtUHyQ5dq5dz1yw73y, component: SubgraphInstanceManager > UserMapping
2024-04-26 14:00:43 Apr 26 11:00:43.069 INFO Decoded value type: 4, data_source: SpawnerFactory, sgd: 39, subgraph_id: QmVXGsTsp6FKTvDQJfV8WhCk3yK9VtUHyQ5dq5dz1yw73y, component: SubgraphInstanceManager > UserMapping
2024-04-26 14:00:43 Apr 26 11:00:43.069 INFO Decoded value type: 4, data_source: SpawnerFactory, sgd: 39, subgraph_id: QmVXGsTsp6FKTvDQJfV8WhCk3yK9VtUHyQ5dq5dz1yw73y, component: SubgraphInstanceManager > UserMapping
2024-04-26 14:00:43 Apr 26 11:00:43.069 INFO Decoded value type: 4, data_source: SpawnerFactory, sgd: 39, subgraph_id: QmVXGsTsp6FKTvDQJfV8WhCk3yK9VtUHyQ5dq5dz1yw73y, component: SubgraphInstanceManager > UserMapping
2024-04-26 14:00:43 Apr 26 11:00:43.069 INFO Decoded value type: 4, data_source: SpawnerFactory, sgd: 39, subgraph_id: QmVXGsTsp6FKTvDQJfV8WhCk3yK9VtUHyQ5dq5dz1yw73y, component: SubgraphInstanceManager > UserMapping
2024-04-26 14:00:43 Apr 26 11:00:43.069 ERRO Handler skipped due to execution failure, transaction: 0x764f…c85a, address: 0xd9c5…721a, signature: SpawnerCreated(indexed address,bytes32), error: transaction 764fd136e83deb4f563a559d0ec030757b9cc17a762e086ce0983c66ce6ec85a: error while executing at wasm backtrace:     0: 0x3c29 - <unknown>!~lib/@graphprotocol/graph-ts/chain/ethereum/ethereum.Value#toBoolean       1: 0x3ee4 - <unknown>!src/entities/process/getProcessSpawnerConfig      2: 0x47fb - <unknown>!src/entities/process/createProcessSpawner          3: 0x4a23 - <unknown>!src/processes/spawner-factory/handleSpawnerCreated: Mapping aborted at ~lib/@graphprotocol/graph-ts/chain/ethereum.ts, line 61, column 7, with message: Ethereum value is not a boolean., handler: handleSpawnerCreated, sgd: 39, subgraph_id: QmVXGsTsp6FKTvDQJfV8WhCk3yK9VtUHyQ5dq5dz1yw73y, component: SubgraphInstanceManager

IPFS hash

No response

Subgraph name or link to explorer

No response

Some information to help us out

OS information

Other (please specify in your bug report)

Pafaul commented 5 months ago

In log it says that values have type 5, 4, 4, 4, 4, 4 which maps to BOOL, UINT, UINT, UINT, UINT, UINT, which is different from provided types for decoding

Pafaul commented 5 months ago

ok, looks like the problem was with having extra spaces between the provided types (idk how, but it works), so the correct one will be:

        const decodedTuple = ethereum
            .decode('(bool,bool,uint256,uint256,uint256,bool)', args)!
            .toTuple();

after this fix all the values decode with correct types