diff --git a/Cargo.lock b/Cargo.lock index 80c4124142..8c8215cb2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5068,6 +5068,7 @@ dependencies = [ "better_any", "fastcrypto", "hex", + "itertools", "linked-hash-map", "log", "move-binary-format", diff --git a/crates/rooch-framework/src/natives/gas_parameter/move_module.rs b/crates/rooch-framework/src/natives/gas_parameter/move_module.rs index 6cc7fce22f..fbd839c343 100644 --- a/crates/rooch-framework/src/natives/gas_parameter/move_module.rs +++ b/crates/rooch-framework/src/natives/gas_parameter/move_module.rs @@ -13,4 +13,6 @@ crate::natives::gas_parameter::native::define_gas_parameters_for_natives!(GasPar [.request_init_functions.per_byte, "request_init_functions.per_byte", (5 + 1) * MUL], [.check_compatibililty_inner.base, "check_compatibililty_inner.base", (5 + 1) * MUL], [.check_compatibililty_inner.per_byte, "check_compatibililty_inner.per_byte", (5 + 1) * MUL], + [.remap_module_addresses_inner.base, "remap_module_addresses_inner.base", (5 + 1) * MUL], + [.remap_module_addresses_inner.per_byte, "remap_module_addresses_inner.per_byte", (5 + 1) * MUL], ]); diff --git a/examples/publish_modules/sources/publish.move b/examples/publish_modules/sources/publish.move index d86e542571..e2ebcc1c8a 100644 --- a/examples/publish_modules/sources/publish.move +++ b/examples/publish_modules/sources/publish.move @@ -14,54 +14,21 @@ module rooch_examples::publish { use moveos_std::context::Context; use moveos_std::account_storage; - #[test_only] - use moveos_std::context; - #[test_only] - use std::debug; - public entry fun publish_modules_entry(ctx: &mut Context, account: &signer, module_bytes: vector) { account_storage::ensure_account_storage(ctx, signer::address_of(account)); let m: MoveModule = move_module::new(module_bytes); account_storage::publish_modules(ctx, account, vector::singleton(m)); } - #[test(account=@0x42)] - fun test_get_module_name(account: &signer) { - let addr = signer::address_of(account); - let ctx = context::new_test_context(addr); - // The following is the bytes and hex of the compiled module: example/counter/sources/counter.move - // with account 0x42 - let module_bytes: vector = x"a11ceb0b060000000b010006020608030e26043406053a32076c7d08e9014006a902220acb02050cd002560da6030200000101010200030c00020400000005000100000600010000070201000008030400010907080108010a09010108010b0a0b0108040605060606010708010002070801060c0106080101030107080001080002070801050107090003070801060c090002060801050106090007636f756e7465720f6163636f756e745f73746f7261676507636f6e7465787407436f756e74657207436f6e7465787408696e63726561736509696e6372656173655f04696e69740576616c756511676c6f62616c5f626f72726f775f6d75740e676c6f62616c5f6d6f76655f746f0d676c6f62616c5f626f72726f77000000000000000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000000000000000020520000000000000000000000000000000000000000000000000000000000000004200020108030001040001030b0011010201010000050d0b00070038000c010a01100014060100000000000000160b010f0015020200000001060b000b0106000000000000000012003801020301000001060b000700380210001402000000"; - let m: MoveModule = move_module::new(module_bytes); - let name = move_module::module_name(&m); - debug::print(&name); - context::drop_test_context(ctx); - } - - #[test(account=@0x42)] - fun test_verify_modules(account: &signer) { - let addr = signer::address_of(account); - let ctx = context::new_test_context(addr); + public entry fun publish_counter_example(ctx: &mut Context, account: &signer) { + account_storage::ensure_account_storage(ctx, signer::address_of(account)); // The following is the bytes and hex of the compiled module: example/counter/sources/counter.move // with account 0x42 let module_bytes: vector = x"a11ceb0b060000000b010006020608030e26043406053a32076c7d08e9014006a902220acb02050cd002560da6030200000101010200030c00020400000005000100000600010000070201000008030400010907080108010a09010108010b0a0b0108040605060606010708010002070801060c0106080101030107080001080002070801050107090003070801060c090002060801050106090007636f756e7465720f6163636f756e745f73746f7261676507636f6e7465787407436f756e74657207436f6e7465787408696e63726561736509696e6372656173655f04696e69740576616c756511676c6f62616c5f626f72726f775f6d75740e676c6f62616c5f6d6f76655f746f0d676c6f62616c5f626f72726f77000000000000000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000000000000000020520000000000000000000000000000000000000000000000000000000000000004200020108030001040001030b0011010201010000050d0b00070038000c010a01100014060100000000000000160b010f0015020200000001060b000b0106000000000000000012003801020301000001060b000700380210001402000000"; - let m: MoveModule = move_module::new(module_bytes); - let modules = vector::singleton(m); - let (module_names, _module_names_with_init_fn) = move_module::sort_and_verify_modules(&modules, addr); - debug::print(&module_names); - context::drop_test_context(ctx); - } - - #[test(account=@0x42)] - fun test_publish_modules(account: &signer) { - let addr = signer::address_of(account); - let ctx = context::new_test_context(addr); - account_storage::create_account_storage(&mut ctx, addr); - // The following is the bytes and hex of the compiled module: example/counter/sources/counter.move - // with account 0x42 - let module_bytes: vector = x"a11ceb0b060000000b010006020608030e26043406053a32076c7d08e9014006a902220acb02050cd002560da6030200000101010200030c00020400000005000100000600010000070201000008030400010907080108010a09010108010b0a0b0108040605060606010708010002070801060c0106080101030107080001080002070801050107090003070801060c090002060801050106090007636f756e7465720f6163636f756e745f73746f7261676507636f6e7465787407436f756e74657207436f6e7465787408696e63726561736509696e6372656173655f04696e69740576616c756511676c6f62616c5f626f72726f775f6d75740e676c6f62616c5f6d6f76655f746f0d676c6f62616c5f626f72726f77000000000000000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000000000000000020520000000000000000000000000000000000000000000000000000000000000004200020108030001040001030b0011010201010000050d0b00070038000c010a01100014060100000000000000160b010f0015020200000001060b000b0106000000000000000012003801020301000001060b000700380210001402000000"; - let m: MoveModule = move_module::new(module_bytes); - account_storage::publish_modules(&mut ctx, account, vector::singleton(m)); - context::drop_test_context(ctx); + let modules = vector::singleton(move_module::new(module_bytes)); + let old_addresses = vector::singleton(@0x42); + let new_addresses = vector::singleton(signer::address_of(account)); + let remapped_modules = move_module::remap_module_addresses(modules, old_addresses, new_addresses); + account_storage::publish_modules(ctx, account, remapped_modules); } } diff --git a/moveos/moveos-stdlib/Cargo.toml b/moveos/moveos-stdlib/Cargo.toml index feb72e9c60..693ad4d0aa 100644 --- a/moveos/moveos-stdlib/Cargo.toml +++ b/moveos/moveos-stdlib/Cargo.toml @@ -27,6 +27,7 @@ smallvec = { workspace = true } hex = { workspace = true } petgraph = { workspace = true } parking_lot = { workspace = true } +itertools = { workspace = true } move-binary-format = { workspace = true } move-bytecode-utils = { workspace = true } diff --git a/moveos/moveos-stdlib/moveos-stdlib/doc/move_module.md b/moveos/moveos-stdlib/moveos-stdlib/doc/move_module.md index 9ffcd35cbf..75d63747ae 100644 --- a/moveos/moveos-stdlib/moveos-stdlib/doc/move_module.md +++ b/moveos/moveos-stdlib/moveos-stdlib/doc/move_module.md @@ -12,10 +12,12 @@ - [Function `module_name`](#0x2_move_module_module_name) - [Function `sort_and_verify_modules`](#0x2_move_module_sort_and_verify_modules) - [Function `check_comatibility`](#0x2_move_module_check_comatibility) +- [Function `remap_module_addresses`](#0x2_move_module_remap_module_addresses) - [Function `request_init_functions`](#0x2_move_module_request_init_functions) -
use 0x1::string;
+
use 0x1::error;
+use 0x1::string;
 
@@ -62,6 +64,16 @@ Module address is not the same as the signer + + +Vector length not match + + +
const ErrorLengthNotMatch: u64 = 4;
+
+ + + Module incompatible with the old ones. @@ -193,6 +205,59 @@ Abort if the new module is not compatible with the old module. + + + + +## Function `remap_module_addresses` + +Remap addresses in module binary where the length of +old_addresses must equal to that of new_addresses. + + +
public fun remap_module_addresses(modules: vector<move_module::MoveModule>, old_addresses: vector<address>, new_addresses: vector<address>): vector<move_module::MoveModule>
+
+ + + +
+Implementation + + +
public fun remap_module_addresses(
+    modules: vector<MoveModule>,
+    old_addresses: vector<address>,
+    new_addresses: vector<address>,
+): vector<MoveModule> {
+    assert!(
+        vector::length(&old_addresses) == vector::length(&new_addresses),
+        error::invalid_argument(ErrorLengthNotMatch)
+    );
+    let bytes_vec = vector::empty<vector<u8>>();
+    let i = 0u64;
+    let len = vector::length(&modules);
+    while (i < len) {
+        vector::push_back(&mut bytes_vec, vector::pop_back(&mut modules).byte_codes);
+        i = i + 1;
+    };
+    let remapped_bytes = remap_module_addresses_inner(bytes_vec, old_addresses, new_addresses);
+    // let remapped_bytes = remap_module_addresses_inner(bytes_vec);
+    let remapped_modules = vector::empty<MoveModule>();
+    i = 0u64;
+    let len = vector::length(&remapped_bytes);
+    while (i < len) {
+        vector::push_back(&mut remapped_modules, MoveModule {
+            byte_codes: vector::pop_back(&mut remapped_bytes),
+        });
+        i = i + 1;
+    };
+    vector::destroy_empty(remapped_bytes);
+    remapped_modules
+}
+
+ + +
diff --git a/moveos/moveos-stdlib/moveos-stdlib/sources/account_storage.move b/moveos/moveos-stdlib/moveos-stdlib/sources/account_storage.move index e011677de4..a9a6e15804 100644 --- a/moveos/moveos-stdlib/moveos-stdlib/sources/account_storage.move +++ b/moveos/moveos-stdlib/moveos-stdlib/sources/account_storage.move @@ -430,4 +430,17 @@ module moveos_std::account_storage { } = test; context::drop_test_context(ctx); } + + #[test(account=@0x42)] + fun test_publish_modules(account: &signer) { + let addr = signer::address_of(account); + let ctx = context::new_test_context(addr); + Self::create_account_storage(&mut ctx, addr); + // The following is the bytes and hex of the compiled module: example/counter/sources/counter.move + // with account 0x42 + let module_bytes: vector = x"a11ceb0b060000000b010006020608030e26043406053a32076c7d08e9014006a902220acb02050cd002560da6030200000101010200030c00020400000005000100000600010000070201000008030400010907080108010a09010108010b0a0b0108040605060606010708010002070801060c0106080101030107080001080002070801050107090003070801060c090002060801050106090007636f756e7465720f6163636f756e745f73746f7261676507636f6e7465787407436f756e74657207436f6e7465787408696e63726561736509696e6372656173655f04696e69740576616c756511676c6f62616c5f626f72726f775f6d75740e676c6f62616c5f6d6f76655f746f0d676c6f62616c5f626f72726f77000000000000000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000000000000000020520000000000000000000000000000000000000000000000000000000000000004200020108030001040001030b0011010201010000050d0b00070038000c010a01100014060100000000000000160b010f0015020200000001060b000b0106000000000000000012003801020301000001060b000700380210001402000000"; + let m: MoveModule = move_module::new(module_bytes); + Self::publish_modules(&mut ctx, account, vector::singleton(m)); + context::drop_test_context(ctx); + } } \ No newline at end of file diff --git a/moveos/moveos-stdlib/moveos-stdlib/sources/move_module.move b/moveos/moveos-stdlib/moveos-stdlib/sources/move_module.move index f540e23126..e805b3c91f 100644 --- a/moveos/moveos-stdlib/moveos-stdlib/sources/move_module.move +++ b/moveos/moveos-stdlib/moveos-stdlib/sources/move_module.move @@ -4,19 +4,20 @@ /// `move_module` provides some basic functions for handle Move module in Move. module moveos_std::move_module { use std::vector; + use std::error; use std::string::String; friend moveos_std::account_storage; /// Module address is not the same as the signer const ErrorAddressNotMatchWithSigner: u64 = 1; - /// Module verification error const ErrorModuleVerificationError: u64 = 2; - /// Module incompatible with the old ones. const ErrorModuleIncompatible: u64 = 3; - + /// Vector length not match + const ErrorLengthNotMatch: u64 = 4; + struct MoveModule has store, drop { byte_codes: vector, } @@ -54,6 +55,39 @@ module moveos_std::move_module { check_compatibililty_inner(new_module.byte_codes, old_module.byte_codes); } + /// Remap addresses in module binary where the length of + /// `old_addresses` must equal to that of `new_addresses`. + public fun remap_module_addresses( + modules: vector, + old_addresses: vector
, + new_addresses: vector
, + ): vector { + assert!( + vector::length(&old_addresses) == vector::length(&new_addresses), + error::invalid_argument(ErrorLengthNotMatch) + ); + let bytes_vec = vector::empty>(); + let i = 0u64; + let len = vector::length(&modules); + while (i < len) { + vector::push_back(&mut bytes_vec, vector::pop_back(&mut modules).byte_codes); + i = i + 1; + }; + let remapped_bytes = remap_module_addresses_inner(bytes_vec, old_addresses, new_addresses); + // let remapped_bytes = remap_module_addresses_inner(bytes_vec); + let remapped_modules = vector::empty(); + i = 0u64; + let len = vector::length(&remapped_bytes); + while (i < len) { + vector::push_back(&mut remapped_modules, MoveModule { + byte_codes: vector::pop_back(&mut remapped_bytes), + }); + i = i + 1; + }; + vector::destroy_empty(remapped_bytes); + remapped_modules + } + native fun module_name_inner(byte_codes: &vector): String; /// Sort modules by dependency order and then verify. @@ -66,4 +100,82 @@ module moveos_std::move_module { native public(friend) fun request_init_functions(module_names: vector, account_address: address); native fun check_compatibililty_inner(new_bytecodes: vector, old_bytecodes: vector); + + /// Native function to remap addresses in module binary where the length of + /// `old_addresses` must equal to that of `new_addresses`. + native fun remap_module_addresses_inner( + bytes: vector>, + old_addresses: vector
, + new_addresses: vector
, + ): vector>; + + + #[test_only] + use std::debug; + #[test_only] + use std::signer; + #[test_only] + use moveos_std::context; + + #[test(account=@0x42)] + fun test_get_module_name(account: &signer) { + let addr = signer::address_of(account); + let ctx = context::new_test_context(addr); + // The following is the bytes and hex of the compiled module: example/counter/sources/counter.move + // with account 0x42 + let module_bytes: vector = x"a11ceb0b060000000b010006020608030e26043406053a32076c7d08e9014006a902220acb02050cd002560da6030200000101010200030c00020400000005000100000600010000070201000008030400010907080108010a09010108010b0a0b0108040605060606010708010002070801060c0106080101030107080001080002070801050107090003070801060c090002060801050106090007636f756e7465720f6163636f756e745f73746f7261676507636f6e7465787407436f756e74657207436f6e7465787408696e63726561736509696e6372656173655f04696e69740576616c756511676c6f62616c5f626f72726f775f6d75740e676c6f62616c5f6d6f76655f746f0d676c6f62616c5f626f72726f77000000000000000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000000000000000020520000000000000000000000000000000000000000000000000000000000000004200020108030001040001030b0011010201010000050d0b00070038000c010a01100014060100000000000000160b010f0015020200000001060b000b0106000000000000000012003801020301000001060b000700380210001402000000"; + let m: MoveModule = Self::new(module_bytes); + let name = Self::module_name(&m); + debug::print(&name); + context::drop_test_context(ctx); + } + + #[test(account=@0x42)] + fun test_verify_modules(account: &signer) { + let addr = signer::address_of(account); + let ctx = context::new_test_context(addr); + // The following is the bytes and hex of the compiled module: example/counter/sources/counter.move + // with account 0x42 + let module_bytes: vector = x"a11ceb0b060000000b010006020608030e26043406053a32076c7d08e9014006a902220acb02050cd002560da6030200000101010200030c00020400000005000100000600010000070201000008030400010907080108010a09010108010b0a0b0108040605060606010708010002070801060c0106080101030107080001080002070801050107090003070801060c090002060801050106090007636f756e7465720f6163636f756e745f73746f7261676507636f6e7465787407436f756e74657207436f6e7465787408696e63726561736509696e6372656173655f04696e69740576616c756511676c6f62616c5f626f72726f775f6d75740e676c6f62616c5f6d6f76655f746f0d676c6f62616c5f626f72726f77000000000000000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000000000000000020520000000000000000000000000000000000000000000000000000000000000004200020108030001040001030b0011010201010000050d0b00070038000c010a01100014060100000000000000160b010f0015020200000001060b000b0106000000000000000012003801020301000001060b000700380210001402000000"; + let m: MoveModule = Self::new(module_bytes); + let modules = vector::singleton(m); + let (module_names, _module_names_with_init_fn) = Self::sort_and_verify_modules(&modules, addr); + debug::print(&module_names); + context::drop_test_context(ctx); + } + + #[test(account=@0x1314)] + #[expected_failure(abort_code = 0x10001, location = Self)] + fun test_address_mismatch_failure(account: &signer) { + let addr = signer::address_of(account); + let ctx = context::new_test_context(addr); + // The following is the bytes and hex of the compiled module: example/counter/sources/counter.move + // with account 0x42 + let module_bytes: vector = x"a11ceb0b060000000b010006020608030e26043406053a32076c7d08e9014006a902220acb02050cd002560da6030200000101010200030c00020400000005000100000600010000070201000008030400010907080108010a09010108010b0a0b0108040605060606010708010002070801060c0106080101030107080001080002070801050107090003070801060c090002060801050106090007636f756e7465720f6163636f756e745f73746f7261676507636f6e7465787407436f756e74657207436f6e7465787408696e63726561736509696e6372656173655f04696e69740576616c756511676c6f62616c5f626f72726f775f6d75740e676c6f62616c5f6d6f76655f746f0d676c6f62616c5f626f72726f77000000000000000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000000000000000020520000000000000000000000000000000000000000000000000000000000000004200020108030001040001030b0011010201010000050d0b00070038000c010a01100014060100000000000000160b010f0015020200000001060b000b0106000000000000000012003801020301000001060b000700380210001402000000"; + let m: MoveModule = Self::new(module_bytes); + let modules = vector::singleton(m); + let (module_names, _module_names_with_init_fn) = Self::sort_and_verify_modules(&modules, addr); + debug::print(&module_names); + context::drop_test_context(ctx); + } + + #[test(account=@0x1314)] + fun test_remap_address(account: &signer) { + let addr = signer::address_of(account); + let ctx = context::new_test_context(addr); + // The following is the bytes and hex of the compiled module: example/counter/sources/counter.move + // with account 0x42 + let module_bytes: vector = x"a11ceb0b060000000b010006020608030e26043406053a32076c7d08e9014006a902220acb02050cd002560da6030200000101010200030c00020400000005000100000600010000070201000008030400010907080108010a09010108010b0a0b0108040605060606010708010002070801060c0106080101030107080001080002070801050107090003070801060c090002060801050106090007636f756e7465720f6163636f756e745f73746f7261676507636f6e7465787407436f756e74657207436f6e7465787408696e63726561736509696e6372656173655f04696e69740576616c756511676c6f62616c5f626f72726f775f6d75740e676c6f62616c5f6d6f76655f746f0d676c6f62616c5f626f72726f77000000000000000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000000000000000020520000000000000000000000000000000000000000000000000000000000000004200020108030001040001030b0011010201010000050d0b00070038000c010a01100014060100000000000000160b010f0015020200000001060b000b0106000000000000000012003801020301000001060b000700380210001402000000"; + let m: MoveModule = Self::new(module_bytes); + let modules = vector::singleton(m); + let new_addresses = vector::singleton(addr); + let old_addresses = vector::singleton(@0x42); + let remapped_modules = Self::remap_module_addresses(modules, old_addresses, new_addresses); + // In `sort_and_verify_modules`, addresses of modules are ensured to be the same with signer address + // So if the remapping is failed, the verification will fail + let (module_names, _module_names_with_init_fn) = Self::sort_and_verify_modules(&remapped_modules, addr); + debug::print(&module_names); + context::drop_test_context(ctx); + } + } \ No newline at end of file diff --git a/moveos/moveos-stdlib/src/natives/moveos_stdlib/move_module.rs b/moveos/moveos-stdlib/src/natives/moveos_stdlib/move_module.rs index 44a733af5c..c89fdc7ef2 100644 --- a/moveos/moveos-stdlib/src/natives/moveos_stdlib/move_module.rs +++ b/moveos/moveos-stdlib/src/natives/moveos_stdlib/move_module.rs @@ -3,6 +3,7 @@ use crate::natives::helpers::{make_module_natives, make_native}; use better_any::{Tid, TidAble}; +use itertools::zip_eq; use move_binary_format::{ compatibility::Compatibility, errors::{PartialVMError, PartialVMResult}, @@ -14,6 +15,7 @@ use move_core_types::{ identifier::Identifier, language_storage::ModuleId, resolver::ModuleResolver, + value::MoveValue, vm_status::StatusCode, }; use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; @@ -25,13 +27,14 @@ use move_vm_types::{ }; use moveos_stdlib_builder::dependency_order::sort_by_dependency_order; use smallvec::smallvec; -use std::collections::{BTreeSet, VecDeque}; +use std::collections::{BTreeSet, HashMap, VecDeque}; // ======================================================================================== const E_ADDRESS_NOT_MATCH_WITH_SIGNER: u64 = 1; const E_MODULE_VERIFICATION_ERROR: u64 = 2; const E_MODULE_INCOMPATIBLE: u64 = 3; +const E_LENTH_NOT_MATCH: u64 = 4; /// The native module context. #[derive(Tid)] @@ -265,6 +268,123 @@ fn check_compatibililty_inner( } Ok(NativeResult::ok(cost, smallvec![])) } + +/*************************************************************************************************** + * native fun remap_module_addresses_inner( + * bytes: vector>, + * old_addresses: vector
, + * new_addresses: vector
, + * ): (vector, vector>); + * Native function to remap addresses in module binary where the length of + * `old_addresses` must equal to that of `new_addresses`. + **************************************************************************************************/ +#[derive(Debug, Clone)] +pub struct RemapAddressesGasParameters { + pub base: InternalGas, + pub per_byte: InternalGasPerByte, +} + +fn remap_module_addresses_inner( + gas_params: &RemapAddressesGasParameters, + _context: &mut NativeContext, + _ty_args: Vec, + mut args: VecDeque, +) -> PartialVMResult { + debug_assert!(args.len() == 3, "Wrong number of arguments"); + let mut cost = gas_params.base; + let new_address_vec = pop_arg!(args, Vector); + let old_address_vec = pop_arg!(args, Vector); + let num_addresses = new_address_vec.elem_views().len(); + if num_addresses != old_address_vec.elem_views().len() { + return Ok(NativeResult::err( + cost, + moveos_types::move_std::error::invalid_argument(E_LENTH_NOT_MATCH), + )); + }; + let num_addresses = num_addresses as u64; + let new_addresses = new_address_vec.unpack(&Type::Address, num_addresses)?; + let old_addresses = old_address_vec.unpack(&Type::Address, num_addresses)?; + + let address_mapping: HashMap = + zip_eq(old_addresses, new_addresses) + .map(|(a, b)| { + Ok(( + a.value_as::()?, + b.value_as::()?, + )) + }) + .collect::>()?; + + let mut bundle = vec![]; + for module in pop_arg!(args, Vec) { + let byte_codes = module.value_as::>()?; + cost += gas_params.per_byte * NumBytes::new(byte_codes.len() as u64); + bundle.push(byte_codes); + } + let mut compiled_modules = bundle + .into_iter() + .map(|b| CompiledModule::deserialize(&b)) + .collect::>>()?; + + let mut remapped_bubdles = vec![]; + for m in compiled_modules.iter_mut() { + // TODO: charge gas + module_remap_addresses(m, &address_mapping)?; + let mut binary: Vec = vec![]; + m.serialize(&mut binary).map_err(|e| { + PartialVMError::new(StatusCode::VALUE_SERIALIZATION_ERROR).with_message(e.to_string()) + })?; + let value = Value::vector_u8(binary); + remapped_bubdles.push(value); + } + let output_modules = Vector::pack(&Type::Vector(Box::new(Type::U8)), remapped_bubdles)?; + Ok(NativeResult::ok(cost, smallvec![output_modules])) +} + +fn module_remap_constant_addresses(value: &mut MoveValue, f: &dyn Fn(&mut AccountAddress)) { + match value { + MoveValue::Address(addr) => f(addr), + MoveValue::Vector(vals) => { + vals.iter_mut() + .for_each(|val| module_remap_constant_addresses(val, f)); + } + // TODO: handle constant addresses in Other struct + _ => {} + } +} + +fn module_remap_addresses( + module: &mut CompiledModule, + address_mapping: &HashMap, +) -> PartialVMResult<()> { + // replace addresses in address identifiers. + for addr in module.address_identifiers.iter_mut() { + if let Some(new_addr) = address_mapping.get(addr) { + *addr = *new_addr; + } + } + // replace addresses in constant. + for constant in module.constant_pool.iter_mut() { + let mut constant_value = constant.deserialize_constant().ok_or_else(|| { + PartialVMError::new(StatusCode::VALUE_DESERIALIZATION_ERROR) + .with_message("cannot deserialize constant".to_string()) + })?; + + module_remap_constant_addresses(&mut constant_value, &|addr| { + if let Some(new_addr) = address_mapping.get(addr) { + *addr = *new_addr; + } + }); + + let bytes = constant_value.simple_serialize().ok_or_else(|| { + PartialVMError::new(StatusCode::VALUE_SERIALIZATION_ERROR) + .with_message("cannot serialize constant".to_string()) + })?; + constant.data = bytes; + } + Ok(()) +} + /*************************************************************************************************** * module * @@ -275,6 +395,7 @@ pub struct GasParameters { pub sort_and_verify_modules_inner: VerifyModulesGasParameters, pub request_init_functions: RequestInitFunctionsGasParameters, pub check_compatibililty_inner: CheckCompatibilityInnerGasParameters, + pub remap_module_addresses_inner: RemapAddressesGasParameters, } impl GasParameters { @@ -296,6 +417,10 @@ impl GasParameters { base: 0.into(), per_byte: 0.into(), }, + remap_module_addresses_inner: RemapAddressesGasParameters { + base: 0.into(), + per_byte: 0.into(), + }, } } } @@ -324,6 +449,13 @@ pub fn make_all(gas_params: GasParameters) -> impl Iterator