Skip to content

Commit

Permalink
[tests][programmable transactions] Add tests for MakeMoveVec (MystenL…
Browse files Browse the repository at this point in the history
…abs#9454)

## Description 

- Added transactional tests for objects
- Added "generated" tests for primitive types
- BCS bytes are now always checked for `MakeMoveVec` primitive
arguments. And checked before args reach the VM. This isn't strictly
necessary for safety, but provides a more predicable UX.

## Test Plan 

- It is tests

---
If your changes are not user-facing and not a breaking change, you can
skip the following section. Otherwise, please indicate what changed, and
then add to the Release Notes section as highlighted during the release
process.

### Type of Change (Check all that apply)

- [ ] user-visible impact
- [ ] breaking change for a client SDKs
- [X] breaking change for FNs (FN binary must upgrade)
- [X] breaking change for validators or node operators (must upgrade
binaries)
- [ ] breaking change for on-chain data layout
- [X] necessitate either a data wipe or data migration

### Release notes
  • Loading branch information
tnowacki authored Mar 17, 2023
1 parent 8330af3 commit aee247b
Show file tree
Hide file tree
Showing 13 changed files with 691 additions and 116 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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,30 @@
processed 8 tasks

init:
A: object(100), B: object(101)

task 1 'publish'. lines 8-47:
created: object(106)
written: object(105)

task 2 'programmable'. lines 48-55:
written: object(107)

task 3 'programmable'. lines 56-63:
written: object(108)

task 4 'programmable'. lines 64-68:
written: object(109)

task 5 'programmable'. lines 69-71:
created: object(111)
written: object(110)

task 6 'view-object'. lines 73-73:
Owner: Account Address ( A )
Version: 2
Contents: test::m1::Pub {id: sui::object::UID {id: sui::object::ID {bytes: fake(111)}}, value: 112u64}

task 7 'programmable'. lines 75-81:
written: object(112)
deleted: object(111)
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

// tessts various vector instantions with objects

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

//# publish
module test::m1 {
use sui::object::{Self, UID};
use sui::tx_context::TxContext;
use std::vector;

struct Pub has key, store {
id: UID,
value: u64,
}

struct Cap {}

struct Cup<T> has key, store {
id: UID,
value: T,
}

public fun new(ctx: &mut TxContext): Pub {
Pub { id: object::new(ctx), value: 112 }
}

public fun cup<T>(value: T, ctx: &mut TxContext): Cup<T> {
Cup { id: object::new(ctx), value }
}

public fun cap(): Cap {
Cap {}
}

public fun pubs(v: vector<Pub>) {
while (!vector::is_empty(&v)) {
let Pub { id, value: _ } = vector::pop_back(&mut v);
object::delete(id);
};
vector::destroy_empty(v);
}
}

// objects
//# programmable --sender A
//> 0: test::m1::new();
//> 1: test::m1::new();
//> 2: test::m1::new();
//> 3: MakeMoveVec([Result(0), Result(1), Result(2)]);
//> test::m1::pubs(Result(3));

// annotated objects
//# programmable --sender A
//> 0: test::m1::new();
//> 1: test::m1::new();
//> 2: test::m1::new();
//> 3: MakeMoveVec<test::m1::Pub>([Result(0), Result(1), Result(2)]);
//> test::m1::pubs(Result(3));

// empty objects
//# programmable --sender A
//> 0: MakeMoveVec<test::m1::Pub>([]);
//> test::m1::pubs(Result(0));

// mixed new and old. Send an object to A and mix it in a vector with the newly created ones.
//# programmable --sender A --inputs @A
//> 0: test::m1::new();
//> TransferObjects([Result(0)], Input(0));

//# view-object 111

//# programmable --sender A --inputs object(111)
//> 0: test::m1::new();
//> 1: test::m1::new();
//> 2: test::m1::new();
// use Input and new objects
//> 3: MakeMoveVec([Result(0), Result(1), Input(0), Result(2)]);
//> test::m1::pubs(Result(3));
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ Error: Transaction Effects Status: Arity mismatch for Move function. The number
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: ArityMismatch, source: Some("Expected 2 arguments calling function 'create', but found 1"), command: Some(0) } }

task 3 'run'. lines 17-17:
Error: Transaction Effects Status: Move Bytecode Verification Error. Please run the Bytecode Verifier for more information.
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: VMVerificationOrDeserializationError, source: Some(VMError { major_status: FAILED_TO_DESERIALIZE_ARGUMENT, sub_status: None, message: None, exec_state: None, location: Undefined, indices: [], offsets: [] }), command: Some(0) } }
Error: Transaction Effects Status: Invalid command argument at 1. The argument cannot be deserialized into a value of the specified type
Execution Error: ExecutionError: ExecutionError { inner: ExecutionErrorInner { kind: CommandArgumentError { arg_idx: 1, kind: InvalidBCSBytes }, source: Some("Function expects address but provided argument's value does not match"), command: Some(0) } }
32 changes: 16 additions & 16 deletions crates/sui-adapter/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use move_vm_runtime::{

use crate::{
execution_mode::ExecutionMode,
programmable_transactions::execution::{special_argument_validate, SpecialArgumentLayout},
programmable_transactions::execution::{bcs_argument_validate, PrimitiveArgumentLayout},
};
use sui_framework::natives::{object_runtime::ObjectRuntime, NativesCostTable};
use sui_protocol_config::ProtocolConfig;
Expand Down Expand Up @@ -257,7 +257,7 @@ pub fn resolve_and_type_check<Mode: ExecutionMode>(
);
}
if let Some(layout) = additional_validation_layout(view, param_type) {
special_argument_validate(&arg, idx as u16, layout)?;
bcs_argument_validate(&arg, idx as u16, layout)?;
}
}
CheckCallArg::Object(ObjectArg::ImmOrOwnedObject(ref_)) => {
Expand Down Expand Up @@ -333,7 +333,7 @@ pub fn resolve_and_type_check<Mode: ExecutionMode>(
fn additional_validation_layout(
view: &BinaryIndexedView,
param_type: &SignatureToken,
) -> Option<SpecialArgumentLayout> {
) -> Option<PrimitiveArgumentLayout> {
match param_type {
// should be ruled out above
SignatureToken::Reference(_)
Expand All @@ -343,34 +343,34 @@ fn additional_validation_layout(
// actually checking this requires a VM instance to load the type arguments
SignatureToken::TypeParameter(_) => None,
// primitives
SignatureToken::Bool => Some(SpecialArgumentLayout::Bool),
SignatureToken::U8 => Some(SpecialArgumentLayout::U8),
SignatureToken::U16 => Some(SpecialArgumentLayout::U16),
SignatureToken::U32 => Some(SpecialArgumentLayout::U32),
SignatureToken::U64 => Some(SpecialArgumentLayout::U64),
SignatureToken::U128 => Some(SpecialArgumentLayout::U128),
SignatureToken::U256 => Some(SpecialArgumentLayout::U256),
SignatureToken::Address => Some(SpecialArgumentLayout::Address),
SignatureToken::Bool => Some(PrimitiveArgumentLayout::Bool),
SignatureToken::U8 => Some(PrimitiveArgumentLayout::U8),
SignatureToken::U16 => Some(PrimitiveArgumentLayout::U16),
SignatureToken::U32 => Some(PrimitiveArgumentLayout::U32),
SignatureToken::U64 => Some(PrimitiveArgumentLayout::U64),
SignatureToken::U128 => Some(PrimitiveArgumentLayout::U128),
SignatureToken::U256 => Some(PrimitiveArgumentLayout::U256),
SignatureToken::Address => Some(PrimitiveArgumentLayout::Address),

SignatureToken::Vector(inner) => additional_validation_layout(view, inner)
.map(|layout| SpecialArgumentLayout::Vector(Box::new(layout))),
.map(|layout| PrimitiveArgumentLayout::Vector(Box::new(layout))),
SignatureToken::StructInstantiation(idx, targs) => {
let resolved_struct = sui_verifier::resolve_struct(view, *idx);
if resolved_struct == RESOLVED_STD_OPTION && targs.len() == 1 {
additional_validation_layout(view, &targs[0])
.map(|layout| SpecialArgumentLayout::Option(Box::new(layout)))
.map(|layout| PrimitiveArgumentLayout::Option(Box::new(layout)))
} else {
None
}
}
SignatureToken::Struct(idx) => {
let resolved_struct = sui_verifier::resolve_struct(view, *idx);
if resolved_struct == RESOLVED_SUI_ID {
Some(SpecialArgumentLayout::Address)
Some(PrimitiveArgumentLayout::Address)
} else if resolved_struct == RESOLVED_ASCII_STR {
Some(SpecialArgumentLayout::Ascii)
Some(PrimitiveArgumentLayout::Ascii)
} else if resolved_struct == RESOLVED_UTF8_STR {
Some(SpecialArgumentLayout::UTF8)
Some(PrimitiveArgumentLayout::UTF8)
} else {
None
}
Expand Down
Loading

0 comments on commit aee247b

Please sign in to comment.