Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ msim-macros = { git = "https://github.com/MystenLabs/mysten-sim.git", rev = "427
multiaddr = "0.17.0"
nexlint = { git = "https://github.com/nextest-rs/nexlint.git", rev = "7ce56bd591242a57660ed05f14ca2483c37d895b" }
nexlint-lints = { git = "https://github.com/nextest-rs/nexlint.git", rev = "7ce56bd591242a57660ed05f14ca2483c37d895b" }
nonempty = "0.9.0"
nonempty = { version = "0.9.0", features = ["serialize"] }
nonzero_ext = "0.3.0"
notify = "6.1.1"
ntest = "0.9.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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);
}
}

//# programmable --sender A --inputs @A
//> 0: test::large_balance::create_holder();
//> 1: test::large_balance::create_holder();
//> TransferObjects([Result(0), Result(1)], Input(0))

//# run test::large_balance::send_large_balance --args object(2,0) @A 18446744073709551614 --sender A

//# create-checkpoint

//# run test::large_balance::send_large_balance --args object(2,1) @A 18446744073709551614 --sender A

//# create-checkpoint

//# 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));
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
source: external-crates/move/crates/move-transactional-test-runner/src/framework.rs
assertion_line: 817
---
processed 8 tasks

init:
A: object(0,0), B: object(0,1)

task 1, lines 11-33:
//# 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 35-38:
//# programmable --sender A --inputs @A
//> 0: test::large_balance::create_holder();
//> 1: test::large_balance::create_holder();
//> TransferObjects([Result(0), Result(1)], Input(0))
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, line 40:
//# 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(3,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 4, line 42:
//# create-checkpoint
Checkpoint created: 1

task 5, line 44:
//# 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(3,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, line 46:
//# create-checkpoint
Checkpoint created: 2

task 7, lines 48-52:
//# 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,54 @@
---
source: external-crates/move/crates/move-transactional-test-runner/src/framework.rs
assertion_line: 811
---
processed 8 tasks

init:
A: object(0,0), B: object(0,1)

task 1, lines 11-33:
//# 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 35-38:
//# programmable --sender A --inputs @A
//> 0: test::large_balance::create_holder();
//> 1: test::large_balance::create_holder();
//> TransferObjects([Result(0), Result(1)], Input(0))
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, line 40:
//# 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(3,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 4, line 42:
//# create-checkpoint
Checkpoint created: 1

task 5, line 44:
//# 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(3,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, line 46:
//# create-checkpoint
Checkpoint created: 2

task 7, lines 48-52:
//# 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)
18 changes: 10 additions & 8 deletions crates/sui-core/src/accumulators/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ impl MergedValueIntermediate {
match value {
AccumulatorValue::Integer(_) => Self::SumU128(0),
AccumulatorValue::IntegerTuple(_, _) => Self::SumU128U128(0, 0),
AccumulatorValue::EventDigest(_, _) => Self::Events(vec![]),
AccumulatorValue::EventDigest(_) => Self::Events(vec![]),
}
}

Expand All @@ -178,13 +178,15 @@ impl MergedValueIntermediate {
*v1 += w1 as u128;
*v2 += w2 as u128;
}
(Self::Events(commitments), AccumulatorValue::EventDigest(event_idx, digest)) => {
commitments.push(EventCommitment::new(
checkpoint_seq,
transaction_idx,
event_idx,
digest,
));
(Self::Events(commitments), AccumulatorValue::EventDigest(event_digests)) => {
for (event_idx, digest) in event_digests {
commitments.push(EventCommitment::new(
checkpoint_seq,
transaction_idx,
event_idx,
digest,
));
}
}
_ => {
fatal!("invalid merge");
Expand Down
18 changes: 10 additions & 8 deletions crates/sui-core/src/rpc_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -702,15 +702,17 @@ impl IndexStoreTables {
for acc in acc_events {
if let Some(stream_id) =
sui_types::accumulator_root::stream_id_from_accumulator_event(&acc)
&& let AccumulatorValue::EventDigest(idx, _d) = acc.write.value
&& let AccumulatorValue::EventDigest(event_digests) = &acc.write.value
{
let key = EventIndexKey {
stream_id,
checkpoint_seq,
transaction_idx: tx_idx,
event_index: idx as u32,
};
entries.push((key, ()));
for (idx, _d) in event_digests {
let key = EventIndexKey {
stream_id,
checkpoint_seq,
transaction_idx: tx_idx,
event_index: *idx as u32,
};
entries.push((key, ()));
}
}
}

Expand Down
8 changes: 5 additions & 3 deletions crates/sui-core/tests/staged/sui.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ AccumulatorValue:
- U64
2:
EventDigest:
TUPLE:
- U64
- TYPENAME: Digest
NEWTYPE:
SEQ:
TUPLE:
- U64
- TYPENAME: Digest
AccumulatorWriteV1:
STRUCT:
- address:
Expand Down
Loading
Loading