Skip to content

Commit

Permalink
Implement rust logics for permissioned signer
Browse files Browse the repository at this point in the history
  • Loading branch information
runtian-zhou committed Sep 17, 2024
1 parent 8cd68d5 commit 6592c01
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 20 deletions.
5 changes: 5 additions & 0 deletions aptos-move/framework/src/natives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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!(
Expand Down
107 changes: 107 additions & 0 deletions aptos-move/framework/src/natives/permissioned_signer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// 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::{SignerRef, Struct, StructRef, Value},
};
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<Type>,
mut arguments: VecDeque<Value>,
) -> SafeNativeResult<SmallVec<[Value; 1]>> {
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<Type>,
mut arguments: VecDeque<Value>,
) -> SafeNativeResult<SmallVec<[Value; 1]>> {
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 });

Check warning on line 56 in aptos-move/framework/src/natives/permissioned_signer.rs

View check run for this annotation

Codecov / codecov/patch

aptos-move/framework/src/natives/permissioned_signer.rs#L56

Added line #L56 was not covered by tests
}

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<Type>,
mut arguments: VecDeque<Value>,
) -> SafeNativeResult<SmallVec<[Value; 1]>> {
debug_assert!(arguments.len() == 1);

let s_arg = safely_pop_arg!(arguments, StructRef);
let fields = s_arg.read_ref()?.value_as::<Struct>()?.unpack()?;

// context.charge()?;

Ok(smallvec![Value::struct_(Struct::pack_variant(1, fields))])
}

/***************************************************************************************************
* module
*
**************************************************************************************************/
pub fn make_all(
builder: &SafeNativeBuilder,
) -> impl Iterator<Item = (String, NativeFunction)> + '_ {
let natives = [
(
"is_permissioned_signer",
native_is_permissioned_signer as RawSafeNative,
),
(
"permission_signer",
native_permission_signer
),
(
"signer_from_permissioned_impl",
native_signer_from_permissioned
),
];

builder.make_named_natives(natives)
}
18 changes: 15 additions & 3 deletions third_party/move/move-compiler/src/unit_test/plan_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
expansion::ast::{
self as E, Address, Attribute, AttributeValue, ModuleAccess_, ModuleIdent, ModuleIdent_,
},
hlir::ast::{BaseType_, SingleType_},
parser::ast::ConstantName,
shared::{
known_attributes::{AttributeKind, KnownAttribute, TestingAttribute},
Expand Down Expand Up @@ -159,10 +160,21 @@ fn build_test_info<'func>(

let test_annotation_params = parse_test_attribute(context, test_attribute, 0);
let mut arguments = Vec::new();
for (var, _) in &function.signature.parameters {
for (var, ty) in &function.signature.parameters {
match test_annotation_params.get(&var.value()) {
Some(value) => arguments.push(value.clone()),
None => {
Some(MoveValue::Address(addr)) => match &ty.value {
SingleType_::Base(ty) => {
arguments.push(if ty == &BaseType_::address(ty.loc) {
MoveValue::Address(*addr)
} else {
MoveValue::Signer(*addr)
})
},
SingleType_::Ref(_, _) => {
arguments.push(MoveValue::Signer(*addr))
},
},
_ => {
let missing_param_msg = "Missing test parameter assignment in test. Expected a \
parameter to be assigned in this attribute";
context.env.add_diag(diag!(
Expand Down
7 changes: 7 additions & 0 deletions third_party/move/move-core/types/src/unit_tests/value_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,10 @@ fn nested_typed_struct_deserialization() {
})
);
}

#[test]
fn signer_deserialization() {
let v = MoveValue::Signer(AccountAddress::ZERO);
let bytes = v.simple_serialize().unwrap();
assert_eq!(MoveValue::simple_deserialize(&bytes, &crate::value::MoveTypeLayout::Signer).unwrap(), v);
}
14 changes: 12 additions & 2 deletions third_party/move/move-core/types/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,10 @@ impl MoveStructLayout {
},
}
}

pub fn signer() -> Self {
MoveStructLayout::RuntimeVariants(vec![vec![MoveTypeLayout::Address], vec![MoveTypeLayout::Address, MoveTypeLayout::Address, MoveTypeLayout::U64]])
}
}

impl<'d> serde::de::DeserializeSeed<'d> for &MoveTypeLayout {
Expand All @@ -473,7 +477,11 @@ impl<'d> serde::de::DeserializeSeed<'d> for &MoveTypeLayout {
AccountAddress::deserialize(deserializer).map(MoveValue::Address)
},
MoveTypeLayout::Signer => {
AccountAddress::deserialize(deserializer).map(MoveValue::Signer)
let (_, fields) = MoveStructLayout::signer().deserialize(deserializer)?.into_optional_variant_and_fields();
Ok(MoveValue::Signer(match fields[0] {
MoveValue::Address(addr) => addr,
_ => return Err(D::Error::custom("signer deserialization error")),

Check warning on line 483 in third_party/move/move-core/types/src/value.rs

View check run for this annotation

Codecov / codecov/patch

third_party/move/move-core/types/src/value.rs#L483

Added line #L483 was not covered by tests
}))
},
MoveTypeLayout::Struct(ty) => Ok(MoveValue::Struct(ty.deserialize(deserializer)?)),
MoveTypeLayout::Vector(layout) => Ok(MoveValue::Vector(
Expand Down Expand Up @@ -678,7 +686,9 @@ impl serde::Serialize for MoveValue {
MoveValue::U128(i) => serializer.serialize_u128(*i),
MoveValue::U256(i) => i.serialize(serializer),
MoveValue::Address(a) => a.serialize(serializer),
MoveValue::Signer(a) => a.serialize(serializer),
MoveValue::Signer(a) => {
MoveStruct::new_variant(0, vec![MoveValue::Address(*a)]).serialize(serializer)
},
MoveValue::Vector(v) => {
let mut t = serializer.serialize_seq(Some(v.len()))?;
for val in v {
Expand Down
4 changes: 3 additions & 1 deletion third_party/move/move-stdlib/src/natives/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ fn native_borrow_address(
debug_assert!(arguments.len() == 1);

let signer_reference = pop_arg!(arguments, SignerRef);
let out = signer_reference.borrow_signer()?;
println!("borrow_address: {:?}", out);

Ok(NativeResult::ok(gas_params.base, smallvec![
signer_reference.borrow_signer()?
out

Check warning on line 44 in third_party/move/move-stdlib/src/natives/signer.rs

View check run for this annotation

Codecov / codecov/patch

third_party/move/move-stdlib/src/natives/signer.rs#L44

Added line #L44 was not covered by tests
]))
}

Expand Down
4 changes: 2 additions & 2 deletions third_party/move/move-vm/runtime/src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2988,7 +2988,7 @@ impl Frame {
let resource = interpreter.operand_stack.pop()?;
let signer_reference = interpreter.operand_stack.pop_as::<StructRef>()?;
let addr = signer_reference
.borrow_field(0)?
.borrow_field(1)?
.value_as::<Reference>()?
.read_ref()?
.value_as::<AccountAddress>()?;
Expand All @@ -3008,7 +3008,7 @@ impl Frame {
let resource = interpreter.operand_stack.pop()?;
let signer_reference = interpreter.operand_stack.pop_as::<StructRef>()?;
let addr = signer_reference
.borrow_field(0)?
.borrow_field(1)?
.value_as::<Reference>()?
.read_ref()?
.value_as::<AccountAddress>()?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,12 @@ fn test_serialized_size() {
assert_err!(serialized_size_allowing_delayed_values(&value, &layout));
}
}

#[test]
fn signer_round_trip_vm_value() {
let v = MoveValue::Signer(AccountAddress::ZERO);
let bytes = v.simple_serialize().unwrap();
let vm_value = Value::simple_deserialize(&bytes, &MoveTypeLayout::Signer).unwrap();
let vm_bytes = serialize_and_allow_delayed_values(&vm_value, &MoveTypeLayout::Signer).unwrap().unwrap();
assert_eq!(v, MoveValue::simple_deserialize(&vm_bytes, &MoveTypeLayout::Signer).unwrap())
}
47 changes: 35 additions & 12 deletions third_party/move/move-vm/types/src/values/values_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ impl Container {
}

fn signer(x: AccountAddress) -> Self {
Container::Struct(Rc::new(RefCell::new(vec![ValueImpl::Address(x)])))
Container::Struct(Rc::new(RefCell::new(vec![ValueImpl::U16(0), ValueImpl::Address(x)])))
}
}

Expand Down Expand Up @@ -1058,7 +1058,31 @@ impl Locals {

impl SignerRef {
pub fn borrow_signer(&self) -> PartialVMResult<Value> {
Ok(Value(self.0.borrow_elem(0)?))
Ok(Value(self.0.borrow_elem(1)?))
}

pub fn is_permissioned(&self) -> PartialVMResult<bool> {
match &self.0 {
ContainerRef::Local(Container::Struct(s)) => {
Ok(*s.borrow()[0].as_value_ref::<u16>()? == 1)
}
_ => Err(
PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
.with_message(format!("unexpected signer value: {:?}", self)),
)

Check warning on line 1072 in third_party/move/move-vm/types/src/values/values_impl.rs

View check run for this annotation

Codecov / codecov/patch

third_party/move/move-vm/types/src/values/values_impl.rs#L1069-L1072

Added lines #L1069 - L1072 were not covered by tests
}
}

pub fn permissioned_signer(&self) -> PartialVMResult<Value> {
match &self.0 {
ContainerRef::Local(Container::Struct(s)) => {
Ok(Value::signer(*s.borrow()[1].as_value_ref::<AccountAddress>()?))
}
_ => Err(
PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
.with_message(format!("unexpected signer value: {:?}", self)),
)

Check warning on line 1084 in third_party/move/move-vm/types/src/values/values_impl.rs

View check run for this annotation

Codecov / codecov/patch

third_party/move/move-vm/types/src/values/values_impl.rs#L1081-L1084

Added lines #L1081 - L1084 were not covered by tests
}
}
}

Expand Down Expand Up @@ -3224,17 +3248,10 @@ impl<'c, 'l, 'v, C: CustomSerializer> serde::Serialize

// Signer.
(L::Signer, ValueImpl::Container(Container::Struct(r))) => {
let v = r.borrow();
if v.len() != 1 {
return Err(invariant_violation::<S>(format!(
"cannot serialize container as a signer -- expected 1 field got {}",
v.len()
)));
}
(SerializationReadyValue {
custom_serializer: self.custom_serializer,
layout: &L::Address,
value: &v[0],
layout: &MoveStructLayout::signer(),
value: &*r.borrow(),
})
.serialize(serializer)
},
Expand Down Expand Up @@ -3368,7 +3385,13 @@ impl<'d, 'c, C: CustomDeserializer> serde::de::DeserializeSeed<'d>
L::U128 => u128::deserialize(deserializer).map(Value::u128),
L::U256 => u256::U256::deserialize(deserializer).map(Value::u256),
L::Address => AccountAddress::deserialize(deserializer).map(Value::address),
L::Signer => AccountAddress::deserialize(deserializer).map(Value::signer),
L::Signer => {
let seed = DeserializationSeed {
custom_deserializer: self.custom_deserializer,
layout: &MoveStructLayout::signer(),
};
Ok(Value::struct_(seed.deserialize(deserializer)?))
},

// Structs.
L::Struct(struct_layout) => {
Expand Down

0 comments on commit 6592c01

Please sign in to comment.