alloy-rs / rlp

Fast implementation of Ethereum RLP serialization
Apache License 2.0
77 stars 16 forks source link

Unable to decode into TxLegacy due to LeadingZero error #16

Closed poplexity closed 2 weeks ago

poplexity commented 2 weeks ago

The below test hits the LeadingZero error from here

Various online tools like this and this seem happy to decode, but assuming that this LeadingZero error is properly enforcing the spec, would there be a way to opt-in to bypass that enforcement?

use alloy::hex;
use alloy::primitives::private::alloy_rlp::Decodable;
use alloy_consensus::TxLegacy;

#[test]
fn test_unsigned_trx() {
    let raw = hex::decode("f78212aa8575a1c379a28307a120947282835cf78a5e88a52fc701f09d1614635be4b8900000000000000000000000000000000080808080").unwrap();

    let tx = TxLegacy::decode(&mut raw.as_slice());
    if tx.is_err() {
        println!("Failed to decode unsigned transaction: {:?}", tx.err());
        assert!(false, "Failed to decode unsigned transaction");
    }
}
Rjected commented 2 weeks ago

Where is the raw rlp from? this looks like invalid rlp, as the value is entirely zeros

Rjected commented 2 weeks ago

For example this is the tx "decoded":

list header: f7
82
nonce: 12aa
85
gas_price: 75a1c379a2
83
gas_limit: 07a120
94
to: 7282835cf78a5e88a52fc701f09d1614635be4b8
90
value: 00000000000000000000000000000000
input: 80
v: 80
r: 80
s: 80
poplexity commented 2 weeks ago

Our EVM is implemented as C++ >> WASM smart contract, and our RLP implementation is adapted from bloq/rlpvalue, we allow interoperability between the WASM network and the EVM which is why there is no signature (it was signed/authorized on the WASM network). This RLP implementation accepted the trx, similarly the tools listed above decode it to the same values that we currently have in our explorer which seems to differ after value:

["0x12aa","0x75a1c379a2","0x07a120","0x7282835cf78a5e88a52fc701f09d1614635be4b8","0x00000000000000000000000000000000","0x","0x","0x","0x"]

Currently we are building our new RPC version that uses alloy/reth and so the goal is to decode into the TxLegacy type from this RLP format that is in our block history.

mattsse commented 2 weeks ago

how are you encoding the value field? this doesn't look like an integer

Rjected commented 2 weeks ago

Our EVM is implemented as C++ >> WASM smart contract, and our RLP implementation is adapted from bloq/rlpvalue, we allow interoperability between the WASM network and the EVM which is why there is no signature (it was signed/authorized on the WASM network). This RLP implementation accepted the trx, similarly the tools listed above decode it to the same values that we currently have in our explorer which seems to differ after value:

["0x12aa","0x75a1c379a2","0x07a120","0x7282835cf78a5e88a52fc701f09d1614635be4b8","0x00000000000000000000000000000000","0x","0x","0x","0x"]

Currently we are building our new RPC version that uses alloy/reth and so the goal is to decode into the TxLegacy type from this RLP format that is in our block history.

yeah, the rlp implementation you are using is incorrect, and should output 0x80 for zero value. the online decoders should note that it's not valid tx rlp

poplexity commented 2 weeks ago

For this specific transaction, I'm 99% sure it came from here via this implementation.

And yes, I assumed this was wrong... totally fine with closing this issue and implementing a workaround on our side.

mattsse commented 2 weeks ago

this looks wrong

https://github.com/AscensionWx/Eosio-smart-contract/blob/08ac7a642f1bad1f45b118601a0e57eb210e3d97/src/helpers.cpp#L168-L169

this uses a padded u8 vec for the amount when encoding the tx body, which would explain this issue

https://github.com/AscensionWx/Eosio-smart-contract/blob/08ac7a642f1bad1f45b118601a0e57eb210e3d97/src/helpers.cpp#L188

this should be uint256_t