diff --git a/aptos-move/aptos-gas-schedule/src/gas_schedule/aptos_framework.rs b/aptos-move/aptos-gas-schedule/src/gas_schedule/aptos_framework.rs index d48c19c67e04b..b9bb7deccfe55 100644 --- a/aptos-move/aptos-gas-schedule/src/gas_schedule/aptos_framework.rs +++ b/aptos-move/aptos-gas-schedule/src/gas_schedule/aptos_framework.rs @@ -6,7 +6,7 @@ use crate::{ gas_feature_versions::{RELEASE_V1_14, RELEASE_V1_8, RELEASE_V1_9_SKIPPED}, gas_schedule::NativeGasParameters, - ver::gas_feature_versions::{RELEASE_V1_12, RELEASE_V1_13, RELEASE_V1_23}, + ver::gas_feature_versions::{RELEASE_V1_12, RELEASE_V1_13, RELEASE_V1_23, RELEASE_V1_26}, }; use aptos_gas_algebra::{ InternalGas, InternalGasPerAbstractValueUnit, InternalGasPerArg, InternalGasPerByte, @@ -20,6 +20,11 @@ crate::gas_schedule::macros::define_gas_parameters!( [account_create_address_base: InternalGas, "account.create_address.base", 1102], [account_create_signer_base: InternalGas, "account.create_signer.base", 1102], + // Permissioned signer gas parameters + [permission_address_base: InternalGas, { RELEASE_V1_26 => "permissioned_signer.permission_address.base"}, 1102], + [is_permissioned_signer_base: InternalGas, { RELEASE_V1_26 => "permissioned_signer.is_permissioned_signer.base"}, 1102], + [signer_from_permissioned_handle_base: InternalGas, { RELEASE_V1_26 => "permissioned_signer.signer_from_permissioned_handle.base"}, 1102], + // BN254 algebra gas parameters begin. // Generated at time 1701559125.5498126 by `scripts/algebra-gas/update_bn254_algebra_gas_params.py` with gas_per_ns=209.10511688369482. [algebra_ark_bn254_fq12_add: InternalGas, { 12.. => "algebra.ark_bn254_fq12_add" }, 809], diff --git a/aptos-move/aptos-gas-schedule/src/ver.rs b/aptos-move/aptos-gas-schedule/src/ver.rs index 9e40e1d833880..feb190e3b8e0e 100644 --- a/aptos-move/aptos-gas-schedule/src/ver.rs +++ b/aptos-move/aptos-gas-schedule/src/ver.rs @@ -89,4 +89,5 @@ pub mod gas_feature_versions { pub const RELEASE_V1_22: u64 = 26; pub const RELEASE_V1_23: u64 = 27; pub const RELEASE_V1_24: u64 = 28; + pub const RELEASE_V1_26: u64 = 29; } diff --git a/aptos-move/aptos-vm-profiling/src/bins/run_move.rs b/aptos-move/aptos-vm-profiling/src/bins/run_move.rs index 667a7c49c0bb4..3a1c51b715662 100644 --- a/aptos-move/aptos-vm-profiling/src/bins/run_move.rs +++ b/aptos-move/aptos-vm-profiling/src/bins/run_move.rs @@ -37,7 +37,7 @@ fn make_native_create_signer() -> NativeFunction { let address = pop_arg!(args, AccountAddress); - Ok(NativeResult::ok(0.into(), smallvec![Value::signer( + Ok(NativeResult::ok(0.into(), smallvec![Value::master_signer( address )])) }) diff --git a/aptos-move/e2e-move-tests/src/tests/gas.rs b/aptos-move/e2e-move-tests/src/tests/gas.rs index ceab7b3508fa9..5af30e8956693 100644 --- a/aptos-move/e2e-move-tests/src/tests/gas.rs +++ b/aptos-move/e2e-move-tests/src/tests/gas.rs @@ -28,7 +28,7 @@ use aptos_types::{ transaction::{EntryFunction, TransactionPayload}, }; use aptos_vm_environment::prod_configs::set_paranoid_type_checks; -use move_core_types::{identifier::Identifier, language_storage::ModuleId}; +use move_core_types::{identifier::Identifier, language_storage::ModuleId, value::MoveValue}; use rand::{rngs::StdRng, SeedableRng}; use sha3::{Digest, Sha3_512}; use std::path::Path; @@ -55,7 +55,9 @@ fn test_modify_gas_schedule_check_hash() { "set_for_next_epoch_check_hash", vec![], vec![ - bcs::to_bytes(&CORE_CODE_ADDRESS).unwrap(), + MoveValue::Signer(CORE_CODE_ADDRESS) + .simple_serialize() + .unwrap(), bcs::to_bytes(&old_hash).unwrap(), bcs::to_bytes(&bcs::to_bytes(&gas_schedule).unwrap()).unwrap(), ], @@ -64,7 +66,9 @@ fn test_modify_gas_schedule_check_hash() { harness .executor .exec("reconfiguration_with_dkg", "finish", vec![], vec![ - bcs::to_bytes(&CORE_CODE_ADDRESS).unwrap(), + MoveValue::Signer(CORE_CODE_ADDRESS) + .simple_serialize() + .unwrap(), ]); let (_, gas_params) = harness.get_gas_params(); diff --git a/aptos-move/e2e-move-tests/src/tests/script_with_signer.data/pack/Move.toml b/aptos-move/e2e-move-tests/src/tests/script_with_signer.data/pack/Move.toml new file mode 100644 index 0000000000000..55c9545287791 --- /dev/null +++ b/aptos-move/e2e-move-tests/src/tests/script_with_signer.data/pack/Move.toml @@ -0,0 +1,5 @@ +[package] +name = "test" +version = "0.0.0" + +[dependencies] diff --git a/aptos-move/e2e-move-tests/src/tests/script_with_signer.data/pack/sources/test.move b/aptos-move/e2e-move-tests/src/tests/script_with_signer.data/pack/sources/test.move new file mode 100644 index 0000000000000..0282617af103e --- /dev/null +++ b/aptos-move/e2e-move-tests/src/tests/script_with_signer.data/pack/sources/test.move @@ -0,0 +1,3 @@ +script { + fun main(s1: &signer, u: u64, s2: &signer) {} +} diff --git a/aptos-move/e2e-move-tests/src/tests/scripts.rs b/aptos-move/e2e-move-tests/src/tests/scripts.rs index 40395dba22ea4..4970695c461ed 100644 --- a/aptos-move/e2e-move-tests/src/tests/scripts.rs +++ b/aptos-move/e2e-move-tests/src/tests/scripts.rs @@ -6,9 +6,9 @@ use aptos_language_e2e_tests::account::TransactionBuilder; use aptos_types::{ account_address::AccountAddress, on_chain_config::FeatureFlag, - transaction::{Script, TransactionArgument}, + transaction::{Script, TransactionArgument, TransactionStatus}, }; -use move_core_types::language_storage::TypeTag; +use move_core_types::{language_storage::TypeTag, value::MoveValue}; #[test] fn test_script_with_object_parameter() { @@ -146,6 +146,45 @@ fn test_script_with_type_parameter() { assert_success!(status); } +#[test] +fn test_script_with_signer_parameter() { + let mut h = MoveHarness::new(); + + let alice = h.new_account_at(AccountAddress::from_hex_literal("0xa11ce").unwrap()); + + let package = build_package( + common::test_dir_path("script_with_signer.data/pack"), + aptos_framework::BuildOptions::default(), + ) + .expect("building package must succeed"); + + let code = package.extract_script_code().into_iter().next().unwrap(); + + let txn = TransactionBuilder::new(alice.clone()) + .script(Script::new(code, vec![], vec![ + TransactionArgument::U64(0), + TransactionArgument::Serialized( + MoveValue::Signer(*alice.address()) + .simple_serialize() + .unwrap(), + ), + ])) + .sequence_number(10) + .max_gas_amount(1_000_000) + .gas_unit_price(1) + .sign(); + + let status = h.run(txn); + assert_eq!( + status, + TransactionStatus::Keep( + aptos_types::transaction::ExecutionStatus::MiscellaneousError(Some( + aptos_types::vm_status::StatusCode::INVALID_MAIN_FUNCTION_SIGNATURE + )) + ) + ); +} + #[test] fn test_two_to_two_transfer() { let mut h = MoveHarness::new(); diff --git a/aptos-move/e2e-tests/src/executor.rs b/aptos-move/e2e-tests/src/executor.rs index 2d3b78221b400..c2039a589d6d6 100644 --- a/aptos-move/e2e-tests/src/executor.rs +++ b/aptos-move/e2e-tests/src/executor.rs @@ -74,6 +74,7 @@ use move_core_types::{ identifier::Identifier, language_storage::{ModuleId, StructTag, TypeTag}, move_resource::{MoveResource, MoveStructType}, + value::MoveValue, }; use move_vm_runtime::{ module_traversal::{TraversalContext, TraversalStorage}, @@ -1042,13 +1043,23 @@ impl FakeExecutor { let mut arg = args.clone(); match &dynamic_args { ExecFuncTimerDynamicArgs::DistinctSigners => { - arg.insert(0, bcs::to_bytes(&extra_accounts.pop().unwrap()).unwrap()); + arg.insert( + 0, + MoveValue::Signer(extra_accounts.pop().unwrap()) + .simple_serialize() + .unwrap(), + ); }, ExecFuncTimerDynamicArgs::DistinctSignersAndFixed(signers) => { for signer in signers.iter().rev() { - arg.insert(0, bcs::to_bytes(&signer).unwrap()); + arg.insert(0, MoveValue::Signer(*signer).simple_serialize().unwrap()); } - arg.insert(0, bcs::to_bytes(&extra_accounts.pop().unwrap()).unwrap()); + arg.insert( + 0, + MoveValue::Signer(extra_accounts.pop().unwrap()) + .simple_serialize() + .unwrap(), + ); }, _ => {}, } diff --git a/aptos-move/framework/aptos-framework/doc/transaction_context.md b/aptos-move/framework/aptos-framework/doc/transaction_context.md index cc7d9010ffc74..d4dbf2d635811 100644 --- a/aptos-move/framework/aptos-framework/doc/transaction_context.md +++ b/aptos-move/framework/aptos-framework/doc/transaction_context.md @@ -1029,6 +1029,7 @@ Returns the inner entry function payload of the multisig payload.
pragma opaque;
+aborts_if [abstract] false;
 ensures [abstract] result == spec_generate_unique_address();
 
@@ -1055,6 +1056,7 @@ Returns the inner entry function payload of the multisig payload.
pragma opaque;
+aborts_if [abstract] false;
 // This enforces high-level requirement 3:
 ensures [abstract] result == spec_generate_unique_address();
 
diff --git a/aptos-move/framework/aptos-framework/doc/util.md b/aptos-move/framework/aptos-framework/doc/util.md index 58f3e29748c93..ca6b1f1264c0e 100644 --- a/aptos-move/framework/aptos-framework/doc/util.md +++ b/aptos-move/framework/aptos-framework/doc/util.md @@ -29,6 +29,8 @@ Note that this function does not put any constraint on T. If code u deserialized a linear value, its their responsibility that the data they deserialize is owned. +Function would abort if T has signer in it. +
public(friend) fun from_bytes<T>(bytes: vector<u8>): T
 
diff --git a/aptos-move/framework/aptos-framework/sources/transaction_context.spec.move b/aptos-move/framework/aptos-framework/sources/transaction_context.spec.move index f9837e26e6a75..07487cb0919ae 100644 --- a/aptos-move/framework/aptos-framework/sources/transaction_context.spec.move +++ b/aptos-move/framework/aptos-framework/sources/transaction_context.spec.move @@ -58,11 +58,13 @@ spec aptos_framework::transaction_context { } spec generate_unique_address(): address { pragma opaque; + aborts_if [abstract] false; ensures [abstract] result == spec_generate_unique_address(); } spec fun spec_generate_unique_address(): address; spec generate_auid_address(): address { pragma opaque; + aborts_if [abstract] false; // property 3: Generating the unique address should return a vector with 32 bytes, if the auid feature flag is enabled. /// [high-level-req-3] ensures [abstract] result == spec_generate_unique_address(); diff --git a/aptos-move/framework/aptos-framework/sources/util.move b/aptos-move/framework/aptos-framework/sources/util.move index 332afa299c784..f57d3cfbf26cb 100644 --- a/aptos-move/framework/aptos-framework/sources/util.move +++ b/aptos-move/framework/aptos-framework/sources/util.move @@ -8,9 +8,17 @@ module aptos_framework::util { /// Note that this function does not put any constraint on `T`. If code uses this function to /// deserialized a linear value, its their responsibility that the data they deserialize is /// owned. + /// + /// Function would abort if T has signer in it. public(friend) native fun from_bytes(bytes: vector): T; public fun address_from_bytes(bytes: vector): address { from_bytes(bytes) } + + #[test(s1 = @0x123)] + #[expected_failure(abort_code = 0x10001, location = Self)] + fun test_signer_roundtrip(s1: signer) { + from_bytes(bcs::to_bytes(&s1)); + } } diff --git a/aptos-move/framework/aptos-stdlib/doc/from_bcs.md b/aptos-move/framework/aptos-stdlib/doc/from_bcs.md index cdcd6b3e1223e..34406eeb53b0c 100644 --- a/aptos-move/framework/aptos-stdlib/doc/from_bcs.md +++ b/aptos-move/framework/aptos-stdlib/doc/from_bcs.md @@ -306,6 +306,8 @@ Note that this function does not put any constraint on T. If code u deserialize a linear value, its their responsibility that the data they deserialize is owned. +Function would abort if T has signer in it. +
public(friend) fun from_bytes<T>(bytes: vector<u8>): T
 
diff --git a/aptos-move/framework/aptos-stdlib/doc/smart_table.md b/aptos-move/framework/aptos-stdlib/doc/smart_table.md index ac5388661f2ca..83eb27ba47fff 100644 --- a/aptos-move/framework/aptos-stdlib/doc/smart_table.md +++ b/aptos-move/framework/aptos-stdlib/doc/smart_table.md @@ -1479,6 +1479,7 @@ map_spec_has_key = spec_contains;
pragma verify = false;
+pragma opaque;
 
@@ -1495,6 +1496,7 @@ map_spec_has_key = spec_contains;
pragma verify = false;
+pragma opaque;
 
diff --git a/aptos-move/framework/aptos-stdlib/sources/data_structures/smart_table.spec.move b/aptos-move/framework/aptos-stdlib/sources/data_structures/smart_table.spec.move index d905a0a40bb3a..4344eb2329efb 100644 --- a/aptos-move/framework/aptos-stdlib/sources/data_structures/smart_table.spec.move +++ b/aptos-move/framework/aptos-stdlib/sources/data_structures/smart_table.spec.move @@ -24,10 +24,12 @@ spec aptos_std::smart_table { spec destroy(self: SmartTable) { pragma verify = false; + pragma opaque; } spec clear(self: &mut SmartTable) { pragma verify = false; + pragma opaque; } spec split_one_bucket(self: &mut SmartTable) { diff --git a/aptos-move/framework/aptos-stdlib/sources/from_bcs.move b/aptos-move/framework/aptos-stdlib/sources/from_bcs.move index 3eb6e2177d2f4..045e77821d385 100644 --- a/aptos-move/framework/aptos-stdlib/sources/from_bcs.move +++ b/aptos-move/framework/aptos-stdlib/sources/from_bcs.move @@ -64,6 +64,8 @@ module aptos_std::from_bcs { /// Note that this function does not put any constraint on `T`. If code uses this function to /// deserialize a linear value, its their responsibility that the data they deserialize is /// owned. + /// + /// Function would abort if T has signer in it. public(friend) native fun from_bytes(bytes: vector): T; friend aptos_std::any; friend aptos_std::copyable_any; @@ -88,4 +90,10 @@ module aptos_std::from_bcs { let bad_vec = b"01"; to_address(bad_vec); } + + #[test(s1 = @0x123)] + #[expected_failure(abort_code = 0x10001, location = Self)] + fun test_signer_roundtrip(s1: signer) { + from_bytes(bcs::to_bytes(&s1)); + } } diff --git a/aptos-move/framework/move-stdlib/doc/bcs.md b/aptos-move/framework/move-stdlib/doc/bcs.md index 8c5b4d152d962..954370f80c5c9 100644 --- a/aptos-move/framework/move-stdlib/doc/bcs.md +++ b/aptos-move/framework/move-stdlib/doc/bcs.md @@ -26,6 +26,7 @@ details on BCS. ## Function `to_bytes` +Note: all natives would fail if the MoveValue contains a permissioned signer in it. Returns the binary representation of v in BCS (Binary Canonical Serialization) format. Aborts with 0x1c5 error code if serialization fails. diff --git a/aptos-move/framework/move-stdlib/doc/signer.md b/aptos-move/framework/move-stdlib/doc/signer.md index f6de8799b571c..13e9e008ef8d3 100644 --- a/aptos-move/framework/move-stdlib/doc/signer.md +++ b/aptos-move/framework/move-stdlib/doc/signer.md @@ -18,12 +18,26 @@ ## Function `borrow_address` -Borrows the address of the signer -Conceptually, you can think of the signer as being a struct wrapper around an -address +signer is a builtin move type that represents an address that has been verfied by the VM. + +VM Runtime representation is equivalent to following: +``` +enum signer has drop { +Master { account: address }, +Permissioned { account: address, permissions_address: address }, +} +``` + +for bcs serialization: + ``` -struct signer has drop { addr: address } +struct signer has drop { +account: address, +} ``` +^ The discrepency is needed to maintain backwards compatibility of signer serialization +semantics. + borrow_address borrows this inner field diff --git a/aptos-move/framework/move-stdlib/sources/bcs.move b/aptos-move/framework/move-stdlib/sources/bcs.move index b803428eef991..1113a02c9c269 100644 --- a/aptos-move/framework/move-stdlib/sources/bcs.move +++ b/aptos-move/framework/move-stdlib/sources/bcs.move @@ -5,6 +5,8 @@ module std::bcs { use std::option::Option; + /// Note: all natives would fail if the MoveValue contains a permissioned signer in it. + /// Returns the binary representation of `v` in BCS (Binary Canonical Serialization) format. /// Aborts with `0x1c5` error code if serialization fails. native public fun to_bytes(v: &MoveValue): vector; diff --git a/aptos-move/framework/move-stdlib/sources/signer.move b/aptos-move/framework/move-stdlib/sources/signer.move index c2e3ab3f559f8..16d5c2cc8ddae 100644 --- a/aptos-move/framework/move-stdlib/sources/signer.move +++ b/aptos-move/framework/move-stdlib/sources/signer.move @@ -1,10 +1,24 @@ module std::signer { - /// Borrows the address of the signer - /// Conceptually, you can think of the `signer` as being a struct wrapper around an - /// address + /// signer is a builtin move type that represents an address that has been verfied by the VM. + /// + /// VM Runtime representation is equivalent to following: /// ``` - /// struct signer has drop { addr: address } + /// enum signer has drop { + /// Master { account: address }, + /// Permissioned { account: address, permissions_address: address }, + /// } /// ``` + /// + /// for bcs serialization: + /// + /// ``` + /// struct signer has drop { + /// account: address, + /// } + /// ``` + /// ^ The discrepency is needed to maintain backwards compatibility of signer serialization + /// semantics. + /// /// `borrow_address` borrows this inner field native public fun borrow_address(s: &signer): &address; diff --git a/aptos-move/framework/move-stdlib/src/natives/bcs.rs b/aptos-move/framework/move-stdlib/src/natives/bcs.rs index d7cd0e9d258c4..0028d48319cbb 100644 --- a/aptos-move/framework/move-stdlib/src/natives/bcs.rs +++ b/aptos-move/framework/move-stdlib/src/natives/bcs.rs @@ -70,6 +70,7 @@ fn native_to_bytes( let val = ref_to_val.read_ref()?; let serialized_value = match ValueSerDeContext::new() + .with_legacy_signer() .with_func_args_deserialization(context.function_value_extension()) .serialize(&val, &layout)? { @@ -136,6 +137,7 @@ fn serialized_size_impl( let ty_layout = context.type_to_type_layout(ty)?; ValueSerDeContext::new() + .with_legacy_signer() .with_func_args_deserialization(context.function_value_extension()) .with_delayed_fields_serde() .serialized_size(&value, &ty_layout) diff --git a/aptos-move/framework/move-stdlib/src/natives/unit_test.rs b/aptos-move/framework/move-stdlib/src/natives/unit_test.rs index f23a1fb56b6f6..9e928af622264 100644 --- a/aptos-move/framework/move-stdlib/src/natives/unit_test.rs +++ b/aptos-move/framework/move-stdlib/src/natives/unit_test.rs @@ -38,7 +38,7 @@ fn native_create_signers_for_testing( let num_signers = safely_pop_arg!(args, u64); let signers = Value::vector_for_testing_only( - (0..num_signers).map(|i| Value::signer(AccountAddress::new(to_le_bytes(i)))), + (0..num_signers).map(|i| Value::master_signer(AccountAddress::new(to_le_bytes(i)))), ); Ok(smallvec![signers]) diff --git a/aptos-move/framework/move-stdlib/tests/bcs_tests.move b/aptos-move/framework/move-stdlib/tests/bcs_tests.move index c22cf8126342d..855a5494691be 100644 --- a/aptos-move/framework/move-stdlib/tests/bcs_tests.move +++ b/aptos-move/framework/move-stdlib/tests/bcs_tests.move @@ -157,4 +157,12 @@ module std::bcs_tests { assert!(std::cmp::compare(&bytes_val, &bytes_other).is_lt()); } + + #[test(s1 = @0x123)] + fun test_signer_serialization(s1: signer) { + assert!( + bcs::to_bytes(&s1) == bcs::to_bytes(&@0x123), + 1 + ); + } } diff --git a/aptos-move/framework/src/natives/create_signer.rs b/aptos-move/framework/src/natives/create_signer.rs index c8605088113da..6ba6f79b578d9 100644 --- a/aptos-move/framework/src/natives/create_signer.rs +++ b/aptos-move/framework/src/natives/create_signer.rs @@ -28,7 +28,7 @@ pub(crate) fn native_create_signer( context.charge(ACCOUNT_CREATE_SIGNER_BASE)?; let address = safely_pop_arg!(arguments, AccountAddress); - Ok(smallvec![Value::signer(address)]) + Ok(smallvec![Value::master_signer(address)]) } /*************************************************************************************************** diff --git a/aptos-move/framework/src/natives/mod.rs b/aptos-move/framework/src/natives/mod.rs index dcfc80407f932..956c590b4afc8 100644 --- a/aptos-move/framework/src/natives/mod.rs +++ b/aptos-move/framework/src/natives/mod.rs @@ -15,6 +15,7 @@ pub mod function_info; pub mod hash; pub mod object; pub mod object_code_deployment; +pub mod permissioned_signer; pub mod randomness; pub mod state_storage; pub mod string_utils; @@ -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..cbebd63bd7f9f --- /dev/null +++ b/aptos-move/framework/src/natives/permissioned_signer.rs @@ -0,0 +1,109 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 +use aptos_gas_schedule::gas_params::natives::aptos_framework::{ + IS_PERMISSIONED_SIGNER_BASE, PERMISSION_ADDRESS_BASE, SIGNER_FROM_PERMISSIONED_HANDLE_BASE, +}; +use aptos_native_interface::{ + safely_pop_arg, RawSafeNative, SafeNativeBuilder, SafeNativeContext, SafeNativeError, + SafeNativeResult, +}; +use move_core_types::account_address::AccountAddress; +use move_vm_runtime::native_functions::NativeFunction; +use move_vm_types::{ + loaded_data::runtime_types::Type, + values::{SignerRef, 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, + mut arguments: VecDeque, +) -> SafeNativeResult> { + debug_assert!(arguments.len() == 1); + + let signer = safely_pop_arg!(arguments, SignerRef); + + context.charge(IS_PERMISSIONED_SIGNER_BASE)?; + let result = signer.is_permissioned()?; + + Ok(smallvec![Value::bool(result)]) +} + +/*************************************************************************************************** + * native fun permission_address + * + * Returns the permission storage address if the signer passed in is a permissioned signer + * gas cost: base_cost + * + **************************************************************************************************/ +fn native_permission_address( + context: &mut SafeNativeContext, + _ty_args: Vec, + mut args: VecDeque, +) -> SafeNativeResult> { + debug_assert!(args.len() == 1); + + let signer = safely_pop_arg!(args, SignerRef); + + context.charge(PERMISSION_ADDRESS_BASE)?; + if !signer.is_permissioned()? { + return Err(SafeNativeError::Abort { abort_code: 3 }); + } + + Ok(smallvec![signer.permission_address()?]) +} + +/*************************************************************************************************** + * native fun signer_from_permissioned_handle_impl + * + * 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() == 2); + + let permission_addr = safely_pop_arg!(arguments, AccountAddress); + let master_addr = safely_pop_arg!(arguments, AccountAddress); + context.charge(SIGNER_FROM_PERMISSIONED_HANDLE_BASE)?; + + Ok(smallvec![Value::permissioned_signer( + master_addr, + permission_addr + )]) +} + +/*************************************************************************************************** + * module + * + **************************************************************************************************/ +pub fn make_all( + builder: &SafeNativeBuilder, +) -> impl Iterator + '_ { + let natives = [ + ( + "is_permissioned_signer", + native_is_permissioned_signer as RawSafeNative, + ), + ("permission_address", native_permission_address), + ( + "signer_from_permissioned_handle_impl", + native_signer_from_permissioned, + ), + ]; + + builder.make_named_natives(natives) +} diff --git a/aptos-move/framework/src/natives/string_utils.rs b/aptos-move/framework/src/natives/string_utils.rs index 0a4c7c71583f8..28e9fd50b103f 100644 --- a/aptos-move/framework/src/natives/string_utils.rs +++ b/aptos-move/framework/src/natives/string_utils.rs @@ -13,7 +13,7 @@ use move_core_types::{ account_address::AccountAddress, language_storage::TypeTag, u256, - value::{MoveFieldLayout, MoveStructLayout, MoveTypeLayout}, + value::{MoveFieldLayout, MoveStructLayout, MoveTypeLayout, MASTER_ADDRESS_FIELD_OFFSET}, }; use move_vm_runtime::native_functions::NativeFunction; use move_vm_types::{ @@ -188,8 +188,11 @@ fn native_format_impl( let addr = if fix_enabled { val.value_as::()? .unpack()? - .next() - .unwrap() + // The second field of a signer is always the master address regardless of which variants. + .nth(MASTER_ADDRESS_FIELD_OFFSET) + .ok_or_else(|| SafeNativeError::Abort { + abort_code: EINVALID_FORMAT, + })? .value_as::()? } else { val.value_as::()? diff --git a/aptos-move/framework/src/natives/util.rs b/aptos-move/framework/src/natives/util.rs index f39239491fae1..4ce9d70880bf1 100644 --- a/aptos-move/framework/src/natives/util.rs +++ b/aptos-move/framework/src/natives/util.rs @@ -43,6 +43,7 @@ fn native_from_bytes( UTIL_FROM_BYTES_BASE + UTIL_FROM_BYTES_PER_BYTE * NumBytes::new(bytes.len() as u64), )?; let val = match ValueSerDeContext::new() + .with_legacy_signer() .with_func_args_deserialization(context.function_value_extension()) .deserialize(&bytes, &layout) { diff --git a/third_party/move/move-bytecode-verifier/transactional-tests/tests/script_signature/signer_double_signer.exp b/third_party/move/move-bytecode-verifier/transactional-tests/tests/script_signature/signer_double_signer.exp deleted file mode 100644 index 4b0549d55c296..0000000000000 --- a/third_party/move/move-bytecode-verifier/transactional-tests/tests/script_signature/signer_double_signer.exp +++ /dev/null @@ -1,19 +0,0 @@ -processed 3 tasks - -task 0 'run'. lines 1-6: -Error: Script execution failed with VMError: { - major_status: NUMBER_OF_ARGUMENTS_MISMATCH, - sub_status: None, - location: undefined, - indices: [], - offsets: [], -} - -task 1 'run'. lines 8-13: -Error: Script execution failed with VMError: { - major_status: NUMBER_OF_ARGUMENTS_MISMATCH, - sub_status: None, - location: undefined, - indices: [], - offsets: [], -} diff --git a/third_party/move/move-bytecode-verifier/transactional-tests/tests/script_signature/signer_double_signer.mvir b/third_party/move/move-bytecode-verifier/transactional-tests/tests/script_signature/signer_double_signer.mvir deleted file mode 100644 index 18b599d5fbd30..0000000000000 --- a/third_party/move/move-bytecode-verifier/transactional-tests/tests/script_signature/signer_double_signer.mvir +++ /dev/null @@ -1,20 +0,0 @@ -//# run --signers 0x1 -// missing signer -main(s: signer, s2: signer) { -label b0: - return; -} - -//# run --signers 0x1 --args 0 -// missing signer -main(s: signer, s2: signer, u: u64,) { -label b0: - return; -} - -//# run --args @0x1 0 @0x2 -// no longer an invalid signature, after V5 -main(s: signer, u: u64, s2: signer) { -label b0: - return; -} diff --git a/third_party/move/move-bytecode-verifier/transactional-tests/tests/script_signature/signer_double_signer.v2_exp b/third_party/move/move-bytecode-verifier/transactional-tests/tests/script_signature/signer_double_signer.v2_exp deleted file mode 100644 index 4b0549d55c296..0000000000000 --- a/third_party/move/move-bytecode-verifier/transactional-tests/tests/script_signature/signer_double_signer.v2_exp +++ /dev/null @@ -1,19 +0,0 @@ -processed 3 tasks - -task 0 'run'. lines 1-6: -Error: Script execution failed with VMError: { - major_status: NUMBER_OF_ARGUMENTS_MISMATCH, - sub_status: None, - location: undefined, - indices: [], - offsets: [], -} - -task 1 'run'. lines 8-13: -Error: Script execution failed with VMError: { - major_status: NUMBER_OF_ARGUMENTS_MISMATCH, - sub_status: None, - location: undefined, - indices: [], - offsets: [], -} diff --git a/third_party/move/move-bytecode-verifier/transactional-tests/tests/script_signature/signer_misplaced_signer_arg.exp b/third_party/move/move-bytecode-verifier/transactional-tests/tests/script_signature/signer_misplaced_signer_arg.exp deleted file mode 100644 index 5d92c423f3fd8..0000000000000 --- a/third_party/move/move-bytecode-verifier/transactional-tests/tests/script_signature/signer_misplaced_signer_arg.exp +++ /dev/null @@ -1 +0,0 @@ -processed 2 tasks diff --git a/third_party/move/move-bytecode-verifier/transactional-tests/tests/script_signature/signer_misplaced_signer_arg.mvir b/third_party/move/move-bytecode-verifier/transactional-tests/tests/script_signature/signer_misplaced_signer_arg.mvir deleted file mode 100644 index 7c0bf2513414f..0000000000000 --- a/third_party/move/move-bytecode-verifier/transactional-tests/tests/script_signature/signer_misplaced_signer_arg.mvir +++ /dev/null @@ -1,13 +0,0 @@ -//# run --args 0 @0x1 -// no longer an invalid signature, after V5 -main(u: u64, s: &signer) { -label b0: - return; -} - -//# run --args 0 @0x1 1 -// no longer an invalid signature, after V5 -main(u: u64, s: &signer, u2: u64) { -label b0: - return; -} diff --git a/third_party/move/move-compiler-v2/src/plan_builder.rs b/third_party/move/move-compiler-v2/src/plan_builder.rs index b03c91c712938..d9bd11fa12485 100644 --- a/third_party/move/move-compiler-v2/src/plan_builder.rs +++ b/third_party/move/move-compiler-v2/src/plan_builder.rs @@ -162,9 +162,29 @@ fn build_test_info( let mut arguments = Vec::new(); for param in function.get_parameters_ref() { - let Parameter(var, _ty, var_loc) = ¶m; + let Parameter(var, ty, var_loc) = ¶m; match test_annotation_params.get(var) { + Some(MoveValue::Address(addr)) => match ty { + Type::Primitive(PrimitiveType::Signer) => arguments.push(MoveValue::Signer(*addr)), + Type::Reference(_, inner) if **inner == Type::Primitive(PrimitiveType::Signer) => { + arguments.push(MoveValue::Signer(*addr)); + }, + Type::Primitive(PrimitiveType::Address) => { + arguments.push(MoveValue::Address(*addr)) + }, + _ => { + let err_msg = "Unexpected argument type: expect an address or a signer"; + let invalid_test = "unable to generate test"; + env.error_with_labels(&fn_id_loc, invalid_test, vec![ + (test_attribute_loc.clone(), err_msg.to_string()), + ( + var_loc.clone(), + "Corresponding to this parameter".to_string(), + ), + ]); + }, + }, Some(value) => arguments.push(value.clone()), None => { let missing_param_msg = "Missing test parameter assignment in test. Expected a \ diff --git a/third_party/move/move-compiler/src/unit_test/plan_builder.rs b/third_party/move/move-compiler/src/unit_test/plan_builder.rs index c53926366cbd9..56b3f5140fd74 100644 --- a/third_party/move/move-compiler/src/unit_test/plan_builder.rs +++ b/third_party/move/move-compiler/src/unit_test/plan_builder.rs @@ -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}, @@ -159,10 +160,19 @@ 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!( diff --git a/third_party/move/move-core/types/src/unit_tests/value_test.rs b/third_party/move/move-core/types/src/unit_tests/value_test.rs index 5c3bb08841503..1519fc7961c57 100644 --- a/third_party/move/move-core/types/src/unit_tests/value_test.rs +++ b/third_party/move/move-core/types/src/unit_tests/value_test.rs @@ -137,3 +137,13 @@ 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 + ); +} diff --git a/third_party/move/move-core/types/src/value.rs b/third_party/move/move-core/types/src/value.rs index de4ef817e4832..62e9bc69cafde 100644 --- a/third_party/move/move-core/types/src/value.rs +++ b/third_party/move/move-core/types/src/value.rs @@ -75,6 +75,19 @@ pub fn variant_name_placeholder(len: usize) -> &'static [&'static str] { } } +/// enum signer { +/// Master { account: address }, +/// Permissioned { account: address, permissions_address: address }, +/// } +/// enum variant tag for a master signer. +pub const MASTER_SIGNER_VARIANT: u16 = 0; +/// enum variant tag for a permissioned signer. +pub const PERMISSIONED_SIGNER_VARIANT: u16 = 1; +/// field offset of a master account address in a enum encoded signer. +pub const MASTER_ADDRESS_FIELD_OFFSET: usize = 1; +/// field offset of a permission storage address in a enum encoded permission signer. +pub const PERMISSION_ADDRESS_FIELD_OFFSET: usize = 2; + #[derive(Debug, PartialEq, Eq, Clone)] #[cfg_attr( any(test, feature = "fuzzing"), @@ -465,6 +478,13 @@ impl MoveStructLayout { }, } } + + pub fn signer_serialization_layout() -> Self { + MoveStructLayout::RuntimeVariants(vec![vec![MoveTypeLayout::Address], vec![ + MoveTypeLayout::Address, + MoveTypeLayout::Address, + ]]) + } } impl<'d> serde::de::DeserializeSeed<'d> for &MoveTypeLayout { @@ -486,7 +506,26 @@ impl<'d> serde::de::DeserializeSeed<'d> for &MoveTypeLayout { AccountAddress::deserialize(deserializer).map(MoveValue::Address) }, MoveTypeLayout::Signer => { - AccountAddress::deserialize(deserializer).map(MoveValue::Signer) + let (variant, fields) = MoveStructLayout::signer_serialization_layout() + .deserialize(deserializer)? + .into_optional_variant_and_fields(); + + if variant != Some(MASTER_SIGNER_VARIANT) { + return Err(D::Error::custom("cannot deserialize permissioned signer")); + } + + // Runtime representation of signer looks following: + // enum signer { + // Master { account: address }, + // Permissioned { account: address, permissions_address: address }, + // } + // + // The first field always refers to the account address. + + Ok(MoveValue::Signer(match fields[0] { + MoveValue::Address(addr) => addr, + _ => return Err(D::Error::custom("signer deserialization error")), + })) }, MoveTypeLayout::Struct(ty) => Ok(MoveValue::Struct(ty.deserialize(deserializer)?)), MoveTypeLayout::Vector(layout) => Ok(MoveValue::Vector( @@ -691,7 +730,15 @@ 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) => { + // Runtime representation of signer looks following: + // enum signer { + // Master { account: address }, + // Permissioned { account: address, permissions_address: address }, + // } + MoveStruct::new_variant(MASTER_SIGNER_VARIANT, vec![MoveValue::Address(*a)]) + .serialize(serializer) + }, MoveValue::Vector(v) => { let mut t = serializer.serialize_seq(Some(v.len()))?; for val in v { diff --git a/third_party/move/move-examples/diem-framework/crates/natives/src/account.rs b/third_party/move/move-examples/diem-framework/crates/natives/src/account.rs index 971da950b9453..026bb9ff4bb03 100644 --- a/third_party/move/move-examples/diem-framework/crates/natives/src/account.rs +++ b/third_party/move/move-examples/diem-framework/crates/natives/src/account.rs @@ -20,7 +20,7 @@ pub fn native_create_signer( debug_assert!(arguments.len() == 1); let address = pop_arg!(arguments, AccountAddress); - Ok(NativeResult::ok(25.into(), smallvec![Value::signer( + Ok(NativeResult::ok(25.into(), smallvec![Value::master_signer( address )])) } diff --git a/third_party/move/move-prover/boogie-backend/src/prelude/prelude.bpl b/third_party/move/move-prover/boogie-backend/src/prelude/prelude.bpl index af262f11c9fbf..970ae252a2a53 100644 --- a/third_party/move/move-prover/boogie-backend/src/prelude/prelude.bpl +++ b/third_party/move/move-prover/boogie-backend/src/prelude/prelude.bpl @@ -1102,13 +1102,25 @@ procedure {:inline 1} $1_Account_create_signer( // Native Signer datatype $signer { - $signer($addr: int) + $signer($addr: int), + $permissioned_signer($addr: int, $permission_addr: int) } + function {:inline} $IsValid'signer'(s: $signer): bool { - $IsValid'address'(s->$addr) + if s is $signer then + $IsValid'address'(s->$addr) + else + $IsValid'address'(s->$addr) && + $IsValid'address'(s->$permission_addr) } + function {:inline} $IsEqual'signer'(s1: $signer, s2: $signer): bool { - s1 == s2 + if s1 is $signer && s2 is $signer then + s1 == s2 + else if s1 is $permissioned_signer && s2 is $permissioned_signer then + s1 == s2 + else + false } procedure {:inline 1} $1_signer_borrow_address(signer: $signer) returns (res: int) { diff --git a/third_party/move/move-prover/tests/sources/functional/bitwise_features.exp b/third_party/move/move-prover/tests/sources/functional/bitwise_features.exp new file mode 100644 index 0000000000000..c7a13354b635e --- /dev/null +++ b/third_party/move/move-prover/tests/sources/functional/bitwise_features.exp @@ -0,0 +1,12 @@ +Move prover returns: exiting with verification errors +error: verification out of resources/timeout (global timeout set to 80s) + ┌─ tests/sources/functional/bitwise_features.move:127:5 + │ +127 │ ╭ public fun disable_feature_flags(disable: vector) acquires Features { +128 │ │ let features = &mut borrow_global_mut(@std).features; +129 │ │ let i = 0; +130 │ │ let n = vector::length(&disable); + · │ +143 │ │ }; +144 │ │ } + │ ╰─────^ diff --git a/third_party/move/move-prover/tests/sources/functional/bitwise_features.v2_exp b/third_party/move/move-prover/tests/sources/functional/bitwise_features.v2_exp deleted file mode 100644 index 5910dbdcebcb8..0000000000000 --- a/third_party/move/move-prover/tests/sources/functional/bitwise_features.v2_exp +++ /dev/null @@ -1,12 +0,0 @@ -Move prover returns: exiting with verification errors -error: verification out of resources/timeout (global timeout set to 80s) - ┌─ tests/sources/functional/bitwise_features.move:154:5 - │ -154 │ ╭ public fun enable_feature_flags(enable: vector) acquires Features { -155 │ │ let features = &mut borrow_global_mut(@std).features; -156 │ │ let i = 0; -157 │ │ let n = vector::length(&enable); - · │ -170 │ │ }; -171 │ │ } - │ ╰─────^ diff --git a/third_party/move/move-prover/tests/sources/functional/global_invariants.exp b/third_party/move/move-prover/tests/sources/functional/global_invariants.exp index c9157f86bb3f4..3365fd61f6356 100644 --- a/third_party/move/move-prover/tests/sources/functional/global_invariants.exp +++ b/third_party/move/move-prover/tests/sources/functional/global_invariants.exp @@ -21,18 +21,18 @@ error: global memory invariant does not hold = at tests/sources/functional/global_invariants.move:53: remove_S_invalid = account = = at tests/sources/functional/global_invariants.move:55: remove_S_invalid - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = at tests/sources/functional/global_invariants.move:55: remove_S_invalid = at tests/sources/functional/global_invariants.move:56: remove_S_invalid - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = at tests/sources/functional/global_invariants.move:18 error: global memory invariant does not hold @@ -44,18 +44,18 @@ error: global memory invariant does not hold = at tests/sources/functional/global_invariants.move:62: remove_R_invalid = account = = at tests/sources/functional/global_invariants.move:64: remove_R_invalid - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = at tests/sources/functional/global_invariants.move:64: remove_R_invalid = at tests/sources/functional/global_invariants.move:65: remove_R_invalid - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = at tests/sources/functional/global_invariants.move:62: remove_R_invalid = at tests/sources/functional/global_invariants.move:65: remove_R_invalid = at tests/sources/functional/global_invariants.move:18 diff --git a/third_party/move/move-prover/tests/sources/functional/global_invariants.v2_exp b/third_party/move/move-prover/tests/sources/functional/global_invariants.v2_exp index 5db58204b04cb..99fab2823d0d0 100644 --- a/third_party/move/move-prover/tests/sources/functional/global_invariants.v2_exp +++ b/third_party/move/move-prover/tests/sources/functional/global_invariants.v2_exp @@ -21,17 +21,17 @@ error: global memory invariant does not hold = at tests/sources/functional/global_invariants.move:53: remove_S_invalid = account = = at tests/sources/functional/global_invariants.move:55: remove_S_invalid - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = at tests/sources/functional/global_invariants.move:56: remove_S_invalid - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = at tests/sources/functional/global_invariants.move:18 error: global memory invariant does not hold @@ -43,17 +43,17 @@ error: global memory invariant does not hold = at tests/sources/functional/global_invariants.move:62: remove_R_invalid = account = = at tests/sources/functional/global_invariants.move:64: remove_R_invalid - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = at tests/sources/functional/global_invariants.move:65: remove_R_invalid - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = at tests/sources/functional/global_invariants.move:62: remove_R_invalid = at tests/sources/functional/global_invariants.move:65: remove_R_invalid = at tests/sources/functional/global_invariants.move:18 diff --git a/third_party/move/move-prover/tests/sources/functional/is_txn_signer.exp b/third_party/move/move-prover/tests/sources/functional/is_txn_signer.exp index 10e0b83097ae0..f1cc9c2443c16 100644 --- a/third_party/move/move-prover/tests/sources/functional/is_txn_signer.exp +++ b/third_party/move/move-prover/tests/sources/functional/is_txn_signer.exp @@ -26,11 +26,11 @@ error: unknown assertion failed = at tests/sources/functional/is_txn_signer.move:29: f4_incorrect = account = = at tests/sources/functional/is_txn_signer.move:30: f4_incorrect - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = at tests/sources/functional/is_txn_signer.move:30: f4_incorrect = at tests/sources/functional/is_txn_signer.move:31: f4_incorrect diff --git a/third_party/move/move-prover/tests/sources/functional/is_txn_signer.v2_exp b/third_party/move/move-prover/tests/sources/functional/is_txn_signer.v2_exp index 9d2fee976c7e8..f93f350ed89de 100644 --- a/third_party/move/move-prover/tests/sources/functional/is_txn_signer.v2_exp +++ b/third_party/move/move-prover/tests/sources/functional/is_txn_signer.v2_exp @@ -26,11 +26,11 @@ error: unknown assertion failed = at tests/sources/functional/is_txn_signer.move:29: f4_incorrect = account = = at tests/sources/functional/is_txn_signer.move:30: f4_incorrect - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = at tests/sources/functional/is_txn_signer.move:31: f4_incorrect error: precondition does not hold at this call diff --git a/third_party/move/move-prover/tests/sources/functional/loops_with_memory_ops.exp b/third_party/move/move-prover/tests/sources/functional/loops_with_memory_ops.exp index 32b6d76bc6da8..828edd8c598d7 100644 --- a/third_party/move/move-prover/tests/sources/functional/loops_with_memory_ops.exp +++ b/third_party/move/move-prover/tests/sources/functional/loops_with_memory_ops.exp @@ -45,8 +45,8 @@ error: induction case of the loop invariant does not hold = at tests/sources/functional/loops_with_memory_ops.move:80: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = b = - = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = a = + = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2 = i = = at tests/sources/functional/loops_with_memory_ops.move:86: nested_loop2 @@ -105,7 +105,6 @@ error: unknown assertion failed = at tests/sources/functional/loops_with_memory_ops.move:80: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = b = - = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = a = = at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2 = i = diff --git a/third_party/move/move-prover/tests/sources/functional/loops_with_memory_ops.v2_exp b/third_party/move/move-prover/tests/sources/functional/loops_with_memory_ops.v2_exp index c54e01557729d..5ad9d66da7ab5 100644 --- a/third_party/move/move-prover/tests/sources/functional/loops_with_memory_ops.v2_exp +++ b/third_party/move/move-prover/tests/sources/functional/loops_with_memory_ops.v2_exp @@ -41,7 +41,7 @@ error: induction case of the loop invariant does not hold = at tests/sources/functional/loops_with_memory_ops.move:80: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = a = - = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 + = b = = at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2 = i = = at tests/sources/functional/loops_with_memory_ops.move:86: nested_loop2 @@ -97,7 +97,6 @@ error: unknown assertion failed = at tests/sources/functional/loops_with_memory_ops.move:80: nested_loop2 = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = a = - = at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2 = b = = at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2 = i = diff --git a/third_party/move/move-prover/tests/sources/functional/resources.exp b/third_party/move/move-prover/tests/sources/functional/resources.exp index 9b6c9c6f3fee3..0f8d8ed128889 100644 --- a/third_party/move/move-prover/tests/sources/functional/resources.exp +++ b/third_party/move/move-prover/tests/sources/functional/resources.exp @@ -8,11 +8,11 @@ error: post-condition does not hold = at tests/sources/functional/resources.move:32: create_resource_incorrect = account = = at tests/sources/functional/resources.move:33: create_resource_incorrect - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = at tests/sources/functional/resources.move:36: create_resource_incorrect = at tests/sources/functional/resources.move:38: create_resource_incorrect (spec) = at tests/sources/functional/resources.move:39: create_resource_incorrect (spec) diff --git a/third_party/move/move-prover/tests/sources/functional/resources.v2_exp b/third_party/move/move-prover/tests/sources/functional/resources.v2_exp index 9b6c9c6f3fee3..0f8d8ed128889 100644 --- a/third_party/move/move-prover/tests/sources/functional/resources.v2_exp +++ b/third_party/move/move-prover/tests/sources/functional/resources.v2_exp @@ -8,11 +8,11 @@ error: post-condition does not hold = at tests/sources/functional/resources.move:32: create_resource_incorrect = account = = at tests/sources/functional/resources.move:33: create_resource_incorrect - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = at tests/sources/functional/resources.move:36: create_resource_incorrect = at tests/sources/functional/resources.move:38: create_resource_incorrect (spec) = at tests/sources/functional/resources.move:39: create_resource_incorrect (spec) diff --git a/third_party/move/move-prover/tests/sources/functional/script_incorrect.exp b/third_party/move/move-prover/tests/sources/functional/script_incorrect.exp index 518b136ed26e8..45513e8b37f6c 100644 --- a/third_party/move/move-prover/tests/sources/functional/script_incorrect.exp +++ b/third_party/move/move-prover/tests/sources/functional/script_incorrect.exp @@ -19,11 +19,11 @@ error: abort not covered by any of the `aborts_if` clauses = at tests/sources/functional/script_provider.move:8: register = account = = at tests/sources/functional/script_provider.move:9: register - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = at tests/sources/functional/script_provider.move:9: register = at tests/sources/functional/script_provider.move:10: register = ABORTED diff --git a/third_party/move/move-prover/tests/sources/functional/script_incorrect.v2_exp b/third_party/move/move-prover/tests/sources/functional/script_incorrect.v2_exp index 52227eb833db7..204c0cea4690e 100644 --- a/third_party/move/move-prover/tests/sources/functional/script_incorrect.v2_exp +++ b/third_party/move/move-prover/tests/sources/functional/script_incorrect.v2_exp @@ -19,10 +19,10 @@ error: abort not covered by any of the `aborts_if` clauses = at tests/sources/functional/script_provider.move:8: register = account = = at tests/sources/functional/script_provider.move:9: register - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = at tests/sources/functional/script_provider.move:10: register = ABORTED diff --git a/third_party/move/move-prover/tests/sources/functional/trace.exp b/third_party/move/move-prover/tests/sources/functional/trace.exp index e24a41719d8a7..5f1a4a7b947ab 100644 --- a/third_party/move/move-prover/tests/sources/functional/trace.exp +++ b/third_party/move/move-prover/tests/sources/functional/trace.exp @@ -47,7 +47,7 @@ error: post-condition does not hold │ = Related Global Memory: = Resource name: TestTracing_R - = Values: {Address(18467): , Default: TestTracing.R{x = 4}} + = Values: {Address(6334): , Default: empty} = Related Bindings: = addr = = exists(addr) = @@ -74,7 +74,7 @@ error: global memory invariant does not hold │ = Related Global Memory: = Resource name: TestTracing_R - = Values: {Address(0): , Default: TestTracing.R{x = 5}} + = Values: {Address(0): , Default: empty} = at tests/sources/functional/trace.move:29: publish_invalid = at tests/sources/functional/trace.move:33: publish_invalid (spec) = `let addr = signer::address_of(s);` = diff --git a/third_party/move/move-prover/tests/sources/functional/trace.v2_exp b/third_party/move/move-prover/tests/sources/functional/trace.v2_exp index e24a41719d8a7..5f1a4a7b947ab 100644 --- a/third_party/move/move-prover/tests/sources/functional/trace.v2_exp +++ b/third_party/move/move-prover/tests/sources/functional/trace.v2_exp @@ -47,7 +47,7 @@ error: post-condition does not hold │ = Related Global Memory: = Resource name: TestTracing_R - = Values: {Address(18467): , Default: TestTracing.R{x = 4}} + = Values: {Address(6334): , Default: empty} = Related Bindings: = addr = = exists(addr) = @@ -74,7 +74,7 @@ error: global memory invariant does not hold │ = Related Global Memory: = Resource name: TestTracing_R - = Values: {Address(0): , Default: TestTracing.R{x = 5}} + = Values: {Address(0): , Default: empty} = at tests/sources/functional/trace.move:29: publish_invalid = at tests/sources/functional/trace.move:33: publish_invalid (spec) = `let addr = signer::address_of(s);` = diff --git a/third_party/move/move-prover/tests/sources/functional/type_dependent_code.exp b/third_party/move/move-prover/tests/sources/functional/type_dependent_code.exp index 872a4493e68d0..55abfd2da20f4 100644 --- a/third_party/move/move-prover/tests/sources/functional/type_dependent_code.exp +++ b/third_party/move/move-prover/tests/sources/functional/type_dependent_code.exp @@ -55,11 +55,11 @@ error: post-condition does not hold = x = = at tests/sources/functional/type_dependent_code.move:45: test1 = at tests/sources/functional/type_dependent_code.move:46: test1 - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = r = = at tests/sources/functional/type_dependent_code.move:47: test1 = at tests/sources/functional/type_dependent_code.move:48: test1 @@ -77,11 +77,11 @@ error: post-condition does not hold = t2 = = at tests/sources/functional/type_dependent_code.move:61: test2 = at tests/sources/functional/type_dependent_code.move:62: test2 - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = r = = at tests/sources/functional/type_dependent_code.move:63: test2 = at tests/sources/functional/type_dependent_code.move:64: test2 diff --git a/third_party/move/move-prover/tests/sources/functional/type_dependent_code.v2_exp b/third_party/move/move-prover/tests/sources/functional/type_dependent_code.v2_exp index cc7a8df74ff9f..9f4c6ecc05cba 100644 --- a/third_party/move/move-prover/tests/sources/functional/type_dependent_code.v2_exp +++ b/third_party/move/move-prover/tests/sources/functional/type_dependent_code.v2_exp @@ -55,11 +55,11 @@ error: post-condition does not hold = x = = at tests/sources/functional/type_dependent_code.move:45: test1 = at tests/sources/functional/type_dependent_code.move:46: test1 - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = at tests/sources/functional/type_dependent_code.move:47: test1 = = = at tests/sources/functional/type_dependent_code.move:48: test1 @@ -77,11 +77,11 @@ error: post-condition does not hold = t2 = = at tests/sources/functional/type_dependent_code.move:61: test2 = at tests/sources/functional/type_dependent_code.move:62: test2 - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = at tests/sources/functional/type_dependent_code.move:63: test2 = = = at tests/sources/functional/type_dependent_code.move:64: test2 diff --git a/third_party/move/move-prover/tests/sources/regression/type_param_bug_121721.exp b/third_party/move/move-prover/tests/sources/regression/type_param_bug_121721.exp index 972aa1db72f40..afc13fe19c7a2 100644 --- a/third_party/move/move-prover/tests/sources/regression/type_param_bug_121721.exp +++ b/third_party/move/move-prover/tests/sources/regression/type_param_bug_121721.exp @@ -9,11 +9,11 @@ error: global memory invariant does not hold = ballot_account = = proposal = = at tests/sources/regression/type_param_bug_121721.move:84: create_ballot - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = ballot_address = = at tests/sources/regression/type_param_bug_121721.move:86: create_ballot = at tests/sources/regression/type_param_bug_121721.move:88: create_ballot diff --git a/third_party/move/move-prover/tests/sources/regression/type_param_bug_121721.v2_exp b/third_party/move/move-prover/tests/sources/regression/type_param_bug_121721.v2_exp index 972aa1db72f40..afc13fe19c7a2 100644 --- a/third_party/move/move-prover/tests/sources/regression/type_param_bug_121721.v2_exp +++ b/third_party/move/move-prover/tests/sources/regression/type_param_bug_121721.v2_exp @@ -9,11 +9,11 @@ error: global memory invariant does not hold = ballot_account = = proposal = = at tests/sources/regression/type_param_bug_121721.move:84: create_ballot - = at ../move-stdlib/sources/signer.move:12: address_of + = at ../move-stdlib/sources/signer.move:21: address_of = s = - = at ../move-stdlib/sources/signer.move:13: address_of + = at ../move-stdlib/sources/signer.move:22: address_of = result = - = at ../move-stdlib/sources/signer.move:14: address_of + = at ../move-stdlib/sources/signer.move:23: address_of = ballot_address = = at tests/sources/regression/type_param_bug_121721.move:86: create_ballot = at tests/sources/regression/type_param_bug_121721.move:88: create_ballot diff --git a/third_party/move/move-stdlib/docs/signer.md b/third_party/move/move-stdlib/docs/signer.md index cbbab944c3dec..f03017d65453a 100644 --- a/third_party/move/move-stdlib/docs/signer.md +++ b/third_party/move/move-stdlib/docs/signer.md @@ -18,6 +18,27 @@ ## Function `borrow_address` +signer is a builtin move type that represents an address that has been verfied by the VM. + +VM Runtime representation is equivalent to following: +``` +enum signer has drop { +Master { account: address }, +Permissioned { account: address, permissions_address: address }, +} +``` + +for bcs serialization: + +``` +struct signer has drop { +account: address, +} +``` +^ The discrepency is needed to maintain backwards compatibility of signer serialization +semantics. + +borrow_address borrows this inner field
public fun borrow_address(s: &signer): &address
diff --git a/third_party/move/move-stdlib/sources/signer.move b/third_party/move/move-stdlib/sources/signer.move
index 1996b4331e987..16d5c2cc8ddae 100644
--- a/third_party/move/move-stdlib/sources/signer.move
+++ b/third_party/move/move-stdlib/sources/signer.move
@@ -1,11 +1,25 @@
 module std::signer {
-    // Borrows the address of the signer
-    // Conceptually, you can think of the `signer` as being a struct wrapper arround an
-    // address
-    // ```
-    // struct signer has drop { addr: address }
-    // ```
-    // `borrow_address` borrows this inner field
+    /// signer is a builtin move type that represents an address that has been verfied by the VM.
+    ///
+    /// VM Runtime representation is equivalent to following:
+    /// ```
+    /// enum signer has drop {
+    ///     Master { account: address },
+    ///     Permissioned { account: address, permissions_address: address },
+    /// }
+    /// ```
+    ///
+    /// for bcs serialization:
+    ///
+    /// ```
+    /// struct signer has drop {
+    ///     account: address,
+    /// }
+    /// ```
+    /// ^ The discrepency is needed to maintain backwards compatibility of signer serialization
+    /// semantics.
+    ///
+    /// `borrow_address` borrows this inner field
     native public fun borrow_address(s: &signer): &address;
 
     // Copies the address of the signer
diff --git a/third_party/move/move-stdlib/src/natives/bcs.rs b/third_party/move/move-stdlib/src/natives/bcs.rs
index c1722c0165fa1..3e9743e2018da 100644
--- a/third_party/move/move-stdlib/src/natives/bcs.rs
+++ b/third_party/move/move-stdlib/src/natives/bcs.rs
@@ -64,6 +64,7 @@ fn native_to_bytes(
     // serialize value
     let val = ref_to_val.read_ref()?;
     let serialized_value = match ValueSerDeContext::new()
+        .with_legacy_signer()
         .with_func_args_deserialization(context.function_value_extension())
         .serialize(&val, &layout)?
     {
diff --git a/third_party/move/move-stdlib/src/natives/signer.rs b/third_party/move/move-stdlib/src/natives/signer.rs
index 3a15343186a0c..90c8ccac06b48 100644
--- a/third_party/move/move-stdlib/src/natives/signer.rs
+++ b/third_party/move/move-stdlib/src/natives/signer.rs
@@ -37,10 +37,9 @@ fn native_borrow_address(
     debug_assert!(arguments.len() == 1);
 
     let signer_reference = pop_arg!(arguments, SignerRef);
+    let addr = signer_reference.borrow_signer()?;
 
-    Ok(NativeResult::ok(gas_params.base, smallvec![
-        signer_reference.borrow_signer()?
-    ]))
+    Ok(NativeResult::ok(gas_params.base, smallvec![addr]))
 }
 
 pub fn make_native_borrow_address(gas_params: BorrowAddressGasParameters) -> NativeFunction {
diff --git a/third_party/move/move-stdlib/src/natives/unit_test.rs b/third_party/move/move-stdlib/src/natives/unit_test.rs
index 31fe78d5490a7..2408e3001935c 100644
--- a/third_party/move/move-stdlib/src/natives/unit_test.rs
+++ b/third_party/move/move-stdlib/src/natives/unit_test.rs
@@ -45,7 +45,7 @@ fn native_create_signers_for_testing(
 
     let num_signers = pop_arg!(args, u64);
     let signers = Value::vector_for_testing_only(
-        (0..num_signers).map(|i| Value::signer(AccountAddress::new(to_le_bytes(i)))),
+        (0..num_signers).map(|i| Value::master_signer(AccountAddress::new(to_le_bytes(i)))),
     );
 
     let cost = gas_params.base_cost + gas_params.unit_cost * NumArgs::new(num_signers);
diff --git a/third_party/move/move-vm/runtime/src/interpreter.rs b/third_party/move/move-vm/runtime/src/interpreter.rs
index 5950c9a08e5f6..03d6364edbb78 100644
--- a/third_party/move/move-vm/runtime/src/interpreter.rs
+++ b/third_party/move/move-vm/runtime/src/interpreter.rs
@@ -35,8 +35,8 @@ use move_vm_types::{
     },
     natives::function::NativeResult,
     values::{
-        self, GlobalValue, IntegerValue, Locals, Reference, Struct, StructRef, VMValueCast, Value,
-        Vector, VectorRef,
+        self, GlobalValue, IntegerValue, Locals, Reference, SignerRef, Struct, StructRef,
+        VMValueCast, Value, Vector, VectorRef,
     },
     views::TypeView,
 };
@@ -2163,9 +2163,9 @@ impl Frame {
                     },
                     Bytecode::MoveTo(sd_idx) => {
                         let resource = interpreter.operand_stack.pop()?;
-                        let signer_reference = interpreter.operand_stack.pop_as::()?;
+                        let signer_reference = interpreter.operand_stack.pop_as::()?;
                         let addr = signer_reference
-                            .borrow_field(0)?
+                            .borrow_signer()?
                             .value_as::()?
                             .read_ref()?
                             .value_as::()?;
@@ -2175,9 +2175,9 @@ impl Frame {
                     },
                     Bytecode::MoveToGeneric(si_idx) => {
                         let resource = interpreter.operand_stack.pop()?;
-                        let signer_reference = interpreter.operand_stack.pop_as::()?;
+                        let signer_reference = interpreter.operand_stack.pop_as::()?;
                         let addr = signer_reference
-                            .borrow_field(0)?
+                            .borrow_signer()?
                             .value_as::()?
                             .read_ref()?
                             .value_as::()?;
diff --git a/third_party/move/move-vm/transactional-tests/tests/builtins/gen_move_to.mvir b/third_party/move/move-vm/transactional-tests/tests/builtins/gen_move_to.mvir
index a73419b95d424..2f6b7aca551ab 100644
--- a/third_party/move/move-vm/transactional-tests/tests/builtins/gen_move_to.mvir
+++ b/third_party/move/move-vm/transactional-tests/tests/builtins/gen_move_to.mvir
@@ -155,7 +155,7 @@ module 0x1.M {
 //
 // create, publish and exists
 
-//# run --args @0x1
+//# run --signers 0x1
 import 0x1.M;
 
 main(account: signer) {
@@ -169,7 +169,7 @@ label b0:
     return;
 }
 
-//# run --args @0x1
+//# run --signers 0x1
 import 0x1.M;
 
 main(account: signer) {
@@ -186,7 +186,7 @@ label b0:
     return;
 }
 
-//# run --args @0x1
+//# run --signers 0x1
 import 0x1.M;
 
 main(account: signer) {
@@ -219,7 +219,7 @@ label b0:
 //
 // borrows and mutations
 
-//# run --args @0x1
+//# run --signers 0x1
 import 0x1.M;
 
 main(account: signer) {
@@ -243,7 +243,7 @@ label b0:
     return;
 }
 
-//# run --args @0x1
+//# run --signers 0x1
 import 0x1.M;
 
 main(account: signer) {
@@ -263,7 +263,7 @@ label b0:
 //
 // unpublish, destroy and exists
 
-//# run --args @0x1
+//# run --signers 0x1
 import 0x1.M;
 
 main(account: signer) {
@@ -277,7 +277,7 @@ label b0:
     return;
 }
 
-//# run --args @0x1
+//# run --signers 0x1
 import 0x1.M;
 
 main(account: signer) {
@@ -303,7 +303,7 @@ label b0:
 }
 
 
-//# run --args @0x1
+//# run --signers 0x1
 import 0x1.M;
 
 main(account: signer) {
diff --git a/third_party/move/move-vm/transactional-tests/tests/entry_points/address_arg_is_not_signer.mvir b/third_party/move/move-vm/transactional-tests/tests/entry_points/address_arg_is_not_signer.mvir
index dd04d0efb75cc..2c5ba78953a87 100644
--- a/third_party/move/move-vm/transactional-tests/tests/entry_points/address_arg_is_not_signer.mvir
+++ b/third_party/move/move-vm/transactional-tests/tests/entry_points/address_arg_is_not_signer.mvir
@@ -1,11 +1,11 @@
-//# run --args @0x1
+//# run --signers 0x1
 main(s: signer) {
 label b0:
     return;
 }
 // DEPRECATED signers can now be passed in as addrs
 
-//# run --args @0x0 @0x2
+//# run --signers 0x0 0x2
 main(s: signer, s2: signer) {
 label b0:
     return;
diff --git a/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_function.exp b/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_function.exp
deleted file mode 100644
index 457ace9c4acb6..0000000000000
--- a/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_function.exp
+++ /dev/null
@@ -1 +0,0 @@
-processed 4 tasks
diff --git a/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_function.mvir b/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_function.mvir
deleted file mode 100644
index a55e7a71e4c76..0000000000000
--- a/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_function.mvir
+++ /dev/null
@@ -1,28 +0,0 @@
-//# publish
-
-// tests various mixed usage of signer in function arguments
-
-module 0x42.M {
-
-public main1(s1: signer, s2: &signer, s3: signer) {
-    label l0:
-    return;
-}
-
-public main2(s1: &signer, u: u64, s2: signer, f: bool, s3: &signer) {
-    label l0:
-    return;
-}
-
-public main3(u: u64, f: bool, a: address, s1: signer, s2: &signer) {
-    label l0:
-    return;
-}
-
-}
-
-//# run 0x42::M::main1 --args @0x1 @0x1 @0x1
-
-//# run 0x42::M::main2 --args @0x1 0 @0x1 false @0x1
-
-//# run 0x42::M::main3 --args 0 false @0x1 @0x2 @0x3
diff --git a/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_function.v2_exp b/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_function.v2_exp
deleted file mode 100644
index 457ace9c4acb6..0000000000000
--- a/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_function.v2_exp
+++ /dev/null
@@ -1 +0,0 @@
-processed 4 tasks
diff --git a/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_scripts.exp b/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_scripts.exp
deleted file mode 100644
index fc5a4436b29d4..0000000000000
--- a/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_scripts.exp
+++ /dev/null
@@ -1 +0,0 @@
-processed 3 tasks
diff --git a/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_scripts.mvir b/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_scripts.mvir
deleted file mode 100644
index 7892f86cc7a3a..0000000000000
--- a/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_scripts.mvir
+++ /dev/null
@@ -1,21 +0,0 @@
-//# run --args @0x1 @0x1 @0x1
-
-// tests various mixed usage of signer in script arguments
-
-main(s1: signer, s2: &signer, s3: signer) {
-    label l0:
-    return;
-}
-
-
-//# run --args @0x1 0 @0x1 false @0x1
-main(s1: &signer, u: u64, s2: signer, f: bool, s3: &signer) {
-    label l0:
-    return;
-}
-
-//# run --args 0 false @0x1 @0x2 @0x3
-main(u: u64, f: bool, a: address, s1: signer, s2: &signer) {
-    label l0:
-    return;
-}
diff --git a/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_scripts.v2_exp b/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_scripts.v2_exp
deleted file mode 100644
index fc5a4436b29d4..0000000000000
--- a/third_party/move/move-vm/transactional-tests/tests/entry_points/mixed_signer_inputs_scripts.v2_exp
+++ /dev/null
@@ -1 +0,0 @@
-processed 3 tasks
diff --git a/third_party/move/move-vm/transactional-tests/tests/entry_points/return_values.exp b/third_party/move/move-vm/transactional-tests/tests/entry_points/return_values.exp
index 13f10dcbdf982..207d694c94d44 100644
--- a/third_party/move/move-vm/transactional-tests/tests/entry_points/return_values.exp
+++ b/third_party/move/move-vm/transactional-tests/tests/entry_points/return_values.exp
@@ -2,4 +2,4 @@ processed 2 tasks
 
 task 1 'run'. lines 20-20:
 mutable inputs after call: local#4: { 4 }
-return values: 0, { 0000000000000000000000000000000000000000000000000000000000000001 }, { 2 }, { 3 }, 3, 4
+return values: 0, { 0, 0000000000000000000000000000000000000000000000000000000000000001 }, { 2 }, { 3 }, 3, 4
diff --git a/third_party/move/move-vm/transactional-tests/tests/entry_points/return_values.mvir b/third_party/move/move-vm/transactional-tests/tests/entry_points/return_values.mvir
index 875876e59f9df..1210f152defe0 100644
--- a/third_party/move/move-vm/transactional-tests/tests/entry_points/return_values.mvir
+++ b/third_party/move/move-vm/transactional-tests/tests/entry_points/return_values.mvir
@@ -6,8 +6,8 @@ module 0x42.M {
     struct S { f: u64 }
 
     public t(
-        x: u64,
         a: signer,
+        x: u64,
         s: Self.S,
         r1: &Self.S,
         r2: &mut Self.S
@@ -17,4 +17,4 @@ module 0x42.M {
     }
 }
 
-//# run 0x42::M::t --args 0 @0x1 2 3 4
+//# run 0x42::M::t --signers 0x1 --args 0 2 3 4
diff --git a/third_party/move/move-vm/transactional-tests/tests/entry_points/return_values.v2_exp b/third_party/move/move-vm/transactional-tests/tests/entry_points/return_values.v2_exp
index 13f10dcbdf982..207d694c94d44 100644
--- a/third_party/move/move-vm/transactional-tests/tests/entry_points/return_values.v2_exp
+++ b/third_party/move/move-vm/transactional-tests/tests/entry_points/return_values.v2_exp
@@ -2,4 +2,4 @@ processed 2 tasks
 
 task 1 'run'. lines 20-20:
 mutable inputs after call: local#4: { 4 }
-return values: 0, { 0000000000000000000000000000000000000000000000000000000000000001 }, { 2 }, { 3 }, 3, 4
+return values: 0, { 0, 0000000000000000000000000000000000000000000000000000000000000001 }, { 2 }, { 3 }, 3, 4
diff --git a/third_party/move/move-vm/transactional-tests/tests/entry_points/script_type_args_type_eq.mvir b/third_party/move/move-vm/transactional-tests/tests/entry_points/script_type_args_type_eq.mvir
index 303be015fcb26..07f1320cb41ea 100644
--- a/third_party/move/move-vm/transactional-tests/tests/entry_points/script_type_args_type_eq.mvir
+++ b/third_party/move/move-vm/transactional-tests/tests/entry_points/script_type_args_type_eq.mvir
@@ -20,7 +20,7 @@ module 0x42.M {
 }
 // check: "Keep(EXECUTED)"
 
-//# run --type-args u64 --args @0x1
+//# run --type-args u64 --signers 0x1
 import 0x42.M;
 
 main(account: signer) {
@@ -32,7 +32,7 @@ label b0:
 
 
 
-//# run --type-args 0x42::M::Item --args @0x2
+//# run --type-args 0x42::M::Item --signers 0x2
 import 0x42.M;
 
 main(account: signer) {
@@ -43,7 +43,7 @@ label b0:
 }
 
 
-//# run --type-args 0x42::M::Cup<0x42::M::Cup>> --args @0x3
+//# run --type-args 0x42::M::Cup<0x42::M::Cup>> --signers 0x3
 import 0x42.M;
 
 main(account: signer) {
diff --git a/third_party/move/move-vm/transactional-tests/tests/entry_points/serializer_deserializer.move b/third_party/move/move-vm/transactional-tests/tests/entry_points/serializer_deserializer.move
index 85e996fad40ac..500f0c1f83633 100644
--- a/third_party/move/move-vm/transactional-tests/tests/entry_points/serializer_deserializer.move
+++ b/third_party/move/move-vm/transactional-tests/tests/entry_points/serializer_deserializer.move
@@ -37,7 +37,7 @@ module 0x42::t {
 
 }
 
-//# run 0x42::t::add --args @0x42
+//# run 0x42::t::add --signers 0x42
 
 //# view --address 0x42 --resource 0x42::t::Ints
 
diff --git a/third_party/move/move-vm/transactional-tests/tests/recursion/runtime_layout_deeply_nested.mvir b/third_party/move/move-vm/transactional-tests/tests/recursion/runtime_layout_deeply_nested.mvir
index 9044139ecd6f3..5a3ffa6b060f3 100644
--- a/third_party/move/move-vm/transactional-tests/tests/recursion/runtime_layout_deeply_nested.mvir
+++ b/third_party/move/move-vm/transactional-tests/tests/recursion/runtime_layout_deeply_nested.mvir
@@ -66,7 +66,7 @@ module 0x42.M {
 }
 
 
-//# run --args @0x1
+//# run --signers 0x1
 import 0x42.M;
 
 main(account: signer) {
@@ -76,7 +76,7 @@ label b0:
     return;
 }
 
-//# run --args @0x2
+//# run --signers 0x2
 import 0x42.M;
 
 main(account: signer) {
@@ -86,7 +86,7 @@ label b0:
 }
 
 
-//# run --args @0x3
+//# run --signers 0x3
 import 0x42.M;
 
 main(account: signer) {
diff --git a/third_party/move/move-vm/types/src/value_serde.rs b/third_party/move/move-vm/types/src/value_serde.rs
index c8f390096f9ac..dd9c22140ad26 100644
--- a/third_party/move/move-vm/types/src/value_serde.rs
+++ b/third_party/move/move-vm/types/src/value_serde.rs
@@ -62,6 +62,7 @@ pub struct ValueSerDeContext<'a> {
     #[allow(dead_code)]
     pub(crate) function_extension: Option<&'a dyn FunctionValueExtension>,
     pub(crate) delayed_fields_extension: Option>,
+    pub(crate) legacy_signer: bool,
 }
 
 impl<'a> ValueSerDeContext<'a> {
@@ -71,9 +72,16 @@ impl<'a> ValueSerDeContext<'a> {
         Self {
             function_extension: None,
             delayed_fields_extension: None,
+            legacy_signer: false,
         }
     }
 
+    /// Serialize signer with legacy format to maintain backwards compatibility.
+    pub fn with_legacy_signer(mut self) -> Self {
+        self.legacy_signer = true;
+        self
+    }
+
     /// Custom (de)serializer such that supports lookup of the argument types of a function during
     /// function value deserialization.
     pub fn with_func_args_deserialization(
@@ -89,6 +97,7 @@ impl<'a> ValueSerDeContext<'a> {
         Self {
             function_extension: self.function_extension,
             delayed_fields_extension: None,
+            legacy_signer: self.legacy_signer,
         }
     }
 
diff --git a/third_party/move/move-vm/types/src/value_traversal.rs b/third_party/move/move-vm/types/src/value_traversal.rs
index 16a1669a6fe00..54cfac487e5bc 100644
--- a/third_party/move/move-vm/types/src/value_traversal.rs
+++ b/third_party/move/move-vm/types/src/value_traversal.rs
@@ -82,7 +82,7 @@ mod test {
 
     #[test]
     fn test_traversal_in_invalid_value() {
-        let a = Value::signer_reference(AccountAddress::random());
+        let a = Value::master_signer_reference(AccountAddress::random());
         assert_err!(find_identifiers_in_value(&a, &mut HashSet::new()));
     }
 
diff --git a/third_party/move/move-vm/types/src/values/serialization_tests.rs b/third_party/move/move-vm/types/src/values/serialization_tests.rs
index e1c48c082fcbe..c2df063f767e1 100644
--- a/third_party/move/move-vm/types/src/values/serialization_tests.rs
+++ b/third_party/move/move-vm/types/src/values/serialization_tests.rs
@@ -216,7 +216,7 @@ fn test_serialized_size() {
         (Value::u256(u256::U256::one()), U256),
         (Value::bool(true), Bool),
         (Value::address(AccountAddress::ONE), Address),
-        (Value::signer(AccountAddress::ONE), Signer),
+        (Value::master_signer(AccountAddress::ONE), Signer),
         (u64_delayed_value, Native(Aggregator, Box::new(U64))),
         (u128_delayed_value, Native(Snapshot, Box::new(U128))),
         (
@@ -261,3 +261,80 @@ fn test_serialized_size() {
             .serialized_size(&value, &layout));
     }
 }
+
+#[test]
+fn new_signer_round_trip_vm_value() {
+    let move_value = MoveValue::Signer(AccountAddress::ZERO);
+    let bytes = move_value.simple_serialize().unwrap();
+
+    let vm_value = Value::master_signer(AccountAddress::ZERO);
+    let vm_bytes = ValueSerDeContext::new()
+        .serialize(&vm_value, &MoveTypeLayout::Signer)
+        .unwrap()
+        .unwrap();
+
+    // VM Value Roundtrip
+    assert!(ValueSerDeContext::new()
+        .deserialize(&vm_bytes, &MoveTypeLayout::Signer)
+        .unwrap()
+        .equals(&vm_value)
+        .unwrap());
+
+    // MoveValue Roundtrip
+    assert_eq!(
+        move_value,
+        MoveValue::simple_deserialize(&bytes, &MoveTypeLayout::Signer).unwrap()
+    );
+
+    // ser(MoveValue) == ser(VMValue)
+    assert_eq!(bytes, vm_bytes);
+
+    // Permissioned Signer Roundtrip
+    let vm_value = Value::permissioned_signer(AccountAddress::ZERO, AccountAddress::ONE);
+    let vm_bytes = ValueSerDeContext::new()
+        .serialize(&vm_value, &MoveTypeLayout::Signer)
+        .unwrap()
+        .unwrap();
+
+    // VM Value Roundtrip
+    assert!(ValueSerDeContext::new()
+        .deserialize(&vm_bytes, &MoveTypeLayout::Signer)
+        .unwrap()
+        .equals(&vm_value)
+        .unwrap());
+
+    // Cannot serialize permissioned signer into bytes with legacy signer
+    assert!(ValueSerDeContext::new()
+        .with_legacy_signer()
+        .serialize(&vm_value, &MoveTypeLayout::Signer)
+        .unwrap()
+        .is_none());
+}
+
+#[test]
+fn legacy_signer_round_trip_vm_value() {
+    let move_value = MoveValue::Address(AccountAddress::ZERO);
+    let bytes = move_value.simple_serialize().unwrap();
+
+    let vm_value = Value::master_signer(AccountAddress::ZERO);
+    let vm_bytes = ValueSerDeContext::new()
+        .with_legacy_signer()
+        .serialize(&vm_value, &MoveTypeLayout::Signer)
+        .unwrap()
+        .unwrap();
+
+    // VM Value Roundtrip
+    assert!(ValueSerDeContext::new()
+        .with_legacy_signer()
+        .deserialize(&vm_bytes, &MoveTypeLayout::Signer)
+        .is_none());
+
+    // MoveValue Roundtrip
+    assert_eq!(
+        move_value,
+        MoveValue::simple_deserialize(&bytes, &MoveTypeLayout::Address).unwrap()
+    );
+
+    // ser(MoveValue) == ser(VMValue)
+    assert_eq!(bytes, vm_bytes);
+}
diff --git a/third_party/move/move-vm/types/src/values/value_tests.rs b/third_party/move/move-vm/types/src/values/value_tests.rs
index c5d7574e774c4..1563c94df055d 100644
--- a/third_party/move/move-vm/types/src/values/value_tests.rs
+++ b/third_party/move/move-vm/types/src/values/value_tests.rs
@@ -251,8 +251,8 @@ fn test_mem_swap() -> PartialVMResult<()> {
     // -- Container of container
     locals.store_loc(8, Value::struct_(Struct::pack(vec![Value::u16(4)])), false)?;
     locals.store_loc(9, Value::struct_(Struct::pack(vec![Value::u16(5)])), false)?;
-    locals.store_loc(10, Value::signer(AccountAddress::ZERO), false)?;
-    locals.store_loc(11, Value::signer(AccountAddress::ONE), false)?;
+    locals.store_loc(10, Value::master_signer(AccountAddress::ZERO), false)?;
+    locals.store_loc(11, Value::master_signer(AccountAddress::ONE), false)?;
 
     // -- Container of vector
     locals.store_loc(
@@ -267,12 +267,12 @@ fn test_mem_swap() -> PartialVMResult<()> {
     )?;
     locals.store_loc(
         14,
-        Value::vector_for_testing_only(vec![Value::signer(AccountAddress::ZERO)]),
+        Value::vector_for_testing_only(vec![Value::master_signer(AccountAddress::ZERO)]),
         false,
     )?;
     locals.store_loc(
         15,
-        Value::vector_for_testing_only(vec![Value::signer(AccountAddress::ONE)]),
+        Value::vector_for_testing_only(vec![Value::master_signer(AccountAddress::ONE)]),
         false,
     )?;
 
@@ -334,8 +334,8 @@ mod native_values {
         assert_err!(Value::u256(U256::zero()).equals(&v));
 
         assert_err!(Value::address(AccountAddress::ONE).equals(&v));
-        assert_err!(Value::signer(AccountAddress::ONE).equals(&v));
-        assert_err!(Value::signer_reference(AccountAddress::ONE).equals(&v));
+        assert_err!(Value::master_signer(AccountAddress::ONE).equals(&v));
+        assert_err!(Value::master_signer_reference(AccountAddress::ONE).equals(&v));
 
         assert_err!(Value::vector_bool(vec![true, false]).equals(&v));
 
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 fae84d1694a85..71ddeea856370 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
@@ -19,8 +19,11 @@ use move_core_types::{
     account_address::AccountAddress,
     effects::Op,
     gas_algebra::AbstractMemorySize,
-    u256, value,
-    value::{MoveStruct, MoveStructLayout, MoveTypeLayout, MoveValue},
+    u256,
+    value::{
+        self, MoveStruct, MoveStructLayout, MoveTypeLayout, MoveValue, MASTER_ADDRESS_FIELD_OFFSET,
+        MASTER_SIGNER_VARIANT, PERMISSIONED_SIGNER_VARIANT, PERMISSION_ADDRESS_FIELD_OFFSET,
+    },
     vm_status::{sub_status::NFE_VECTOR_ERROR_BASE, StatusCode},
 };
 use serde::{
@@ -290,8 +293,11 @@ impl Container {
         }
     }
 
-    fn signer(x: AccountAddress) -> Self {
-        Container::Struct(Rc::new(RefCell::new(vec![ValueImpl::Address(x)])))
+    fn master_signer(x: AccountAddress) -> Self {
+        Container::Struct(Rc::new(RefCell::new(vec![
+            ValueImpl::U16(MASTER_SIGNER_VARIANT),
+            ValueImpl::Address(x),
+        ])))
     }
 }
 
@@ -1513,7 +1519,39 @@ impl Locals {
 
 impl SignerRef {
     pub fn borrow_signer(&self) -> PartialVMResult {
-        Ok(Value(self.0.borrow_elem(0)?))
+        Ok(Value(self.0.borrow_elem(1)?))
+    }
+
+    pub fn is_permissioned(&self) -> PartialVMResult {
+        match &self.0 {
+            ContainerRef::Local(Container::Struct(s)) => {
+                Ok(*s.borrow()[0].as_value_ref::()? == PERMISSIONED_SIGNER_VARIANT)
+            },
+            _ => Err(
+                PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
+                    .with_message(format!("unexpected signer value: {:?}", self)),
+            ),
+        }
+    }
+
+    /// Get the permission address associated with a signer.
+    /// Needs to make sure the signer passed in is a permissioned signer.
+    pub fn permission_address(&self) -> PartialVMResult {
+        match &self.0 {
+            ContainerRef::Local(Container::Struct(s)) => Ok(Value::address(
+                *s.borrow()
+                    .get(PERMISSION_ADDRESS_FIELD_OFFSET)
+                    .ok_or_else(|| {
+                        PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
+                            .with_message(format!("unexpected signer value: {:?}", self))
+                    })?
+                    .as_value_ref::()?,
+            )),
+            _ => Err(
+                PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
+                    .with_message(format!("unexpected signer value: {:?}", self)),
+            ),
+        }
     }
 }
 
@@ -1672,15 +1710,22 @@ impl Value {
         Self(ValueImpl::Address(x))
     }
 
-    pub fn signer(x: AccountAddress) -> Self {
-        Self(ValueImpl::Container(Container::signer(x)))
+    pub fn master_signer(x: AccountAddress) -> Self {
+        Self(ValueImpl::Container(Container::master_signer(x)))
+    }
+
+    pub fn permissioned_signer(x: AccountAddress, perm_storage_address: AccountAddress) -> Self {
+        Self::struct_(Struct::pack_variant(PERMISSIONED_SIGNER_VARIANT, vec![
+            Value::address(x),
+            Value::address(perm_storage_address),
+        ]))
     }
 
     /// Create a "unowned" reference to a signer value (&signer) for populating the &signer in
     /// execute function
-    pub fn signer_reference(x: AccountAddress) -> Self {
+    pub fn master_signer_reference(x: AccountAddress) -> Self {
         Self(ValueImpl::ContainerRef(ContainerRef::Local(
-            Container::signer(x),
+            Container::master_signer(x),
         )))
     }
 
@@ -3710,19 +3755,41 @@ impl<'c, 'l, 'v> serde::Serialize
 
             // Signer.
             (L::Signer, ValueImpl::Container(Container::Struct(r))) => {
-                let v = r.borrow();
-                if v.len() != 1 {
-                    return Err(invariant_violation::(format!(
-                        "cannot serialize container as a signer -- expected 1 field got {}",
-                        v.len()
-                    )));
+                if self.ctx.legacy_signer {
+                    // Only allow serialization of master signer.
+                    if *r.borrow()[0].as_value_ref::().map_err(|_| {
+                        invariant_violation::(format!(
+                            "First field of a signer needs to be an enum descriminator, got {:?}",
+                            self.value
+                        ))
+                    })? != MASTER_SIGNER_VARIANT
+                    {
+                        return Err(S::Error::custom(PartialVMError::new(StatusCode::ABORTED)));
+                    }
+                    r.borrow()
+                        .get(MASTER_ADDRESS_FIELD_OFFSET)
+                        .ok_or_else(|| {
+                            invariant_violation::(format!(
+                                "cannot serialize container {:?} as {:?}",
+                                self.value, self.layout
+                            ))
+                        })?
+                        .as_value_ref::()
+                        .map_err(|_| {
+                            invariant_violation::(format!(
+                                "cannot serialize container {:?} as {:?}",
+                                self.value, self.layout
+                            ))
+                        })?
+                        .serialize(serializer)
+                } else {
+                    (SerializationReadyValue {
+                        ctx: self.ctx,
+                        layout: &MoveStructLayout::signer_serialization_layout(),
+                        value: &*r.borrow(),
+                    })
+                    .serialize(serializer)
                 }
-                (SerializationReadyValue {
-                    ctx: self.ctx,
-                    layout: &L::Address,
-                    value: &v[0],
-                })
-                .serialize(serializer)
             },
 
             // Delayed values. For their serialization, we must have custom
@@ -3874,7 +3941,19 @@ impl<'d, 'c> serde::de::DeserializeSeed<'d> for DeserializationSeed<'c, &MoveTyp
             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 => {
+                if self.ctx.legacy_signer {
+                    Err(D::Error::custom(
+                        "Cannot deserialize signer into value".to_string(),
+                    ))
+                } else {
+                    let seed = DeserializationSeed {
+                        ctx: self.ctx,
+                        layout: &MoveStructLayout::signer_serialization_layout(),
+                    };
+                    Ok(Value::struct_(seed.deserialize(deserializer)?))
+                }
+            },
 
             // Structs.
             L::Struct(struct_layout) => {
@@ -4466,7 +4545,9 @@ pub mod prop {
             L::U256 => any::().prop_map(Value::u256).boxed(),
             L::Bool => any::().prop_map(Value::bool).boxed(),
             L::Address => any::().prop_map(Value::address).boxed(),
-            L::Signer => any::().prop_map(Value::signer).boxed(),
+            L::Signer => any::()
+                .prop_map(Value::master_signer)
+                .boxed(),
 
             L::Vector(layout) => match &**layout {
                 L::U8 => vec(any::(), 0..10)
@@ -4660,10 +4741,7 @@ impl ValueImpl {
 
             (L::Signer, ValueImpl::Container(Container::Struct(r))) => {
                 let v = r.borrow();
-                if v.len() != 1 {
-                    panic!("Unexpected signer layout: {:?}", v);
-                }
-                match &v[0] {
+                match &v[MASTER_ADDRESS_FIELD_OFFSET] {
                     ValueImpl::Address(a) => MoveValue::Signer(*a),
                     v => panic!("Unexpected non-address while converting signer: {:?}", v),
                 }