From 7686df16878108cab7d7486b1612de71fb64ae5e Mon Sep 17 00:00:00 2001 From: Xun Li Date: Fri, 14 Jan 2022 16:58:09 -0800 Subject: [PATCH] Publish one package at a time --- fastx_programmability/adapter/src/adapter.rs | 83 +++++++++---------- fastx_programmability/adapter/src/genesis.rs | 44 +++------- .../adapter/src/unit_tests/adapter_tests.rs | 2 +- .../examples/CombinableObjects.move | 0 .../examples/CustomObjectTemplate.move | 0 .../{framework => }/examples/EconMod.move | 0 .../{framework => }/examples/Hero.move | 0 .../{framework => }/examples/HeroMod.move | 0 .../{framework => }/examples/TrustedCoin.move | 0 fastx_programmability/framework/Move.toml | 4 - .../framework/deps/move-stdlib/Move.toml | 2 +- fastx_programmability/framework/src/lib.rs | 81 +++++++++--------- .../struct_with_key_verification_test.rs | 11 ++- fastx_types/src/coin.rs | 4 +- fastx_types/src/gas_coin.rs | 4 +- fastx_types/src/lib.rs | 10 --- 16 files changed, 106 insertions(+), 139 deletions(-) rename fastx_programmability/{framework => }/examples/CombinableObjects.move (100%) rename fastx_programmability/{framework => }/examples/CustomObjectTemplate.move (100%) rename fastx_programmability/{framework => }/examples/EconMod.move (100%) rename fastx_programmability/{framework => }/examples/Hero.move (100%) rename fastx_programmability/{framework => }/examples/HeroMod.move (100%) rename fastx_programmability/{framework => }/examples/TrustedCoin.move (100%) diff --git a/fastx_programmability/adapter/src/adapter.rs b/fastx_programmability/adapter/src/adapter.rs index a0b82cfd3c2a2..c34f97e3f0508 100644 --- a/fastx_programmability/adapter/src/adapter.rs +++ b/fastx_programmability/adapter/src/adapter.rs @@ -15,7 +15,7 @@ use fastx_types::{ }, object::{Data, MoveObject, Object}, storage::Storage, - FASTX_FRAMEWORK_OBJECT_ID, + FASTX_FRAMEWORK_ADDRESS, }; use fastx_verifier::verifier; use move_binary_format::{ @@ -148,7 +148,7 @@ pub fn publish + ModuleResolver + ModuleResolver>>()?; - let packages = generate_package_info_map(modules, ctx)?; + generate_package_id(&mut modules, ctx)?; // verify and link modules, wrap them in objects, write them to the store - for (_, modules) in packages.into_values() { - for module in modules.iter() { - // It is important to do this before running the FastX verifier, since the fastX - // verifier may assume well-formedness conditions enforced by the Move verifier hold - move_bytecode_verifier::verify_module(module).map_err(|e| { - FastPayError::ModuleVerificationFailure { - error: e.to_string(), - } - })?; - // Run FastX bytecode verifier - verifier::verify_module(module)?; + for module in modules.iter() { + // It is important to do this before running the FastX verifier, since the fastX + // verifier may assume well-formedness conditions enforced by the Move verifier hold + move_bytecode_verifier::verify_module(module).map_err(|e| { + FastPayError::ModuleVerificationFailure { + error: e.to_string(), + } + })?; + // Run FastX bytecode verifier + verifier::verify_module(module)?; - // TODO(https://github.com/MystenLabs/fastnft/issues/69): - // run Move linker using state_view. it currently can only be called through the VM's publish or publish_module_bundle API's, - // but we can't use those because they require module.self_address() == sender, which is not true for FastX modules - } - let package_object = Object::new_package(modules, sender, ctx.digest()); - state_view.write_object(package_object); + // TODO(https://github.com/MystenLabs/fastnft/issues/69): + // run Move linker using state_view. it currently can only be called through the VM's publish or publish_module_bundle API's, + // but we can't use those because they require module.self_address() == sender, which is not true for FastX modules } + let package_object = Object::new_package(modules, sender, ctx.digest()); + state_view.write_object(package_object); Ok(()) } -/// Given a list of `modules`, regonize the packages from them (i.e. modules with the same address), -/// use `ctx` to generate a fresh ID for each of those packages. +/// Given a list of `modules`, use `ctx` to generate a fresh ID for the new packages. +/// If `is_framework` is true, then the modules can have arbitrary user-defined address, +/// otherwise their addresses must be 0. /// Mutate each module's self ID to the appropriate fresh ID and update its module handle tables /// to reflect the new ID's of its dependencies. -/// Returns the mapping from the old package addresses to the new addresses. -/// Note: id and address means the same thing here. -pub fn generate_package_info_map( - modules: Vec, +/// Returns the newly created package ID. +pub fn generate_package_id( + modules: &mut Vec, ctx: &mut TxContext, -) -> Result)>, FastPayError> { +) -> FastPayResult { let mut sub_map = BTreeMap::new(); - let mut packages = BTreeMap::new(); - for module in modules { + let package_id = ctx.fresh_id(); + for module in modules.iter() { let old_module_id = module.self_id(); let old_address = *old_module_id.address(); - let package_info = packages - .entry(old_address) - .or_insert((ctx.fresh_id(), vec![])); - package_info.1.push(module); - let new_module_id = ModuleId::new(package_info.0, old_module_id.name().to_owned()); + if old_address != AccountAddress::ZERO { + return Err(FastPayError::ModulePublishFailure { + error: "Publishing modules with non-zero address is not allowed".to_string(), + }); + } + let new_module_id = ModuleId::new(package_id, old_module_id.name().to_owned()); if sub_map.insert(old_module_id, new_module_id).is_some() { return Err(FastPayError::ModulePublishFailure { error: "Publishing two modules with the same ID".to_string(), @@ -210,13 +209,11 @@ pub fn generate_package_info_map( // Safe to unwrap because we checked for duplicate domain entries above, and range entries are fresh ID's let rewriter = ModuleHandleRewriter::new(sub_map).unwrap(); - for (_, modules) in packages.values_mut() { - for module in modules.iter_mut() { - // rewrite module handles to reflect freshly generated ID's - rewriter.sub_module_ids(module); - } + for module in modules.iter_mut() { + // rewrite module handles to reflect freshly generated ID's + rewriter.sub_module_ids(module); } - Ok(packages) + Ok(()) } type Event = (Vec, u64, TypeTag, Vec); @@ -404,7 +401,7 @@ fn resolve_and_type_check( module, name, type_arguments, - } if address == &FASTX_FRAMEWORK_OBJECT_ID + } if address == &FASTX_FRAMEWORK_ADDRESS && module.as_ident_str() == TX_CONTEXT_MODULE_NAME && name.as_ident_str() == TX_CONTEXT_STRUCT_NAME && type_arguments.is_empty() => {} @@ -412,7 +409,7 @@ fn resolve_and_type_check( return Err(FastPayError::InvalidFunctionSignature { error: format!( "Expected last parameter of function signature to be &mut {}::{}::{}, but found {}", - FASTX_FRAMEWORK_OBJECT_ID, TX_CONTEXT_MODULE_NAME, TX_CONTEXT_STRUCT_NAME, t + FASTX_FRAMEWORK_ADDRESS, TX_CONTEXT_MODULE_NAME, TX_CONTEXT_STRUCT_NAME, t ), }) } @@ -421,7 +418,7 @@ fn resolve_and_type_check( return Err(FastPayError::InvalidFunctionSignature { error: format!( "Expected last parameter of function signature to be &mut {}::{}::{}, but found non-reference_type", - FASTX_FRAMEWORK_OBJECT_ID, TX_CONTEXT_MODULE_NAME, TX_CONTEXT_STRUCT_NAME + FASTX_FRAMEWORK_ADDRESS, TX_CONTEXT_MODULE_NAME, TX_CONTEXT_STRUCT_NAME ), }); } diff --git a/fastx_programmability/adapter/src/genesis.rs b/fastx_programmability/adapter/src/genesis.rs index 79b86e9935c84..7cc4d26c2d8e1 100644 --- a/fastx_programmability/adapter/src/genesis.rs +++ b/fastx_programmability/adapter/src/genesis.rs @@ -1,20 +1,17 @@ // Copyright (c) Mysten Labs // SPDX-License-Identifier: Apache-2.0 -use crate::adapter; -use anyhow::Result; use fastx_framework::{self}; use fastx_types::{ - base_types::{FastPayAddress, TransactionDigest, TxContext}, + base_types::{FastPayAddress, TransactionDigest}, object::Object, - FASTX_FRAMEWORK_ADDRESS, FASTX_FRAMEWORK_OBJECT_ID, MOVE_STDLIB_ADDRESS, MOVE_STDLIB_OBJECT_ID, + FASTX_FRAMEWORK_ADDRESS, MOVE_STDLIB_ADDRESS, }; use move_vm_runtime::native_functions::NativeFunctionTable; use once_cell::sync::Lazy; use std::sync::Mutex; -static GENESIS: Lazy> = - Lazy::new(|| Mutex::new(create_genesis_module_objects().unwrap())); +static GENESIS: Lazy> = Lazy::new(|| Mutex::new(create_genesis_module_objects())); struct Genesis { pub objects: Vec, @@ -27,33 +24,18 @@ pub fn clone_genesis_data() -> (Vec, NativeFunctionTable) { } /// Create and return objects wrapping the genesis modules for fastX -fn create_genesis_module_objects() -> Result { - let mut tx_context = TxContext::new(TransactionDigest::genesis()); - let modules = fastx_framework::get_framework_packages()?; - let packages = adapter::generate_package_info_map(modules, &mut tx_context)?; - let fastx_framework_addr = packages[&FASTX_FRAMEWORK_ADDRESS].0; - let move_stdlib_addr = packages[&MOVE_STDLIB_ADDRESS].0; - if fastx_framework_addr != FASTX_FRAMEWORK_OBJECT_ID { - panic!( - "FastX framework address doesn't match, expecting: {:#X?}", - fastx_framework_addr - ); - } - if move_stdlib_addr != MOVE_STDLIB_OBJECT_ID { - panic!( - "Move stdlib address doesn't match, expecting: {:#X?}", - move_stdlib_addr - ); - } +fn create_genesis_module_objects() -> Genesis { + let fastx_modules = fastx_framework::get_fastx_framework_modules(); + let std_modules = fastx_framework::get_move_stdlib_modules(); let native_functions = - fastx_framework::natives::all_natives(move_stdlib_addr, fastx_framework_addr); + fastx_framework::natives::all_natives(MOVE_STDLIB_ADDRESS, FASTX_FRAMEWORK_ADDRESS); let owner = FastPayAddress::default(); - let objects = packages - .into_values() - .map(|(_, modules)| Object::new_package(modules, owner, TransactionDigest::genesis())) - .collect(); - Ok(Genesis { + let objects = vec![ + Object::new_package(fastx_modules, owner, TransactionDigest::genesis()), + Object::new_package(std_modules, owner, TransactionDigest::genesis()), + ]; + Genesis { objects, native_functions, - }) + } } diff --git a/fastx_programmability/adapter/src/unit_tests/adapter_tests.rs b/fastx_programmability/adapter/src/unit_tests/adapter_tests.rs index 57b1e738936e3..f0f50a7888cac 100644 --- a/fastx_programmability/adapter/src/unit_tests/adapter_tests.rs +++ b/fastx_programmability/adapter/src/unit_tests/adapter_tests.rs @@ -556,7 +556,7 @@ fn test_transfer_and_freeze() { &mut storage, &native_functions, "set_value", - gas_object.clone(), + gas_object, MAX_GAS, vec![obj1], pure_args, diff --git a/fastx_programmability/framework/examples/CombinableObjects.move b/fastx_programmability/examples/CombinableObjects.move similarity index 100% rename from fastx_programmability/framework/examples/CombinableObjects.move rename to fastx_programmability/examples/CombinableObjects.move diff --git a/fastx_programmability/framework/examples/CustomObjectTemplate.move b/fastx_programmability/examples/CustomObjectTemplate.move similarity index 100% rename from fastx_programmability/framework/examples/CustomObjectTemplate.move rename to fastx_programmability/examples/CustomObjectTemplate.move diff --git a/fastx_programmability/framework/examples/EconMod.move b/fastx_programmability/examples/EconMod.move similarity index 100% rename from fastx_programmability/framework/examples/EconMod.move rename to fastx_programmability/examples/EconMod.move diff --git a/fastx_programmability/framework/examples/Hero.move b/fastx_programmability/examples/Hero.move similarity index 100% rename from fastx_programmability/framework/examples/Hero.move rename to fastx_programmability/examples/Hero.move diff --git a/fastx_programmability/framework/examples/HeroMod.move b/fastx_programmability/examples/HeroMod.move similarity index 100% rename from fastx_programmability/framework/examples/HeroMod.move rename to fastx_programmability/examples/HeroMod.move diff --git a/fastx_programmability/framework/examples/TrustedCoin.move b/fastx_programmability/examples/TrustedCoin.move similarity index 100% rename from fastx_programmability/framework/examples/TrustedCoin.move rename to fastx_programmability/examples/TrustedCoin.move diff --git a/fastx_programmability/framework/Move.toml b/fastx_programmability/framework/Move.toml index 28ca5a0efc57e..c106ce6404e7c 100644 --- a/fastx_programmability/framework/Move.toml +++ b/fastx_programmability/framework/Move.toml @@ -9,11 +9,7 @@ MoveStdlib = { local = "deps/move-stdlib" } #MoveStdlib = { git = "https://github.com/diem/diem.git", subdir="language/move-stdlib", rev = "346301f33b3489bb4e486ae6c0aa5e030223b492" } [addresses] -Std = "0x1" FastX = "0x2" -Examples = "0x2" [dev-addresses] -Std = "0x1" FastX = "0x2" -Examples = "0x2" diff --git a/fastx_programmability/framework/deps/move-stdlib/Move.toml b/fastx_programmability/framework/deps/move-stdlib/Move.toml index 7025173394653..0af1c19ac45b9 100644 --- a/fastx_programmability/framework/deps/move-stdlib/Move.toml +++ b/fastx_programmability/framework/deps/move-stdlib/Move.toml @@ -3,7 +3,7 @@ name = "MoveStdlib" version = "1.5.0" [addresses] -Std = "_" +Std = "0x1" [dev-addresses] Std = "0x1" diff --git a/fastx_programmability/framework/src/lib.rs b/fastx_programmability/framework/src/lib.rs index c88a919e587a3..663978417d8b3 100644 --- a/fastx_programmability/framework/src/lib.rs +++ b/fastx_programmability/framework/src/lib.rs @@ -1,12 +1,10 @@ // Copyright (c) Mysten Labs // SPDX-License-Identifier: Apache-2.0 -use anyhow::Result; -use fastx_types::MOVE_STDLIB_ADDRESS; use fastx_verifier::verifier as fastx_bytecode_verifier; use move_binary_format::CompiledModule; -use move_core_types::{ident_str, language_storage::ModuleId}; -use move_package::{compilation::compiled_package::CompiledPackage, BuildConfig}; +use move_core_types::ident_str; +use move_package::BuildConfig; use std::path::PathBuf; pub mod natives; @@ -15,55 +13,51 @@ pub mod natives; #[cfg(test)] const MAX_UNIT_TEST_INSTRUCTIONS: u64 = 100_000; -/// Return all the modules of the fastX framework and its dependencies in topologically -/// sorted dependency order (leaves first). The packages are organized -/// as a map from the address to all modules in that address. -pub fn get_framework_packages() -> Result> { - let include_examples = false; - let verify = true; - get_framework_packages_(include_examples, verify) +pub fn get_fastx_framework_modules() -> Vec { + let modules = build("."); + veirfy_modules(&modules); + modules } -fn get_framework_packages_(include_examples: bool, verify: bool) -> Result> { - // TODO: prune unused deps from Move stdlib instead of using an explicit denylist. - // The manually curated list are modules that do not pass the FastX verifier +pub fn get_move_stdlib_modules() -> Vec { let denylist = vec![ - ModuleId::new(MOVE_STDLIB_ADDRESS, ident_str!("Capability").to_owned()), - ModuleId::new(MOVE_STDLIB_ADDRESS, ident_str!("Event").to_owned()), - ModuleId::new(MOVE_STDLIB_ADDRESS, ident_str!("GUID").to_owned()), + ident_str!("Capability").to_owned(), + ident_str!("Event").to_owned(), + ident_str!("GUID").to_owned(), ]; - let package = build(include_examples)?; - let filtered_modules: Vec = package - .transitive_compiled_modules() - .iter_modules_owned() + let modules: Vec = build("deps/move-stdlib") .into_iter() - .filter(|m| !denylist.contains(&m.self_id())) + .filter(|m| !denylist.contains(&m.self_id().name().to_owned())) .collect(); - if verify { - for m in &filtered_modules { - move_bytecode_verifier::verify_module(m).unwrap(); - fastx_bytecode_verifier::verify_module(m).unwrap(); - // TODO(https://github.com/MystenLabs/fastnft/issues/69): Run Move linker - } + veirfy_modules(&modules); + modules +} + +fn veirfy_modules(modules: &[CompiledModule]) { + for m in modules { + move_bytecode_verifier::verify_module(m).unwrap(); + fastx_bytecode_verifier::verify_module(m).unwrap(); + // TODO(https://github.com/MystenLabs/fastnft/issues/69): Run Move linker } - Ok(filtered_modules) } -/// Include the Move package's `example` modules if `include_examples` is true, omits them otherwise -fn build(include_examples: bool) -> Result { - let framework_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); +fn build(sub_dir: &str) -> Vec { + let mut framework_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + framework_dir.push(sub_dir); let build_config = BuildConfig { - dev_mode: include_examples, + dev_mode: false, ..Default::default() }; - build_config.compile_package(&framework_dir, &mut Vec::new()) + build_config + .compile_package(&framework_dir, &mut Vec::new()) + .unwrap() + .compiled_modules() + .iter_modules_owned() } #[test] -fn check_that_move_code_can_be_built_verified_testsd() { - let include_examples = true; - let verify = true; - get_framework_packages_(include_examples, verify).unwrap(); +fn check_that_move_code_can_be_built_verified_tested() { + get_fastx_framework_modules(); // ideally this would be a separate test, but doing so introduces // races because of https://github.com/diem/diem/issues/10102 run_move_unit_tests(); @@ -71,17 +65,17 @@ fn check_that_move_code_can_be_built_verified_testsd() { #[cfg(test)] fn run_move_unit_tests() { - use fastx_types::FASTX_FRAMEWORK_ADDRESS; - use move_cli::package::cli; + use fastx_types::{FASTX_FRAMEWORK_ADDRESS, MOVE_STDLIB_ADDRESS}; + use move_cli::package::cli::{self, UnitTestResult}; + use move_unit_test::UnitTestingConfig; use std::path::Path; let framework_dir = Path::new(env!("CARGO_MANIFEST_DIR")); - let include_examples = true; - cli::run_move_unit_tests( + let result = cli::run_move_unit_tests( framework_dir, BuildConfig { - dev_mode: include_examples, + dev_mode: false, ..Default::default() }, UnitTestingConfig::default_with_bound(Some(MAX_UNIT_TEST_INSTRUCTIONS)), @@ -89,4 +83,5 @@ fn run_move_unit_tests() { /* compute_coverage */ false, ) .unwrap(); + assert!(result == UnitTestResult::Success); } diff --git a/fastx_programmability/verifier/tests/struct_with_key_verification_test.rs b/fastx_programmability/verifier/tests/struct_with_key_verification_test.rs index 82f129612ad2a..db0c09fb151e1 100644 --- a/fastx_programmability/verifier/tests/struct_with_key_verification_test.rs +++ b/fastx_programmability/verifier/tests/struct_with_key_verification_test.rs @@ -4,6 +4,7 @@ mod common; pub use common::module_builder::ModuleBuilder; +use fastx_types::FASTX_FRAMEWORK_ADDRESS; use fastx_verifier::struct_with_key_verifier::verify_module; use move_binary_format::file_format::*; use move_core_types::account_address::AccountAddress; @@ -110,7 +111,7 @@ fn key_struct_id_field_incorrect_struct_address() { AbilitySet::EMPTY | Ability::Key, vec![("id", SignatureToken::Struct(fake_id_struct.handle))], ); - assert!(verify_module(module.get_module()).unwrap_err().to_string().contains("First field of struct S must be of type 00000000000000000000000000000002::ID::ID, 01010101010101010101010101010101::ID::ID type found")); + assert!(verify_module(module.get_module()).unwrap_err().to_string().contains(&format!("First field of struct S must be of type {}::ID::ID, 01010101010101010101010101010101::ID::ID type found", FASTX_FRAMEWORK_ADDRESS))); } #[test] @@ -128,7 +129,13 @@ fn key_struct_id_field_incorrect_struct_name() { AbilitySet::EMPTY | Ability::Key, vec![("id", SignatureToken::Struct(fake_id_struct.handle))], ); - assert!(verify_module(module.get_module()).unwrap_err().to_string().contains("First field of struct S must be of type 00000000000000000000000000000002::ID::ID, 00000000000000000000000000000002::ID::FOO type found")); + assert!(verify_module(module.get_module()) + .unwrap_err() + .to_string() + .contains(&format!( + "First field of struct S must be of type {0}::ID::ID, {0}::ID::FOO type found", + FASTX_FRAMEWORK_ADDRESS + ))); } #[test] diff --git a/fastx_types/src/coin.rs b/fastx_types/src/coin.rs index 624f01cef86f4..473941f8fc26f 100644 --- a/fastx_types/src/coin.rs +++ b/fastx_types/src/coin.rs @@ -12,7 +12,7 @@ use crate::{ base_types::{ObjectID, SequenceNumber}, gas_coin::{GAS_MODULE_NAME, GAS_STRUCT_NAME}, id::ID, - FASTX_FRAMEWORK_OBJECT_ID, + FASTX_FRAMEWORK_ADDRESS, }; pub const COIN_MODULE_NAME: &IdentStr = ident_str!("Coin"); @@ -32,7 +32,7 @@ impl Coin { pub fn type_(type_param: StructTag) -> StructTag { StructTag { - address: FASTX_FRAMEWORK_OBJECT_ID, + address: FASTX_FRAMEWORK_ADDRESS, name: GAS_STRUCT_NAME.to_owned(), module: GAS_MODULE_NAME.to_owned(), type_params: vec![TypeTag::Struct(type_param)], diff --git a/fastx_types/src/gas_coin.rs b/fastx_types/src/gas_coin.rs index 4e04f78180d09..5a264253663fd 100644 --- a/fastx_types/src/gas_coin.rs +++ b/fastx_types/src/gas_coin.rs @@ -11,7 +11,7 @@ use crate::{ error::{FastPayError, FastPayResult}, id::ID, object::{Data, MoveObject, Object}, - FASTX_FRAMEWORK_OBJECT_ID, + FASTX_FRAMEWORK_ADDRESS, }; pub const GAS_MODULE_NAME: &IdentStr = ident_str!("GAS"); @@ -32,7 +32,7 @@ impl GasCoin { pub fn type_() -> StructTag { Coin::type_(StructTag { - address: FASTX_FRAMEWORK_OBJECT_ID, + address: FASTX_FRAMEWORK_ADDRESS, name: GAS_STRUCT_NAME.to_owned(), module: GAS_MODULE_NAME.to_owned(), type_params: Vec::new(), diff --git a/fastx_types/src/lib.rs b/fastx_types/src/lib.rs index d356a028e46ab..7d29b35e4445d 100644 --- a/fastx_types/src/lib.rs +++ b/fastx_types/src/lib.rs @@ -33,13 +33,3 @@ pub const MOVE_STDLIB_ADDRESS: AccountAddress = AccountAddress::new([ pub const FASTX_FRAMEWORK_ADDRESS: AccountAddress = AccountAddress::new([ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, ]); - -/// 0xFDC6D587C83A348E456B034E1E0C31E9, object ID of the move stdlib package. -pub const MOVE_STDLIB_OBJECT_ID: AccountAddress = AccountAddress::new([ - 0xFD, 0xC6, 0xD5, 0x87, 0xC8, 0x3A, 0x34, 0x8E, 0x45, 0x6B, 0x03, 0x4E, 0x1E, 0x0C, 0x31, 0xE9, -]); - -/// 0x6D3FFC5213ED4DF6802CD4535D3C18F6, object ID of the fastx framework package. -pub const FASTX_FRAMEWORK_OBJECT_ID: AccountAddress = AccountAddress::new([ - 0x6D, 0x3F, 0xFC, 0x52, 0x13, 0xED, 0x4D, 0xF6, 0x80, 0x2C, 0xD4, 0x53, 0x5D, 0x3C, 0x18, 0xF6, -]);