cairo_native
cairo_native copied to clipboard
u256_mul overflow in 0x00a1e8372b6de461e939b63d7d2a7c4a60bc333cae92a9e0800a575e13f202f7
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)
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"
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)
}
@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:
- class hash: 0x07fe6c3f183b4ecd4f644ed472df2c5ec3e15a3c90d92988a1f8cd5ffda56266
- selector: 0x00b52e773ecde68f056f2f6fbaef2a7825a618be9e5f07e7bb0049c746652ec2
- storage address: 0x02ffce9d48390d497f7dfafa9dfd22025d9c285135bcc26c955aea8741f081d2
- call data:
- 0x03ddeeae1e54ed0b70d57e067fa696ef333e69cc6dbe8b4469ad0e9900546b54
- 0x0000000000000000000000000000000000000000000000000000000000000000
- 0x00000000000000000000000000000000000000000000002d84d9652e0defb2f4
- 0x0000000000000000000000000000000000000000000000000000000000000000
- 0x0000000000000000000000000000000000000000000000000000000000000001
- caller address: 0x0038925b0bcf4dce081042ca26a96300d9e181b910328db54a6c89e5451503f5
- code address: 0x02ffce9d48390d497f7dfafa9dfd22025d9c285135bcc26c955aea8741f081d2
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.
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.
Fixed on latest main
2024-10-10T10:57:24.156478Z INFO replay: execution finished successfully, transaction_hash: "0x00a1e8372b6de461e939b63d7d2a7c4a60bc333cae92a9e0800a575e13f202f7", chain: "mainnet", execution_status: "SUCCEEDED", rpc_execution_status: "SUCCEEDED", n_events_and_messages: "{ events_number: 24, l2_to_l1_messages_number: 0 }", rpc_n_events_and_msgs: "{ events_number: 24, l2_to_l1_messages_number: 0 }", da_gas: "{ l1_da_gas: 1920, l1_gas: 0 }", state_changes_for_fee_str: "{ n_class_hash_updates: 0, n_compiled_class_hash_updates: 0, n_modified_contracts: 7, n_storage_updates: 23 }"
at replay/src/main.rs:356
in replay::transaction with hash: "0x00a1e8372b6de461e939b63d7d2a7c4a60bc333cae92a9e0800a575e13f202f7", chain: "mainnet"