Skip to content
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

[adapter][verifier] allow option and ID arguments in entry points #2149

Merged
merged 1 commit into from
May 24, 2022
Merged
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
76 changes: 51 additions & 25 deletions crates/sui-adapter/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ use sui_types::{
object::{self, Data, MoveObject, Object, Owner},
storage::{DeleteKind, Storage},
};
use sui_verifier::{entry_points_verifier::INIT_FN_NAME, verifier};
use sui_verifier::{
entry_points_verifier::{INIT_FN_NAME, RESOLVED_STD_OPTION, RESOLVED_SUI_ID},
verifier,
};

use move_core_types::{
account_address::AccountAddress,
Expand Down Expand Up @@ -692,15 +695,15 @@ pub fn resolve_and_type_check(
// Track the mapping from each input object to its Move type.
// This will be needed latter in `check_child_object_of_shared_object`.
let mut object_type_map = BTreeMap::new();

let view = &BinaryIndexedView::Module(module);
let bcs_args = args
.into_iter()
.enumerate()
.map(|(idx, arg)| {
let param_type = &parameters[idx];
let object_kind = match arg {
CallArg::Pure(arg) => {
if !is_primitive(module, type_args, param_type) {
if !is_primitive(view, type_args, param_type) {
return Err(SuiError::TypeError {
error: format!(
"Non-primitive argument at index {}. If it is an object, it must \
Expand Down Expand Up @@ -799,7 +802,7 @@ pub fn resolve_and_type_check(
})
}
};
type_check_struct(module, type_args, &move_object.type_, inner_param_type)?;
type_check_struct(view, type_args, &move_object.type_, inner_param_type)?;
object_type_map.insert(id, move_object.type_.module_id());
Ok(object_arg)
})
Expand Down Expand Up @@ -891,7 +894,7 @@ fn check_child_object_of_shared_object(
}

fn is_primitive(
_module: &CompiledModule,
view: &BinaryIndexedView,
function_type_arguments: &[TypeTag],
t: &SignatureToken,
) -> bool {
Expand All @@ -902,16 +905,27 @@ fn is_primitive(
| SignatureToken::U128
| SignatureToken::Address => true,

SignatureToken::Vector(inner) => is_primitive(_module, function_type_arguments, inner),
SignatureToken::Struct(idx) => {
let resolved_struct = sui_verifier::resolve_struct(view, *idx);
// is ID
resolved_struct == RESOLVED_SUI_ID
}

SignatureToken::StructInstantiation(idx, targs) => {
let resolved_struct = sui_verifier::resolve_struct(view, *idx);
// is option of a primitive
resolved_struct == RESOLVED_STD_OPTION
Copy link
Collaborator

@kchalkias kchalkias May 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will an Option<ID> work as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

&& targs.len() == 1
&& is_primitive(view, function_type_arguments, &targs[0])
}
SignatureToken::Vector(inner) => is_primitive(view, function_type_arguments, inner),

SignatureToken::TypeParameter(idx) => function_type_arguments
.get(*idx as usize)
.map(is_primitive_type_tag)
.unwrap_or(false),

SignatureToken::Signer
| SignatureToken::Struct(_)
| SignatureToken::StructInstantiation(_, _)
| SignatureToken::Reference(_)
| SignatureToken::MutableReference(_) => false,
}
Expand All @@ -921,24 +935,37 @@ fn is_primitive_type_tag(t: &TypeTag) -> bool {
match t {
TypeTag::Bool | TypeTag::U8 | TypeTag::U64 | TypeTag::U128 | TypeTag::Address => true,
TypeTag::Vector(inner) => is_primitive_type_tag(inner),
TypeTag::Signer | TypeTag::Struct(_) => false,
TypeTag::Struct(StructTag {
address,
module,
name,
type_params: type_args,
}) => {
let resolved_struct = (address, module.as_ident_str(), name.as_ident_str());
// is id or..
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this comment about?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is id or... is option of a primitive (down below)

if resolved_struct == RESOLVED_SUI_ID {
return true;
}
// is option of a primitive
resolved_struct == RESOLVED_STD_OPTION
&& type_args.len() == 1
&& is_primitive_type_tag(&type_args[0])
}
TypeTag::Signer => false,
}
}

fn type_check_struct(
module: &CompiledModule,
view: &BinaryIndexedView,
function_type_arguments: &[TypeTag],
arg_type: &StructTag,
param_type: &SignatureToken,
) -> Result<(), SuiError> {
if !struct_tag_equals_sig_token(module, function_type_arguments, arg_type, param_type) {
if !struct_tag_equals_sig_token(view, function_type_arguments, arg_type, param_type) {
Err(SuiError::TypeError {
error: format!(
"Expected argument of type {}, but found type {}",
sui_verifier::format_signature_token(
&BinaryIndexedView::Module(module),
param_type
),
sui_verifier::format_signature_token(view, param_type),
arg_type
),
})
Expand All @@ -948,7 +975,7 @@ fn type_check_struct(
}

fn type_tag_equals_sig_token(
module: &CompiledModule,
view: &BinaryIndexedView,
function_type_arguments: &[TypeTag],
arg_type: &TypeTag,
param_type: &SignatureToken,
Expand All @@ -963,7 +990,7 @@ fn type_tag_equals_sig_token(

(TypeTag::Vector(inner_arg_type), SignatureToken::Vector(inner_param_type)) => {
type_tag_equals_sig_token(
module,
view,
function_type_arguments,
inner_arg_type,
inner_param_type,
Expand All @@ -972,7 +999,7 @@ fn type_tag_equals_sig_token(

(TypeTag::Struct(arg_struct), SignatureToken::Struct(_))
| (TypeTag::Struct(arg_struct), SignatureToken::StructInstantiation(_, _)) => {
struct_tag_equals_sig_token(module, function_type_arguments, arg_struct, param_type)
struct_tag_equals_sig_token(view, function_type_arguments, arg_struct, param_type)
}

(_, SignatureToken::TypeParameter(idx)) => {
Expand All @@ -983,17 +1010,17 @@ fn type_tag_equals_sig_token(
}

fn struct_tag_equals_sig_token(
module: &CompiledModule,
view: &BinaryIndexedView,
function_type_arguments: &[TypeTag],
arg_type: &StructTag,
param_type: &SignatureToken,
) -> bool {
match param_type {
SignatureToken::Struct(idx) => {
struct_tag_equals_struct_inst(module, function_type_arguments, arg_type, *idx, &[])
struct_tag_equals_struct_inst(view, function_type_arguments, arg_type, *idx, &[])
}
SignatureToken::StructInstantiation(idx, args) => {
struct_tag_equals_struct_inst(module, function_type_arguments, arg_type, *idx, args)
struct_tag_equals_struct_inst(view, function_type_arguments, arg_type, *idx, args)
}
SignatureToken::TypeParameter(idx) => match &function_type_arguments[*idx as usize] {
TypeTag::Struct(s) => arg_type == s,
Expand All @@ -1004,14 +1031,13 @@ fn struct_tag_equals_sig_token(
}

fn struct_tag_equals_struct_inst(
module: &CompiledModule,
view: &BinaryIndexedView,
function_type_arguments: &[TypeTag],
arg_type: &StructTag,
param_type: StructHandleIndex,
param_type_arguments: &[SignatureToken],
) -> bool {
let view = BinaryIndexedView::Module(module);
let (address, module_name, struct_name) = sui_verifier::resolve_struct(&view, param_type);
let (address, module_name, struct_name) = sui_verifier::resolve_struct(view, param_type);

// same address, module, name, and type parameters
&arg_type.address == address
Expand All @@ -1021,7 +1047,7 @@ fn struct_tag_equals_struct_inst(
&& arg_type.type_params.iter().zip(param_type_arguments).all(
|(arg_type_arg, param_type_arg)| {
type_tag_equals_sig_token(
module,
view,
function_type_arguments,
arg_type_arg,
param_type_arg,
Expand Down
3 changes: 3 additions & 0 deletions crates/sui-types/src/base_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,9 @@ pub struct TransactionEffectsDigest(
pub [u8; TRANSACTION_DIGEST_LENGTH],
);

pub const STD_OPTION_MODULE_NAME: &IdentStr = ident_str!("Option");
pub const STD_OPTION_STRUCT_NAME: &IdentStr = STD_OPTION_MODULE_NAME;

pub const TX_CONTEXT_MODULE_NAME: &IdentStr = ident_str!("TxContext");
pub const TX_CONTEXT_STRUCT_NAME: &IdentStr = TX_CONTEXT_MODULE_NAME;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
processed 2 tasks

task 0 'publish'. lines 6-16:
Error: Failed to verify the Move module, reason: "Invalid entry point parameter type. Expected primitive or object type. Got: Std::Option::Option<T0>".

task 1 'publish'. lines 18-28:
Error: Failed to verify the Move module, reason: "Invalid entry point parameter type. Expected primitive or object type. Got: vector<Std::Option::Option<T0>>".
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

// invalid, type parameters with key are not valid when nested as no primitive has key

//# publish
module 0x0.M {
import 0x2.TxContext;
import 0x1.Option;

public(script) no<T:key>(l0: Option.Option<T>, ctx: &mut TxContext.TxContext) {
label l0:
abort 0;
}

}

//# publish
module 0x0.M {
import 0x2.TxContext;
import 0x1.Option;

public(script) no<T:key>(l0: vector<Option.Option<T>>, ctx: &mut TxContext.TxContext) {
label l0:
abort 0;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
processed 1 task

task 0 'publish'. lines 6-16:
created: object(103)
written: object(102)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

// valid, type parameters with key are valid as long as they are not nested

//# publish
module 0x0.M {
import 0x2.TxContext;
import 0x1.Option;

public(script) yes<T:key>(l0: T, l1: &T, l2: &mut T, ctx: &mut TxContext.TxContext) {
label l0:
abort 0;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
processed 1 task

task 0 'publish'. lines 6-21:
created: object(103)
written: object(102)
21 changes: 21 additions & 0 deletions crates/sui-verifier-transactional-tests/tests/entry_points/id.mvir
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

// valid, ID is allowed

//# publish
module 0x0.M {
import 0x2.TxContext;
import 0x2.ID;

public(script) yes<T>(
l0: ID.ID,
l1: vector<ID.ID>,
l2: vector<vector<ID.ID>>,
ctx: &mut TxContext.TxContext,
) {
label l0:
abort 0;
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
processed 1 task

task 0 'publish'. lines 6-16:
Error: Failed to verify the Move module, reason: "Invalid entry point parameter type. Expected primitive or object type. Got: Std::Option::Option<u64>".
task 0 'publish'. lines 6-23:
created: object(103)
written: object(102)
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

// invalid, non key structs are not supported
// valid, option of primitives is allowed

//# publish
module 0x0.M {
import 0x2.TxContext;
import 0x1.Option;

public(script) no(s: Option.Option<u64>, ctx: &mut TxContext.TxContext) {
public(script) yes<T>(
l0: Option.Option<u64>,
l1: Option.Option<Option.Option<u64>>,
l2: Option.Option<vector<u64>>,
l3: vector<Option.Option<u64>>,
l4: Option.Option<Option.Option<T>>,
ctx: &mut TxContext.TxContext
) {
label l0:
abort 0;
}
Expand Down
Loading