diff --git a/aptos-move/framework/src/natives/mod.rs b/aptos-move/framework/src/natives/mod.rs index dcfc80407f932..c251893032810 100644 --- a/aptos-move/framework/src/natives/mod.rs +++ b/aptos-move/framework/src/natives/mod.rs @@ -16,6 +16,7 @@ pub mod hash; pub mod object; pub mod object_code_deployment; pub mod randomness; +pub mod permissioned_signer; pub mod state_storage; pub mod string_utils; pub mod transaction_context; @@ -91,6 +92,10 @@ pub fn all_natives( "dispatchable_fungible_asset", dispatchable_fungible_asset::make_all(builder) ); + add_natives_from_module!( + "permissioned_signer", + permissioned_signer::make_all(builder) + ); if inject_create_signer_for_gov_sim { add_natives_from_module!( diff --git a/aptos-move/framework/src/natives/permissioned_signer.rs b/aptos-move/framework/src/natives/permissioned_signer.rs new file mode 100644 index 0000000000000..9c4f7e438c3bb --- /dev/null +++ b/aptos-move/framework/src/natives/permissioned_signer.rs @@ -0,0 +1,106 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 +use aptos_native_interface::{ + safely_pop_arg, RawSafeNative, SafeNativeBuilder, SafeNativeContext, SafeNativeError, + SafeNativeResult, +}; +use move_vm_runtime::native_functions::NativeFunction; +use move_vm_types::{ + loaded_data::runtime_types::Type, + values::{StructRef, Value, SignerRef}, +}; +use smallvec::{smallvec, SmallVec}; +use std::collections::VecDeque; + +/*************************************************************************************************** + * native fun is_permissioned_signer + * + * Returns true if the signer passed in is a permissioned signer + * gas cost: base_cost + * + **************************************************************************************************/ +fn native_is_permissioned_signer( + _context: &mut SafeNativeContext, + _ty_args: Vec, + mut arguments: VecDeque, +) -> SafeNativeResult> { + debug_assert!(arguments.len() == 1); + + let s_arg = safely_pop_arg!(arguments, SignerRef); + + // context.charge()?; + let result = s_arg.is_permissioned()?; + + + Ok(smallvec![Value::bool(result)]) +} + +/*************************************************************************************************** + * native fun permission_signer + * + * Returns the permission signer if the signer passed in is a permissioned signer + * gas cost: base_cost + * + **************************************************************************************************/ + fn native_permission_signer( + _context: &mut SafeNativeContext, + _ty_args: Vec, + mut arguments: VecDeque, +) -> SafeNativeResult> { + debug_assert!(arguments.len() == 1); + + let s_arg = safely_pop_arg!(arguments, SignerRef); + + // context.charge()?; + if !s_arg.is_permissioned()? { + return Err(SafeNativeError::Abort { abort_code: 3 }); + } + + Ok(smallvec![s_arg.permissioned_signer()?]) +} + +/*************************************************************************************************** + * native fun signer_from_permissioned + * + * Returns the permission signer from a master signer. + * gas cost: base_cost + * + **************************************************************************************************/ + fn native_signer_from_permissioned( + _context: &mut SafeNativeContext, + _ty_args: Vec, + mut arguments: VecDeque, +) -> SafeNativeResult> { + debug_assert!(arguments.len() == 1); + + let s_arg = safely_pop_arg!(arguments, StructRef); + + // context.charge()?; + + Ok(smallvec![s_arg.read_ref()?]) +} + +/*************************************************************************************************** + * module + * + **************************************************************************************************/ +pub fn make_all( + builder: &SafeNativeBuilder, +) -> impl Iterator + '_ { + let natives = [ + ( + "is_permissioned_signer", + native_is_permissioned_signer as RawSafeNative, + ), + ( + "permission_signer", + native_permission_signer + ), + ( + "signer_from_permissioned", + native_signer_from_permissioned + ), + ]; + + builder.make_named_natives(natives) +} diff --git a/third_party/move/move-vm/types/src/values/values_impl.rs b/third_party/move/move-vm/types/src/values/values_impl.rs index 006c16d6b9dd1..81b818997488d 100644 --- a/third_party/move/move-vm/types/src/values/values_impl.rs +++ b/third_party/move/move-vm/types/src/values/values_impl.rs @@ -285,6 +285,10 @@ impl Container { fn signer(x: AccountAddress) -> Self { Container::Struct(Rc::new(RefCell::new(vec![ValueImpl::Address(x)]))) } + + fn permissioned_signer(x: AccountAddress, permission_address: AccountAddress) -> Self { + Container::Struct(Rc::new(RefCell::new(vec![ValueImpl::Address(x), ValueImpl::Address(permission_address)]))) + } } /*************************************************************************************** @@ -1060,6 +1064,30 @@ impl SignerRef { pub fn borrow_signer(&self) -> PartialVMResult { Ok(Value(self.0.borrow_elem(0)?)) } + + pub fn is_permissioned(&self) -> PartialVMResult { + match &self.0 { + ContainerRef::Local(Container::Struct(s)) => { + Ok(s.borrow().len() == 2) + } + _ => Err( + PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) + .with_message(format!("unexpected signer value: {:?}", self)), + ) + } + } + + pub fn permissioned_signer(&self) -> PartialVMResult { + match &self.0 { + ContainerRef::Local(Container::Struct(s)) if s.borrow().len() == 2 => { + Ok(Value::signer(*s.borrow()[1].as_value_ref::()?)) + } + _ => Err( + PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) + .with_message(format!("unexpected signer value: {:?}", self)), + ) + } + } } /*************************************************************************************** @@ -1221,6 +1249,10 @@ impl Value { Self(ValueImpl::Container(Container::signer(x))) } + pub fn permissioned_signer(x: AccountAddress, permission_address: AccountAddress) -> Self { + Self(ValueImpl::Container(Container::permissioned_signer(x, permission_address))) + } + /// Create a "unowned" reference to a signer value (&signer) for populating the &signer in /// execute function pub fn signer_reference(x: AccountAddress) -> Self {