lambdaclass / cairo_native

A compiler to convert Cairo's intermediate representation "Sierra" code to MLIR.
https://lambdaclass.github.io/cairo_native/cairo_native
Apache License 2.0
111 stars 43 forks source link

u256_mul overflow in 0x00a1e8372b6de461e939b63d7d2a7c4a60bc333cae92a9e0800a575e13f202f7 #714

Open JulianGCalderon opened 2 months ago

JulianGCalderon commented 2 months ago

When executing transaction 0x00a1e8372b6de461e939b63d7d2a7c4a60bc333cae92a9e0800a575e13f202f7 with starknet-replay, Cairo Native fails with u256_mul Overflow

Complete error message:

Transaction execution has failed:
0: Error in the called contract (
    contract address: 0x01ae80d66cc58dc4250a95a019a8c6dcb11f2bd0053ae6e9136c03b01be59a88
    class hash: 0x01a736d6ed154502257f02b1ccdf4d9d1089f80811cd6acad48e6b6a9d1f2003
    selector: 0x015d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad
):
Native execution error: argent/multicall-failed\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\u{1}Error at pc=0:10:
Got an exception while executing a hint: Native execution error: Native execution error: Native execution error: Native execution error: u256_mul Overflow
Cairo traceback (most recent call last):
Unknown location (pc=0:430)
Unknown location (pc=0:416)
pefontana commented 1 month ago

Here i got some other u256_mul Overflow error examples, I found in block 626173 txs

2024-07-07T15:13:50.719094Z ERROR replay: rpc and execution status diverged, transaction_hash: "0xb2867a82804fcf3c9f99c11f58ee417f03e1524f44a3a5693f4fc293005761", chain: "mainnet", execution_status: "REVERTED", rpc_execution_status: "SUCCEEDED", execution_error_message: "Transaction execution has failed:\n0: Error in the called contract (contract address: 0x07051f0b3042662c9094813c0b87996c1df451ab39839757d804c8cd8cdaf2c5, class hash: 0x029927c8af6bccf3f6fda035981e765a7bdbf18a2dc0d630494f8758aa908e2b, selector: 0x015d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad):\nNative execution error: argent/multicall-failed\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\u{1}Native execution error: u256_mul Overflow\n"
2024-07-07T15:30:26.099594Z ERROR replay: rpc and execution status diverged, transaction_hash: "0x8eb8b1b474172281ea9616166faba9bd1c41972762cfd6e299b2a605592dfb", chain: "mainnet", execution_status: "REVERTED", rpc_execution_status: "SUCCEEDED", execution_error_message: "Transaction execution has failed:\n0: Error in the called contract (contract address: 0x00e09313ea0664b945c278dc24e8ba14907b0895d4de113045dd915033e158ca, class hash: 0x00816dd0297efc55dc1e7559020a3a825e81ef734b558f03c83325d4da7e6253, selector: 0x015d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad):\nNative execution error: Error at pc=0:10:\nGot an exception while executing a hint: Native execution error: Native execution error: Native execution error: u256_mul Overflow\nCairo traceback (most recent call last):\nUnknown location (pc=0:430)\nUnknown location (pc=0:416)\n\n"
2024-07-07T16:14:28.250570Z ERROR replay: rpc and execution status diverged, transaction_hash: "0x10b00fcea9baac38510875f8cffcb1ba13897c2b38c6a4cac9949e785970e05", chain: "mainnet", execution_status: "REVERTED", rpc_execution_status: "SUCCEEDED", execution_error_message: "Transaction execution has failed:\n0: Error in the called contract (contract address: 0x0198784821a897eb844a7a81b94121d5bfb9d9e005e8844ebab5153c888b5029, class hash: 0x01a736d6ed154502257f02b1ccdf4d9d1089f80811cd6acad48e6b6a9d1f2003, selector: 0x015d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad):\nNative execution error: argent/multicall-failed\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\u{1}Error at pc=0:10:\nGot an exception while executing a hint: Native execution error: Native execution error: Native execution error: u256_mul Overflow\nCairo traceback (most recent call last):\nUnknown location (pc=0:430)\nUnknown location (pc=0:416)\n\n"
edg-l commented 1 month ago

this is the function used to mul u256 with overflow

pub fn u256_overflow_mul(lhs: u256, rhs: u256) -> (u256, bool) {
    let (high1, low) = u128_wide_mul(lhs.low, rhs.low);
    let (overflow_value1, high2) = u128_wide_mul(lhs.low, rhs.high);
    let (overflow_value2, high3) = u128_wide_mul(lhs.high, rhs.low);
    let (high, overflow) = match u128_overflowing_add(high1, high2) {
        Result::Ok(high) => (
            high,
            overflow_value1 != 0_u128
                || overflow_value2 != 0_u128
                || (lhs.high > 0_u128 && rhs.high > 0_u128)
        ),
        Result::Err(high) => (high, true),
    };
    let (high, overflow) = match u128_overflowing_add(high, high3) {
        Result::Ok(high) => (high, overflow),
        Result::Err(high) => (high, true),
    };
    (u256 { low, high }, overflow)
}
JulianGCalderon commented 1 month ago

@edg-l this is a summary of the information I have so far.

The contracts calls many aditional contracts inside. I first tried to isolate the actual contract that was failing, and with what arguments it was executed:

Then I constructed a small rust example to execute only that contract. It can be found here.

When I executed it, it failed with the same error.

Then, I tried to trace where the error occurs and isolate the function. To do this I used the sierra-mapper.

The error messages comes from the following corelib function:

impl U256Mul of Mul<u256> {
    fn mul(lhs: u256, rhs: u256) -> u256 {
        u256_checked_mul(lhs, rhs).expect('u256_mul Overflow')
    }
}

Which internally calls the function mentioned by @edg-l.

I tried printing the arguments passed to the function (in this branch) and got the following:

[DEBUG] Memory dump at 0x7ffc0f3d9b30:
  0x7ffc0f3d9b30: 05 43 07 b5 eb f4 2c e8
  0x7ffc0f3d9b30: a7 72 a5 60 0b b6 62 b4
  0x7ffc0f3d9b30: 51 ed dc 32 01 00 00 00
  0x7ffc0f3d9b30: 00 00 00 00 00 00 00 00
[DEBUG] Memory dump at 0x7ffc0f3d9b10:
  0x7ffc0f3d9b10: 05 43 07 b5 eb f4 2c e8
  0x7ffc0f3d9b10: a7 72 a5 60 0b b6 62 b4
  0x7ffc0f3d9b10: 51 ed dc 32 01 00 00 00
  0x7ffc0f3d9b10: 00 00 00 00 00 00 00 00

If I interpret it as a u256 and multiply it, I get an overflow. This lead me to believe that the bug is not in the actual multiplication, but in how does numbers where obtained.

I can't think of any good way to locate where the bug actually is. A possible approach is to find another contract with public code, so we can better inspect it. Another approach to compare the execution of the contract along side the CairoVM function by function and find where there is a mismatch, this would require extra work but may be useful in other bugs.

JulianGCalderon commented 13 minutes ago

Update: This transaction is still failing due to the same bug. Execution with cairo-vm and sierra-emu is successful.

I'm going to compare sierra-emu trace dump with native trace dump to (hopefully) isolate the libfunc that causes this.