Skip to content

Commit 76f4ce9

Browse files
authored
Merge AccumulatorEvents in temporary_store so that transaction effects are accurate (#24176)
## Description Merge AccumulatorWriteV1 objects in temporary_store. This allows authenticated events to be indexed correctly in rpc_index and provides accurate transaction_effects. ## Test plan Address Balance and Authenticated Events tests added; they fail without this change. --- ## Release notes Check each box that your changes affect. If none of the boxes relate to your changes, release notes aren't required. For each box you select, include information after the relevant heading that describes the impact of your changes that a user might notice and any actions they must take to implement updates. - [ ] Protocol: - [ ] Nodes (Validators and Full nodes): - [ ] gRPC: - [ ] JSON-RPC: - [ ] GraphQL: - [ ] CLI: - [ ] Rust SDK:
1 parent 8940349 commit 76f4ce9

File tree

21 files changed

+1005
-60
lines changed

21 files changed

+1005
-60
lines changed

Cargo.lock

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ msim-macros = { git = "https://github.com/MystenLabs/mysten-sim.git", rev = "427
440440
multiaddr = "0.17.0"
441441
nexlint = { git = "https://github.com/nextest-rs/nexlint.git", rev = "7ce56bd591242a57660ed05f14ca2483c37d895b" }
442442
nexlint-lints = { git = "https://github.com/nextest-rs/nexlint.git", rev = "7ce56bd591242a57660ed05f14ca2483c37d895b" }
443-
nonempty = "0.9.0"
443+
nonempty = { version = "0.9.0", features = ["serialize"] }
444444
nonzero_ext = "0.3.0"
445445
notify = "6.1.1"
446446
ntest = "0.9.0"
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright (c) Mysten Labs, Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
// Test demonstrating arithmetic overflow protection when withdrawing from address balances.
5+
// Creates two independent Supply objects, mints 18446744073709551614 (u64::MAX - 1) from each,
6+
// sends both amounts to address A, then attempts to withdraw both amounts in a single PTB.
7+
// The withdraw operation fails with arithmetic error because the total exceeds u64::MAX.
8+
9+
//# init --addresses test=0x0 --accounts A B --enable-accumulators --simulator
10+
11+
//# publish --sender A
12+
module test::large_balance {
13+
use sui::balance::{Self, Supply};
14+
15+
public struct MARKER has drop {}
16+
17+
public struct SupplyHolder has key, store {
18+
id: UID,
19+
supply: Supply<MARKER>,
20+
}
21+
22+
public fun create_holder(ctx: &mut TxContext): SupplyHolder {
23+
SupplyHolder {
24+
id: object::new(ctx),
25+
supply: balance::create_supply(MARKER {}),
26+
}
27+
}
28+
29+
public fun send_large_balance(holder: &mut SupplyHolder, recipient: address, amount: u64) {
30+
let balance = holder.supply.increase_supply(amount);
31+
balance::send_funds(balance, recipient);
32+
}
33+
}
34+
35+
// Create two supply holders
36+
//# programmable --sender A --inputs @A
37+
//> 0: test::large_balance::create_holder();
38+
//> 1: test::large_balance::create_holder();
39+
//> TransferObjects([Result(0), Result(1)], Input(0))
40+
41+
// Send two large transfers in a single PTB - should cause Move abort due to overflow
42+
//# programmable --sender A --inputs object(2,0) object(2,1) @A 18446744073709551614
43+
//> 0: test::large_balance::send_large_balance(Input(0), Input(2), Input(3));
44+
//> 1: test::large_balance::send_large_balance(Input(1), Input(2), Input(3));
45+
46+
//# create-checkpoint
47+
48+
// Send first large amount separately - should succeed
49+
//# run test::large_balance::send_large_balance --args object(2,0) @A 18446744073709551614 --sender A
50+
51+
//# create-checkpoint
52+
53+
// Send second large amount separately - should succeed
54+
//# run test::large_balance::send_large_balance --args object(2,1) @A 18446744073709551614 --sender A
55+
56+
//# create-checkpoint
57+
58+
// Withdraw first large amount - should succeed
59+
//# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B
60+
//> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0));
61+
//> 1: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(1));
62+
63+
//# create-checkpoint
64+
65+
// Withdraw second large amount - should succeed
66+
//# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B
67+
//> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0));
68+
//> 1: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(1));
69+
70+
//# create-checkpoint
71+
72+
// Attempt to withdraw both large amounts in a single PTB - should fail with arithmetic error
73+
//# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B
74+
//> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0));
75+
//> 1: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(1));
76+
//> 2: sui::balance::join<test::large_balance::MARKER>(Result(0), Result(1));
77+
//> 3: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(2));
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
---
2+
source: external-crates/move/crates/move-transactional-test-runner/src/framework.rs
3+
---
4+
processed 14 tasks
5+
6+
init:
7+
A: object(0,0), B: object(0,1)
8+
9+
task 1, lines 11-35:
10+
//# publish --sender A
11+
created: object(1,0)
12+
mutated: object(0,0)
13+
gas summary: computation_cost: 1000000, storage_cost: 7311200, storage_rebate: 0, non_refundable_storage_fee: 0
14+
15+
task 2, lines 36-41:
16+
//# programmable --sender A --inputs @A
17+
//> 0: test::large_balance::create_holder();
18+
//> 1: test::large_balance::create_holder();
19+
//> TransferObjects([Result(0), Result(1)], Input(0))
20+
// Send two large transfers in a single PTB - should cause Move abort due to overflow
21+
created: object(2,0), object(2,1)
22+
mutated: object(0,0)
23+
gas summary: computation_cost: 1000000, storage_cost: 3876000, storage_rebate: 978120, non_refundable_storage_fee: 9880
24+
25+
task 3, lines 42-44:
26+
//# programmable --sender A --inputs object(2,0) object(2,1) @A 18446744073709551614
27+
//> 0: test::large_balance::send_large_balance(Input(0), Input(2), Input(3));
28+
//> 1: test::large_balance::send_large_balance(Input(1), Input(2), Input(3));
29+
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.
30+
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) } }
31+
32+
task 4, lines 46-48:
33+
//# create-checkpoint
34+
Checkpoint created: 1
35+
36+
task 5, line 49:
37+
//# run test::large_balance::send_large_balance --args object(2,0) @A 18446744073709551614 --sender A
38+
mutated: object(0,0), object(2,0)
39+
unchanged_shared: 0x0000000000000000000000000000000000000000000000000000000000000403
40+
accumulators_written: (object(5,0), A, sui::balance::Balance<test::large_balance::MARKER>, Merge)
41+
gas summary: computation_cost: 1000000, storage_cost: 2432000, storage_rebate: 2407680, non_refundable_storage_fee: 24320
42+
43+
task 6, lines 51-53:
44+
//# create-checkpoint
45+
Checkpoint created: 2
46+
47+
task 7, line 54:
48+
//# run test::large_balance::send_large_balance --args object(2,1) @A 18446744073709551614 --sender A
49+
mutated: object(0,0), object(2,1)
50+
unchanged_shared: 0x0000000000000000000000000000000000000000000000000000000000000403
51+
accumulators_written: (object(5,0), A, sui::balance::Balance<test::large_balance::MARKER>, Merge)
52+
gas summary: computation_cost: 1000000, storage_cost: 2432000, storage_rebate: 2407680, non_refundable_storage_fee: 24320
53+
54+
task 8, lines 56-58:
55+
//# create-checkpoint
56+
Checkpoint created: 3
57+
58+
task 9, lines 59-61:
59+
//# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B
60+
//> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0));
61+
//> 1: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(1));
62+
mutated: object(0,0)
63+
unchanged_shared: 0x0000000000000000000000000000000000000000000000000000000000000403
64+
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)
65+
gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880
66+
67+
task 10, lines 63-65:
68+
//# create-checkpoint
69+
Checkpoint created: 4
70+
71+
task 11, lines 66-68:
72+
//# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B
73+
//> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0));
74+
//> 1: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(1));
75+
mutated: object(0,0)
76+
unchanged_shared: 0x0000000000000000000000000000000000000000000000000000000000000403
77+
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)
78+
gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880
79+
80+
task 12, lines 70-72:
81+
//# create-checkpoint
82+
Checkpoint created: 5
83+
84+
task 13, lines 73-77:
85+
//# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B
86+
//> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0));
87+
//> 1: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(1));
88+
//> 2: sui::balance::join<test::large_balance::MARKER>(Result(0), Result(1));
89+
//> 3: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(2));
90+
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.
91+
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)
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
---
2+
source: external-crates/move/crates/move-transactional-test-runner/src/framework.rs
3+
---
4+
processed 14 tasks
5+
6+
init:
7+
A: object(0,0), B: object(0,1)
8+
9+
task 1, lines 11-35:
10+
//# publish --sender A
11+
created: object(1,0)
12+
mutated: object(0,0)
13+
gas summary: computation_cost: 1000000, storage_cost: 7311200, storage_rebate: 0, non_refundable_storage_fee: 0
14+
15+
task 2, lines 36-41:
16+
//# programmable --sender A --inputs @A
17+
//> 0: test::large_balance::create_holder();
18+
//> 1: test::large_balance::create_holder();
19+
//> TransferObjects([Result(0), Result(1)], Input(0))
20+
// Send two large transfers in a single PTB - should cause Move abort due to overflow
21+
created: object(2,0), object(2,1)
22+
mutated: object(0,0)
23+
gas summary: computation_cost: 1000000, storage_cost: 3876000, storage_rebate: 978120, non_refundable_storage_fee: 9880
24+
25+
task 3, lines 42-44:
26+
//# programmable --sender A --inputs object(2,0) object(2,1) @A 18446744073709551614
27+
//> 0: test::large_balance::send_large_balance(Input(0), Input(2), Input(3));
28+
//> 1: test::large_balance::send_large_balance(Input(1), Input(2), Input(3));
29+
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.
30+
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) } }
31+
32+
task 4, lines 46-48:
33+
//# create-checkpoint
34+
Checkpoint created: 1
35+
36+
task 5, line 49:
37+
//# run test::large_balance::send_large_balance --args object(2,0) @A 18446744073709551614 --sender A
38+
mutated: object(0,0), object(2,0)
39+
unchanged_shared: 0x0000000000000000000000000000000000000000000000000000000000000403
40+
accumulators_written: (object(5,0), A, sui::balance::Balance<test::large_balance::MARKER>, Merge)
41+
gas summary: computation_cost: 1000000, storage_cost: 2432000, storage_rebate: 2407680, non_refundable_storage_fee: 24320
42+
43+
task 6, lines 51-53:
44+
//# create-checkpoint
45+
Checkpoint created: 2
46+
47+
task 7, line 54:
48+
//# run test::large_balance::send_large_balance --args object(2,1) @A 18446744073709551614 --sender A
49+
mutated: object(0,0), object(2,1)
50+
unchanged_shared: 0x0000000000000000000000000000000000000000000000000000000000000403
51+
accumulators_written: (object(5,0), A, sui::balance::Balance<test::large_balance::MARKER>, Merge)
52+
gas summary: computation_cost: 1000000, storage_cost: 2432000, storage_rebate: 2407680, non_refundable_storage_fee: 24320
53+
54+
task 8, lines 56-58:
55+
//# create-checkpoint
56+
Checkpoint created: 3
57+
58+
task 9, lines 59-61:
59+
//# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B
60+
//> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0));
61+
//> 1: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(1));
62+
mutated: object(0,0)
63+
unchanged_shared: 0x0000000000000000000000000000000000000000000000000000000000000403
64+
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)
65+
gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880
66+
67+
task 10, lines 63-65:
68+
//# create-checkpoint
69+
Checkpoint created: 4
70+
71+
task 11, lines 66-68:
72+
//# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B
73+
//> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0));
74+
//> 1: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(1));
75+
mutated: object(0,0)
76+
unchanged_shared: 0x0000000000000000000000000000000000000000000000000000000000000403
77+
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)
78+
gas summary: computation_cost: 1000000, storage_cost: 988000, storage_rebate: 978120, non_refundable_storage_fee: 9880
79+
80+
task 12, lines 70-72:
81+
//# create-checkpoint
82+
Checkpoint created: 5
83+
84+
task 13, lines 73-77:
85+
//# programmable --sender A --inputs withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) withdraw<sui::balance::Balance<test::large_balance::MARKER>>(18446744073709551614) @B
86+
//> 0: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(0));
87+
//> 1: sui::balance::redeem_funds<test::large_balance::MARKER>(Input(1));
88+
//> 2: sui::balance::join<test::large_balance::MARKER>(Result(0), Result(1));
89+
//> 3: sui::balance::send_funds<test::large_balance::MARKER>(Result(0), Input(2));
90+
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.
91+
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)

crates/sui-core/src/accumulators/mod.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ impl MergedValueIntermediate {
162162
match value {
163163
AccumulatorValue::Integer(_) => Self::SumU128(0),
164164
AccumulatorValue::IntegerTuple(_, _) => Self::SumU128U128(0, 0),
165-
AccumulatorValue::EventDigest(_, _) => Self::Events(vec![]),
165+
AccumulatorValue::EventDigest(_) => Self::Events(vec![]),
166166
}
167167
}
168168

@@ -178,13 +178,15 @@ impl MergedValueIntermediate {
178178
*v1 += w1 as u128;
179179
*v2 += w2 as u128;
180180
}
181-
(Self::Events(commitments), AccumulatorValue::EventDigest(event_idx, digest)) => {
182-
commitments.push(EventCommitment::new(
183-
checkpoint_seq,
184-
transaction_idx,
185-
event_idx,
186-
digest,
187-
));
181+
(Self::Events(commitments), AccumulatorValue::EventDigest(event_digests)) => {
182+
for (event_idx, digest) in event_digests {
183+
commitments.push(EventCommitment::new(
184+
checkpoint_seq,
185+
transaction_idx,
186+
event_idx,
187+
digest,
188+
));
189+
}
188190
}
189191
_ => {
190192
fatal!("invalid merge");

crates/sui-core/src/rpc_index.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -702,15 +702,17 @@ impl IndexStoreTables {
702702
for acc in acc_events {
703703
if let Some(stream_id) =
704704
sui_types::accumulator_root::stream_id_from_accumulator_event(&acc)
705-
&& let AccumulatorValue::EventDigest(idx, _d) = acc.write.value
705+
&& let AccumulatorValue::EventDigest(event_digests) = &acc.write.value
706706
{
707-
let key = EventIndexKey {
708-
stream_id,
709-
checkpoint_seq,
710-
transaction_idx: tx_idx,
711-
event_index: idx as u32,
712-
};
713-
entries.push((key, ()));
707+
for (idx, _d) in event_digests {
708+
let key = EventIndexKey {
709+
stream_id,
710+
checkpoint_seq,
711+
transaction_idx: tx_idx,
712+
event_index: *idx as u32,
713+
};
714+
entries.push((key, ()));
715+
}
714716
}
715717
}
716718

crates/sui-core/tests/staged/sui.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ AccumulatorValue:
2828
- U64
2929
2:
3030
EventDigest:
31-
TUPLE:
32-
- U64
33-
- TYPENAME: Digest
31+
NEWTYPE:
32+
SEQ:
33+
TUPLE:
34+
- U64
35+
- TYPENAME: Digest
3436
AccumulatorWriteV1:
3537
STRUCT:
3638
- address:

0 commit comments

Comments
 (0)