Skip to content

Commit

Permalink
[hardening] make get_total_sui look inside vectors
Browse files Browse the repository at this point in the history
Fixing a silly bug that makes the conservation checks fail if a coin flows into or out of a vector
  • Loading branch information
sblackshear committed Mar 25, 2023
1 parent 5679d63 commit 0b909e3
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 6 deletions.
15 changes: 15 additions & 0 deletions crates/sui-adapter-transactional-tests/tests/sui/coin_in_vec.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
processed 4 tasks

init:
A: object(103)

task 1 'publish'. lines 6-32:
created: object(105), object(106)
written: object(104)

task 2 'run'. lines 34-34:
written: object(105), object(107)
deleted: object(104)

task 3 'run'. lines 36-36:
written: object(104), object(105), object(108)
36 changes: 36 additions & 0 deletions crates/sui-adapter-transactional-tests/tests/sui/coin_in_vec.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//# init --addresses test=0x0 --accounts A

//# publish --sender A

module test::coin_in_vec {
use std::vector;
use sui::coin::Coin;
use sui::object::{Self, UID};
use sui::sui::SUI;
use sui::transfer;
use sui::tx_context::{Self, TxContext};

struct Wrapper has key {
id: UID,
coins: vector<Coin<SUI>>,
}

fun init(ctx: &mut TxContext) {
transfer::transfer(Wrapper { id: object::new(ctx), coins: vector[] }, tx_context::sender(ctx));
}

public fun deposit(wrapper: &mut Wrapper, c: Coin<SUI>) {
vector::push_back(&mut wrapper.coins, c)
}

public fun withdraw(wrapper: &mut Wrapper, ctx: &mut TxContext) {
transfer::public_transfer(vector::pop_back(&mut wrapper.coins), tx_context::sender(ctx))
}
}

//# run test::coin_in_vec::deposit --args --args object(105) object(104) --sender A

//# run test::coin_in_vec::withdraw --args object(105) --sender A
21 changes: 15 additions & 6 deletions crates/sui-types/src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,11 +329,11 @@ impl MoveObject {
pub fn get_total_sui(&self, resolver: &impl GetModule) -> Result<u64, SuiError> {
let layout = self.get_layout(ObjectFormatOptions::with_types(), resolver)?;
let move_struct = self.to_move_struct(&layout)?;
Ok(Self::get_total_sui_(&move_struct, 0))
Ok(Self::get_total_sui_in_struct(&move_struct, 0))
}

/// Get all SUI in `s`, either directly or in its (transitive) fields. Intended for testing purposes
fn get_total_sui_(s: &MoveStruct, acc: u64) -> u64 {
fn get_total_sui_in_struct(s: &MoveStruct, acc: u64) -> u64 {
match s {
MoveStruct::WithTypes { type_, fields } => {
if GasCoin::is_gas_balance(type_) {
Expand All @@ -342,15 +342,24 @@ impl MoveObject {
_ => unreachable!(), // a Balance<SUI> object should have exactly one field, of type int
}
} else {
fields.iter().fold(acc, |acc, (_, v)| match v {
MoveValue::Struct(s) => Self::get_total_sui_(s, acc),
_ => acc,
})
fields
.iter()
.fold(acc, |acc, (_, v)| Self::get_total_sui_in_value(v, acc))
}
}
_ => unreachable!(),
}
}

fn get_total_sui_in_value(v: &MoveValue, acc: u64) -> u64 {
match v {
MoveValue::Struct(s) => Self::get_total_sui_in_struct(s, acc),
MoveValue::Vector(vec) => vec
.iter()
.fold(acc, |acc, v| Self::get_total_sui_in_value(v, acc)),
_ => acc,
}
}
}

#[derive(Eq, PartialEq, Debug, Clone, Deserialize, Serialize, Hash)]
Expand Down

0 comments on commit 0b909e3

Please sign in to comment.