diff --git a/Cargo.lock b/Cargo.lock index f1312fa136..f4f3c04864 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10160,6 +10160,26 @@ dependencies = [ "test-case", ] +[[package]] +name = "starcoin-asset-mapping" +version = "2.0.1" +dependencies = [ + "anyhow", + "bcs-ext", + "forkable-jellyfish-merkle", + "starcoin-cached-packages", + "starcoin-chain", + "starcoin-config", + "starcoin-consensus", + "starcoin-crypto", + "starcoin-logger", + "starcoin-state-api", + "starcoin-transaction-builder", + "starcoin-types", + "starcoin-vm-types", + "test-helper", +] + [[package]] name = "starcoin-block-relayer" version = "2.0.1" @@ -10601,12 +10621,14 @@ version = "2.0.1" dependencies = [ "anyhow", "bcs-ext", + "forkable-jellyfish-merkle", "hex", "log 0.4.22", "move-transactional-test-runner", "once_cell", "serde", "serde_json", + "sha3", "starcoin-abi-resolver", "starcoin-abi-types", "starcoin-config", diff --git a/Cargo.toml b/Cargo.toml index 7b22e373e4..b9c041ffa4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -122,6 +122,7 @@ members = [ "cmd/db-exporter", "cmd/genesis-nft-miner", "flexidag", + "asset-mapping", ] default-members = [ @@ -238,6 +239,7 @@ default-members = [ "cmd/miner_client/api", "cmd/db-exporter", "flexidag", + "asset-mapping", ] [workspace.lints.clippy] @@ -513,6 +515,7 @@ starcoin-account-api = { path = "account/api" } starcoin-account-provider = { path = "account/provider" } starcoin-account-service = { path = "account/service" } starcoin-accumulator = { path = "commons/accumulator", package = "starcoin-accumulator" } +starcoin-asset-mapping = { path = "asset-mapping" } starcoin-block-relayer = { path = "block-relayer" } starcoin-chain = { path = "chain" } starcoin-chain-api = { path = "chain/api" } diff --git a/asset-mapping/Cargo.toml b/asset-mapping/Cargo.toml new file mode 100644 index 0000000000..927efd14a1 --- /dev/null +++ b/asset-mapping/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "starcoin-asset-mapping" +version = "2.0.1" +authors = { workspace = true } +edition = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +publish = { workspace = true } +repository = { workspace = true } +rust-version = { workspace = true } + +[dependencies] +anyhow = { workspace = true } +bcs-ext = { workspace = true } +forkable-jellyfish-merkle = { workspace = true } +starcoin-transaction-builder = { workspace = true } +starcoin-chain = { workspace = true } +starcoin-config = { workspace = true } +starcoin-consensus = { workspace = true } +starcoin-crypto = { workspace = true } +starcoin-cached-packages = { workspace = true } +starcoin-logger = { workspace = true } +starcoin-state-api = { workspace = true } +starcoin-types = { workspace = true } +starcoin-vm-types = { workspace = true } +test-helper = { workspace = true } \ No newline at end of file diff --git a/asset-mapping/src/lib.rs b/asset-mapping/src/lib.rs new file mode 100644 index 0000000000..4cb9704ccf --- /dev/null +++ b/asset-mapping/src/lib.rs @@ -0,0 +1,300 @@ +use std::str::FromStr; +use std::sync::Arc; + +use anyhow::Result; +use starcoin_crypto::{hash::PlainCryptoHash, HashValue}; + +use forkable_jellyfish_merkle::{blob::Blob, node_type::SparseMerkleLeafNode, RawKey}; +use starcoin_cached_packages::starcoin_framework_sdk_builder::asset_mapping_assign_to_account_with_proof; +use starcoin_chain::{BlockChain, ChainReader, ChainWriter}; +use starcoin_config::{ChainNetwork, NodeConfig, G_TEST_CONFIG}; +use starcoin_consensus::Consensus; +use starcoin_state_api::ChainStateReader; +use starcoin_transaction_builder::DEFAULT_MAX_GAS_AMOUNT; +use starcoin_types::account::Account; +use starcoin_types::{ + account::DEFAULT_EXPIRATION_TIME, account_address::AccountAddress, + account_config::CORE_CODE_ADDRESS, identifier::Identifier, language_storage::StructTag, +}; +use starcoin_vm_types::transaction::SignedUserTransaction; +use starcoin_vm_types::{ + access_path::AccessPath, + account_config, + account_config::{genesis_address, stc_type_tag}, + genesis_config::ChainId, + state_store::state_key::StateKey, + state_view::StateReaderExt, +}; +use test_helper::executor::prepare_genesis; + +#[test] +fn test_get_chain_id_after_genesis_with_proof_verify() -> Result<()> { + let (chain_state, _) = prepare_genesis(); + let chain_id_struct_tag = StructTag { + address: CORE_CODE_ADDRESS, + module: Identifier::new("chain_id").unwrap(), + name: Identifier::new("ChainId").unwrap(), + type_args: vec![], + }; + + let path_statekey = StateKey::resource(&CORE_CODE_ADDRESS, &chain_id_struct_tag)?; + + // Print 0x1 version resource + let resource_value = bcs_ext::from_bytes::( + &chain_state.get_resource(CORE_CODE_ADDRESS, &chain_id_struct_tag)?, + )?; + println!( + "test_get_chain_id_after_genesis_with_proof_verify | path: {:?}, state_value : {:?}", + chain_id_struct_tag, resource_value + ); + assert_eq!(resource_value.id(), 0xff, "not expect chain id"); + + // Get proof and verify proof + let mut state_proof = chain_state.get_with_proof(&path_statekey)?; + let proof_path = AccessPath::resource_access_path(genesis_address(), chain_id_struct_tag); + state_proof.verify(chain_state.state_root(), proof_path.clone())?; + + state_proof.state.as_mut().unwrap()[0] = 0xFE; + assert!(state_proof + .verify(chain_state.state_root(), proof_path) + .is_err()); + Ok(()) +} + +#[test] +fn test_sha3_256_diffrent_with_crypto_macro() -> Result<()> { + let element_key_hash = HashValue::from_hex_literal( + "0x4cc8bd9df94b37c233555d9a3bba0a712c3c709f047486d1e624b2bcd3b83266", + )?; + let blob_hash = HashValue::from_hex_literal( + "0x4f2b59b9af93b435e0a33b6ab7a8a90e471dba936be2bc2937629b7782b8ebd0", + )?; + + let leaf_node = SparseMerkleLeafNode::new(element_key_hash, blob_hash); + + let smt_hash = leaf_node.crypto_hash(); + println!( + "test_sha3_256_diffrent_with_crypto_macro | SparseMerkleLeafNode crypto hash: {:?}", + SparseMerkleLeafNode::new(element_key_hash, blob_hash).crypto_hash() + ); + + let ser = bcs_ext::to_bytes(&leaf_node)?; + const STARCOIN_HASH_PREFIX: &[u8] = b"STARCOIN::SparseMerkleLeafNode"; + let hash_vec = [ + HashValue::sha3_256_of(STARCOIN_HASH_PREFIX).as_slice(), + ser.as_slice(), + ] + .concat(); + + let move_hash = HashValue::sha3_256_of(&hash_vec[..]); + println!( + "test_sha3_256_diffrent_with_crypto_macro | sha3 crypto {:?}", + move_hash, + ); + assert_eq!(move_hash, smt_hash, "Failed to get the same hash"); + + let check_blob_hash = Blob::from(Vec::from([255])).crypto_hash(); + assert_eq!( + check_blob_hash, blob_hash, + "Check not equal with crypto_hash from Blob" + ); + + Ok(()) +} + +#[test] +fn test_asset_mapping_for_specified_coin_type() -> Result<()> { + let (_chain_state, _net) = prepare_genesis(); + let stc_store_tag = StructTag { + address: CORE_CODE_ADDRESS, + module: Identifier::new("coin").unwrap(), + name: Identifier::new("CoinStore").unwrap(), + type_args: vec![stc_type_tag()], + }; + + let access_path = AccessPath::resource_access_path(genesis_address(), stc_store_tag); + let (account_address, data_path) = access_path.into_inner(); + + println!( + "test_asset_mapping_for_specified_coin_type | account {:?}, data_path: {:?}, data_path key hash: {:?}", + account_address, + data_path.encode_key()?, + data_path.key_hash() + ); + Ok(()) +} + +#[test] +fn test_asset_mapping_whole_process() -> Result<()> { + starcoin_logger::init_for_test(); + + let block_gas_limit: u64 = 10000000; + let initial_balance: u128 = 100000000000; // 1000 STC + let receiver = AccountAddress::from_str("0xd0c5a06ae6100ce115cad1600fe59e96").unwrap(); + + // Create a source BlockChain + let (proof_root_hash, proof_path_hash, proof_value_hash, proof_siblings) = { + // construct a test network + let config = Arc::new(NodeConfig::random_for_test()); + let mut block_chain = test_helper::gen_blockchain_with_blocks_for_test(0, config.net())?; + + let peer_to_peer_txn = { + local_build_peer_to_peer_from_association( + &block_chain, + receiver, + initial_balance, + config.net(), + )? + }; + local_block_chain_excecute_txn(&mut block_chain, peer_to_peer_txn)?; + + { + let chain_state = block_chain.chain_state_reader(); + + // Check balance is initial_balance + let balance = block_chain.chain_state_reader().get_balance(receiver)?; + assert_eq!(balance, initial_balance); + + let proof = chain_state.get_with_proof(&StateKey::resource( + &CORE_CODE_ADDRESS, + &StructTag { + address: CORE_CODE_ADDRESS, + module: Identifier::new("coin").unwrap(), + name: Identifier::new("CoinStore").unwrap(), + type_args: vec![stc_type_tag()], + }, + )?)?; + ( + chain_state.state_root(), + proof.proof.account_state_proof.leaf.unwrap().0, + proof.proof.account_state_proof.leaf.unwrap().1, + proof.proof.account_state_proof.siblings, + ) + } + }; + + println!( + "test_asset_mapping_whole_process | proof_root_hash: {:?}, proof_path_hash: {:?}, proof_value_hash: {:?}, proof_siblings: {:?}", + proof_root_hash, proof_path_hash, proof_value_hash, proof_siblings, + ); + + // Create a new blockchain and verify proof + { + let custom_chain_id = ChainId::new(100); + let mut genesis_config = G_TEST_CONFIG.clone(); + genesis_config.asset_mapping_root_hash = proof_root_hash; + + let net = ChainNetwork::new_custom( + "asset_mapping_test".parse()?, + custom_chain_id, + genesis_config, + )?; + + let mut block_chain = test_helper::gen_blockchain_with_blocks_for_test(0, &net)?; + + let mut proof_encoded_siblings: Vec = Vec::new(); + proof_siblings.iter().for_each(|hash| { + proof_encoded_siblings.extend_from_slice(hash.as_ref()); + proof_encoded_siblings.push(0x7c); + }); + + let genesis_sequence_number = { + block_chain + .chain_state_reader() + .get_sequence_number(genesis_address())? + }; + + { + // Transfer STC from association account to receiver account + let peer_to_peer_txn = + { local_build_peer_to_peer_from_association(&block_chain, receiver, 1, &net)? }; + local_block_chain_excecute_txn(&mut block_chain, peer_to_peer_txn)?; + } + + { + // Transfer STC from association account to framework account for gas fee + let peer_to_peer_txn = + { local_build_peer_to_peer_from_association(&block_chain, AccountAddress::from_hex_literal("0x1").unwrap(), 1000000000, &net)? }; + local_block_chain_excecute_txn(&mut block_chain, peer_to_peer_txn)?; + } + + // Verify proof and assign asset mapping to receiver account + local_block_chain_excecute_txn( + &mut block_chain, + Account::new_genesis_account(genesis_address()).create_signed_txn_with_args( + asset_mapping_assign_to_account_with_proof( + receiver, + "0x1::STC::STC".as_bytes().to_vec(), + proof_path_hash.to_vec(), + proof_value_hash.to_vec(), + proof_encoded_siblings, + initial_balance as u64, + ), + genesis_sequence_number, + DEFAULT_MAX_GAS_AMOUNT, + 1, + DEFAULT_EXPIRATION_TIME, + net.chain_id(), + ), + )?; + + { + let balance = block_chain.chain_state_reader().get_balance(receiver)?; + println!("The verify blockchain receiver balance is: {:?}", balance); + assert_eq!(balance, initial_balance + 1); + } + } + + Ok(()) +} + +fn local_build_peer_to_peer_from_association( + chain: &BlockChain, + receiver: AccountAddress, + amount: u128, + net: &ChainNetwork, +) -> Result { + let association_sequence_num = { + chain + .chain_state_reader() + .get_sequence_number(account_config::association_address())? + }; + + Ok( + starcoin_transaction_builder::build_transfer_from_association( + receiver, + association_sequence_num, + amount, + net.time_service().now_secs() + DEFAULT_EXPIRATION_TIME, + net, + ) + .try_into()?, + ) +} + +fn local_block_chain_excecute_txn( + chain: &mut BlockChain, + txn: SignedUserTransaction, +) -> Result<()> { + let (block_template, excluded) = chain + .create_block_template( + account_config::association_address(), + None, + vec![txn], + vec![], + Some(DEFAULT_MAX_GAS_AMOUNT), + None, + ) + .unwrap(); + + assert!(excluded.discarded_txns.is_empty(), "Execute txn failed!"); + assert!(excluded.untouched_txns.is_empty(), "Execute txn failed!"); + + let block = chain + .consensus() + .create_block(block_template, chain.time_service().as_ref())?; + + chain.apply(block)?; + + Ok(()) +} diff --git a/config/src/genesis_config.rs b/config/src/genesis_config.rs index d8717d4610..3b9ad4b6cd 100644 --- a/config/src/genesis_config.rs +++ b/config/src/genesis_config.rs @@ -650,6 +650,9 @@ pub struct GenesisConfig { /// Flexidag effective height pub dag_effective_height: u64, + + /// Asset mapping proof root hash + pub asset_mapping_root_hash: HashValue, } impl GenesisConfig { @@ -799,6 +802,7 @@ pub static G_DAG_TEST_CONFIG: Lazy = Lazy::new(|| { }, transaction_timeout: ONE_DAY, dag_effective_height: 0, + asset_mapping_root_hash: HashValue::zero(), } }); @@ -854,6 +858,7 @@ pub static G_TEST_CONFIG: Lazy = Lazy::new(|| { }, transaction_timeout: ONE_DAY, dag_effective_height: u64::MAX, + asset_mapping_root_hash: HashValue::zero(), } }); @@ -912,6 +917,7 @@ pub static G_DEV_CONFIG: Lazy = Lazy::new(|| { }, transaction_timeout: ONE_DAY, dag_effective_height: 0, + asset_mapping_root_hash: HashValue::zero(), } }); @@ -975,6 +981,7 @@ pub static G_HALLEY_CONFIG: Lazy = Lazy::new(|| { }, transaction_timeout: ONE_DAY, dag_effective_height: 0, + asset_mapping_root_hash: HashValue::zero(), } }); @@ -1034,6 +1041,7 @@ pub static G_PROXIMA_CONFIG: Lazy = Lazy::new(|| { }, transaction_timeout: ONE_DAY, dag_effective_height: 0u64, + asset_mapping_root_hash: HashValue::zero(), } }); @@ -1092,6 +1100,7 @@ pub static G_BARNARD_CONFIG: Lazy = Lazy::new(|| { }, transaction_timeout: ONE_DAY, dag_effective_height: u64::MAX, + asset_mapping_root_hash: HashValue::zero(), } }); @@ -1164,6 +1173,8 @@ pub static G_MAIN_CONFIG: Lazy = Lazy::new(|| { }, transaction_timeout: ONE_DAY, dag_effective_height: u64::MAX, + // TODO(BobOng): [asset-mapping] To confirm the asset mapping proof root hash + asset_mapping_root_hash: HashValue::zero(), } }); @@ -1218,6 +1229,7 @@ pub static G_VEGA_CONFIG: Lazy = Lazy::new(|| { }, transaction_timeout: ONE_DAY, dag_effective_height: 0, + asset_mapping_root_hash: HashValue::zero(), } }); diff --git a/executor/Cargo.toml b/executor/Cargo.toml index 524ac0aab1..b236d90b43 100644 --- a/executor/Cargo.toml +++ b/executor/Cargo.toml @@ -34,6 +34,8 @@ stest = { workspace = true } tempfile = { workspace = true } test-helper = { workspace = true } move-transactional-test-runner = { workspace = true } +forkable-jellyfish-merkle = { workspace = true } +sha3 = { workspace = true } [features] default = [] diff --git a/executor/tests/executor_test.rs b/executor/tests/executor_test.rs index cbb07528ae..7214562fb7 100644 --- a/executor/tests/executor_test.rs +++ b/executor/tests/executor_test.rs @@ -1,45 +1,53 @@ // Copyright (c) The Starcoin Core Contributors // SPDX-License-Identifier: Apache-2.0 +use std::hash::Hash; + use anyhow::anyhow; use anyhow::Result; +use starcoin_crypto::{hash::PlainCryptoHash, HashValue}; + +use forkable_jellyfish_merkle::{blob::Blob, node_type::SparseMerkleLeafNode, RawKey}; use starcoin_config::{BuiltinNetworkID, ChainNetwork}; use starcoin_executor::validate_transaction; use starcoin_logger::prelude::*; +use starcoin_state_api::{ChainStateReader, StateReaderExt}; +use starcoin_statedb::ChainStateDB; use starcoin_transaction_builder::{ build_batch_payload_same_amount, build_transfer_txn, encode_transfer_script_by_token_code, raw_peer_to_peer_txn, DEFAULT_EXPIRATION_TIME, DEFAULT_MAX_GAS_AMOUNT, }; use starcoin_types::account::peer_to_peer_txn; +use starcoin_types::account::Account; +use starcoin_types::account_config::G_STC_TOKEN_CODE; use starcoin_types::identifier::Identifier; -use starcoin_types::language_storage::ModuleId; +use starcoin_types::language_storage::{ModuleId, StructTag, TypeTag, CORE_CODE_ADDRESS}; use starcoin_types::transaction::{EntryFunction, RawUserTransaction, TransactionArgument}; use starcoin_types::{ account_config, block_metadata::BlockMetadata, transaction::Transaction, transaction::TransactionPayload, transaction::TransactionStatus, }; +use starcoin_vm_runtime::starcoin_vm::{chunk_block_transactions, StarcoinVM}; +use starcoin_vm_types::access_path::AccessPath; +use starcoin_vm_types::account_config::{core_code_address, ModuleUpgradeStrategy}; use starcoin_vm_types::account_config::genesis_address; use starcoin_vm_types::account_config::AccountResource; use starcoin_vm_types::genesis_config::ChainId; -use starcoin_vm_types::on_chain_config::{ConsensusConfig, OnChainConfig}; +use starcoin_vm_types::state_store::state_key::StateKey; +use starcoin_vm_types::state_store::state_value::StateValue; use starcoin_vm_types::state_store::TStateView; use starcoin_vm_types::token::stc::{stc_type_tag, STCUnit}; use starcoin_vm_types::vm_status::KeptVMStatus; -use starcoin_vm_types::{transaction::Package, vm_status::StatusCode}; +use starcoin_vm_types::{ + on_chain_config::{ConsensusConfig, OnChainConfig}, + transaction::Package, + vm_status::StatusCode, +}; use test_helper::executor::{ account_execute, account_execute_should_success, association_execute_should_success, blockmeta_execute, build_raw_txn, current_block_number, prepare_customized_genesis, TEST_MODULE, TEST_MODULE_1, TEST_MODULE_2, }; - -// use test_helper::Account; -use starcoin_state_api::StateReaderExt; -use starcoin_types::account::Account; -use starcoin_types::account_config::G_STC_TOKEN_CODE; -use starcoin_vm_runtime::starcoin_vm::{chunk_block_transactions, StarcoinVM}; -use starcoin_vm_types::account_config::core_code_address; -use starcoin_vm_types::state_store::state_key::StateKey; -use starcoin_vm_types::state_store::state_value::StateValue; use test_helper::executor::{ compile_modules_with_address, execute_and_apply, get_balance, get_sequence_number, prepare_genesis, @@ -85,7 +93,7 @@ fn test_vm_version() { vec![TransactionArgument::Address(genesis_address())], None, ) - .unwrap(); + .unwrap(); let readed_version: u64 = bcs_ext::from_bytes(&value.pop().unwrap().1).unwrap(); let version = { @@ -113,7 +121,7 @@ fn test_flexidag_config_get() { vec![TransactionArgument::Address(genesis_address())], None, ) - .unwrap(); + .unwrap(); let read_version: u64 = bcs_ext::from_bytes(&value.pop().unwrap().1).unwrap(); let version = { @@ -564,7 +572,7 @@ fn test_validate_txn_args() -> Result<()> { ); account1.sign_txn(txn) } - .unwrap(); + .unwrap(); assert!(validate_transaction(&chain_state, txn, None).is_some()); let txn = { @@ -585,7 +593,7 @@ fn test_validate_txn_args() -> Result<()> { ); account1.sign_txn(txn) } - .unwrap(); + .unwrap(); assert!(validate_transaction(&chain_state, txn, None).is_some()); let txn = { @@ -606,7 +614,7 @@ fn test_validate_txn_args() -> Result<()> { ); account1.sign_txn(txn) } - .unwrap(); + .unwrap(); assert!(validate_transaction(&chain_state, txn, None).is_some()); Ok(()) } @@ -1134,3 +1142,19 @@ fn test_chunk_block_transactions() -> Result<()> { Ok(()) } + +#[test] +fn test_genesis_writeset_for_object() -> Result<()> { + starcoin_logger::init_for_test(); + + let (chain_statedb, _network) = prepare_genesis(); + let state_key = StateKey::resource(&genesis_address(), &StructTag { + address: genesis_address(), + module: Identifier::new("object").unwrap(), + name: Identifier::new("ObjectCore").unwrap(), + type_args: vec![], + })?; + let state = chain_statedb.get_state_value(&state_key)?; + assert!(state.is_some(), "failed to get object"); + Ok(()) +} \ No newline at end of file diff --git a/vm/framework/cached-packages/src/starcoin_framework_sdk_builder.rs b/vm/framework/cached-packages/src/starcoin_framework_sdk_builder.rs index 0cc0595a14..057bf9b81d 100644 --- a/vm/framework/cached-packages/src/starcoin_framework_sdk_builder.rs +++ b/vm/framework/cached-packages/src/starcoin_framework_sdk_builder.rs @@ -150,6 +150,15 @@ pub enum EntryFunctionCall { cap_update_table: Vec, }, + AssetMappingAssignToAccountWithProof { + receiper: AccountAddress, + old_token_str: Vec, + proof_path_hash: Vec, + proof_value_hash: Vec, + proof_siblings: Vec, + amount: u64, + }, + CoinCreateCoinConversionMap {}, /// Create STC pairing by passing `StarcoinCoin`. @@ -518,6 +527,7 @@ pub enum EntryFunctionCall { transaction_timeout: u64, dag_effective_height: u64, features: Vec, + asset_mapping_proof_root: Vec, }, /// Batch transfer token to others. @@ -642,6 +652,21 @@ impl EntryFunctionCall { new_public_key_bytes, cap_update_table, ), + AssetMappingAssignToAccountWithProof { + receiper, + old_token_str, + proof_path_hash, + proof_value_hash, + proof_siblings, + amount, + } => asset_mapping_assign_to_account_with_proof( + receiper, + old_token_str, + proof_path_hash, + proof_value_hash, + proof_siblings, + amount, + ), CoinCreateCoinConversionMap {} => coin_create_coin_conversion_map(), CoinCreatePairing { coin_type } => coin_create_pairing(coin_type), CoinMigrateToFungibleStore { coin_type } => coin_migrate_to_fungible_store(coin_type), @@ -930,6 +955,7 @@ impl EntryFunctionCall { transaction_timeout, dag_effective_height, features, + asset_mapping_proof_root, } => stc_genesis_initialize( stdlib_version, reward_delay, @@ -963,6 +989,7 @@ impl EntryFunctionCall { transaction_timeout, dag_effective_height, features, + asset_mapping_proof_root, ), TransferScriptsBatchPeerToPeer { token_type, @@ -1254,6 +1281,32 @@ pub fn account_rotate_authentication_key_with_rotation_capability( )) } +pub fn asset_mapping_assign_to_account_with_proof( + receiper: AccountAddress, + old_token_str: Vec, + proof_path_hash: Vec, + proof_value_hash: Vec, + proof_siblings: Vec, + amount: u64, +) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]), + ident_str!("asset_mapping").to_owned(), + ), + ident_str!("assign_to_account_with_proof").to_owned(), + vec![], + vec![ + bcs::to_bytes(&receiper).unwrap(), + bcs::to_bytes(&old_token_str).unwrap(), + bcs::to_bytes(&proof_path_hash).unwrap(), + bcs::to_bytes(&proof_value_hash).unwrap(), + bcs::to_bytes(&proof_siblings).unwrap(), + bcs::to_bytes(&amount).unwrap(), + ], + )) +} + pub fn coin_create_coin_conversion_map() -> TransactionPayload { TransactionPayload::EntryFunction(EntryFunction::new( ModuleId::new( @@ -2192,6 +2245,7 @@ pub fn stc_genesis_initialize( transaction_timeout: u64, dag_effective_height: u64, features: Vec, + asset_mapping_proof_root: Vec, ) -> TransactionPayload { TransactionPayload::EntryFunction(EntryFunction::new( ModuleId::new( @@ -2233,6 +2287,7 @@ pub fn stc_genesis_initialize( bcs::to_bytes(&transaction_timeout).unwrap(), bcs::to_bytes(&dag_effective_height).unwrap(), bcs::to_bytes(&features).unwrap(), + bcs::to_bytes(&asset_mapping_proof_root).unwrap(), ], )) } @@ -2521,6 +2576,23 @@ mod decoder { } } + pub fn asset_mapping_assign_to_account_with_proof( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::AssetMappingAssignToAccountWithProof { + receiper: bcs::from_bytes(script.args().get(0)?).ok()?, + old_token_str: bcs::from_bytes(script.args().get(1)?).ok()?, + proof_path_hash: bcs::from_bytes(script.args().get(2)?).ok()?, + proof_value_hash: bcs::from_bytes(script.args().get(3)?).ok()?, + proof_siblings: bcs::from_bytes(script.args().get(4)?).ok()?, + amount: bcs::from_bytes(script.args().get(5)?).ok()?, + }) + } else { + None + } + } + pub fn coin_create_coin_conversion_map( payload: &TransactionPayload, ) -> Option { @@ -3233,6 +3305,7 @@ mod decoder { transaction_timeout: bcs::from_bytes(script.args().get(29)?).ok()?, dag_effective_height: bcs::from_bytes(script.args().get(30)?).ok()?, features: bcs::from_bytes(script.args().get(31)?).ok()?, + asset_mapping_proof_root: bcs::from_bytes(script.args().get(32)?).ok()?, }) } else { None @@ -3407,6 +3480,10 @@ static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy + +# Module `0x1::asset_mapping` + +Asset Mapping Module +This module implements functionality for managing fungible asset mappings in the Starcoin framework. +It provides capabilities for creating stores, managing balances, and assigning assets to accounts +with proof verification. + + +- [Resource `AssetMappingStore`](#0x1_asset_mapping_AssetMappingStore) +- [Resource `AssetMappingStoreT`](#0x1_asset_mapping_AssetMappingStoreT) +- [Resource `AssetMappingPool`](#0x1_asset_mapping_AssetMappingPool) +- [Constants](#@Constants_0) +- [Function `initialize`](#0x1_asset_mapping_initialize) +- [Function `create_store_from_coin`](#0x1_asset_mapping_create_store_from_coin) +- [Function `create_store_for_coin_type`](#0x1_asset_mapping_create_store_for_coin_type) +- [Function `fungible_store_balance`](#0x1_asset_mapping_fungible_store_balance) +- [Function `assign_to_account_with_proof`](#0x1_asset_mapping_assign_to_account_with_proof) +- [Function `assign_to_account`](#0x1_asset_mapping_assign_to_account) +- [Function `calculation_proof`](#0x1_asset_mapping_calculation_proof) + + +
use 0x1::coin;
+use 0x1::debug;
+use 0x1::error;
+use 0x1::fungible_asset;
+use 0x1::object;
+use 0x1::primary_fungible_store;
+use 0x1::signer;
+use 0x1::simple_map;
+use 0x1::starcoin_proof_verifier;
+use 0x1::stc_util;
+use 0x1::string;
+use 0x1::system_addresses;
+
+ + + + + +## Resource `AssetMappingStore` + +AssetMappingStore represents a store for mapped assets +Contains: +- extend_ref: Reference for extending object capabilities +- fungible_store: The actual store holding fungible assets +- fungible_metadata: The type of fungible assets + + +
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]
+struct AssetMappingStore has store, key
+
+ + + +
+Fields + + +
+
+extend_ref: object::ExtendRef +
+
+ +
+
+fungible_store: object::Object<fungible_asset::FungibleStore> +
+
+ +
+
+metadata: object::Object<fungible_asset::Metadata> +
+
+ +
+
+ + +
+ + + +## Resource `AssetMappingStoreT` + + + +
struct AssetMappingStoreT<T> has key
+
+ + + +
+Fields + + +
+
+coin: coin::Coin<T> +
+
+ +
+
+old_path_str: vector<u8> +
+
+ +
+
+ + +
+ + + +## Resource `AssetMappingPool` + +AssetMappingCoinType represents a mapping that from old version token types to now version asset stores +eg. 0x1::STC::STC -> 0x1::starcoin_coin::STC + + +
struct AssetMappingPool has store, key
+
+ + + +
+Fields + + +
+
+proof_root: vector<u8> +
+
+ +
+
+token_mapping: simple_map::SimpleMap<string::String, address> +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const ASSET_MAPPING_OBJECT_SEED: vector<u8> = [97, 115, 115, 101, 116, 45, 109, 97, 112, 112, 105, 110, 103];
+
+ + + + + + + +
const EINVALID_ASSET_MAPPING_POOL: u64 = 104;
+
+ + + + + + + +
const EINVALID_NOT_PROOF: u64 = 103;
+
+ + + + + + + +
const EINVALID_PROOF_ROOT: u64 = 102;
+
+ + + + + +Error code for invalid signer + + +
const EINVALID_SIGNER: u64 = 101;
+
+ + + + + +## Function `initialize` + +Initializes the asset mapping pool +@param framework - The framework signer +@param proof_root - Initial proof root for verification +Verifies the framework signer and creates a new AssetMappingPool + + +
public fun initialize(framework: &signer, proof_root: vector<u8>)
+
+ + + +
+Implementation + + +
public fun initialize(framework: &signer, proof_root: vector<u8>){
+    assert!(
+        signer::address_of(framework) == system_addresses::get_starcoin_framework(),
+        error::unauthenticated(EINVALID_SIGNER)
+    );
+    move_to(framework, AssetMappingPool {
+        token_mapping: simple_map::new(),
+        proof_root,
+    });
+}
+
+ + + +
+ + + +## Function `create_store_from_coin` + +Creates a new store from a coin +@param token_issuer - The token issuer signer +@param coin - The coin to be stored +Requirements: +- Token issuer must be authorized for the given token type +- Converts coin to fungible asset and stores it + + +
public fun create_store_from_coin<T: key>(token_issuer: &signer, old_token_str: vector<u8>, coin: coin::Coin<T>)
+
+ + + +
+Implementation + + +
public fun create_store_from_coin<T: key>(
+    token_issuer: &signer,
+    old_token_str: vector<u8>,
+    coin: coin::Coin<T>
+) acquires AssetMappingPool {
+    debug::print(&string::utf8(b"asset_mapping::create_store_from_coin | entered"));
+
+    let token_issuer_addr = signer::address_of(token_issuer);
+    assert!(
+        token_issuer_addr == stc_util::token_issuer<T>(),
+        error::unauthenticated(EINVALID_SIGNER)
+    );
+
+    debug::print(&string::utf8(b"asset_mapping::create_store_from_coin | coin_to_fungible_asset"));
+
+    let fungible_asset = coin::coin_to_fungible_asset(coin);
+
+    let (
+        metadata,
+        fungible_store,
+        extend_ref
+    ) = create_store_for_coin_type<T>(token_issuer);
+
+    debug::print(&string::utf8(b"asset_mapping::create_store_from_coin | created token store"));
+    debug::print(&fungible_store);
+
+    fungible_asset::deposit(fungible_store, fungible_asset);
+
+    // Add token mapping coin type
+    let asset_coin_type =
+        borrow_global_mut<AssetMappingPool>(system_addresses::get_starcoin_framework());
+
+    let store_constructor_ref = &object::create_object(system_addresses::get_core_resource_address());
+    let store_signer = &object::generate_signer(store_constructor_ref);
+    move_to(store_signer, AssetMappingStore {
+        extend_ref,
+        fungible_store,
+        metadata,
+    });
+
+    simple_map::add(
+        &mut asset_coin_type.token_mapping,
+        string::utf8(old_token_str),
+        object::address_from_constructor_ref(store_constructor_ref),
+    );
+
+    debug::print(&string::utf8(b"asset_mapping::create_store_from_coin | exited"));
+}
+
+ + + +
+ + + +## Function `create_store_for_coin_type` + +Creates a store for a specific token type +@param framework - The framework signer +@returns (metadata, store, extend_ref): +- metadata: Token metadata object +- store: Created fungible store +- extend_ref: Extension reference for the store + + +
fun create_store_for_coin_type<T>(account: &signer): (object::Object<fungible_asset::Metadata>, object::Object<fungible_asset::FungibleStore>, object::ExtendRef)
+
+ + + +
+Implementation + + +
fun create_store_for_coin_type<T>(account: &signer): (Object<Metadata>, Object<FungibleStore>, ExtendRef) {
+    debug::print(&std::string::utf8(b"asset_mapping::create_store_for_type | entered"));
+
+    let metadata = coin::ensure_paired_metadata<T>();
+    let construct_ref = object::create_object_from_account(account);
+
+    let store = fungible_asset::create_store(&construct_ref, metadata);
+
+    // Generate extend reference
+    let extend_ref = object::generate_extend_ref(&construct_ref);
+    debug::print(&std::string::utf8(b"asset_mapping::create_store_for_type | exited"));
+
+    (metadata, store, extend_ref)
+}
+
+ + + +
+ + + +## Function `fungible_store_balance` + +Retrieves the balance for a specific token type +@returns Current balance of the token in the mapping pool + + +
fun fungible_store_balance(old_asset_str: vector<u8>): u64
+
+ + + +
+Implementation + + +
fun fungible_store_balance(old_asset_str: vector<u8>): u64 acquires AssetMappingPool, AssetMappingStore {
+    let pool = borrow_global<AssetMappingPool>(system_addresses::get_starcoin_framework());
+    let store_object_addr = simple_map::borrow(&pool.token_mapping, &string::utf8(old_asset_str));
+    let mapping_store = borrow_global<AssetMappingStore>(*store_object_addr);
+    fungible_asset::balance(mapping_store.fungible_store)
+}
+
+ + + +
+ + + +## Function `assign_to_account_with_proof` + + + +
public entry fun assign_to_account_with_proof(token_issuer: &signer, receiper: address, old_token_str: vector<u8>, proof_path_hash: vector<u8>, proof_value_hash: vector<u8>, proof_siblings: vector<u8>, amount: u64)
+
+ + + +
+Implementation + + +
public entry fun assign_to_account_with_proof(
+    token_issuer: &signer,
+    receiper: address,
+    old_token_str: vector<u8>,
+    proof_path_hash: vector<u8>,
+    proof_value_hash: vector<u8>,
+    proof_siblings: vector<u8>,
+    amount: u64
+) acquires AssetMappingPool, AssetMappingStore {
+    assert!(
+        exists<AssetMappingPool>(system_addresses::get_starcoin_framework()),
+        error::invalid_state(EINVALID_PROOF_ROOT)
+    );
+
+    // Verify that the token type of the request mapping is the passed-in verification type
+    assert!(
+        calculation_proof(proof_path_hash, proof_value_hash, starcoin_proof_verifier::split(proof_siblings)),
+        error::unauthenticated(EINVALID_NOT_PROOF)
+    );
+
+    assign_to_account(token_issuer, receiper, old_token_str, amount);
+}
+
+ + + +
+ + + +## Function `assign_to_account` + +Assigns tokens to a recipient account with proof verification +@param token_issuer - The token issuer signer +@param receiper - Recipient address +@param proove - Proof data for verification +@param amount - Amount of tokens to assign +Requirements: +- Valid proof must be provided +- Sufficient balance must exist + + +
public fun assign_to_account(system_account: &signer, receiver: address, old_token_str: vector<u8>, amount: u64)
+
+ + + +
+Implementation + + +
public fun assign_to_account(
+    system_account: &signer,
+    receiver: address,
+    old_token_str: vector<u8>,
+    amount: u64
+) acquires AssetMappingPool, AssetMappingStore {
+    debug::print(&string::utf8(b"asset_mapping::assign_to_account | entered"));
+
+    let account_addr = signer::address_of(system_account);
+    assert!(
+        system_addresses::is_starcoin_framework_address(account_addr) ||
+            system_addresses::is_core_resource_address(account_addr),
+        EINVALID_SIGNER
+    );
+
+    assert!(
+        exists<AssetMappingPool>(system_addresses::get_starcoin_framework()),
+        error::invalid_state(EINVALID_ASSET_MAPPING_POOL)
+    );
+
+    let coin_type_mapping =
+        borrow_global_mut<AssetMappingPool>(system_addresses::get_starcoin_framework());
+    debug::print(&string::utf8(b"asset_mapping::assign_to_account | coin_type_mapping"));
+    debug::print(&coin_type_mapping.token_mapping);
+
+    let mapping_store_addr = simple_map::borrow(&coin_type_mapping.token_mapping, &string::utf8(old_token_str));
+    debug::print(mapping_store_addr);
+    let mapping_store = borrow_global<AssetMappingStore>(*mapping_store_addr);
+
+    // debug::print(&string::utf8(b"asset_mapping::assign_to_account | metadata"));
+    // debug::print(&fungible_asset::is_frozen(mapping_store.fungible_store));
+
+    debug::print(&string::utf8(b"asset_mapping::assign_to_account | fungible_asset::withdraw"));
+    let mapping_fa = fungible_asset::withdraw(
+        &object::generate_signer_for_extending(&mapping_store.extend_ref),
+        mapping_store.fungible_store,
+        amount
+    );
+    debug::print(&string::utf8(b"asset_mapping::assign_to_account | Getting receiver fungible store: "));
+
+    let target_store =
+        primary_fungible_store::ensure_primary_store_exists(receiver, mapping_store.metadata);
+
+    fungible_asset::deposit(target_store, mapping_fa);
+    debug::print(&string::utf8(b"asset_mapping::assign_to_account | exited"));
+}
+
+ + + +
+ + + +## Function `calculation_proof` + +Computes and verifies the provided proof + + +
fun calculation_proof(proof_path_hash: vector<u8>, blob_hash: vector<u8>, proof_siblings: vector<vector<u8>>): bool
+
+ + + +
+Implementation + + +
fun calculation_proof(
+    proof_path_hash: vector<u8>,
+    blob_hash: vector<u8>,
+    proof_siblings: vector<vector<u8>>
+): bool acquires AssetMappingPool {
+    let expect_proof_root =
+        borrow_global_mut<AssetMappingPool>(system_addresses::get_starcoin_framework()).proof_root;
+    let actual_root = starcoin_proof_verifier::computer_root_hash(
+        proof_path_hash,
+        blob_hash,
+        proof_siblings
+    );
+    expect_proof_root == actual_root
+}
+
+ + + +
+ + +[move-book]: https://starcoin.dev/move/book/SUMMARY diff --git a/vm/framework/starcoin-framework/doc/coin.md b/vm/framework/starcoin-framework/doc/coin.md index 1e289beab4..b142bc52a9 100644 --- a/vm/framework/starcoin-framework/doc/coin.md +++ b/vm/framework/starcoin-framework/doc/coin.md @@ -1201,6 +1201,15 @@ CoinStore is frozen. Coins cannot be deposited or withdrawn + + + + +
const EMETA_DATA_NOT_FOUND: u64 = 30;
+
+ + + The migration process from coin to fungible asset is not enabled yet. @@ -1450,18 +1459,37 @@ Create STC pairing by passing StarcoinCoin. let map = borrow_global_mut<CoinConversionMap>(@starcoin_framework); let type = type_info::type_of<CoinType>(); if (!table::contains(&map.coin_to_fungible_asset_map, type)) { + debug::print( + &std::string::utf8(b"coin::create_and_return_paired_metadata_if_not_exist | map not contain type") + ); let is_stc = is_stc<CoinType>(); assert!(!is_stc || allow_stc_creation, error::invalid_state(EAPT_PAIRING_IS_NOT_ENABLED)); let metadata_object_cref = if (is_stc) { + debug::print( + &std::string::utf8( + b"coin::create_and_return_paired_metadata_if_not_exist | type is stc, create sticky object at 0x1" + ) + ); object::create_sticky_object_at_address(@starcoin_framework, @starcoin_fungible_asset) } else { + debug::print( + &std::string::utf8( + b"coin::create_and_return_paired_metadata_if_not_exist | type is not stc, create new asset sub object" + ) + ); object::create_named_object( &create_signer::create_signer(@starcoin_fungible_asset), *string::bytes(&type_info::type_name<CoinType>()) ) }; + debug::print(&metadata_object_cref); + assert!( + object::is_object(object::address_from_constructor_ref(&metadata_object_cref)), + error::invalid_state(EMETA_DATA_NOT_FOUND) + ); + primary_fungible_store::create_primary_store_enabled_fungible_asset( &metadata_object_cref, option::none(), @@ -1578,9 +1606,15 @@ Conversion from coin to fungible asset
public fun coin_to_fungible_asset<CoinType>(
     coin: Coin<CoinType>
 ): FungibleAsset acquires CoinConversionMap, CoinInfo {
+    debug::print(&string::utf8(b"coin::coin_to_fungible_asset | entered"));
+
     let metadata = ensure_paired_metadata<CoinType>();
     let amount = burn_internal(coin);
-    fungible_asset::mint_internal(metadata, amount)
+
+    let ret = fungible_asset::mint_internal(metadata, amount);
+
+    debug::print(&string::utf8(b"coin::coin_to_fungible_asset | exited"));
+    ret
 }
 
@@ -4678,27 +4712,6 @@ The creator of CoinType must be @starcoin_framework. -Make sure name and symbol are legal length. -Only the creator of CoinType can initialize. - - - - - -
schema InitializeInternalSchema<CoinType> {
-    account: signer;
-    name: vector<u8>;
-    symbol: vector<u8>;
-    let account_addr = signer::address_of(account);
-    let coin_address = type_info::type_of<CoinType>().account_address;
-    aborts_if coin_address != account_addr;
-    aborts_if exists<CoinInfo<CoinType>>(account_addr);
-    aborts_if len(name) > MAX_COIN_NAME_LENGTH;
-    aborts_if len(symbol) > MAX_COIN_SYMBOL_LENGTH;
-}
-
- - diff --git a/vm/framework/starcoin-framework/doc/fungible_asset.md b/vm/framework/starcoin-framework/doc/fungible_asset.md index be6434bb05..e1b42385cd 100644 --- a/vm/framework/starcoin-framework/doc/fungible_asset.md +++ b/vm/framework/starcoin-framework/doc/fungible_asset.md @@ -2593,6 +2593,9 @@ Applications can use this to create multiple stores for isolating fungible asset constructor_ref: &ConstructorRef, metadata: Object<T>, ): Object<FungibleStore> { + debug::print(&string::utf8(b"fungible_asset::create_store | entered")); + debug::print(constructor_ref); + let store_obj = &object::generate_signer(constructor_ref); move_to(store_obj, FungibleStore { metadata: object::convert(metadata), @@ -2610,6 +2613,8 @@ Applications can use this to create multiple stores for isolating fungible asset }); }; + debug::print(&string::utf8(b"fungible_asset::create_store | exited")); + object::object_from_constructor_ref<FungibleStore>(constructor_ref) } @@ -2635,6 +2640,9 @@ Used to delete a store. Requires the store to be completely empty prior to remo
public fun remove_store(delete_ref: &DeleteRef) acquires FungibleStore, FungibleAssetEvents, ConcurrentFungibleBalance {
+    debug::print(&string::utf8(b"fungible_asset::remove_store | entered"));
+    debug::print(delete_ref);
+
     let store = &object::object_from_delete_ref<FungibleStore>(delete_ref);
     let addr = object::object_address(store);
     let FungibleStore { metadata: _, balance, frozen: _ }
@@ -2657,6 +2665,7 @@ Used to delete a store.  Requires the store to be completely empty prior to remo
         event::destroy_handle(withdraw_events);
         event::destroy_handle(frozen_events);
     };
+    debug::print(&string::utf8(b"fungible_asset::remove_store | exited"));
 }
 
@@ -2779,8 +2788,11 @@ Deposit amount of the fungible asset to store.
public fun deposit<T: key>(store: Object<T>, fa: FungibleAsset) acquires FungibleStore, DispatchFunctionStore, ConcurrentFungibleBalance {
+    debug::print(&string::utf8(b"fungible_asset::deposit | entered"));
+    debug::print(&store);
     deposit_sanity_check(store, true);
     deposit_internal(object::object_address(&store), fa);
+    debug::print(&string::utf8(b"fungible_asset::deposit | exited"));
 }
 
@@ -3564,8 +3576,11 @@ Decrease the supply of a fungible asset by burning.
inline fun borrow_store_resource<T: key>(store: &Object<T>): &FungibleStore acquires FungibleStore {
+    // debug::print(&string::utf8(b"fungible_asset::borrow_store_resource | entered"));
     let store_addr = object::object_address(store);
+    debug::print(&store_addr);
     assert!(exists<FungibleStore>(store_addr), error::not_found(EFUNGIBLE_STORE_EXISTENCE));
+    // debug::print(&string::utf8(b"fungible_asset::borrow_store_resource | exited"));
     borrow_global<FungibleStore>(store_addr)
 }
 
diff --git a/vm/framework/starcoin-framework/doc/object.md b/vm/framework/starcoin-framework/doc/object.md index 3a043c2b8c..f62819822b 100644 --- a/vm/framework/starcoin-framework/doc/object.md +++ b/vm/framework/starcoin-framework/doc/object.md @@ -139,6 +139,7 @@ make it so that a reference to a global object can be returned from a function. use 0x1::bcs; use 0x1::bcs_util; use 0x1::create_signer; +use 0x1::debug; use 0x1::error; use 0x1::event; use 0x1::features; @@ -146,6 +147,7 @@ make it so that a reference to a global object can be returned from a function. use 0x1::guid; use 0x1::hash; use 0x1::signer; +use 0x1::string; use 0x1::transaction_context; use 0x1::vector; @@ -1095,11 +1097,9 @@ by knowing the user generated seed used to create them. Named objects cannot be
public fun create_named_object(creator: &signer, seed: vector<u8>): ConstructorRef {
-    // debug::print(&string::utf8(b"object::create_named_object | entered"));
     let creator_address = signer::address_of(creator);
     let obj_addr = create_object_address(&creator_address, seed);
     let ret = create_object_internal(creator_address, obj_addr, false);
-    // debug::print(&string::utf8(b"object::create_named_object | exited"));
     ret
 }
 
@@ -1329,7 +1329,9 @@ doesn't have the same bottlenecks. object: address, can_delete: bool, ): ConstructorRef { - // debug::print(&string::utf8(b"object::create_object_internal | entered")); + debug::print(&string::utf8(b"object::create_object_internal | entered")); + debug::print(&creator_address); + debug::print(&object); assert!(!exists<ObjectCore>(object), error::already_exists(EOBJECT_EXISTS)); @@ -1347,7 +1349,7 @@ doesn't have the same bottlenecks. }, ); - // debug::print(&string::utf8(b"object::create_object_internal | exited")); + debug::print(&string::utf8(b"object::create_object_internal | exited")); ConstructorRef { self: object, can_delete } } diff --git a/vm/framework/starcoin-framework/doc/overview.md b/vm/framework/starcoin-framework/doc/overview.md index 2b57111917..9031493613 100644 --- a/vm/framework/starcoin-framework/doc/overview.md +++ b/vm/framework/starcoin-framework/doc/overview.md @@ -16,6 +16,7 @@ This is the reference documentation of the Starcoin framework. - [`0x1::aggregator`](aggregator.md#0x1_aggregator) - [`0x1::aggregator_factory`](aggregator_factory.md#0x1_aggregator_factory) - [`0x1::aggregator_v2`](aggregator_v2.md#0x1_aggregator_v2) +- [`0x1::asset_mapping`](asset_mapping.md#0x1_asset_mapping) - [`0x1::bcs_util`](bcs_util.md#0x1_bcs_util) - [`0x1::block_reward`](block_reward.md#0x1_block_reward) - [`0x1::block_reward_config`](block_reward_config.md#0x1_block_reward_config) @@ -57,6 +58,9 @@ This is the reference documentation of the Starcoin framework. - [`0x1::ring`](ring.md#0x1_ring) - [`0x1::starcoin_account`](starcoin_account.md#0x1_starcoin_account) - [`0x1::starcoin_coin`](starcoin_coin.md#0x1_starcoin_coin) +- [`0x1::starcoin_proof_bit`](starcoin_proof_bit.md#0x1_starcoin_proof_bit) +- [`0x1::starcoin_proof_structured_hash`](starcoin_proof_structured_hash.md#0x1_starcoin_proof_structured_hash) +- [`0x1::starcoin_proof_verifier`](starcoin_proof.md#0x1_starcoin_proof_verifier) - [`0x1::stc_block`](stc_block.md#0x1_stc_block) - [`0x1::stc_genesis`](stc_genesis.md#0x1_stc_genesis) - [`0x1::stc_language_version`](stc_language_version.md#0x1_stc_language_version) diff --git a/vm/framework/starcoin-framework/doc/primary_fungible_store.md b/vm/framework/starcoin-framework/doc/primary_fungible_store.md index 5043b16dca..347e673d26 100644 --- a/vm/framework/starcoin-framework/doc/primary_fungible_store.md +++ b/vm/framework/starcoin-framework/doc/primary_fungible_store.md @@ -117,6 +117,7 @@ so that users can easily deposit/withdraw/transfer fungible assets. icon_uri: String, project_uri: String, ) { + debug::print(&string::utf8(b"primary_fungible_store::create_primary_store_enabled_fungible_asset | entered")); fungible_asset::add_fungibility( constructor_ref, maximum_supply, @@ -130,6 +131,7 @@ so that users can easily deposit/withdraw/transfer fungible assets. move_to(metadata_obj, DeriveRefPod { metadata_derive_ref: object::generate_derive_ref(constructor_ref), }); + debug::print(&string::utf8(b"primary_fungible_store::create_primary_store_enabled_fungible_asset | exited")); } @@ -158,6 +160,8 @@ Ensure that the primary store object for the given address exists. If it doesn't metadata: Object<T>, ): Object<FungibleStore> acquires DeriveRefPod { debug::print(&string::utf8(b"primary_fungible_store::ensure_primary_store_exists | entered")); + debug::print(&owner); + let store_addr = primary_store_address(owner, metadata); let ret = if (fungible_asset::store_exists(store_addr)) { object::address_to_object(store_addr) @@ -198,13 +202,22 @@ Create a primary store object to hold fungible asset for the given address. debug::print(&metadata); let metadata_addr = object::object_address(&metadata); + debug::print(&string::utf8(b"primary_fungible_store::create_primary_store | 1")); + debug::print(&metadata_addr); + object::address_to_object<Metadata>(metadata_addr); + + debug::print(&string::utf8(b"primary_fungible_store::create_primary_store | 2")); let derive_ref = &borrow_global<DeriveRefPod>(metadata_addr).metadata_derive_ref; let constructor_ref = &object::create_user_derived_object(owner_addr, derive_ref); + + debug::print(&string::utf8(b"primary_fungible_store::create_primary_store | 3")); // Disable ungated transfer as deterministic stores shouldn't be transferrable. let transfer_ref = &object::generate_transfer_ref(constructor_ref); object::disable_ungated_transfer(transfer_ref); + debug::print(&string::utf8(b"primary_fungible_store::create_primary_store | 4")); + let ret = fungible_asset::create_store(constructor_ref, metadata); debug::print(&string::utf8(b"primary_fungible_store::create_primary_store | exited")); debug::print(&ret); diff --git a/vm/framework/starcoin-framework/doc/smt_hash.md b/vm/framework/starcoin-framework/doc/smt_hash.md new file mode 100644 index 0000000000..f9a32f9a65 --- /dev/null +++ b/vm/framework/starcoin-framework/doc/smt_hash.md @@ -0,0 +1,106 @@ + + + +# Module `0x1::smt_hash` + + + +- [Constants](#@Constants_0) +- [Function `size`](#0x1_smt_hash_size) +- [Function `hash`](#0x1_smt_hash_hash) +- [Function `size_zero_bytes`](#0x1_smt_hash_size_zero_bytes) + + +
use 0x1::hash;
+
+ + + + + +## Constants + + + + + + +
const SIZE_ZERO_BYTES: vector<u8> = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+
+ + + + + +## Function `size` + + + +
public fun size(): u64
+
+ + + +
+Implementation + + +
public fun size(): u64 {
+    32
+}
+
+ + + +
+ + + +## Function `hash` + + + +
public fun hash(data: &vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
public fun hash(data: &vector<u8>): vector<u8> {
+    hash::sha3_256(*data)
+}
+
+ + + +
+ + + +## Function `size_zero_bytes` + + + +
public fun size_zero_bytes(): vector<u8>
+
+ + + +
+Implementation + + +
public fun size_zero_bytes(): vector<u8> {
+    SIZE_ZERO_BYTES
+}
+
+ + + +
+ + +[move-book]: https://starcoin.dev/move/book/SUMMARY diff --git a/vm/framework/starcoin-framework/doc/smt_proofs.md b/vm/framework/starcoin-framework/doc/smt_proofs.md new file mode 100644 index 0000000000..c2d8560c49 --- /dev/null +++ b/vm/framework/starcoin-framework/doc/smt_proofs.md @@ -0,0 +1,425 @@ + + + +# Module `0x1::smt_proofs` + + + +- [Constants](#@Constants_0) +- [Function `verify_non_membership_proof_by_key`](#0x1_smt_proofs_verify_non_membership_proof_by_key) +- [Function `verify_non_membership_proof_by_leaf_path`](#0x1_smt_proofs_verify_non_membership_proof_by_leaf_path) +- [Function `verify_membership_proof_by_key_value`](#0x1_smt_proofs_verify_membership_proof_by_key_value) +- [Function `verify_membership_proof`](#0x1_smt_proofs_verify_membership_proof) +- [Function `compute_root_hash_by_leaf`](#0x1_smt_proofs_compute_root_hash_by_leaf) +- [Function `compute_root_hash_new_leaf_included`](#0x1_smt_proofs_compute_root_hash_new_leaf_included) +- [Function `create_membership_proof`](#0x1_smt_proofs_create_membership_proof) +- [Function `create_membership_side_nodes`](#0x1_smt_proofs_create_membership_side_nodes) +- [Function `compute_root_hash`](#0x1_smt_proofs_compute_root_hash) + + +
use 0x1::debug;
+use 0x1::error;
+use 0x1::smt_tree_hasher;
+use 0x1::smt_utils;
+use 0x1::string;
+
+ + + + + +## Constants + + + + + + +
const BIT_RIGHT: bool = true;
+
+ + + + + + + +
const ERROR_COUNT_COMMON_PREFIX: u64 = 102;
+
+ + + + + + + +
const ERROR_KEY_ALREADY_EXISTS_IN_PROOF: u64 = 101;
+
+ + + + + +## Function `verify_non_membership_proof_by_key` + + + +
public fun verify_non_membership_proof_by_key(root_hash: &vector<u8>, non_membership_leaf_data: &vector<u8>, side_nodes: &vector<vector<u8>>, key: &vector<u8>): bool
+
+ + + +
+Implementation + + +
public fun verify_non_membership_proof_by_key(
+    root_hash: &vector<u8>,
+    non_membership_leaf_data: &vector<u8>,
+    side_nodes: &vector<vector<u8>>,
+    key: &vector<u8>
+): bool {
+    let leaf_path = smt_tree_hasher::digest(key);
+    verify_non_membership_proof_by_leaf_path(root_hash, non_membership_leaf_data, side_nodes, &leaf_path)
+}
+
+ + + +
+ + + +## Function `verify_non_membership_proof_by_leaf_path` + + + +
public fun verify_non_membership_proof_by_leaf_path(root_hash: &vector<u8>, non_membership_leaf_data: &vector<u8>, side_nodes: &vector<vector<u8>>, leaf_path: &vector<u8>): bool
+
+ + + +
+Implementation + + +
public fun verify_non_membership_proof_by_leaf_path(
+    root_hash: &vector<u8>,
+    non_membership_leaf_data: &vector<u8>,
+    side_nodes: &vector<vector<u8>>,
+    leaf_path: &vector<u8>
+): bool {
+    let non_membership_leaf_hash = if (vector::length<u8>(non_membership_leaf_data) > 0) {
+        let (non_membership_leaf_path, _) = smt_tree_hasher::parse_leaf(non_membership_leaf_data);
+        assert!(*leaf_path != *&non_membership_leaf_path, error::invalid_state(ERROR_KEY_ALREADY_EXISTS_IN_PROOF));
+        assert!(
+            (smt_utils::count_common_prefix(leaf_path, &non_membership_leaf_path) >= vector::length(side_nodes)),
+            ERROR_COUNT_COMMON_PREFIX
+        );
+        smt_tree_hasher::digest_leaf_data(non_membership_leaf_data)
+    } else {
+        smt_tree_hasher::placeholder()
+    };
+    compute_root_hash(leaf_path, &non_membership_leaf_hash, side_nodes) == *root_hash
+}
+
+ + + +
+ + + +## Function `verify_membership_proof_by_key_value` + + + +
public fun verify_membership_proof_by_key_value(root_hash: &vector<u8>, side_nodes: &vector<vector<u8>>, key: &vector<u8>, value: &vector<u8>, is_raw_value: bool): bool
+
+ + + +
+Implementation + + +
public fun verify_membership_proof_by_key_value(
+    root_hash: &vector<u8>,
+    side_nodes: &vector<vector<u8>>,
+    key: &vector<u8>,
+    value: &vector<u8>,
+    is_raw_value: bool
+): bool {
+    let leaf_path = smt_tree_hasher::digest(key);
+    let leaf_value_hash = if (is_raw_value) {
+        &smt_tree_hasher::digest(value)
+    } else {
+        value
+    };
+    verify_membership_proof(root_hash, side_nodes, &leaf_path, leaf_value_hash)
+}
+
+ + + +
+ + + +## Function `verify_membership_proof` + + + +
public fun verify_membership_proof(expect_root_hash: &vector<u8>, sibling_nodes: &vector<vector<u8>>, leaf_path: &vector<u8>, leaf_value_hash: &vector<u8>): bool
+
+ + + +
+Implementation + + +
public fun verify_membership_proof(
+    expect_root_hash: &vector<u8>,
+    sibling_nodes: &vector<vector<u8>>,
+    leaf_path: &vector<u8>,
+    leaf_value_hash: &vector<u8>
+): bool {
+    debug::print(
+        &string::utf8(b"smt_proofs::verify_membership_proof | entered, leaf path & leaf value hash & sibling_nodes")
+    );
+    debug::print(leaf_path);
+    debug::print(leaf_value_hash);
+    debug::print(sibling_nodes);
+
+    let (leaf_hash, leaf_value) = smt_tree_hasher::digest_leaf(leaf_path, leaf_value_hash);
+    debug::print(
+        &string::utf8(
+            b"smt_proofs::verify_membership_proof | after smt_tree_hasher::digest_leaf, leaf_path & leaf_value: "
+        )
+    );
+    debug::print(&leaf_hash);
+    debug::print(&leaf_value);
+
+    let ret_hash = compute_root_hash(leaf_path, &leaf_hash, sibling_nodes);
+    debug::print(
+        &string::utf8(
+            b"smt_proofs::verify_membership_proof | after Self::compute_root_hash, ret_hash & expect_root_hash: "
+        )
+    );
+    debug::print(&ret_hash);
+    debug::print(expect_root_hash);
+    ret_hash == *expect_root_hash
+}
+
+ + + +
+ + + +## Function `compute_root_hash_by_leaf` + + + +
public fun compute_root_hash_by_leaf(leaf_path: &vector<u8>, leaf_value_hash: &vector<u8>, side_nodes: &vector<vector<u8>>): vector<u8>
+
+ + + +
+Implementation + + +
public fun compute_root_hash_by_leaf(
+    leaf_path: &vector<u8>,
+    leaf_value_hash: &vector<u8>,
+    side_nodes: &vector<vector<u8>>
+): vector<u8> {
+    let (leaf_hash, _) = smt_tree_hasher::digest_leaf(leaf_path, leaf_value_hash);
+    compute_root_hash(leaf_path, &leaf_hash, side_nodes)
+}
+
+ + + +
+ + + +## Function `compute_root_hash_new_leaf_included` + + + +
public fun compute_root_hash_new_leaf_included(leaf_path: &vector<u8>, leaf_value_hash: &vector<u8>, non_membership_leaf_data: &vector<u8>, side_nodes: &vector<vector<u8>>): vector<u8>
+
+ + + +
+Implementation + + +
public fun compute_root_hash_new_leaf_included(
+    leaf_path: &vector<u8>,
+    leaf_value_hash: &vector<u8>,
+    non_membership_leaf_data: &vector<u8>,
+    side_nodes: &vector<vector<u8>>
+): vector<u8> {
+    let (new_side_nodes, leaf_node_hash) = create_membership_side_nodes(
+        leaf_path,
+        leaf_value_hash,
+        non_membership_leaf_data,
+        side_nodes
+    );
+
+    compute_root_hash(leaf_path, &leaf_node_hash, &new_side_nodes)
+}
+
+ + + +
+ + + +## Function `create_membership_proof` + + + +
public fun create_membership_proof(leaf_path: &vector<u8>, leaf_value_hash: &vector<u8>, non_membership_leaf_data: &vector<u8>, side_nodes: &vector<vector<u8>>): (vector<u8>, vector<vector<u8>>)
+
+ + + +
+Implementation + + +
public fun create_membership_proof(
+    leaf_path: &vector<u8>,
+    leaf_value_hash: &vector<u8>,
+    non_membership_leaf_data: &vector<u8>,
+    side_nodes: &vector<vector<u8>>
+): (vector<u8>, vector<vector<u8>>) {
+    let (new_side_nodes, leaf_node_hash) = create_membership_side_nodes(
+        leaf_path,
+        leaf_value_hash,
+        non_membership_leaf_data,
+        side_nodes
+    );
+    let new_root_hash = compute_root_hash(leaf_path, &leaf_node_hash, &new_side_nodes);
+    (new_root_hash, new_side_nodes)
+}
+
+ + + +
+ + + +## Function `create_membership_side_nodes` + + + +
fun create_membership_side_nodes(leaf_path: &vector<u8>, leaf_value_hash: &vector<u8>, non_membership_leaf_data: &vector<u8>, side_nodes: &vector<vector<u8>>): (vector<vector<u8>>, vector<u8>)
+
+ + + +
+Implementation + + +
fun create_membership_side_nodes(
+    leaf_path: &vector<u8>,
+    leaf_value_hash: &vector<u8>,
+    non_membership_leaf_data: &vector<u8>,
+    side_nodes: &vector<vector<u8>>
+): (vector<vector<u8>>, vector<u8>) {
+    let side_nodes_len = vector::length<vector<u8>>(side_nodes);
+    let (new_leaf_hash, _) = smt_tree_hasher::digest_leaf(leaf_path, leaf_value_hash);
+    let new_side_nodes = if (vector::length(non_membership_leaf_data) > 0) {
+        let (non_membership_leaf_path, _) = smt_tree_hasher::parse_leaf(non_membership_leaf_data);
+        assert!(*leaf_path != *&non_membership_leaf_path, error::invalid_state(ERROR_KEY_ALREADY_EXISTS_IN_PROOF));
+
+        let common_prefix_count = smt_utils::count_common_prefix(leaf_path, &non_membership_leaf_path);
+        let old_leaf_hash = smt_tree_hasher::digest_leaf_data(non_membership_leaf_data);
+        let new_side_nodes = vector::empty<vector<u8>>();
+
+        vector::push_back(&mut new_side_nodes, old_leaf_hash);
+        if (common_prefix_count > side_nodes_len) {
+            let place_holder_len = (common_prefix_count - side_nodes_len);
+            // Put placeholders
+            let idx = 0;
+            while (idx < place_holder_len) {
+                vector::push_back(&mut new_side_nodes, smt_tree_hasher::placeholder());
+                idx = idx + 1;
+            };
+        };
+        new_side_nodes
+    } else {
+        vector::empty<vector<u8>>()
+    };
+
+    // Push old siblings into the new siblings array
+    let idx = 0;
+    while (idx < side_nodes_len) {
+        vector::push_back(&mut new_side_nodes, *vector::borrow(side_nodes, idx));
+        idx = idx + 1;
+    };
+    (new_side_nodes, new_leaf_hash)
+}
+
+ + + +
+ + + +## Function `compute_root_hash` + + + +
public fun compute_root_hash(path: &vector<u8>, node_hash: &vector<u8>, side_nodes: &vector<vector<u8>>): vector<u8>
+
+ + + +
+Implementation + + +
public fun compute_root_hash(
+    path: &vector<u8>,
+    node_hash: &vector<u8>,
+    side_nodes: &vector<vector<u8>>
+): vector<u8> {
+    let side_nodes_len = vector::length<vector<u8>>(side_nodes);
+
+    let i = 0;
+    let current_hash = *node_hash;
+    while (i < side_nodes_len) {
+        let bit = smt_utils::get_bit_at_from_msb(path, side_nodes_len - i - 1);
+        let sibling_hash = vector::borrow<vector<u8>>(side_nodes, i);
+        if (bit == BIT_RIGHT) {
+            (current_hash, _) = smt_tree_hasher::digest_node(sibling_hash, ¤t_hash);
+        } else {
+            // left
+            (current_hash, _) = smt_tree_hasher::digest_node(¤t_hash, sibling_hash);
+        };
+        i = i + 1;
+    };
+    current_hash
+}
+
+ + + +
+ + +[move-book]: https://starcoin.dev/move/book/SUMMARY diff --git a/vm/framework/starcoin-framework/doc/smt_tree_hasher.md b/vm/framework/starcoin-framework/doc/smt_tree_hasher.md new file mode 100644 index 0000000000..19968ed255 --- /dev/null +++ b/vm/framework/starcoin-framework/doc/smt_tree_hasher.md @@ -0,0 +1,403 @@ + + + +# Module `0x1::smt_tree_hasher` + + + +- [Constants](#@Constants_0) +- [Function `parse_leaf`](#0x1_smt_tree_hasher_parse_leaf) +- [Function `parse_node`](#0x1_smt_tree_hasher_parse_node) +- [Function `digest_leaf`](#0x1_smt_tree_hasher_digest_leaf) +- [Function `create_leaf_data`](#0x1_smt_tree_hasher_create_leaf_data) +- [Function `digest_leaf_data`](#0x1_smt_tree_hasher_digest_leaf_data) +- [Function `digest_node`](#0x1_smt_tree_hasher_digest_node) +- [Function `path`](#0x1_smt_tree_hasher_path) +- [Function `digest`](#0x1_smt_tree_hasher_digest) +- [Function `path_size`](#0x1_smt_tree_hasher_path_size) +- [Function `path_size_in_bits`](#0x1_smt_tree_hasher_path_size_in_bits) +- [Function `placeholder`](#0x1_smt_tree_hasher_placeholder) + + +
use 0x1::error;
+use 0x1::smt_hash;
+use 0x1::smt_utils;
+
+ + + + + +## Constants + + + + + + +
const ERROR_INVALID_LEAF_DATA: u64 = 102;
+
+ + + + + + + +
const ERROR_INVALID_LEAF_DATA_LENGTH: u64 = 104;
+
+ + + + + + + +
const ERROR_INVALID_NODE_DATA: u64 = 103;
+
+ + + + + + + +
const ERROR_INVALID_NODE_DATA_LENGTH: u64 = 105;
+
+ + + + + + + +
const LEAF_PREFIX: vector<u8> = [0];
+
+ + + + + + + +
const NODE_PREFIX: vector<u8> = [1];
+
+ + + + + +## Function `parse_leaf` + + + +
public fun parse_leaf(data: &vector<u8>): (vector<u8>, vector<u8>)
+
+ + + +
+Implementation + + +
public fun parse_leaf(data: &vector<u8>): (vector<u8>, vector<u8>) {
+    let data_len = vector::length(data);
+
+    let prefix_len = vector::length(&LEAF_PREFIX);
+    assert!(data_len >= prefix_len + path_size(), error::invalid_argument(ERROR_INVALID_LEAF_DATA));
+    assert!(smt_utils::sub_u8_vector(data, 0, prefix_len) == LEAF_PREFIX, error::invalid_argument(ERROR_INVALID_LEAF_DATA));
+
+    let start = 0;
+    let end = prefix_len;
+    _ = start;//let prefix = smt_utils::sub_u8_vector(data, start, end);
+
+    start = end;
+    end = start + path_size();
+    let leaf_node_path = smt_utils::sub_u8_vector(data, start, end);
+
+    start = end;
+    end = vector::length(data);
+    let leaf_node_value = smt_utils::sub_u8_vector(data, start, end);
+    (leaf_node_path, leaf_node_value)
+}
+
+ + + +
+ + + +## Function `parse_node` + + + +
public fun parse_node(data: &vector<u8>): (vector<u8>, vector<u8>)
+
+ + + +
+Implementation + + +
public fun parse_node(data: &vector<u8>): (vector<u8>, vector<u8>) {
+    let data_len = vector::length(data);
+    let prefix_len = vector::length(&NODE_PREFIX);
+    assert!(data_len == prefix_len + path_size() * 2, error::invalid_argument(ERROR_INVALID_NODE_DATA));
+    assert!(smt_utils::sub_u8_vector(data, 0, prefix_len) == NODE_PREFIX, error::invalid_argument(ERROR_INVALID_NODE_DATA));
+
+    let start = 0;
+    let end = prefix_len;
+    _ = start;//let prefix = smt_utils::sub_u8_vector(data, start, end);
+
+    start = end;
+    end = start + path_size();
+    let left_data = smt_utils::sub_u8_vector(data, start, end);
+
+    start = end;
+    end = vector::length(data);
+    let right_data = smt_utils::sub_u8_vector(data, start, end);
+    (left_data, right_data)
+}
+
+ + + +
+ + + +## Function `digest_leaf` + + + +
public fun digest_leaf(path: &vector<u8>, leaf_value: &vector<u8>): (vector<u8>, vector<u8>)
+
+ + + +
+Implementation + + +
public fun digest_leaf(path: &vector<u8>, leaf_value: &vector<u8>): (vector<u8>, vector<u8>) {
+    let value = LEAF_PREFIX;
+    value = smt_utils::concat_u8_vectors(&value, *path);
+    value = smt_utils::concat_u8_vectors(&value, *leaf_value);
+    (smt_hash::hash(&value), value)
+}
+
+ + + +
+ + + +## Function `create_leaf_data` + + + +
public fun create_leaf_data(path: &vector<u8>, leaf_value: &vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
public fun create_leaf_data(path: &vector<u8>, leaf_value: &vector<u8>): vector<u8> {
+    let value = LEAF_PREFIX;
+    value = smt_utils::concat_u8_vectors(&value, *path);
+    value = smt_utils::concat_u8_vectors(&value, *leaf_value);
+    value
+}
+
+ + + +
+ + + +## Function `digest_leaf_data` + + + +
public fun digest_leaf_data(data: &vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
public fun digest_leaf_data(data: &vector<u8>): vector<u8> {
+    let data_len = vector::length(data);
+    let prefix_len = vector::length(&LEAF_PREFIX);
+    assert!(data_len >= prefix_len + path_size(), error::invalid_state(ERROR_INVALID_LEAF_DATA_LENGTH));
+    assert!(smt_utils::sub_u8_vector(data, 0, prefix_len) == LEAF_PREFIX, error::invalid_argument(ERROR_INVALID_LEAF_DATA));
+    smt_hash::hash(data)
+}
+
+ + + +
+ + + +## Function `digest_node` + + + +
public fun digest_node(left_data: &vector<u8>, right_data: &vector<u8>): (vector<u8>, vector<u8>)
+
+ + + +
+Implementation + + +
public fun digest_node(left_data: &vector<u8>, right_data: &vector<u8>): (vector<u8>, vector<u8>) {
+    let node_left_right_data_length = smt_hash::size();
+    assert!(vector::length(left_data) == node_left_right_data_length, error::invalid_state(ERROR_INVALID_NODE_DATA_LENGTH));
+    assert!(vector::length(right_data) == node_left_right_data_length, error::invalid_state(ERROR_INVALID_NODE_DATA_LENGTH));
+
+    let value = NODE_PREFIX;
+    value = smt_utils::concat_u8_vectors(&value, *left_data);
+    value = smt_utils::concat_u8_vectors(&value, *right_data);
+    (smt_hash::hash(&value), value)
+}
+
+ + + +
+ + + +## Function `path` + + + +
public fun path(key: &vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
public fun path(key: &vector<u8>): vector<u8> {
+    digest(key)
+}
+
+ + + +
+ + + +## Function `digest` + + + +
public fun digest(data: &vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
public fun digest(data: &vector<u8>): vector<u8> {
+    smt_hash::hash(data)
+}
+
+ + + +
+ + + +## Function `path_size` + + + +
public fun path_size(): u64
+
+ + + +
+Implementation + + +
public fun path_size(): u64 {
+    smt_hash::size()
+}
+
+ + + +
+ + + +## Function `path_size_in_bits` + + + +
public fun path_size_in_bits(): u64
+
+ + + +
+Implementation + + +
public fun path_size_in_bits(): u64 {
+    smt_hash::size() * 8
+}
+
+ + + +
+ + + +## Function `placeholder` + + + +
public fun placeholder(): vector<u8>
+
+ + + +
+Implementation + + +
public fun placeholder(): vector<u8> {
+    smt_hash::size_zero_bytes()
+}
+
+ + + +
+ + +[move-book]: https://starcoin.dev/move/book/SUMMARY diff --git a/vm/framework/starcoin-framework/doc/smt_utils.md b/vm/framework/starcoin-framework/doc/smt_utils.md new file mode 100644 index 0000000000..0b79e070c0 --- /dev/null +++ b/vm/framework/starcoin-framework/doc/smt_utils.md @@ -0,0 +1,388 @@ + + + +# Module `0x1::smt_utils` + + + +- [Constants](#@Constants_0) +- [Function `get_bit_at_from_msb`](#0x1_smt_utils_get_bit_at_from_msb) +- [Function `count_common_prefix`](#0x1_smt_utils_count_common_prefix) +- [Function `count_vector_common_prefix`](#0x1_smt_utils_count_vector_common_prefix) +- [Function `bits_to_bool_vector_from_msb`](#0x1_smt_utils_bits_to_bool_vector_from_msb) +- [Function `concat_u8_vectors`](#0x1_smt_utils_concat_u8_vectors) +- [Function `sub_u8_vector`](#0x1_smt_utils_sub_u8_vector) +- [Function `sub_vector`](#0x1_smt_utils_sub_vector) +- [Function `path_bits_to_bool_vector_from_msb`](#0x1_smt_utils_path_bits_to_bool_vector_from_msb) +- [Function `split_side_nodes_data`](#0x1_smt_utils_split_side_nodes_data) + + +
use 0x1::error;
+use 0x1::smt_hash;
+use 0x1::vector;
+
+ + + + + +## Constants + + + + + + +
const BIT_LEFT: bool = false;
+
+ + + + + + + +
const BIT_RIGHT: bool = true;
+
+ + + + + + + +
const ERROR_INVALID_NODES_DATA_PACKAGE_LENGTH: u64 = 103;
+
+ + + + + + + +
const ERROR_INVALID_PATH_BITS_LENGTH: u64 = 102;
+
+ + + + + + + +
const ERROR_INVALID_PATH_BYTES_LENGTH: u64 = 101;
+
+ + + + + + + +
const ERROR_VECTORS_NOT_SAME_LENGTH: u64 = 103;
+
+ + + + + +## Function `get_bit_at_from_msb` + + + +
public fun get_bit_at_from_msb(data: &vector<u8>, position: u64): bool
+
+ + + +
+Implementation + + +
public fun get_bit_at_from_msb(data: &vector<u8>, position: u64): bool {
+    let byte = (*vector::borrow<u8>(data, position / 8) as u64);
+    // let bit = BitOperators::rshift(byte, ((7 - (position % 8)) as u8));
+    let bit = byte >> ((7 - (position % 8)) as u8);
+    if (bit & 1 != 0) {
+        BIT_RIGHT
+    } else {
+        BIT_LEFT
+    }
+}
+
+ + + +
+ + + +## Function `count_common_prefix` + + + +
public fun count_common_prefix(data1: &vector<u8>, data2: &vector<u8>): u64
+
+ + + +
+Implementation + + +
public fun count_common_prefix(data1: &vector<u8>, data2: &vector<u8>): u64 {
+    let count = 0;
+    let i = 0;
+    while (i < vector::length(data1) * 8) {
+        if (get_bit_at_from_msb(data1, i) == get_bit_at_from_msb(data2, i)) {
+            count = count + 1;
+        } else {
+            break
+        };
+        i = i + 1;
+    };
+    count
+}
+
+ + + +
+ + + +## Function `count_vector_common_prefix` + + + +
public fun count_vector_common_prefix<ElementT: copy, drop>(vec1: &vector<ElementT>, vec2: &vector<ElementT>): u64
+
+ + + +
+Implementation + + +
public fun count_vector_common_prefix<ElementT: copy + drop>(
+    vec1: &vector<ElementT>,
+    vec2: &vector<ElementT>
+): u64 {
+    let vec_len = vector::length<ElementT>(vec1);
+    assert!(vec_len == vector::length<ElementT>(vec2), error::invalid_state(ERROR_VECTORS_NOT_SAME_LENGTH));
+    let idx = 0;
+    while (idx < vec_len) {
+        if (*vector::borrow(vec1, idx) != *vector::borrow(vec2, idx)) {
+            break
+        };
+        idx = idx + 1;
+    };
+    idx
+}
+
+ + + +
+ + + +## Function `bits_to_bool_vector_from_msb` + + + +
public fun bits_to_bool_vector_from_msb(data: &vector<u8>): vector<bool>
+
+ + + +
+Implementation + + +
public fun bits_to_bool_vector_from_msb(data: &vector<u8>): vector<bool> {
+    let i = 0;
+    let vec = vector::empty<bool>();
+    while (i < vector::length(data) * 8) {
+        vector::push_back<bool>(&mut vec, get_bit_at_from_msb(data, i));
+        i = i + 1;
+    };
+    vec
+}
+
+ + + +
+ + + +## Function `concat_u8_vectors` + + + +
public fun concat_u8_vectors(v1: &vector<u8>, v2: vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
public fun concat_u8_vectors(v1: &vector<u8>, v2: vector<u8>): vector<u8> {
+    let data = *v1;
+    vector::append(&mut data, v2);
+    data
+}
+
+ + + +
+ + + +## Function `sub_u8_vector` + + + +
public fun sub_u8_vector(vec: &vector<u8>, start: u64, end: u64): vector<u8>
+
+ + + +
+Implementation + + +
public fun sub_u8_vector(vec: &vector<u8>, start: u64, end: u64): vector<u8> {
+    let i = start;
+    let result = vector::empty<u8>();
+    let data_len = vector::length(vec);
+    let actual_end = if (end < data_len) {
+        end
+    } else {
+        data_len
+    };
+    while (i < actual_end) {
+        vector::push_back(&mut result, *vector::borrow(vec, i));
+        i = i + 1;
+    };
+    result
+}
+
+ + + +
+ + + +## Function `sub_vector` + + + +
public fun sub_vector<ElementT: copy>(vec: &vector<ElementT>, start: u64, end: u64): vector<ElementT>
+
+ + + +
+Implementation + + +
public fun sub_vector<ElementT: copy>(vec: &vector<ElementT>, start: u64, end: u64): vector<ElementT> {
+    let i = start;
+    let result = vector::empty<ElementT>();
+    let data_len = vector::length(vec);
+    let actual_end = if (end < data_len) {
+        end
+    } else {
+        data_len
+    };
+    while (i < actual_end) {
+        vector::push_back(&mut result, *vector::borrow(vec, i));
+        i = i + 1;
+    };
+    result
+}
+
+ + + +
+ + + +## Function `path_bits_to_bool_vector_from_msb` + + + +
public fun path_bits_to_bool_vector_from_msb(path: &vector<u8>): vector<bool>
+
+ + + +
+Implementation + + +
public fun path_bits_to_bool_vector_from_msb(path: &vector<u8>): vector<bool> {
+    let path_len = vector::length<u8>(path);
+    assert!(path_len == smt_hash::size(), error::invalid_argument(ERROR_INVALID_PATH_BYTES_LENGTH));
+    let result_vec = bits_to_bool_vector_from_msb(path);
+    assert!(
+        vector::length<bool>(&result_vec) == smt_hash::size() * 8,// smt_tree_hasher::path_size_in_bits(),
+        error::invalid_state(ERROR_INVALID_PATH_BITS_LENGTH)
+    );
+    result_vec
+}
+
+ + + +
+ + + +## Function `split_side_nodes_data` + + + +
public fun split_side_nodes_data(side_nodes_data: &vector<u8>): vector<vector<u8>>
+
+ + + +
+Implementation + + +
public fun split_side_nodes_data(side_nodes_data: &vector<u8>): vector<vector<u8>> {
+    let node_data_length = smt_hash::size();
+    let len = vector::length(side_nodes_data);
+    assert!(len % node_data_length == 0, error::invalid_state(ERROR_INVALID_NODES_DATA_PACKAGE_LENGTH));
+
+    if (len > 0) {
+        let result = vector::empty<vector<u8>>();
+        let size = len / node_data_length;
+        let idx = 0;
+        while (idx < size) {
+            let start = idx * node_data_length;
+            let end = start + node_data_length;
+            vector::push_back(&mut result, sub_u8_vector(side_nodes_data, start, end));
+            idx = idx + 1;
+        };
+        result
+    } else {
+        vector::empty<vector<u8>>()
+    }
+}
+
+ + + +
+ + +[move-book]: https://starcoin.dev/move/book/SUMMARY diff --git a/vm/framework/starcoin-framework/doc/starcoin_account.md b/vm/framework/starcoin-framework/doc/starcoin_account.md index a8bd45c9de..66ead12446 100644 --- a/vm/framework/starcoin-framework/doc/starcoin_account.md +++ b/vm/framework/starcoin-framework/doc/starcoin_account.md @@ -693,7 +693,12 @@ Ensure that APT Primary FungibleStore exists (and create if it doesn't) if (fungible_asset::store_exists(store_addr)) { store_addr } else { - object::object_address(&primary_fungible_store::create_primary_store(owner, object::address_to_object<Metadata>(@starcoin_fungible_asset))) + object::object_address( + &primary_fungible_store::create_primary_store( + owner, + object::address_to_object<Metadata>(@starcoin_fungible_asset) + ) + ) } } diff --git a/vm/framework/starcoin-framework/doc/starcoin_proof.md b/vm/framework/starcoin-framework/doc/starcoin_proof.md new file mode 100644 index 0000000000..7b786843e3 --- /dev/null +++ b/vm/framework/starcoin-framework/doc/starcoin_proof.md @@ -0,0 +1,328 @@ + + + +# Module `0x1::starcoin_proof_verifier` + + + +- [Resource `StarcoinMerkle`](#0x1_starcoin_proof_verifier_StarcoinMerkle) +- [Struct `Node`](#0x1_starcoin_proof_verifier_Node) +- [Constants](#@Constants_0) +- [Function `create`](#0x1_starcoin_proof_verifier_create) +- [Function `verify_on`](#0x1_starcoin_proof_verifier_verify_on) +- [Function `verify`](#0x1_starcoin_proof_verifier_verify) +- [Function `computer_root_hash`](#0x1_starcoin_proof_verifier_computer_root_hash) +- [Function `splite_symbol`](#0x1_starcoin_proof_verifier_splite_symbol) +- [Function `split`](#0x1_starcoin_proof_verifier_split) + + +
use 0x1::hash;
+use 0x1::starcoin_proof_bit;
+use 0x1::starcoin_proof_structured_hash;
+use 0x1::vector;
+
+ + + + + +## Resource `StarcoinMerkle` + + + +
struct StarcoinMerkle has key
+
+ + + +
+Fields + + +
+
+merkle_root: vector<u8> +
+
+ +
+
+ + +
+ + + +## Struct `Node` + + + +
struct Node has drop, store
+
+ + + +
+Fields + + +
+
+hash1: vector<u8> +
+
+ +
+
+hash2: vector<u8> +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const DELMITER: u8 = 124;
+
+ + + + + + + +
const HASH_LEN_IN_BIT: u64 = 256;
+
+ + + + + + + +
const SPARSE_MERKLE_INTERNAL_NODE: vector<u8> = [83, 112, 97, 114, 115, 101, 77, 101, 114, 107, 108, 101, 73, 110, 116, 101, 114, 110, 97, 108, 78, 111, 100, 101];
+
+ + + + + + + +
const SPARSE_MERKLE_LEAF_NODE: vector<u8> = [83, 112, 97, 114, 115, 101, 77, 101, 114, 107, 108, 101, 76, 101, 97, 102, 78, 111, 100, 101];
+
+ + + + + +## Function `create` + + + +
public fun create(signer: &signer, merkle_root: vector<u8>)
+
+ + + +
+Implementation + + +
public fun create(signer: &signer, merkle_root: vector<u8>) {
+    let s = StarcoinMerkle {
+        merkle_root
+    };
+    move_to(signer, s);
+}
+
+ + + +
+ + + +## Function `verify_on` + + + +
public fun verify_on(merkle_address: address, account_address: vector<u8>, account_state_root_hash: vector<u8>, proofs: vector<vector<u8>>): bool
+
+ + + +
+Implementation + + +
public fun verify_on(
+    merkle_address: address,
+    account_address: vector<u8>,
+    account_state_root_hash: vector<u8>,
+    proofs: vector<vector<u8>>
+): bool
+acquires StarcoinMerkle {
+    let merkle = borrow_global<StarcoinMerkle>(merkle_address);
+    verify(*&merkle.merkle_root, account_address, account_state_root_hash, proofs)
+}
+
+ + + +
+ + + +## Function `verify` + + + +
public fun verify(expected_root: vector<u8>, account_address: vector<u8>, account_state_root_hash: vector<u8>, proofs: vector<vector<u8>>): bool
+
+ + + +
+Implementation + + +
public fun verify(
+    expected_root: vector<u8>,
+    account_address: vector<u8>,
+    account_state_root_hash: vector<u8>,
+    proofs: vector<vector<u8>>
+): bool {
+    Self::computer_root_hash(hash::sha3_256(account_address), account_state_root_hash, proofs) == expected_root
+}
+
+ + + +
+ + + +## Function `computer_root_hash` + + + +
public fun computer_root_hash(element_key: vector<u8>, element_blob_hash: vector<u8>, proofs: vector<vector<u8>>): vector<u8>
+
+ + + +
+Implementation + + +
public fun computer_root_hash(
+    element_key: vector<u8>,
+    element_blob_hash: vector<u8>,
+    proofs: vector<vector<u8>>
+): vector<u8> {
+    let leaf_node = Node { hash1: element_key, hash2: element_blob_hash };
+    let current_hash = starcoin_proof_structured_hash::hash(SPARSE_MERKLE_LEAF_NODE, &leaf_node);
+    let i = 0;
+    let proof_length = vector::length(&proofs);
+    while (i < proof_length) {
+        let sibling = *vector::borrow(&proofs, i);
+        let bit = starcoin_proof_bit::get_bit(&element_key, proof_length - i - 1);
+        let internal_node = if (bit) {
+            Node { hash1: sibling, hash2: current_hash }
+        } else {
+            Node { hash1: current_hash, hash2: sibling }
+        };
+        current_hash = starcoin_proof_structured_hash::hash(SPARSE_MERKLE_INTERNAL_NODE, &internal_node);
+        i = i + 1;
+    };
+    current_hash
+}
+
+ + + +
+ + + +## Function `splite_symbol` + + + +
public fun splite_symbol(): u8
+
+ + + +
+Implementation + + +
public fun splite_symbol(): u8 {
+    DELMITER
+}
+
+ + + +
+ + + +## Function `split` + + + +
public fun split(input: vector<u8>): vector<vector<u8>>
+
+ + + +
+Implementation + + +
public fun split(input: vector<u8>): vector<vector<u8>> {
+    let result: vector<vector<u8>> = vector::empty();
+    let current_segment = vector::empty<u8>();
+    let i = 0;
+    let len = vector::length(&input);
+
+    while (i < len) {
+        let current_byte = *vector::borrow(&input, i);
+        if (current_byte == DELMITER) {
+            if (!vector::is_empty(¤t_segment)) {
+                vector::push_back(&mut result, current_segment);
+                current_segment = vector::empty();
+            };
+        } else {
+            vector::push_back(&mut current_segment, current_byte);
+        };
+        i = i + 1;
+    };
+
+    if (!vector::is_empty(¤t_segment)) {
+        vector::push_back(&mut result, current_segment);
+    };
+    result
+}
+
+ + + +
+ + +[move-book]: https://starcoin.dev/move/book/SUMMARY diff --git a/vm/framework/starcoin-framework/doc/starcoin_proof_bit.md b/vm/framework/starcoin-framework/doc/starcoin_proof_bit.md new file mode 100644 index 0000000000..e27a83cf8a --- /dev/null +++ b/vm/framework/starcoin-framework/doc/starcoin_proof_bit.md @@ -0,0 +1,42 @@ + + + +# Module `0x1::starcoin_proof_bit` + + + +- [Function `get_bit`](#0x1_starcoin_proof_bit_get_bit) + + +
+ + + + + +## Function `get_bit` + + + +
public fun get_bit(data: &vector<u8>, index: u64): bool
+
+ + + +
+Implementation + + +
public fun get_bit(data: &vector<u8>, index: u64): bool {
+    let pos = index / 8;
+    let bit = (7 - index % 8);
+    (*vector::borrow(data, pos) >> (bit as u8)) & 1u8 != 0
+}
+
+ + + +
+ + +[move-book]: https://starcoin.dev/move/book/SUMMARY diff --git a/vm/framework/starcoin-framework/doc/starcoin_proof_structured_hash.md b/vm/framework/starcoin-framework/doc/starcoin_proof_structured_hash.md new file mode 100644 index 0000000000..3698755a39 --- /dev/null +++ b/vm/framework/starcoin-framework/doc/starcoin_proof_structured_hash.md @@ -0,0 +1,87 @@ + + + +# Module `0x1::starcoin_proof_structured_hash` + + + +- [Constants](#@Constants_0) +- [Function `hash`](#0x1_starcoin_proof_structured_hash_hash) +- [Function `concat`](#0x1_starcoin_proof_structured_hash_concat) + + +
use 0x1::bcs;
+use 0x1::hash;
+use 0x1::vector;
+
+ + + + + +## Constants + + + + + + +
const STARCOIN_HASH_PREFIX: vector<u8> = [83, 84, 65, 82, 67, 79, 73, 78, 58, 58];
+
+ + + + + +## Function `hash` + + + +
public fun hash<MoveValue: store>(structure: vector<u8>, data: &MoveValue): vector<u8>
+
+ + + +
+Implementation + + +
public fun hash<MoveValue: store>(structure: vector<u8>, data: &MoveValue): vector<u8> {
+    let prefix_hash = hash::sha3_256(concat(&STARCOIN_HASH_PREFIX, structure));
+    let bcs_bytes = bcs::to_bytes(data);
+    hash::sha3_256(concat(&prefix_hash, bcs_bytes))
+}
+
+ + + +
+ + + +## Function `concat` + + + +
fun concat(v1: &vector<u8>, v2: vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
fun concat(v1: &vector<u8>, v2: vector<u8>): vector<u8> {
+    let data = *v1;
+    vector::append(&mut data, v2);
+    data
+}
+
+ + + +
+ + +[move-book]: https://starcoin.dev/move/book/SUMMARY diff --git a/vm/framework/starcoin-framework/doc/stc_genesis.md b/vm/framework/starcoin-framework/doc/stc_genesis.md index 84c6362784..4f284ca618 100644 --- a/vm/framework/starcoin-framework/doc/stc_genesis.md +++ b/vm/framework/starcoin-framework/doc/stc_genesis.md @@ -16,6 +16,7 @@ The module for init Genesis
use 0x1::account;
 use 0x1::aggregator_factory;
+use 0x1::asset_mapping;
 use 0x1::block_reward;
 use 0x1::block_reward_config;
 use 0x1::chain_id;
@@ -59,7 +60,7 @@ The module for init Genesis
 
 
 
-
public entry fun initialize(stdlib_version: u64, reward_delay: u64, total_stc_amount: u128, pre_mine_stc_amount: u128, time_mint_stc_amount: u128, time_mint_stc_period: u64, parent_hash: vector<u8>, association_auth_key: vector<u8>, genesis_auth_key: vector<u8>, chain_id: u8, _genesis_timestamp: u64, uncle_rate_target: u64, epoch_block_count: u64, base_block_time_target: u64, base_block_difficulty_window: u64, base_reward_per_block: u128, base_reward_per_uncle_percent: u64, min_block_time_target: u64, max_block_time_target: u64, base_max_uncles_per_block: u64, base_block_gas_limit: u64, strategy: u8, script_allowed: bool, module_publishing_allowed: bool, gas_schedule_blob: vector<u8>, voting_delay: u64, voting_period: u64, voting_quorum_rate: u8, min_action_delay: u64, transaction_timeout: u64, dag_effective_height: u64, features: vector<u8>)
+
public entry fun initialize(stdlib_version: u64, reward_delay: u64, total_stc_amount: u128, pre_mine_stc_amount: u128, time_mint_stc_amount: u128, time_mint_stc_period: u64, parent_hash: vector<u8>, association_auth_key: vector<u8>, genesis_auth_key: vector<u8>, chain_id: u8, _genesis_timestamp: u64, uncle_rate_target: u64, epoch_block_count: u64, base_block_time_target: u64, base_block_difficulty_window: u64, base_reward_per_block: u128, base_reward_per_uncle_percent: u64, min_block_time_target: u64, max_block_time_target: u64, base_max_uncles_per_block: u64, base_block_gas_limit: u64, strategy: u8, script_allowed: bool, module_publishing_allowed: bool, gas_schedule_blob: vector<u8>, voting_delay: u64, voting_period: u64, voting_quorum_rate: u8, min_action_delay: u64, transaction_timeout: u64, dag_effective_height: u64, features: vector<u8>, asset_mapping_proof_root: vector<u8>)
 
@@ -106,10 +107,10 @@ The module for init Genesis transaction_timeout: u64, dag_effective_height: u64, features: vector<u8>, + asset_mapping_proof_root: vector<u8>, ) { debug::print(&std::string::utf8(b"stc_genesis::initialize Entered")); - // create genesis account let (starcoin_framework_account, _genesis_signer_cap) = account::create_framework_reserved_account(@starcoin_framework); @@ -192,6 +193,9 @@ The module for init Genesis debug::print(&std::string::utf8(b"stc_genesis::initialize | initialize_stc ")); + // Asset mapping initialize + asset_mapping::initialize(&starcoin_framework_account, asset_mapping_proof_root); + // Init goverances account let core_resource_account = account::create_account(@core_resources); coin::register<STC>(&core_resource_account); @@ -383,6 +387,16 @@ Overall governance allocation strategy: time_mint_stc_amount: u128, time_mint_stc_period: u64, ) { + // TODO(BobOng): [asset-mapping] To confirm how many STC put into asset mapping pool, now is 10,000,000,000 STC + // let asset_mapping_coin = coin::extract<STC>(&mut total_supply_stc, 100000000000000000); + // asset_mapping::create_store_from_coin<STC>( + // starcoin_framework, + // b"0x1::STC::STC", + // asset_mapping_coin + // ); + // fungible_asset::put_test_store_genesis(core_resource_account); + + // Initialize treasury let treasury_withdraw_cap = treasury::initialize(starcoin_framework, total_supply_stc); if (pre_mine_stc_amount > 0) { @@ -393,6 +407,7 @@ Overall governance allocation strategy: ); coin::deposit(core_resource_address, stc); }; + if (time_mint_stc_amount > 0) { let liner_withdraw_cap = treasury::issue_linear_withdraw_capability<STC>( &mut treasury_withdraw_cap, @@ -500,6 +515,7 @@ Overall governance allocation strategy: transaction_timeout, 0, vector::empty(), + vector::empty(), ); }
diff --git a/vm/framework/starcoin-framework/doc/stc_transaction_validation.md b/vm/framework/starcoin-framework/doc/stc_transaction_validation.md index ece12af1bc..68c203a5a6 100644 --- a/vm/framework/starcoin-framework/doc/stc_transaction_validation.md +++ b/vm/framework/starcoin-framework/doc/stc_transaction_validation.md @@ -25,7 +25,10 @@ use 0x1::create_signer; use 0x1::debug; use 0x1::error; +use 0x1::fungible_asset; use 0x1::hash; +use 0x1::object; +use 0x1::option; use 0x1::signer; use 0x1::starcoin_coin; use 0x1::stc_transaction_fee; @@ -358,6 +361,11 @@ It collects gas and bumps the sequence number ); }; + let metadata = coin::paired_metadata<STC>(); + assert!(option::is_some(&metadata), 10000); + let metdata_obj = option::destroy_some(metadata); + assert!(object::is_object(object::object_address(&metdata_obj)), 10001); + debug::print(&std::string::utf8(b"stc_transaction_validation::epilogue | Exited")); }
diff --git a/vm/framework/starcoin-framework/integration-tests/asset_mapping/basic.exp b/vm/framework/starcoin-framework/integration-tests/asset_mapping/basic.exp new file mode 100644 index 0000000000..e0ac221789 --- /dev/null +++ b/vm/framework/starcoin-framework/integration-tests/asset_mapping/basic.exp @@ -0,0 +1,18 @@ +processed 6 tasks + +task 5 'run'. lines 108-120: +{ + "gas_used": 936902, + "status": { + "ExecutionFailure": { + "location": { + "Module": { + "address": "0x00000000000000000000000000000001", + "name": "asset_mapping" + } + }, + "function": 0, + "code_offset": 54 + } + } +} diff --git a/vm/framework/starcoin-framework/integration-tests/asset_mapping/basic.move b/vm/framework/starcoin-framework/integration-tests/asset_mapping/basic.move new file mode 100644 index 0000000000..0040186842 --- /dev/null +++ b/vm/framework/starcoin-framework/integration-tests/asset_mapping/basic.move @@ -0,0 +1,120 @@ +//# init -n dev + +//# faucet --addr alice --amount 0 + +//# faucet --addr bob --amount 10000000000000000 + +//# faucet --addr Genesis --amount 10000000000000000 + +//# faucet --addr core_resources + +// +// //# publish +// module bob::fake_money { +// use std::signer; +// use std::string; +// +// use starcoin_framework::coin; +// +// struct FakeMoney has key {} +// +// struct FakeMoneyCapabilities has key { +// burn_cap: coin::BurnCapability, +// freeze_cap: coin::FreezeCapability, +// mint_cap: coin::MintCapability, +// } +// +// public fun init(account: &signer, decimal: u8) { +// let ( +// burn_cap, +// freeze_cap, +// mint_cap +// ) = coin::initialize( +// account, +// string::utf8(b"FakeMoney"), +// string::utf8(b"FakeMoney"), +// decimal, +// true, +// ); +// coin::register(account); +// move_to(account, FakeMoneyCapabilities { +// burn_cap, +// freeze_cap, +// mint_cap, +// }) +// } +// +// public fun mint(account: &signer, amount: u64): coin::Coin acquires FakeMoneyCapabilities { +// let cap = borrow_global(signer::address_of(account)); +// coin::mint(amount, &cap.mint_cap) +// } +// +// public fun burn(coin: coin::Coin) acquires FakeMoneyCapabilities { +// let cap = borrow_global(@bob); +// coin::burn(coin, &cap.burn_cap) +// } +// } +// // check: EXECUTED +// +// //# run --signers bob +// script { +// use bob::fake_money::{Self, FakeMoney}; +// use starcoin_framework::asset_mapping; +// +// fun test_create_fake_money_store(account: &signer) { +// fake_money::init(account, 9); +// let fake_money_coin = fake_money::mint(account, 100000000000); +// asset_mapping::create_store_from_coin(account, b"bob::fake_money::FakeMoney", fake_money_coin); +// } +// } +// +// //# run --signers Genesis +// script { +// use bob::fake_money::{FakeMoney}; +// use starcoin_framework::coin; +// use starcoin_framework::asset_mapping; +// +// fun test_create_fake_money_store(account: &signer) { +// asset_mapping::assign_to_account(account, @bob, b"bob::fake_money::FakeMoney", 50000000000); +// assert!(coin::balance(@bob) == 50000000000, 10001); +// } +// } +// // check: EXECUTED +// +// //# run --signers core_resources +// script { +// use starcoin_framework::coin; +// use starcoin_framework::asset_mapping; +// use bob::fake_money::{FakeMoney}; +// +// fun test_create_fake_money_store(account: &signer) { +// asset_mapping::assign_to_account(account, @bob, b"bob::fake_money::FakeMoney", 50000000000); +// assert!(coin::balance(@bob) == 100000000000, 10002); +// } +// } +// // check: EXECUTED +// +// //# run --signers core_resources +// script { +// use starcoin_framework::asset_mapping; +// +// fun test_create_fake_money_store(account: &signer) { +// asset_mapping::assign_to_account(account, @bob, b"bob::fake_money::FakeMoney", 50000000000); +// } +// } +// // check: ABORT: fungible_asset.move 65540 + + +//# run --signers Genesis +script { + use starcoin_framework::starcoin_coin::STC; + use starcoin_framework::coin; + use starcoin_framework::asset_mapping; + + fun test_asset_mapping_assign_to_account_with_proof(account: &signer) { + assert!(coin::balance(@alice) == 0, 10001); + asset_mapping::assign_to_account(account, @alice, b"0x1::STC::STC", 1000000000); + assert!(coin::balance(@alice) == 1000000000, 10002); + } +} +// check: EXECUTED diff --git a/vm/framework/starcoin-framework/integration-tests/object/basic.exp b/vm/framework/starcoin-framework/integration-tests/object/basic.exp new file mode 100644 index 0000000000..5b3b20e7c6 --- /dev/null +++ b/vm/framework/starcoin-framework/integration-tests/object/basic.exp @@ -0,0 +1,12 @@ +processed 3 tasks + +task 2 'run'. lines 60-93: +{ + "gas_used": 678890, + "status": { + "MoveAbort": { + "location": "Script", + "abort_code": "10001" + } + } +} diff --git a/vm/framework/starcoin-framework/integration-tests/object/basic.move b/vm/framework/starcoin-framework/integration-tests/object/basic.move new file mode 100644 index 0000000000..63d5863029 --- /dev/null +++ b/vm/framework/starcoin-framework/integration-tests/object/basic.move @@ -0,0 +1,93 @@ +//# init -n dev + +//# faucet --addr alice --amount 10000000000000000 + +// +// //# publish +// module alice::basic_module { +// use std::option; +// use std::signer; +// use std::string; +// +// use starcoin_framework::coin; +// use starcoin_framework::fungible_asset::{create_store, FungibleStore}; +// use starcoin_framework::object; +// use starcoin_framework::starcoin_coin::STC; +// use starcoin_std::debug; +// +// #[resource_group_member(group = starcoin_framework::object::ObjectGroup)] +// struct Sample has key { +// value: u64 +// } +// +// struct ObjectWrap has key { +// obj_addr: address, +// store: object::Object +// } +// +// public fun create_sample(account: &signer, value: u64) { +// debug::print(&string::utf8(b"alice::basic_module::create_sample | 1")); +// +// let ref = object::create_object_from_account(account); +// move_to(&object::generate_signer(&ref), Sample { +// value +// }); +// +// debug::print(&string::utf8(b"alice::basic_module::create_sample | 2")); +// +// let metadata = coin::paired_metadata(); +// +// debug::print(&string::utf8(b"alice::basic_module::create_sample | 3")); +// +// let store = create_store(&ref, option::destroy_some(metadata)); +// +// debug::print(&string::utf8(b"alice::basic_module::create_sample | 4")); +// +// move_to(account, ObjectWrap { +// obj_addr: object::address_from_constructor_ref(&ref), +// store, +// }); +// +// debug::print(&string::utf8(b"alice::basic_module::create_sample | 5")); +// } +// +// public fun check_value(account: &signer): u64 acquires ObjectWrap, Sample { +// let obj_wrap = borrow_global(signer::address_of(account)); +// borrow_global(obj_wrap.obj_addr).value +// } +// } + +//# run --signers alice +script { + use std::option; + use starcoin_framework::object; + use starcoin_framework::coin; + use starcoin_framework::starcoin_coin::STC; + + fun test_metadata(_account: &signer) { + let metadata = coin::paired_metadata(); + assert!(option::is_some(&metadata), 10000); + let metdata_obj = option::destroy_some(metadata); + assert!(object::is_object(object::object_address(&metdata_obj)), 10001); + } +} + + +// //# run --signers alice +// script { +// use alice::basic_module; +// +// fun test_create_object(account: &signer) { +// basic_module::create_sample(account, 10); +// } +// } +// +// +// //# run --signers alice +// script { +// use alice::basic_module; +// +// fun test_create_object(account: &signer) { +// assert!(basic_module::check_value(account) == 10, 10010); +// } +// } \ No newline at end of file diff --git a/vm/framework/starcoin-framework/sources/asset_mapping.move b/vm/framework/starcoin-framework/sources/asset_mapping.move new file mode 100644 index 0000000000..379bef0681 --- /dev/null +++ b/vm/framework/starcoin-framework/sources/asset_mapping.move @@ -0,0 +1,383 @@ +/// Asset Mapping Module +/// This module implements functionality for managing fungible asset mappings in the Starcoin framework. +/// It provides capabilities for creating stores, managing balances, and assigning assets to accounts +/// with proof verification. +module starcoin_framework::asset_mapping { + + use std::error; + use std::signer; + use std::string; + + use starcoin_framework::coin; + use starcoin_framework::fungible_asset::{Self, FungibleStore, Metadata}; + use starcoin_framework::object::{Self, ExtendRef, Object}; + use starcoin_framework::primary_fungible_store; + use starcoin_framework::starcoin_proof_verifier; + use starcoin_framework::stc_util; + use starcoin_framework::system_addresses; + use starcoin_std::debug; + use starcoin_std::simple_map::{Self, SimpleMap}; + + #[test_only] + use std::vector; + #[test_only] + use starcoin_framework::account; + #[test_only] + use starcoin_framework::starcoin_coin::{Self, STC}; + #[test_only] + use starcoin_framework::starcoin_proof_verifier::splite_symbol; + #[test_only] + use starcoin_std::type_info; + + #[resource_group_member(group = starcoin_framework::object::ObjectGroup)] + /// AssetMappingStore represents a store for mapped assets + /// Contains: + /// - extend_ref: Reference for extending object capabilities + /// - fungible_store: The actual store holding fungible assets + /// - fungible_metadata: The type of fungible assets + struct AssetMappingStore has key, store { + extend_ref: ExtendRef, + fungible_store: Object, + metadata: Object + } + + struct AssetMappingStoreT has key { + coin: coin::Coin, + old_path_str: vector, + } + + /// AssetMappingCoinType represents a mapping that from old version token types to now version asset stores + /// eg. 0x1::STC::STC -> 0x1::starcoin_coin::STC + /// + struct AssetMappingPool has key, store { + proof_root: vector, + token_mapping: SimpleMap, + } + + /// Error code for invalid signer + const EINVALID_SIGNER: u64 = 101; + const EINVALID_PROOF_ROOT: u64 = 102; + const EINVALID_NOT_PROOF: u64 = 103; + const EINVALID_ASSET_MAPPING_POOL: u64 = 104; + + const ASSET_MAPPING_OBJECT_SEED: vector = b"asset-mapping"; + + /// Initializes the asset mapping pool + /// @param framework - The framework signer + /// @param proof_root - Initial proof root for verification + /// Verifies the framework signer and creates a new AssetMappingPool + public fun initialize(framework: &signer, proof_root: vector){ + assert!( + signer::address_of(framework) == system_addresses::get_starcoin_framework(), + error::unauthenticated(EINVALID_SIGNER) + ); + move_to(framework, AssetMappingPool { + token_mapping: simple_map::new(), + proof_root, + }); + } + + + /// Creates a new store from a coin + /// @param token_issuer - The token issuer signer + /// @param coin - The coin to be stored + /// Requirements: + /// - Token issuer must be authorized for the given token type + /// - Converts coin to fungible asset and stores it + public fun create_store_from_coin( + token_issuer: &signer, + old_token_str: vector, + coin: coin::Coin + ) acquires AssetMappingPool { + debug::print(&string::utf8(b"asset_mapping::create_store_from_coin | entered")); + + let token_issuer_addr = signer::address_of(token_issuer); + assert!( + token_issuer_addr == stc_util::token_issuer(), + error::unauthenticated(EINVALID_SIGNER) + ); + + debug::print(&string::utf8(b"asset_mapping::create_store_from_coin | coin_to_fungible_asset")); + + let fungible_asset = coin::coin_to_fungible_asset(coin); + + let ( + metadata, + fungible_store, + extend_ref + ) = create_store_for_coin_type(token_issuer); + + debug::print(&string::utf8(b"asset_mapping::create_store_from_coin | created token store")); + debug::print(&fungible_store); + + fungible_asset::deposit(fungible_store, fungible_asset); + + // Add token mapping coin type + let asset_coin_type = + borrow_global_mut(system_addresses::get_starcoin_framework()); + + let store_constructor_ref = &object::create_object(system_addresses::get_core_resource_address()); + let store_signer = &object::generate_signer(store_constructor_ref); + move_to(store_signer, AssetMappingStore { + extend_ref, + fungible_store, + metadata, + }); + + simple_map::add( + &mut asset_coin_type.token_mapping, + string::utf8(old_token_str), + object::address_from_constructor_ref(store_constructor_ref), + ); + + debug::print(&string::utf8(b"asset_mapping::create_store_from_coin | exited")); + } + + /// Creates a store for a specific token type + /// @param framework - The framework signer + /// @returns (metadata, store, extend_ref): + /// - metadata: Token metadata object + /// - store: Created fungible store + /// - extend_ref: Extension reference for the store + fun create_store_for_coin_type(account: &signer): (Object, Object, ExtendRef) { + debug::print(&std::string::utf8(b"asset_mapping::create_store_for_type | entered")); + + let metadata = coin::ensure_paired_metadata(); + let construct_ref = object::create_object_from_account(account); + + let store = fungible_asset::create_store(&construct_ref, metadata); + + // Generate extend reference + let extend_ref = object::generate_extend_ref(&construct_ref); + debug::print(&std::string::utf8(b"asset_mapping::create_store_for_type | exited")); + + (metadata, store, extend_ref) + } + + /// Retrieves the balance for a specific token type + /// @returns Current balance of the token in the mapping pool + fun fungible_store_balance(old_asset_str: vector): u64 acquires AssetMappingPool, AssetMappingStore { + let pool = borrow_global(system_addresses::get_starcoin_framework()); + let store_object_addr = simple_map::borrow(&pool.token_mapping, &string::utf8(old_asset_str)); + let mapping_store = borrow_global(*store_object_addr); + fungible_asset::balance(mapping_store.fungible_store) + } + + public entry fun assign_to_account_with_proof( + token_issuer: &signer, + receiper: address, + old_token_str: vector, + proof_path_hash: vector, + proof_value_hash: vector, + proof_siblings: vector, + amount: u64 + ) acquires AssetMappingPool, AssetMappingStore { + assert!( + exists(system_addresses::get_starcoin_framework()), + error::invalid_state(EINVALID_PROOF_ROOT) + ); + + // Verify that the token type of the request mapping is the passed-in verification type + assert!( + calculation_proof(proof_path_hash, proof_value_hash, starcoin_proof_verifier::split(proof_siblings)), + error::unauthenticated(EINVALID_NOT_PROOF) + ); + + assign_to_account(token_issuer, receiper, old_token_str, amount); + } + + /// Assigns tokens to a recipient account with proof verification + /// @param token_issuer - The token issuer signer + /// @param receiper - Recipient address + /// @param proove - Proof data for verification + /// @param amount - Amount of tokens to assign + /// Requirements: + /// - Valid proof must be provided + /// - Sufficient balance must exist + public fun assign_to_account( + system_account: &signer, + receiver: address, + old_token_str: vector, + amount: u64 + ) acquires AssetMappingPool, AssetMappingStore { + debug::print(&string::utf8(b"asset_mapping::assign_to_account | entered")); + + let account_addr = signer::address_of(system_account); + assert!( + system_addresses::is_starcoin_framework_address(account_addr) || + system_addresses::is_core_resource_address(account_addr), + EINVALID_SIGNER + ); + + assert!( + exists(system_addresses::get_starcoin_framework()), + error::invalid_state(EINVALID_ASSET_MAPPING_POOL) + ); + + let coin_type_mapping = + borrow_global_mut(system_addresses::get_starcoin_framework()); + debug::print(&string::utf8(b"asset_mapping::assign_to_account | coin_type_mapping")); + debug::print(&coin_type_mapping.token_mapping); + + let mapping_store_addr = simple_map::borrow(&coin_type_mapping.token_mapping, &string::utf8(old_token_str)); + debug::print(mapping_store_addr); + let mapping_store = borrow_global(*mapping_store_addr); + + // debug::print(&string::utf8(b"asset_mapping::assign_to_account | metadata")); + // debug::print(&fungible_asset::is_frozen(mapping_store.fungible_store)); + + debug::print(&string::utf8(b"asset_mapping::assign_to_account | fungible_asset::withdraw")); + let mapping_fa = fungible_asset::withdraw( + &object::generate_signer_for_extending(&mapping_store.extend_ref), + mapping_store.fungible_store, + amount + ); + debug::print(&string::utf8(b"asset_mapping::assign_to_account | Getting receiver fungible store: ")); + + let target_store = + primary_fungible_store::ensure_primary_store_exists(receiver, mapping_store.metadata); + + fungible_asset::deposit(target_store, mapping_fa); + debug::print(&string::utf8(b"asset_mapping::assign_to_account | exited")); + } + + /// Computes and verifies the provided proof + fun calculation_proof( + proof_path_hash: vector, + blob_hash: vector, + proof_siblings: vector> + ): bool acquires AssetMappingPool { + let expect_proof_root = + borrow_global_mut(system_addresses::get_starcoin_framework()).proof_root; + let actual_root = starcoin_proof_verifier::computer_root_hash( + proof_path_hash, + blob_hash, + proof_siblings + ); + expect_proof_root == actual_root + } + + + // Test function for asset mapping store creation and assignment + // Tests + // Store creation from coin + // Balance checking + // Asset assignment to account + // Final balance verification + #[test(framework= @starcoin_framework, alice= @0x123)] + fun test_asset_mapping_create_store_from_coin( + framework: &signer, + alice: &signer + ) acquires AssetMappingPool, AssetMappingStore { + debug::print(&std::string::utf8(b"asset_mapping::test_asset_mapping_create_store_from_coin | entered")); + + let amount = 10000000000; + Self::initialize(framework, vector::empty()); + + debug::print(&std::string::utf8(b"asset_mapping::test_asset_mapping_create_store_from_coin | before create_account_for_test")); + // create genesis account + account::create_account_for_test(signer::address_of(framework)); + + debug::print(&std::string::utf8(b"asset_mapping::test_asset_mapping_create_store_from_coin | starcoin_coin::initialize_for_test")); + + let (burn_cap, mint_cap) = starcoin_coin::initialize_for_test(framework); + + debug::print(&std::string::utf8(b"asset_mapping::test_asset_mapping_create_store_from_coin | coin::register(framework)")); + coin::register(framework); + + debug::print(&std::string::utf8(b"asset_mapping::test_asset_mapping_create_store_from_coin | starcoin_coin::mint")); + starcoin_coin::mint(framework, signer::address_of(framework), amount); + + debug::print(&std::string::utf8(b"asset_mapping::test_asset_mapping_create_store_from_coin | after coin::register(framework) and mint")); + + // Construct Old token string + let old_token_str = b"0x00000000000000000000000000000001::starcoin_coin::STC"; + let coin = coin::withdraw(framework, amount); + Self::create_store_from_coin( + framework, + old_token_str, + coin + ); + assert!(Self::fungible_store_balance(old_token_str) == amount, 10001); + + // Assign to alice + let alice_addr = signer::address_of(alice); + Self::assign_to_account( + framework, + alice_addr, + old_token_str, + amount + ); + assert!(Self::fungible_store_balance(old_token_str) == 0, 10002); + + let stc_metadata = coin::ensure_paired_metadata(); + assert!(primary_fungible_store::balance(alice_addr, stc_metadata) == amount, 10003); + + coin::destroy_burn_cap(burn_cap); + coin::destroy_mint_cap(mint_cap); + + debug::print(&std::string::utf8(b"asset_mapping::test_asset_mapping_create_store_from_coin | exited")); + } + + #[test(framework= @starcoin_framework)] + fun test_asset_mapping_calculation_proof(framework: &signer) acquires AssetMappingPool { + let siblings_data = vector::empty(); + vector::append(&mut siblings_data, x"cfb1462d4fc72f736eab2a56b2bf72ca6ad1c4e8c79557046a8b0adce047f007"); + vector::push_back(&mut siblings_data, splite_symbol()); + + vector::append(&mut siblings_data, x"5350415253455f4d45524b4c455f504c414345484f4c4445525f484153480000"); + vector::push_back(&mut siblings_data, splite_symbol()); + + vector::append(&mut siblings_data, x"5ca9febe74c7fde3fdcf2bd464de6d8899a0a13d464893aada2714c6fa774f9d"); + vector::push_back(&mut siblings_data, splite_symbol()); + + vector::append(&mut siblings_data, x"1519a398fed69687cabf51adf831f0ee1650aaf79775d00135fc70f55a73e151"); + vector::push_back(&mut siblings_data, splite_symbol()); + + vector::append(&mut siblings_data, x"50ce5c38983ba2eb196acd44e0aaedf040b1437ad1106e05ca452d7e27e4e03f"); + vector::push_back(&mut siblings_data, splite_symbol()); + + vector::append(&mut siblings_data, x"55ed28435637a061a6dd9e20b72849199cd36184570f976b7e306a27bebf2fdf"); + vector::push_back(&mut siblings_data, splite_symbol()); + + vector::append(&mut siblings_data, x"0dc23e31614798a6f67659b0b808b3eadc3b13a2a7bc03580a9e3004e45c2e6c"); + vector::push_back(&mut siblings_data, splite_symbol()); + + vector::append(&mut siblings_data, x"83bed048bc0bc452c98cb0e9f1cc0f691919eaf756864fc44940c2d1e01da92a"); + vector::push_back(&mut siblings_data, splite_symbol()); + + let siblings = starcoin_proof_verifier::split(siblings_data); + + let element_key = x"4cc8bd9df94b37c233555d9a3bba0a712c3c709f047486d1e624b2bcd3b83266"; + Self::initialize(framework, x"f65860f575bf2a198c069adb4e7872037e3a329b63ef617e40afa39b87b067c8"); + assert!( + Self::calculation_proof( + element_key, + x"4f2b59b9af93b435e0a33b6ab7a8a90e471dba936be2bc2937629b7782b8ebd0", + siblings + ), + 10010 + ); + } + + #[test] + fun test_asset_mapping_proof_coin_type_name() { + debug::print(&std::string::utf8(b"asset_mapping::test_asset_mapping_coin_type_verify | entered")); + + // Check type path name + let type_name = type_info::type_name>(); + debug::print( + &std::string::utf8( + b"asset_mapping::test_asset_mapping_coin_type_verify | type of coin::CoinStore" + ) + ); + debug::print(&type_name); + assert!( + type_name == std::string::utf8( + b"0x00000000000000000000000000000001::coin::CoinStore<0x00000000000000000000000000000001::starcoin_coin::STC>" + ), + 10020 + ); + debug::print(&std::string::utf8(b"asset_mapping::test_asset_mapping_coin_type_verify | exited")); + } +} diff --git a/vm/framework/starcoin-framework/sources/coin.move b/vm/framework/starcoin-framework/sources/coin.move index 6a1835523c..0ba9c1a76a 100644 --- a/vm/framework/starcoin-framework/sources/coin.move +++ b/vm/framework/starcoin-framework/sources/coin.move @@ -13,7 +13,7 @@ module starcoin_framework::coin { use starcoin_framework::event::{Self, EventHandle}; use starcoin_framework::fungible_asset::{Self, BurnRef, FungibleAsset, Metadata, MintRef, TransferRef}; use starcoin_framework::guid; - use starcoin_framework::object::{Self, Object, object_address}; + use starcoin_framework::object::{Self, Object, object_address, is_object}; use starcoin_framework::optional_aggregator::{Self, OptionalAggregator}; use starcoin_framework::primary_fungible_store; use starcoin_framework::system_addresses; @@ -22,6 +22,7 @@ module starcoin_framework::coin { use starcoin_std::type_info::{Self, type_name, TypeInfo}; friend starcoin_framework::starcoin_coin; + friend starcoin_framework::asset_mapping; // // Errors. @@ -108,6 +109,9 @@ module starcoin_framework::coin { /// The coin decimal too long const ECOIN_COIN_DECIMAL_TOO_LARGE: u64 = 29; + // The metadata create failed + const EMETA_DATA_NOT_FOUND: u64 = 30; + // // Constants // @@ -320,18 +324,37 @@ module starcoin_framework::coin { let map = borrow_global_mut(@starcoin_framework); let type = type_info::type_of(); if (!table::contains(&map.coin_to_fungible_asset_map, type)) { + debug::print( + &std::string::utf8(b"coin::create_and_return_paired_metadata_if_not_exist | map not contain type") + ); let is_stc = is_stc(); assert!(!is_stc || allow_stc_creation, error::invalid_state(EAPT_PAIRING_IS_NOT_ENABLED)); let metadata_object_cref = if (is_stc) { + debug::print( + &std::string::utf8( + b"coin::create_and_return_paired_metadata_if_not_exist | type is stc, create sticky object at 0x1" + ) + ); object::create_sticky_object_at_address(@starcoin_framework, @starcoin_fungible_asset) } else { + debug::print( + &std::string::utf8( + b"coin::create_and_return_paired_metadata_if_not_exist | type is not stc, create new asset sub object" + ) + ); object::create_named_object( &create_signer::create_signer(@starcoin_fungible_asset), *string::bytes(&type_info::type_name()) ) }; + debug::print(&metadata_object_cref); + assert!( + object::is_object(object::address_from_constructor_ref(&metadata_object_cref)), + error::invalid_state(EMETA_DATA_NOT_FOUND) + ); + primary_fungible_store::create_primary_store_enabled_fungible_asset( &metadata_object_cref, option::none(), @@ -388,9 +411,15 @@ module starcoin_framework::coin { public fun coin_to_fungible_asset( coin: Coin ): FungibleAsset acquires CoinConversionMap, CoinInfo { + debug::print(&string::utf8(b"coin::coin_to_fungible_asset | entered")); + let metadata = ensure_paired_metadata(); let amount = burn_internal(coin); - fungible_asset::mint_internal(metadata, amount) + + let ret = fungible_asset::mint_internal(metadata, amount); + + debug::print(&string::utf8(b"coin::coin_to_fungible_asset | exited")); + ret } /// Conversion from fungible asset to coin. Not public to push the migration to FA. diff --git a/vm/framework/starcoin-framework/sources/fungible_asset.move b/vm/framework/starcoin-framework/sources/fungible_asset.move index 85d56e2483..719579a1c1 100644 --- a/vm/framework/starcoin-framework/sources/fungible_asset.move +++ b/vm/framework/starcoin-framework/sources/fungible_asset.move @@ -746,6 +746,9 @@ module starcoin_framework::fungible_asset { constructor_ref: &ConstructorRef, metadata: Object, ): Object { + debug::print(&string::utf8(b"fungible_asset::create_store | entered")); + debug::print(constructor_ref); + let store_obj = &object::generate_signer(constructor_ref); move_to(store_obj, FungibleStore { metadata: object::convert(metadata), @@ -763,11 +766,16 @@ module starcoin_framework::fungible_asset { }); }; + debug::print(&string::utf8(b"fungible_asset::create_store | exited")); + object::object_from_constructor_ref(constructor_ref) } /// Used to delete a store. Requires the store to be completely empty prior to removing it public fun remove_store(delete_ref: &DeleteRef) acquires FungibleStore, FungibleAssetEvents, ConcurrentFungibleBalance { + debug::print(&string::utf8(b"fungible_asset::remove_store | entered")); + debug::print(delete_ref); + let store = &object::object_from_delete_ref(delete_ref); let addr = object::object_address(store); let FungibleStore { metadata: _, balance, frozen: _ } @@ -790,6 +798,7 @@ module starcoin_framework::fungible_asset { event::destroy_handle(withdraw_events); event::destroy_handle(frozen_events); }; + debug::print(&string::utf8(b"fungible_asset::remove_store | exited")); } /// Withdraw `amount` of the fungible asset from `store` by the owner. @@ -832,8 +841,11 @@ module starcoin_framework::fungible_asset { /// Deposit `amount` of the fungible asset to `store`. public fun deposit(store: Object, fa: FungibleAsset) acquires FungibleStore, DispatchFunctionStore, ConcurrentFungibleBalance { + debug::print(&string::utf8(b"fungible_asset::deposit | entered")); + debug::print(&store); deposit_sanity_check(store, true); deposit_internal(object::object_address(&store), fa); + debug::print(&string::utf8(b"fungible_asset::deposit | exited")); } /// Mint the specified `amount` of the fungible asset. @@ -1137,8 +1149,11 @@ module starcoin_framework::fungible_asset { } inline fun borrow_store_resource(store: &Object): &FungibleStore acquires FungibleStore { + // debug::print(&string::utf8(b"fungible_asset::borrow_store_resource | entered")); let store_addr = object::object_address(store); + debug::print(&store_addr); assert!(exists(store_addr), error::not_found(EFUNGIBLE_STORE_EXISTENCE)); + // debug::print(&string::utf8(b"fungible_asset::borrow_store_resource | exited")); borrow_global(store_addr) } @@ -1193,6 +1208,7 @@ module starcoin_framework::fungible_asset { move_to(&object_signer, ConcurrentFungibleBalance { balance }); } + #[test_only] #[resource_group_member(group = starcoin_framework::object::ObjectGroup)] diff --git a/vm/framework/starcoin-framework/sources/object.move b/vm/framework/starcoin-framework/sources/object.move index eab7b2c453..4bf36e69d8 100644 --- a/vm/framework/starcoin-framework/sources/object.move +++ b/vm/framework/starcoin-framework/sources/object.move @@ -19,6 +19,7 @@ module starcoin_framework::object { use std::error; use std::hash; use std::signer; + use std::string; use std::vector; use starcoin_framework::account; @@ -27,10 +28,9 @@ module starcoin_framework::object { use starcoin_framework::event; use starcoin_framework::guid; use starcoin_framework::transaction_context; + use starcoin_std::debug; use starcoin_std::from_bcs; - #[test_only] - use std::debug; #[test_only] use std::option::{Self, Option}; @@ -258,11 +258,9 @@ module starcoin_framework::object { /// Create a new named object and return the ConstructorRef. Named objects can be queried globally /// by knowing the user generated seed used to create them. Named objects cannot be deleted. public fun create_named_object(creator: &signer, seed: vector): ConstructorRef { - // debug::print(&string::utf8(b"object::create_named_object | entered")); let creator_address = signer::address_of(creator); let obj_addr = create_object_address(&creator_address, seed); let ret = create_object_internal(creator_address, obj_addr, false); - // debug::print(&string::utf8(b"object::create_named_object | exited")); ret } @@ -332,7 +330,9 @@ module starcoin_framework::object { object: address, can_delete: bool, ): ConstructorRef { - // debug::print(&string::utf8(b"object::create_object_internal | entered")); + debug::print(&string::utf8(b"object::create_object_internal | entered")); + debug::print(&creator_address); + debug::print(&object); assert!(!exists(object), error::already_exists(EOBJECT_EXISTS)); @@ -350,7 +350,7 @@ module starcoin_framework::object { }, ); - // debug::print(&string::utf8(b"object::create_object_internal | exited")); + debug::print(&string::utf8(b"object::create_object_internal | exited")); ConstructorRef { self: object, can_delete } } diff --git a/vm/framework/starcoin-framework/sources/primary_fungible_store.move b/vm/framework/starcoin-framework/sources/primary_fungible_store.move index a2cf51daa2..eb5afa7e67 100644 --- a/vm/framework/starcoin-framework/sources/primary_fungible_store.move +++ b/vm/framework/starcoin-framework/sources/primary_fungible_store.move @@ -41,6 +41,7 @@ module starcoin_framework::primary_fungible_store { icon_uri: String, project_uri: String, ) { + debug::print(&string::utf8(b"primary_fungible_store::create_primary_store_enabled_fungible_asset | entered")); fungible_asset::add_fungibility( constructor_ref, maximum_supply, @@ -54,6 +55,7 @@ module starcoin_framework::primary_fungible_store { move_to(metadata_obj, DeriveRefPod { metadata_derive_ref: object::generate_derive_ref(constructor_ref), }); + debug::print(&string::utf8(b"primary_fungible_store::create_primary_store_enabled_fungible_asset | exited")); } /// Ensure that the primary store object for the given address exists. If it doesn't, create it. @@ -62,6 +64,8 @@ module starcoin_framework::primary_fungible_store { metadata: Object, ): Object acquires DeriveRefPod { debug::print(&string::utf8(b"primary_fungible_store::ensure_primary_store_exists | entered")); + debug::print(&owner); + let store_addr = primary_store_address(owner, metadata); let ret = if (fungible_asset::store_exists(store_addr)) { object::address_to_object(store_addr) @@ -82,13 +86,22 @@ module starcoin_framework::primary_fungible_store { debug::print(&metadata); let metadata_addr = object::object_address(&metadata); + debug::print(&string::utf8(b"primary_fungible_store::create_primary_store | 1")); + debug::print(&metadata_addr); + object::address_to_object(metadata_addr); + + debug::print(&string::utf8(b"primary_fungible_store::create_primary_store | 2")); let derive_ref = &borrow_global(metadata_addr).metadata_derive_ref; let constructor_ref = &object::create_user_derived_object(owner_addr, derive_ref); + + debug::print(&string::utf8(b"primary_fungible_store::create_primary_store | 3")); // Disable ungated transfer as deterministic stores shouldn't be transferrable. let transfer_ref = &object::generate_transfer_ref(constructor_ref); object::disable_ungated_transfer(transfer_ref); + debug::print(&string::utf8(b"primary_fungible_store::create_primary_store | 4")); + let ret = fungible_asset::create_store(constructor_ref, metadata); debug::print(&string::utf8(b"primary_fungible_store::create_primary_store | exited")); debug::print(&ret); diff --git a/vm/framework/starcoin-framework/sources/proof/starcoin_proof.move b/vm/framework/starcoin-framework/sources/proof/starcoin_proof.move new file mode 100644 index 0000000000..2a1cfc1ccc --- /dev/null +++ b/vm/framework/starcoin-framework/sources/proof/starcoin_proof.move @@ -0,0 +1,150 @@ +module starcoin_framework::starcoin_proof_verifier { + use std::hash; + use std::vector; + + use starcoin_framework::starcoin_proof_bit; + use starcoin_framework::starcoin_proof_structured_hash; + + struct StarcoinMerkle has key { + merkle_root: vector, + } + + struct Node has store, drop { + hash1: vector, + hash2: vector, + } + + const HASH_LEN_IN_BIT: u64 = 32 * 8; + const SPARSE_MERKLE_LEAF_NODE: vector = b"SparseMerkleLeafNode"; + const SPARSE_MERKLE_INTERNAL_NODE: vector = b"SparseMerkleInternalNode"; + + public fun create(signer: &signer, merkle_root: vector) { + let s = StarcoinMerkle { + merkle_root + }; + move_to(signer, s); + } + + public fun verify_on( + merkle_address: address, + account_address: vector, + account_state_root_hash: vector, + proofs: vector> + ): bool + acquires StarcoinMerkle { + let merkle = borrow_global(merkle_address); + verify(*&merkle.merkle_root, account_address, account_state_root_hash, proofs) + } + + public fun verify( + expected_root: vector, + account_address: vector, + account_state_root_hash: vector, + proofs: vector> + ): bool { + Self::computer_root_hash(hash::sha3_256(account_address), account_state_root_hash, proofs) == expected_root + } + + public fun computer_root_hash( + element_key: vector, + element_blob_hash: vector, + proofs: vector> + ): vector { + let leaf_node = Node { hash1: element_key, hash2: element_blob_hash }; + let current_hash = starcoin_proof_structured_hash::hash(SPARSE_MERKLE_LEAF_NODE, &leaf_node); + let i = 0; + let proof_length = vector::length(&proofs); + while (i < proof_length) { + let sibling = *vector::borrow(&proofs, i); + let bit = starcoin_proof_bit::get_bit(&element_key, proof_length - i - 1); + let internal_node = if (bit) { + Node { hash1: sibling, hash2: current_hash } + } else { + Node { hash1: current_hash, hash2: sibling } + }; + current_hash = starcoin_proof_structured_hash::hash(SPARSE_MERKLE_INTERNAL_NODE, &internal_node); + i = i + 1; + }; + current_hash + } + + + // ASCII for '|' + const DELMITER: u8 = 124; + + public fun splite_symbol(): u8 { + DELMITER + } + + public fun split(input: vector): vector> { + let result: vector> = vector::empty(); + let current_segment = vector::empty(); + let i = 0; + let len = vector::length(&input); + + while (i < len) { + let current_byte = *vector::borrow(&input, i); + if (current_byte == DELMITER) { + if (!vector::is_empty(¤t_segment)) { + vector::push_back(&mut result, current_segment); + current_segment = vector::empty(); + }; + } else { + vector::push_back(&mut current_segment, current_byte); + }; + i = i + 1; + }; + + if (!vector::is_empty(¤t_segment)) { + vector::push_back(&mut result, current_segment); + }; + result + } + + #[test] + public fun test_starcoin_proof_verify_is_expect_root() { + let siblings = vector::empty>(); + vector::push_back(&mut siblings, x"cfb1462d4fc72f736eab2a56b2bf72ca6ad1c4e8c79557046a8b0adce047f007"); + vector::push_back(&mut siblings, x"5350415253455f4d45524b4c455f504c414345484f4c4445525f484153480000"); + vector::push_back(&mut siblings, x"5ca9febe74c7fde3fdcf2bd464de6d8899a0a13d464893aada2714c6fa774f9d"); + vector::push_back(&mut siblings, x"1519a398fed69687cabf51adf831f0ee1650aaf79775d00135fc70f55a73e151"); + vector::push_back(&mut siblings, x"50ce5c38983ba2eb196acd44e0aaedf040b1437ad1106e05ca452d7e27e4e03f"); + vector::push_back(&mut siblings, x"55ed28435637a061a6dd9e20b72849199cd36184570f976b7e306a27bebf2fdf"); + vector::push_back(&mut siblings, x"0dc23e31614798a6f67659b0b808b3eadc3b13a2a7bc03580a9e3004e45c2e6c"); + vector::push_back(&mut siblings, x"83bed048bc0bc452c98cb0e9f1cc0f691919eaf756864fc44940c2d1e01da92a"); + + let expect_root_hash = x"f65860f575bf2a198c069adb4e7872037e3a329b63ef617e40afa39b87b067c8"; + let element_key = x"4cc8bd9df94b37c233555d9a3bba0a712c3c709f047486d1e624b2bcd3b83266"; + let actual_root_hash = Self::computer_root_hash( + element_key, + x"4f2b59b9af93b435e0a33b6ab7a8a90e471dba936be2bc2937629b7782b8ebd0", + siblings, + ); + assert!(actual_root_hash == expect_root_hash, 1000); + } + + #[test] + public fun test_starcoin_proof_split() { + // Test case 1: Normal split + let input1 = b"hello|world|test"; + let result1 = split(input1); + assert!(vector::length(&result1) == 3, 10010); + + // Test case 2: Empty segments + let input2 = b"||test||"; + let result2 = split(input2); + assert!(vector::length(&result2) == 1, 10011); + + // Test case 3: Single segment + let input3 = b"hello"; + let result3 = split(input3); + assert!(vector::length(&result3) == 1, 10012); + + // Test case 4: Empty input + let input4 = b""; + let result4 = split(input4); + assert!(vector::length(&result4) == 0, 10013); + } +} + + diff --git a/vm/framework/starcoin-framework/sources/proof/starcoin_proof_bit.move b/vm/framework/starcoin-framework/sources/proof/starcoin_proof_bit.move new file mode 100644 index 0000000000..249aec05f4 --- /dev/null +++ b/vm/framework/starcoin-framework/sources/proof/starcoin_proof_bit.move @@ -0,0 +1,9 @@ +module starcoin_framework::starcoin_proof_bit { + use std::vector; + + public fun get_bit(data: &vector, index: u64): bool { + let pos = index / 8; + let bit = (7 - index % 8); + (*vector::borrow(data, pos) >> (bit as u8)) & 1u8 != 0 + } +} \ No newline at end of file diff --git a/vm/framework/starcoin-framework/sources/proof/starcoin_proof_structured_hash.move b/vm/framework/starcoin-framework/sources/proof/starcoin_proof_structured_hash.move new file mode 100644 index 0000000000..019d7caee0 --- /dev/null +++ b/vm/framework/starcoin-framework/sources/proof/starcoin_proof_structured_hash.move @@ -0,0 +1,19 @@ +module starcoin_framework::starcoin_proof_structured_hash { + use std::bcs; + use std::hash; + use std::vector; + + const STARCOIN_HASH_PREFIX: vector = b"STARCOIN::"; + + public fun hash(structure: vector, data: &MoveValue): vector { + let prefix_hash = hash::sha3_256(concat(&STARCOIN_HASH_PREFIX, structure)); + let bcs_bytes = bcs::to_bytes(data); + hash::sha3_256(concat(&prefix_hash, bcs_bytes)) + } + + fun concat(v1: &vector, v2: vector): vector { + let data = *v1; + vector::append(&mut data, v2); + data + } +} \ No newline at end of file diff --git a/vm/framework/starcoin-framework/sources/starcoin_account.move b/vm/framework/starcoin-framework/sources/starcoin_account.move index a22e1cf91a..f14e941bea 100644 --- a/vm/framework/starcoin-framework/sources/starcoin_account.move +++ b/vm/framework/starcoin-framework/sources/starcoin_account.move @@ -246,7 +246,12 @@ module starcoin_framework::starcoin_account { if (fungible_asset::store_exists(store_addr)) { store_addr } else { - object::object_address(&primary_fungible_store::create_primary_store(owner, object::address_to_object(@starcoin_fungible_asset))) + object::object_address( + &primary_fungible_store::create_primary_store( + owner, + object::address_to_object(@starcoin_fungible_asset) + ) + ) } } @@ -437,7 +442,7 @@ module starcoin_framework::starcoin_account { use starcoin_framework::fungible_asset::Metadata; use starcoin_framework::starcoin_coin; - starcoin_coin::ensure_initialized_with_apt_fa_metadata_for_test(); + starcoin_coin::ensure_initialized_with_stc_fa_metadata_for_test(); let apt_metadata = object::address_to_object(@starcoin_fungible_asset); let user_addr = signer::address_of(user); diff --git a/vm/framework/starcoin-framework/sources/starcoin_coin.move b/vm/framework/starcoin-framework/sources/starcoin_coin.move index 77752758bf..6b52b84303 100644 --- a/vm/framework/starcoin-framework/sources/starcoin_coin.move +++ b/vm/framework/starcoin-framework/sources/starcoin_coin.move @@ -156,10 +156,12 @@ module starcoin_framework::starcoin_coin { use starcoin_framework::aggregator_factory; #[test_only] use starcoin_framework::fungible_asset::FungibleAsset; + #[test_only] + use starcoin_std::debug; #[test_only] - public fun mint_apt_fa_for_test(amount: u64): FungibleAsset acquires MintCapStore { - ensure_initialized_with_apt_fa_metadata_for_test(); + public fun mint_stc_fa_for_test(amount: u64): FungibleAsset acquires MintCapStore { + ensure_initialized_with_stc_fa_metadata_for_test(); coin::coin_to_fungible_asset( coin::mint( amount, @@ -169,7 +171,7 @@ module starcoin_framework::starcoin_coin { } #[test_only] - public fun ensure_initialized_with_apt_fa_metadata_for_test() { + public fun ensure_initialized_with_stc_fa_metadata_for_test() { let starcoin_framework = account::create_signer_for_test(@starcoin_framework); if (!exists(@starcoin_framework)) { if (!aggregator_factory::aggregator_factory_exists_for_testing()) { @@ -185,10 +187,13 @@ module starcoin_framework::starcoin_coin { #[test_only] public fun initialize_for_test(starcoin_framework: &signer): (BurnCapability, MintCapability) { + debug::print(&string::utf8(b"starcoin_coin::initialize_for_test | entered")); aggregator_factory::initialize_aggregator_factory_for_test(starcoin_framework); let (burn_cap, mint_cap) = initialize(starcoin_framework); coin::create_coin_conversion_map(starcoin_framework); coin::create_pairing(starcoin_framework); + + debug::print(&string::utf8(b"starcoin_coin::initialize_for_test | exited")); (burn_cap, mint_cap) } diff --git a/vm/framework/starcoin-framework/sources/stc/stc_genesis.move b/vm/framework/starcoin-framework/sources/stc/stc_genesis.move index aa5ff13a22..a4f21934d9 100644 --- a/vm/framework/starcoin-framework/sources/stc/stc_genesis.move +++ b/vm/framework/starcoin-framework/sources/stc/stc_genesis.move @@ -4,6 +4,8 @@ module starcoin_framework::stc_genesis { use std::features; use std::option; use std::vector; + use starcoin_framework::fungible_asset; + use starcoin_framework::asset_mapping; use starcoin_framework::account; use starcoin_framework::aggregator_factory; @@ -82,10 +84,10 @@ module starcoin_framework::stc_genesis { transaction_timeout: u64, dag_effective_height: u64, features: vector, + asset_mapping_proof_root: vector, ) { debug::print(&std::string::utf8(b"stc_genesis::initialize Entered")); - // create genesis account let (starcoin_framework_account, _genesis_signer_cap) = account::create_framework_reserved_account(@starcoin_framework); @@ -168,6 +170,9 @@ module starcoin_framework::stc_genesis { debug::print(&std::string::utf8(b"stc_genesis::initialize | initialize_stc ")); + // Asset mapping initialize + asset_mapping::initialize(&starcoin_framework_account, asset_mapping_proof_root); + // Init goverances account let core_resource_account = account::create_account(@core_resources); coin::register(&core_resource_account); @@ -299,6 +304,16 @@ module starcoin_framework::stc_genesis { time_mint_stc_amount: u128, time_mint_stc_period: u64, ) { + // TODO(BobOng): [asset-mapping] To confirm how many STC put into asset mapping pool, now is 10,000,000,000 STC + // let asset_mapping_coin = coin::extract(&mut total_supply_stc, 100000000000000000); + // asset_mapping::create_store_from_coin( + // starcoin_framework, + // b"0x1::STC::STC", + // asset_mapping_coin + // ); + // fungible_asset::put_test_store_genesis(core_resource_account); + + // Initialize treasury let treasury_withdraw_cap = treasury::initialize(starcoin_framework, total_supply_stc); if (pre_mine_stc_amount > 0) { @@ -309,6 +324,7 @@ module starcoin_framework::stc_genesis { ); coin::deposit(core_resource_address, stc); }; + if (time_mint_stc_amount > 0) { let liner_withdraw_cap = treasury::issue_linear_withdraw_capability( &mut treasury_withdraw_cap, @@ -397,6 +413,7 @@ module starcoin_framework::stc_genesis { transaction_timeout, 0, vector::empty(), + vector::empty(), ); } } \ No newline at end of file diff --git a/vm/framework/starcoin-framework/sources/stc/stc_transaction_validation.move b/vm/framework/starcoin-framework/sources/stc/stc_transaction_validation.move index a48015bbac..1488451b10 100644 --- a/vm/framework/starcoin-framework/sources/stc/stc_transaction_validation.move +++ b/vm/framework/starcoin-framework/sources/stc/stc_transaction_validation.move @@ -5,8 +5,11 @@ module starcoin_framework::stc_transaction_validation { use std::error; use std::hash; + use std::option; use std::signer; use std::vector; + use starcoin_framework::object; + use starcoin_framework::fungible_asset; use starcoin_std::debug; use starcoin_framework::account; @@ -154,6 +157,11 @@ module starcoin_framework::stc_transaction_validation { ); }; + let metadata = coin::paired_metadata(); + assert!(option::is_some(&metadata), 10000); + let metdata_obj = option::destroy_some(metadata); + assert!(object::is_object(object::object_address(&metdata_obj)), 10001); + debug::print(&std::string::utf8(b"stc_transaction_validation::epilogue | Exited")); } diff --git a/vm/framework/starcoin-framework/tests/starcoin_coin_tests.move b/vm/framework/starcoin-framework/tests/starcoin_coin_tests.move index 92dc654c82..09cbdc698a 100644 --- a/vm/framework/starcoin-framework/tests/starcoin_coin_tests.move +++ b/vm/framework/starcoin-framework/tests/starcoin_coin_tests.move @@ -7,18 +7,18 @@ module starcoin_framework::starcoin_coin_tests { use starcoin_framework::object::{Self, Object}; public fun mint_apt_fa_to_for_test(store: Object, amount: u64) { - fungible_asset::deposit(store, starcoin_coin::mint_apt_fa_for_test(amount)); + fungible_asset::deposit(store, starcoin_coin::mint_stc_fa_for_test(amount)); } public fun mint_apt_fa_to_primary_fungible_store_for_test( owner: address, amount: u64, ) { - primary_fungible_store::deposit(owner, starcoin_coin::mint_apt_fa_for_test(amount)); + primary_fungible_store::deposit(owner, starcoin_coin::mint_stc_fa_for_test(amount)); } #[test(starcoin_framework = @starcoin_framework)] - fun test_apt_setup_and_mint(starcoin_framework: &signer) { + fun test_stc_setup_and_mint(starcoin_framework: &signer) { let (burn_cap, mint_cap) = starcoin_coin::initialize_for_test(starcoin_framework); let coin = coin::mint(100, &mint_cap); let fa = coin::coin_to_fungible_asset(coin); @@ -37,7 +37,7 @@ module starcoin_framework::starcoin_coin_tests { #[test] fun test_fa_helpers_for_test() { assert!(!object::object_exists(@starcoin_fungible_asset), 0); - starcoin_coin::ensure_initialized_with_apt_fa_metadata_for_test(); + starcoin_coin::ensure_initialized_with_stc_fa_metadata_for_test(); assert!(object::object_exists(@starcoin_fungible_asset), 0); mint_apt_fa_to_primary_fungible_store_for_test(@starcoin_framework, 100); let metadata = object::address_to_object(@starcoin_fungible_asset); diff --git a/vm/transaction-builder/src/lib.rs b/vm/transaction-builder/src/lib.rs index a126260271..4e77319576 100644 --- a/vm/transaction-builder/src/lib.rs +++ b/vm/transaction-builder/src/lib.rs @@ -395,6 +395,7 @@ pub fn build_init_script(net: &ChainNetwork) -> EntryFunction { // flexidag effective height genesis_config.dag_effective_height, Features::default().features, + genesis_config.asset_mapping_root_hash.to_vec(), ); match payload { diff --git a/vm/types/src/transaction/package.rs b/vm/types/src/transaction/package.rs index 52eac11b3e..930f9f486e 100644 --- a/vm/types/src/transaction/package.rs +++ b/vm/types/src/transaction/package.rs @@ -70,15 +70,15 @@ impl Package { } fn check_module_address( - _package_address: &AccountAddress, - _module_address: &AccountAddress, + package_address: &AccountAddress, + module_address: &AccountAddress, ) -> Result<()> { - //ensure!( - // package_address == module_address, - // "module's address ({:?}) not same as package module address {:?}", - // module_address, - // package_address, - //); + ensure!( + package_address == module_address, + "module's address ({:?}) not same as package module address {:?}", + module_address, + package_address, + ); Ok(()) } diff --git a/vm/vm-runtime/src/move_vm_ext/vm.rs b/vm/vm-runtime/src/move_vm_ext/vm.rs index a7454c9521..c8b792ae21 100644 --- a/vm/vm-runtime/src/move_vm_ext/vm.rs +++ b/vm/vm-runtime/src/move_vm_ext/vm.rs @@ -25,10 +25,11 @@ use starcoin_vm_types::{ use std::ops::Deref; use std::sync::Arc; +use starcoin_framework::natives::transaction_context::NativeTransactionContext; pub struct MoveVmExt { inner: MoveVM, - _chain_id: u8, + chain_id: u8, features: Arc, } @@ -37,7 +38,7 @@ impl MoveVmExt { native_gas_parameters: NativeGasParameters, misc_gas_parameters: MiscGasParameters, gas_feature_version: u64, - _chain_id: u8, + chain_id: u8, features: Features, timed_features: TimedFeatures, gas_hook: Option, @@ -65,7 +66,7 @@ impl MoveVmExt { } Ok(Self { inner: WarmVmCache::get_warm_vm(builder, vm_config, resolver)?, - _chain_id, + chain_id, features: Arc::new(features), }) } @@ -131,6 +132,14 @@ impl MoveVmExt { extensions.add(NativeAggregatorContext::new(txn_hash, resolver, resolver)); extensions.add(NativeEventContext::default()); extensions.add(NativeObjectContext::default()); + extensions.add(NativeTransactionContext::new( + txn_hash.to_vec(), + //session_id.into_script_hash(), + vec![1], // TODO(BobOng): [compiler-v2] to confirm the script hash + self.chain_id, + // TODO(BobOng): [compiler-v2] to confirm the user transaction context + None, + )); // The VM code loader has bugs around module upgrade. After a module upgrade, the internal // cache needs to be flushed to work around those bugs.