-
Notifications
You must be signed in to change notification settings - Fork 11.7k
Merge AccumulatorEvents in temporary_store so that transaction effects are accurate #24176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| // Copyright (c) Mysten Labs, Inc. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| // Test demonstrating arithmetic overflow protection when withdrawing from address balances. | ||
| // Creates two independent Supply objects, mints 18446744073709551614 (u64::MAX - 1) from each, | ||
| // sends both amounts to address A, then attempts to withdraw both amounts in a single PTB. | ||
| // The withdraw operation fails with arithmetic error because the total exceeds u64::MAX. | ||
|
|
||
| //# init --addresses test=0x0 --accounts A B --enable-accumulators --simulator | ||
|
|
||
| //# publish --sender A | ||
| module test::large_balance { | ||
| use sui::balance::{Self, Supply}; | ||
|
|
||
| public struct MARKER has drop {} | ||
|
|
||
| public struct SupplyHolder has key, store { | ||
| id: UID, | ||
| supply: Supply<MARKER>, | ||
| } | ||
|
|
||
| public fun create_holder(ctx: &mut TxContext): SupplyHolder { | ||
| SupplyHolder { | ||
| id: object::new(ctx), | ||
| supply: balance::create_supply(MARKER {}), | ||
| } | ||
| } | ||
|
|
||
| public fun send_large_balance(holder: &mut SupplyHolder, recipient: address, amount: u64) { | ||
| let balance = holder.supply.increase_supply(amount); | ||
| balance::send_funds(balance, recipient); | ||
| } | ||
| } | ||
|
|
||
| // Create two supply holders | ||
| //# programmable --sender A --inputs @A | ||
| //> 0: test::large_balance::create_holder(); | ||
| //> 1: test::large_balance::create_holder(); | ||
| //> TransferObjects([Result(0), Result(1)], Input(0)) | ||
|
|
||
| // Send two large transfers in a single PTB - should cause Move abort due to overflow | ||
| //# programmable --sender A --inputs object(2,0) object(2,1) @A 18446744073709551614 | ||
| //> 0: test::large_balance::send_large_balance(Input(0), Input(2), Input(3)); | ||
| //> 1: test::large_balance::send_large_balance(Input(1), Input(2), Input(3)); | ||
|
|
||
| //# create-checkpoint | ||
|
|
||
| // Send first large amount separately - should succeed | ||
| //# run test::large_balance::send_large_balance --args object(2,0) @A 18446744073709551614 --sender A | ||
|
|
||
| //# create-checkpoint | ||
|
|
||
| // Send second large amount separately - should succeed | ||
| //# run test::large_balance::send_large_balance --args object(2,1) @A 18446744073709551614 --sender A | ||
|
|
||
| //# create-checkpoint | ||
|
|
||
| // Withdraw first large amount - should succeed | ||
| //# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B | ||
| //> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0)); | ||
| //> 1: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(1)); | ||
|
|
||
| //# create-checkpoint | ||
|
|
||
| // Withdraw second large amount - should succeed | ||
| //# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B | ||
| //> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0)); | ||
| //> 1: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(1)); | ||
|
|
||
| //# create-checkpoint | ||
|
|
||
| // Attempt to withdraw both large amounts in a single PTB - should fail with arithmetic error | ||
| //# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B | ||
| //> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0)); | ||
| //> 1: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(1)); | ||
| //> 2: sui::balance::join<test::large_balance::MARKER>(Result(0), Result(1)); | ||
| //> 3: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(2)); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we follow this up with a check that we can successfully withdraw the large amounts one at a time? Or do we already have that?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test added |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| --- | ||
| source: external-crates/move/crates/move-transactional-test-runner/src/framework.rs | ||
| --- | ||
| processed 14 tasks | ||
|
|
||
| init: | ||
| A: object(0,0), B: object(0,1) | ||
|
|
||
| task 1, lines 11-35: | ||
| //# publish --sender A | ||
| created: object(1,0) | ||
| mutated: object(0,0) | ||
| gas summary: computation_cost: 1000000, storage_cost: 7311200, storage_rebate: 0, non_refundable_storage_fee: 0 | ||
|
|
||
| task 2, lines 36-41: | ||
| //# programmable --sender A --inputs @A | ||
| //> 0: test::large_balance::create_holder(); | ||
| //> 1: test::large_balance::create_holder(); | ||
| //> TransferObjects([Result(0), Result(1)], Input(0)) | ||
| // Send two large transfers in a single PTB - should cause Move abort due to overflow | ||
| created: object(2,0), object(2,1) | ||
| mutated: object(0,0) | ||
| gas summary: computation_cost: 1000000, storage_cost: 3876000, storage_rebate: 978120, non_refundable_storage_fee: 9880 | ||
|
|
||
| task 3, lines 42-44: | ||
| //# programmable --sender A --inputs object(2,0) object(2,1) @A 18446744073709551614 | ||
| //> 0: test::large_balance::send_large_balance(Input(0), Input(2), Input(3)); | ||
| //> 1: test::large_balance::send_large_balance(Input(1), Input(2), Input(3)); | ||
| Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::funds_accumulator::add_to_accumulator_address (function index 8) at offset 0. Arithmetic error, stack overflow, max value depth, etc. | ||
| Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("funds_accumulator") }, function: 8, instruction: 0, function_name: Some("add_to_accumulator_address") }))), source: Some(VMError { major_status: ARITHMETIC_ERROR, sub_status: None, message: Some("accumulator merge overflow: total merges 36893488147419103228 exceed u64::MAX"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("funds_accumulator") }), indices: [], offsets: [(FunctionDefinitionIndex(8), 0)] }), command: Some(1) } } | ||
|
|
||
| task 4, lines 46-48: | ||
| //# create-checkpoint | ||
| Checkpoint created: 1 | ||
|
|
||
| task 5, line 49: | ||
| //# run test::large_balance::send_large_balance --args object(2,0) @A 18446744073709551614 --sender A | ||
| mutated: object(0,0), object(2,0) | ||
| unchanged_shared: 0x0000000000000000000000000000000000000000000000000000000000000403 | ||
| accumulators_written: (object(5,0), A, sui::balance::Balance<test::large_balance::MARKER>, Merge) | ||
| gas summary: computation_cost: 1000000, storage_cost: 2432000, storage_rebate: 2407680, non_refundable_storage_fee: 24320 | ||
|
|
||
| task 6, lines 51-53: | ||
| //# create-checkpoint | ||
| Checkpoint created: 2 | ||
|
|
||
| task 7, line 54: | ||
| //# run test::large_balance::send_large_balance --args object(2,1) @A 18446744073709551614 --sender A | ||
| mutated: object(0,0), object(2,1) | ||
| unchanged_shared: 0x0000000000000000000000000000000000000000000000000000000000000403 | ||
| accumulators_written: (object(5,0), A, sui::balance::Balance<test::large_balance::MARKER>, Merge) | ||
| gas summary: computation_cost: 1000000, storage_cost: 2432000, storage_rebate: 2407680, non_refundable_storage_fee: 24320 | ||
|
|
||
| task 8, lines 56-58: | ||
| //# create-checkpoint | ||
| Checkpoint created: 3 | ||
|
|
||
| task 9, lines 59-61: | ||
| //# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B | ||
| //> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0)); | ||
| //> 1: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(1)); | ||
| mutated: object(0,0) | ||
| unchanged_shared: 0x0000000000000000000000000000000000000000000000000000000000000403 | ||
| accumulators_written: (object(5,0), A, sui::balance::Balance<test::large_balance::MARKER>, Split), (object(9,0), B, sui::balance::Balance<test::large_balance::MARKER>, Merge) | ||
| gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 | ||
|
|
||
| task 10, lines 63-65: | ||
| //# create-checkpoint | ||
| Checkpoint created: 4 | ||
|
|
||
| task 11, lines 66-68: | ||
| //# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B | ||
| //> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0)); | ||
| //> 1: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(1)); | ||
| mutated: object(0,0) | ||
| unchanged_shared: 0x0000000000000000000000000000000000000000000000000000000000000403 | ||
| accumulators_written: (object(5,0), A, sui::balance::Balance<test::large_balance::MARKER>, Split), (object(9,0), B, sui::balance::Balance<test::large_balance::MARKER>, Merge) | ||
| gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 | ||
|
|
||
| task 12, lines 70-72: | ||
| //# create-checkpoint | ||
| Checkpoint created: 5 | ||
|
|
||
| task 13, lines 73-77: | ||
| //# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B | ||
| //> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0)); | ||
| //> 1: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(1)); | ||
| //> 2: sui::balance::join<test::large_balance::MARKER>(Result(0), Result(1)); | ||
| //> 3: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(2)); | ||
| Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::funds_accumulator::withdraw_from_accumulator_address (function index 9) at offset 0. Arithmetic error, stack overflow, max value depth, etc. | ||
| Debug of error: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("funds_accumulator") }, function: 9, instruction: 0, function_name: Some("withdraw_from_accumulator_address") }))) at command Some(1) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| --- | ||
| source: external-crates/move/crates/move-transactional-test-runner/src/framework.rs | ||
| --- | ||
| processed 14 tasks | ||
|
|
||
| init: | ||
| A: object(0,0), B: object(0,1) | ||
|
|
||
| task 1, lines 11-35: | ||
| //# publish --sender A | ||
| created: object(1,0) | ||
| mutated: object(0,0) | ||
| gas summary: computation_cost: 1000000, storage_cost: 7311200, storage_rebate: 0, non_refundable_storage_fee: 0 | ||
|
|
||
| task 2, lines 36-41: | ||
| //# programmable --sender A --inputs @A | ||
| //> 0: test::large_balance::create_holder(); | ||
| //> 1: test::large_balance::create_holder(); | ||
| //> TransferObjects([Result(0), Result(1)], Input(0)) | ||
| // Send two large transfers in a single PTB - should cause Move abort due to overflow | ||
| created: object(2,0), object(2,1) | ||
| mutated: object(0,0) | ||
| gas summary: computation_cost: 1000000, storage_cost: 3876000, storage_rebate: 978120, non_refundable_storage_fee: 9880 | ||
|
|
||
| task 3, lines 42-44: | ||
| //# programmable --sender A --inputs object(2,0) object(2,1) @A 18446744073709551614 | ||
| //> 0: test::large_balance::send_large_balance(Input(0), Input(2), Input(3)); | ||
| //> 1: test::large_balance::send_large_balance(Input(1), Input(2), Input(3)); | ||
| Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::funds_accumulator::add_to_accumulator_address (function index 8) at offset 0. Arithmetic error, stack overflow, max value depth, etc. | ||
| Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("funds_accumulator") }, function: 8, instruction: 0, function_name: Some("add_to_accumulator_address") }))), source: Some(VMError { major_status: ARITHMETIC_ERROR, sub_status: None, message: Some("accumulator merge overflow: total merges 36893488147419103228 exceed u64::MAX"), exec_state: None, location: Module(ModuleId { address: sui, name: Identifier("funds_accumulator") }), indices: [], offsets: [(FunctionDefinitionIndex(8), 0)] }), command: Some(1) } } | ||
|
|
||
| task 4, lines 46-48: | ||
| //# create-checkpoint | ||
| Checkpoint created: 1 | ||
|
|
||
| task 5, line 49: | ||
| //# run test::large_balance::send_large_balance --args object(2,0) @A 18446744073709551614 --sender A | ||
| mutated: object(0,0), object(2,0) | ||
| unchanged_shared: 0x0000000000000000000000000000000000000000000000000000000000000403 | ||
| accumulators_written: (object(5,0), A, sui::balance::Balance<test::large_balance::MARKER>, Merge) | ||
| gas summary: computation_cost: 1000000, storage_cost: 2432000, storage_rebate: 2407680, non_refundable_storage_fee: 24320 | ||
|
|
||
| task 6, lines 51-53: | ||
| //# create-checkpoint | ||
| Checkpoint created: 2 | ||
|
|
||
| task 7, line 54: | ||
| //# run test::large_balance::send_large_balance --args object(2,1) @A 18446744073709551614 --sender A | ||
| mutated: object(0,0), object(2,1) | ||
| unchanged_shared: 0x0000000000000000000000000000000000000000000000000000000000000403 | ||
| accumulators_written: (object(5,0), A, sui::balance::Balance<test::large_balance::MARKER>, Merge) | ||
| gas summary: computation_cost: 1000000, storage_cost: 2432000, storage_rebate: 2407680, non_refundable_storage_fee: 24320 | ||
|
|
||
| task 8, lines 56-58: | ||
| //# create-checkpoint | ||
| Checkpoint created: 3 | ||
|
|
||
| task 9, lines 59-61: | ||
| //# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B | ||
| //> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0)); | ||
| //> 1: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(1)); | ||
| mutated: object(0,0) | ||
| unchanged_shared: 0x0000000000000000000000000000000000000000000000000000000000000403 | ||
| accumulators_written: (object(5,0), A, sui::balance::Balance<test::large_balance::MARKER>, Split), (object(9,0), B, sui::balance::Balance<test::large_balance::MARKER>, Merge) | ||
| gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 | ||
|
|
||
| task 10, lines 63-65: | ||
| //# create-checkpoint | ||
| Checkpoint created: 4 | ||
|
|
||
| task 11, lines 66-68: | ||
| //# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B | ||
| //> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0)); | ||
| //> 1: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(1)); | ||
| mutated: object(0,0) | ||
| unchanged_shared: 0x0000000000000000000000000000000000000000000000000000000000000403 | ||
| accumulators_written: (object(5,0), A, sui::balance::Balance<test::large_balance::MARKER>, Split), (object(9,0), B, sui::balance::Balance<test::large_balance::MARKER>, Merge) | ||
| gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880 | ||
|
|
||
| task 12, lines 70-72: | ||
| //# create-checkpoint | ||
| Checkpoint created: 5 | ||
|
|
||
| task 13, lines 73-77: | ||
| //# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B | ||
| //> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0)); | ||
| //> 1: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(1)); | ||
| //> 2: sui::balance::join<test::large_balance::MARKER>(Result(0), Result(1)); | ||
| //> 3: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(2)); | ||
| Error: Transaction Effects Status: Move Primitive Runtime Error. Location: sui::funds_accumulator::withdraw_from_accumulator_address (function index 9) at offset 0. Arithmetic error, stack overflow, max value depth, etc. | ||
| Debug of error: MovePrimitiveRuntimeError(MoveLocationOpt(Some(MoveLocation { module: ModuleId { address: sui, name: Identifier("funds_accumulator") }, function: 9, instruction: 0, function_name: Some("withdraw_from_accumulator_address") }))) at command Some(1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
before this, we should have a case that sends two large transfers in a single PTB, to test that it causes a move abort
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test added