diff --git a/container/Dockerfile-binary-image-dev b/container/Dockerfile-binary-image-dev index 0b4306c7f..d9ad5e587 100644 --- a/container/Dockerfile-binary-image-dev +++ b/container/Dockerfile-binary-image-dev @@ -7,9 +7,9 @@ ENV PATH=$PATH:/root/.cargo/bin/ COPY . $WORK_DIR WORKDIR $WORK_DIR -RUN rustup toolchain install 1.70 && \ - rustup component add clippy --toolchain 1.70 && \ - rustup component add rustfmt --toolchain 1.70 +RUN rustup toolchain install stable && \ + rustup component add clippy --toolchain stable && \ + rustup component add rustfmt --toolchain stable RUN mkdir /binary RUN mkdir -p /binary/cleveldb && mkdir -p /binary/goleveldb diff --git a/container/Dockerfile-binary-image-release b/container/Dockerfile-binary-image-release index 4a3a5f0e6..44af02908 100644 --- a/container/Dockerfile-binary-image-release +++ b/container/Dockerfile-binary-image-release @@ -7,9 +7,9 @@ ENV PATH=$PATH:/root/.cargo/bin/ COPY . $WORK_DIR WORKDIR $WORK_DIR -RUN rustup toolchain install 1.70 && \ - rustup component add clippy --toolchain 1.70 && \ - rustup component add rustfmt --toolchain 1.70 +RUN rustup toolchain install stable && \ + rustup component add clippy --toolchain stable && \ + rustup component add rustfmt --toolchain stable RUN mkdir /binary RUN mkdir -p /binary/cleveldb && mkdir -p /binary/goleveldb diff --git a/rust-toolchain b/rust-toolchain index bfe79d0bd..2bf5ad044 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.70 +stable diff --git a/src/components/abciapp/src/abci/server/callback/mod.rs b/src/components/abciapp/src/abci/server/callback/mod.rs index faac5cdb5..0945cdfc8 100644 --- a/src/components/abciapp/src/abci/server/callback/mod.rs +++ b/src/components/abciapp/src/abci/server/callback/mod.rs @@ -48,7 +48,6 @@ use { std::{ fs, mem::take, - ops::Deref, sync::{ atomic::{AtomicI64, Ordering}, Arc, @@ -569,7 +568,7 @@ pub fn end_block( } if td_height <= CFG.checkpoint.evm_staking_inital_height { if let Ok(Some(vs)) = ruc::info!(staking::get_validators( - la.get_committed_state().read().get_staking().deref(), + la.get_committed_state().read().get_staking(), begin_block_req.last_commit_info.as_ref() )) { resp.set_validator_updates(RepeatedField::from_vec(vs)); @@ -691,13 +690,13 @@ pub fn commit(s: &mut ABCISubmissionServer, req: &RequestCommit) -> ResponseComm Default::default() }; - let total_issuance = if let Ok(mut receipts) = TOTAL_ISSUANCE.lock() { - take(&mut *receipts) + let total_issuance = if let Ok(mut total_issuance) = TOTAL_ISSUANCE.lock() { + take(&mut *total_issuance) } else { Default::default() }; - let allowances = if let Ok(mut receipts) = ALLOWANCES.lock() { - take(&mut *receipts) + let allowances = if let Ok(mut allowances) = ALLOWANCES.lock() { + take(&mut *allowances) } else { Default::default() }; @@ -706,9 +705,9 @@ pub fn commit(s: &mut ABCISubmissionServer, req: &RequestCommit) -> ResponseComm .set_total_issuance(height, v) .map_err(|e| eg!("set redis error: {:?}", e))); } - for ((owner, spender), amount) in allowances.iter() { + for (key, amount) in allowances.iter() { pnk!(setter - .set_allowances(height, *owner, *spender, *amount) + .set_allowances(height, key.owner_address, key.spender_address, *amount) .map_err(|e| eg!("set redis error: {:?}", e))); } diff --git a/src/components/abciapp/src/abci/server/mod.rs b/src/components/abciapp/src/abci/server/mod.rs index cfbe32570..6753049a1 100644 --- a/src/components/abciapp/src/abci/server/mod.rs +++ b/src/components/abciapp/src/abci/server/mod.rs @@ -27,8 +27,6 @@ use { tx_sender::TendermintForward, }; -pub use tx_sender::forward_txn_with_mode; - pub mod callback; pub mod tx_sender; diff --git a/src/components/abciapp/src/abci/server/tx_sender.rs b/src/components/abciapp/src/abci/server/tx_sender.rs index 10306e0d6..4cf747be6 100644 --- a/src/components/abciapp/src/abci/server/tx_sender.rs +++ b/src/components/abciapp/src/abci/server/tx_sender.rs @@ -4,6 +4,7 @@ use { crate::{abci::POOL, api::submission_server::TxnForward}, + config::abci::global_cfg::CFG, ledger::data_model::Transaction, ruc::*, std::sync::atomic::{AtomicU16, Ordering}, @@ -36,7 +37,10 @@ pub fn forward_txn_with_mode( const ASYNC_API: &str = "broadcast_tx_async"; let txn_json = serde_json::to_string(&txn).c(d!())?; - let txn_b64 = base64::encode_config(&txn_json.as_str(), base64::URL_SAFE); + let txn_b64 = base64::encode_config(txn_json, base64::URL_SAFE); + if txn_b64.len() > CFG.checkpoint.tx_size as usize { + return Err(eg!("Transaction too large")); + } let json_rpc = if async_mode { format!( diff --git a/src/components/abciapp/src/abci/staking/mod.rs b/src/components/abciapp/src/abci/staking/mod.rs index 45f83544b..6bee70012 100644 --- a/src/components/abciapp/src/abci/staking/mod.rs +++ b/src/components/abciapp/src/abci/staking/mod.rs @@ -35,7 +35,7 @@ use { serde::Serialize, std::{ collections::{BTreeMap, BTreeSet}, - ops::{Deref, DerefMut}, + ops::DerefMut, sync::atomic::Ordering, }, }; @@ -283,10 +283,9 @@ pub fn system_ops( } if online_list.len() != lci.votes.len() { - if let Ok(pl) = ruc::info!(gen_offline_punish_list( - la.get_staking().deref(), - &online_list - )) { + if let Ok(pl) = + ruc::info!(gen_offline_punish_list(la.get_staking(), &online_list)) + { pl.into_iter().for_each(|v| { let bz = ByzantineInfo { addr: &td_addr_to_string(&v), diff --git a/src/components/abciapp/src/abci/staking/test.rs b/src/components/abciapp/src/abci/staking/test.rs index a379226e0..3984fd56d 100644 --- a/src/components/abciapp/src/abci/staking/test.rs +++ b/src/components/abciapp/src/abci/staking/test.rs @@ -5,7 +5,7 @@ use { ledger::{ data_model::{ Transaction, TransferType, TxnEffect, TxoRef, ASSET_TYPE_FRA, - BLACK_HOLE_PUBKEY, TX_FEE_MIN, + BLACK_HOLE_PUBKEY, TX_FEE_MIN_V0, }, staking::{FF_PK_LIST, FRA_PRE_ISSUE_AMOUNT}, store::{utils::fra_gen_initial_tx, LedgerState}, @@ -99,7 +99,7 @@ fn gen_transfer_tx( ) -> Result { let mut tx_builder = TransactionBuilder::from_seq_id(seq_id); - let target_list = vec![(target_pk, am), (&*BLACK_HOLE_PUBKEY, TX_FEE_MIN)]; + let target_list = vec![(target_pk, am), (&*BLACK_HOLE_PUBKEY, TX_FEE_MIN_V0)]; let mut trans_builder = TransferOperationBuilder::new(); @@ -159,5 +159,5 @@ fn gen_transfer_tx( .c(d!())?; tx_builder.add_operation(op); - Ok(tx_builder.take_transaction().into()) + Ok(tx_builder.take_transaction()) } diff --git a/src/components/abciapp/src/abci/staking/whoami.rs b/src/components/abciapp/src/abci/staking/whoami.rs index 211758cf4..b45e44a00 100644 --- a/src/components/abciapp/src/abci/staking/whoami.rs +++ b/src/components/abciapp/src/abci/staking/whoami.rs @@ -30,7 +30,7 @@ fn from_config_file() -> Result> { .unwrap_or(CFG_PATH_FF); } - fs::read_to_string(&*CFG_PATH) + fs::read_to_string(*CFG_PATH) .c(d!()) .and_then(|cfg| serde_json::from_str::(&cfg).c(d!())) .and_then(|sa| td_addr_to_bytes(&sa.address).c(d!())) diff --git a/src/components/abciapp/src/api/submission_server/submission_api.rs b/src/components/abciapp/src/api/submission_server/submission_api.rs index 08bf57e19..7a613ebe7 100644 --- a/src/components/abciapp/src/api/submission_server/submission_api.rs +++ b/src/components/abciapp/src/api/submission_server/submission_api.rs @@ -130,7 +130,7 @@ impl SubmissionApi { web::get().to(txn_status::), ) }) - .bind(&format!("{host}:{port}")) + .bind(format!("{host}:{port}")) .c(d!())? .run(); diff --git a/src/components/config/src/abci/mod.rs b/src/components/config/src/abci/mod.rs index 89572ad83..70ad782b4 100644 --- a/src/components/config/src/abci/mod.rs +++ b/src/components/config/src/abci/mod.rs @@ -150,6 +150,11 @@ pub struct CheckPointConfig { #[serde(default = "def_evm_staking_address")] pub evm_staking_address: String, + + #[serde(default = "def_evm_staking_inital_height")] + pub utxo_fee_height: i64, + + pub tx_size: u32, } fn def_fix_check_replay() -> u64 { @@ -271,6 +276,8 @@ lazy_static! { max_gas_price_limit: 0, evm_staking_inital_height: 128, evm_staking_address: "0x321DF28026D01858906D322533900aD3435eE964".to_owned(), + utxo_fee_height: 128, + tx_size: 8192 }; } @@ -605,6 +612,8 @@ lazy_static! { max_gas_price_limit: 4636000, evm_staking_inital_height: 4636000, evm_staking_address: "0x38d49e3bd5144059c9f3bA10CF7306E84155B603".to_owned(), + utxo_fee_height: 50000000, + tx_size: 8192 }; } diff --git a/src/components/contracts/baseapp/src/lib.rs b/src/components/contracts/baseapp/src/lib.rs index 1eabdb61e..bd814e9d5 100644 --- a/src/components/contracts/baseapp/src/lib.rs +++ b/src/components/contracts/baseapp/src/lib.rs @@ -92,7 +92,7 @@ pub struct StableTxFee; impl FeeCalculator for StableTxFee { fn min_fee() -> U256 { - // TX_FEE_MIN + // TX_FEE_MIN_V0 U256::from(1_0000_0000_0000_0000_u64) } } diff --git a/src/components/contracts/modules/account/src/impls.rs b/src/components/contracts/modules/account/src/impls.rs index e7e24d978..ca4ac7ed1 100644 --- a/src/components/contracts/modules/account/src/impls.rs +++ b/src/components/contracts/modules/account/src/impls.rs @@ -1,7 +1,7 @@ use crate::{storage::*, App, Config}; use config::abci::global_cfg::CFG; use enterprise_web3::{ - ALLOWANCES, BALANCE_MAP, TOTAL_ISSUANCE, WEB3_SERVICE_START_HEIGHT, + AllowancesKey, ALLOWANCES, BALANCE_MAP, TOTAL_ISSUANCE, WEB3_SERVICE_START_HEIGHT, }; use fp_core::{account::SmartAccount, context::Context}; use fp_storage::BorrowMut; @@ -211,9 +211,9 @@ impl AccountAsset
for App { fn approve( ctx: &Context, owner: &Address, - owner_addr: H160, + owner_address: H160, spender: &Address, - spender_addr: H160, + spender_address: H160, amount: U256, ) -> Result<()> { Allowances::insert(ctx.state.write().borrow_mut(), owner, spender, &amount)?; @@ -222,7 +222,13 @@ impl AccountAsset
for App { { let mut allowances = ALLOWANCES.lock().c(d!())?; - allowances.push(((owner_addr, spender_addr), amount)); + allowances.push(( + AllowancesKey { + owner_address, + spender_address, + }, + amount, + )); } Ok(()) } diff --git a/src/components/contracts/modules/evm/src/lib.rs b/src/components/contracts/modules/evm/src/lib.rs index 323a17167..63aef29b3 100644 --- a/src/components/contracts/modules/evm/src/lib.rs +++ b/src/components/contracts/modules/evm/src/lib.rs @@ -343,7 +343,7 @@ impl App { if log.address != addr { continue; } - match log.topics.get(0).cloned() { + match log.topics.first().cloned() { Some(v) => { if v != signature { continue; @@ -871,7 +871,7 @@ impl App { if log.address != addr { continue; } - match log.topics.get(0).cloned() { + match log.topics.first().cloned() { Some(v) => { if v != signature { continue; @@ -1137,7 +1137,7 @@ pub fn get_claim_on_contract_address( )?; let ret = function.decode_output(&data).c(d!())?; - if let Some(Token::Address(addr)) = ret.get(0) { + if let Some(Token::Address(addr)) = ret.first() { Ok(*addr) } else { Err(eg!("address not found")) diff --git a/src/components/contracts/modules/evm/src/utils.rs b/src/components/contracts/modules/evm/src/utils.rs index c7185c945..59d9b21f6 100644 --- a/src/components/contracts/modules/evm/src/utils.rs +++ b/src/components/contracts/modules/evm/src/utils.rs @@ -168,7 +168,7 @@ fn build_update_info(tk: &Token) -> Result { let mut pub_key = abci::PubKey::default(); - if let Token::Bytes(pk) = v.get(0).ok_or(eg!("update info 0 must bytes"))? { + if let Token::Bytes(pk) = v.first().ok_or(eg!("update info 0 must bytes"))? { pub_key.set_data(pk.clone()); } else { return Err(eg!("Error type of public key")); @@ -210,7 +210,7 @@ pub fn build_validator_updates( let func = sc.staking.function("getValidatorsList").c(d!())?; let dp = func.decode_output(data).c(d!())?; - if let Token::Array(output) = dp.get(0).c(d!())? { + if let Token::Array(output) = dp.first().c(d!())? { let mut res = Vec::with_capacity(output.len()); for o in output.iter() { @@ -227,7 +227,7 @@ pub fn build_validator_updates( fn build_claim_info(tk: &Token) -> Result<(H160, U256)> { if let Token::Tuple(v) = tk { let addr = if let Token::Address(addr) = - v.get(0).ok_or(eg!("update info 0 must bytes"))? + v.first().ok_or(eg!("update info 0 must bytes"))? { *addr } else { @@ -254,7 +254,7 @@ pub fn build_claim_ops(sc: &SystemContracts, data: &[u8]) -> Result>> = Arc::new(Mutex::new(vec![])); @@ -40,8 +45,8 @@ lazy_static! { pub static ref REMOVE_PENDING_STATE_UPDATE_LIST: Arc>> = Arc::new(Mutex::new(vec![])); pub static ref TOTAL_ISSUANCE: Arc>> = Arc::new(Mutex::new(None)); - pub static ref ALLOWANCES: Arc>> = - Arc::new(Mutex::new(vec![])); + pub static ref ALLOWANCES: Arc>> = + Arc::new(Mutex::new(Vec::new())); } fn gen_redis_client() -> r2d2::Pool { diff --git a/src/components/contracts/rpc/src/eth_pubsub.rs b/src/components/contracts/rpc/src/eth_pubsub.rs index 5f63d76fc..25b744a44 100644 --- a/src/components/contracts/rpc/src/eth_pubsub.rs +++ b/src/components/contracts/rpc/src/eth_pubsub.rs @@ -219,9 +219,8 @@ impl SubscriptionResult { receipts: Vec, params: &FilteredParams, ) -> Vec { - let block_hash = Some(H256::from_slice( - Keccak256::digest(&rlp::encode(&block.header)).as_slice(), - )); + let block_hash = + H256::from_slice(Keccak256::digest(&rlp::encode(&block.header)).as_slice()); let mut logs: Vec = vec![]; let mut log_index: u32 = 0; for (receipt_index, receipt) in receipts.into_iter().enumerate() { @@ -234,12 +233,12 @@ impl SubscriptionResult { None }; for (transaction_log_index, log) in receipt.logs.into_iter().enumerate() { - if self.add_log(block_hash.unwrap(), &log, &block, params) { + if self.add_log(block_hash, &log, &block, params) { logs.push(Log { address: log.address, topics: log.topics, data: Bytes(log.data), - block_hash, + block_hash: Some(block_hash), block_number: Some(block.header.number), transaction_hash, transaction_index: Some(U256::from(receipt_index)), diff --git a/src/components/finutils/src/bins/cfg_generator.rs b/src/components/finutils/src/bins/cfg_generator.rs index d42aa7aaf..8f0f7d950 100644 --- a/src/components/finutils/src/bins/cfg_generator.rs +++ b/src/components/finutils/src/bins/cfg_generator.rs @@ -63,7 +63,7 @@ fn gen() -> Result<()> { cfg_template .valiators .iter_mut() - .zip(id_list.into_iter()) + .zip(id_list) .for_each(|(v, id)| { v.id = id; }); diff --git a/src/components/finutils/src/bins/stt/init/i_testing.rs b/src/components/finutils/src/bins/stt/init/i_testing.rs index d0dc743ed..75c598433 100644 --- a/src/components/finutils/src/bins/stt/init/i_testing.rs +++ b/src/components/finutils/src/bins/stt/init/i_testing.rs @@ -16,7 +16,7 @@ use { utils::{get_asset_balance, get_balance, get_validator_detail}, }, ledger::{ - data_model::{gen_random_keypair, TX_FEE_MIN}, + data_model::{gen_random_keypair, TX_FEE_MIN_V0}, staking::FRA, }, ruc::*, @@ -255,8 +255,8 @@ pub fn run_all() -> Result<()> { let mut balances = get_balance(&v_set[0].keypair).c(d!())?; for v in v_set.iter().skip(1) { get_balance(&v.keypair).c(d!()).and_then(|mut n| { - if TX_FEE_MIN < n { - n -= TX_FEE_MIN; + if TX_FEE_MIN_V0 < n { + n -= TX_FEE_MIN_V0; balances += n; transfer_asset_batch_x( &v.keypair, @@ -294,7 +294,7 @@ pub fn run_all() -> Result<()> { &v_set[0].keypair, &targets, None, - 1 + TX_FEE_MIN, + 1 + TX_FEE_MIN_V0, false, false, ) @@ -305,7 +305,7 @@ pub fn run_all() -> Result<()> { sleep_n_block!(1.2); println!(">>> Check balances of the 10 random addresses ..."); for k in rkps.iter() { - assert_eq!(1 + TX_FEE_MIN, get_asset_balance(k, None).c(d!())?); + assert_eq!(1 + TX_FEE_MIN_V0, get_asset_balance(k, None).c(d!())?); } // 19. diff --git a/src/components/finutils/src/bins/stt/init/mod.rs b/src/components/finutils/src/bins/stt/init/mod.rs index bee180fe7..d88265b3c 100644 --- a/src/components/finutils/src/bins/stt/init/mod.rs +++ b/src/components/finutils/src/bins/stt/init/mod.rs @@ -9,7 +9,7 @@ pub mod i_testing; use { super::*, finutils::common::{transfer_asset_batch_x, utils::get_balance}, - ledger::data_model::TX_FEE_MIN, + ledger::data_model::TX_FEE_MIN_V0, }; pub fn init(mut interval: u64, is_mainnet: bool, skip_validator: bool) -> Result<()> { @@ -30,7 +30,7 @@ pub fn init(mut interval: u64, is_mainnet: bool, skip_validator: bool) -> Result println!(">>> Block interval: {interval} seconds"); println!(">>> Define and issue FRA ..."); - common::utils::send_tx(&fra_gen_initial_tx(&root_kp).into()).c(d!())?; + common::utils::send_tx(&fra_gen_initial_tx(&root_kp)).c(d!())?; println!(">>> Wait 1.2 block ..."); sleep_n_block!(1.2, interval); @@ -73,7 +73,7 @@ pub fn init(mut interval: u64, is_mainnet: bool, skip_validator: bool) -> Result for (i, v) in VALIDATOR_LIST.values().enumerate() { delegate::gen_tx(&v.name, (400_0000 + i as u64 * 1_0000) * FRA, &v.name) .c(d!()) - .and_then(|tx| common::utils::send_tx(&tx.into()).c(d!()))?; + .and_then(|tx| common::utils::send_tx(&tx).c(d!()))?; } println!(">>> Wait 5 block ..."); @@ -99,12 +99,12 @@ fn re_distribution() -> Result<()> { // 1. for v in v_set.iter().skip(1) { get_balance(&v.keypair).c(d!()).and_then(|n| { - if TX_FEE_MIN < n { + if TX_FEE_MIN_V0 < n { transfer_asset_batch_x( &v.keypair, &[(v_set[0].pubkey, None)], None, - n - TX_FEE_MIN, + n - TX_FEE_MIN_V0, true, true, ) @@ -147,7 +147,7 @@ fn re_distribution() -> Result<()> { for v in v_set.iter().skip(1) { let actual = get_balance(&v.keypair).c(d!())?; alt!( - actual > expected + TX_FEE_MIN || actual < expected, + actual > expected + TX_FEE_MIN_V0 || actual < expected, return Err(eg!("incorrect balance")) ); } diff --git a/src/components/finutils/src/bins/stt/stt.rs b/src/components/finutils/src/bins/stt/stt.rs index 61c63ec6f..63f35e0a0 100644 --- a/src/components/finutils/src/bins/stt/stt.rs +++ b/src/components/finutils/src/bins/stt/stt.rs @@ -127,7 +127,7 @@ fn run() -> Result<()> { let amount = amount.unwrap().parse::().c(d!())?; delegate::gen_tx(user.unwrap(), amount, validator.unwrap()) .c(d!()) - .and_then(|tx| common::utils::send_tx(&tx.into()).c(d!()))?; + .and_then(|tx| common::utils::send_tx(&tx).c(d!()))?; } } else if let Some(m) = matches.subcommand_matches("undelegate") { let user = m.value_of("user"); @@ -143,7 +143,7 @@ fn run() -> Result<()> { let amount = amount.and_then(|am| am.parse::().ok()); undelegate::gen_tx(user.unwrap(), amount, validator) .c(d!()) - .and_then(|tx| common::utils::send_tx(&tx.into()).c(d!()))?; + .and_then(|tx| common::utils::send_tx(&tx).c(d!()))?; } } else if let Some(m) = matches.subcommand_matches("claim") { let user = m.value_of("user"); @@ -158,7 +158,7 @@ fn run() -> Result<()> { }; claim::gen_tx(user.unwrap(), amount) .c(d!()) - .and_then(|tx| common::utils::send_tx(&tx.into()).c(d!()))?; + .and_then(|tx| common::utils::send_tx(&tx).c(d!()))?; } } else if let Some(m) = matches.subcommand_matches("transfer") { let from = m.value_of("from-user"); @@ -204,7 +204,7 @@ mod issue { use { super::*, - finutils::transaction::BuildOperation, + ledger::data_model::Operation, ledger::{ data_model::{ AssetTypeCode, IssueAsset, IssueAssetBody, IssuerKeyPair, TxOutput, @@ -224,7 +224,7 @@ mod issue { pub fn issue() -> Result<()> { gen_issue_tx() .c(d!()) - .and_then(|tx| common::utils::send_tx(&tx.into()).c(d!())) + .and_then(|tx| common::utils::send_tx(&tx).c(d!())) } fn gen_issue_tx() -> Result { @@ -253,6 +253,7 @@ mod issue { id: None, record: ba, lien: None, + memo: None, }, None, ) @@ -269,8 +270,8 @@ mod issue { let asset_issuance_operation = IssueAsset::new(aib, &IssuerKeyPair { keypair: &root_kp }).c(d!())?; - builder.add_operation(BuildOperation::IssueAsset(asset_issuance_operation)); - Ok(builder.take_transaction().into()) + builder.add_operation(Operation::IssueAsset(asset_issuance_operation)); + Ok(builder.take_transaction()) } } @@ -309,7 +310,7 @@ mod delegate { let mut tx = builder.take_transaction(); tx.sign(owner_kp); - Ok(tx.into()) + Ok(tx) } } @@ -345,7 +346,7 @@ mod undelegate { } })?; - Ok(builder.take_transaction().into()) + Ok(builder.take_transaction()) } } @@ -362,7 +363,7 @@ mod claim { builder.add_operation_claim(None, owner_kp, amount); })?; - Ok(builder.take_transaction().into()) + Ok(builder.take_transaction()) } } diff --git a/src/components/finutils/src/common/ddev/init.rs b/src/components/finutils/src/common/ddev/init.rs index 43a38d610..ac6936c47 100644 --- a/src/components/finutils/src/common/ddev/init.rs +++ b/src/components/finutils/src/common/ddev/init.rs @@ -136,7 +136,7 @@ pub(super) fn init(env: &mut Env) -> Result<()> { })?; let mut tx = builder.take_transaction(); tx.sign(&v.xfr_keypair); - send_tx(env, &tx.into()).c(d!())?; + send_tx(env, &tx).c(d!())?; } println!("[ {} ] >>> Init work done !", &env.name); @@ -154,7 +154,7 @@ fn setup_initial_validators(env: &Env) -> Result<()> { .collect::>(); builder.add_operation_update_validator(&[], 1, vs).c(d!())?; - send_tx(env, &builder.take_transaction().into()).c(d!()) + send_tx(env, &builder.take_transaction()).c(d!()) } fn send_tx(env: &Env, tx: &Transaction) -> Result<()> { @@ -196,7 +196,7 @@ fn transfer_batch( let mut tx = builder.take_transaction(); tx.sign(owner_kp); - send_tx(env, &tx.into()).c(d!()) + send_tx(env, &tx).c(d!()) } fn new_tx_builder(env: &Env) -> Result { @@ -262,11 +262,13 @@ pub(crate) struct BankAccount { } impl BankAccount { - const BANK_ACCOUNT_ADDR: &str = + const BANK_ACCOUNT_ADDR: &'static str = "fra18xkez3fum44jq0zhvwq380rfme7u624cccn3z56fjeex6uuhpq6qv9e4g5"; - const BANK_ACCOUNT_PUBKEY: &str = "Oa2RRTzdayA8V2OBE7xp3n3NKrjGJxFTSZZybXOXCDQ="; - const BANK_ACCOUNT_SECKEY: &str = "Ew9fMaryTL44ZXnEhcF7hQ-AB-fxgaC8vyCH-hCGtzg="; - const BANK_ACCOUNT_MNEMONIC: &str = "field ranch pencil chest effort coyote april move injury illegal forest amount bid sound mixture use second pet embrace twice total essay valve loan"; + const BANK_ACCOUNT_PUBKEY: &'static str = + "Oa2RRTzdayA8V2OBE7xp3n3NKrjGJxFTSZZybXOXCDQ="; + const BANK_ACCOUNT_SECKEY: &'static str = + "Ew9fMaryTL44ZXnEhcF7hQ-AB-fxgaC8vyCH-hCGtzg="; + const BANK_ACCOUNT_MNEMONIC: &'static str = "field ranch pencil chest effort coyote april move injury illegal forest amount bid sound mixture use second pet embrace twice total essay valve loan"; } impl Default for BankAccount { diff --git a/src/components/finutils/src/common/mod.rs b/src/components/finutils/src/common/mod.rs index 5dc6236b3..2a47229de 100644 --- a/src/components/finutils/src/common/mod.rs +++ b/src/components/finutils/src/common/mod.rs @@ -21,13 +21,12 @@ use { common::utils::{ get_evm_staking_address, get_validator_memo_and_rate, mapping_address, }, - transaction::BuildTransaction, }, globutils::wallet, lazy_static::lazy_static, ledger::{ data_model::{ - gen_random_keypair, AssetRules, AssetTypeCode, AssetTypePrefix, + gen_random_keypair, AssetRules, AssetTypeCode, AssetTypePrefix, Transaction, BLACK_HOLE_PUBKEY_STAKING, }, staking::{ @@ -38,13 +37,12 @@ use { }, ruc::*, sha3::{Digest, Keccak256}, - std::str::FromStr, - std::{env, fs}, + std::{env, fs, str::FromStr}, tendermint::PrivateKey, utils::{get_block_height, get_local_block_height, parse_td_validator_keys}, web3::types::H160, - zei::serialization::ZeiFromToBytes, zei::{ + serialization::ZeiFromToBytes, setup::PublicParams, xfr::{ asset_record::AssetRecordType, @@ -685,7 +683,7 @@ pub fn show_delegations(sk_str: Option<&str>) -> Result<()> { fn gen_undelegate_tx( owner_kp: &XfrKeyPair, param: Option<(u64, &str)>, -) -> Result { +) -> Result { let mut builder = utils::new_tx_builder().c(d!())?; utils::gen_fee_op(owner_kp).c(d!()).map(|op| { builder.add_operation(op); @@ -714,7 +712,7 @@ fn gen_delegate_tx( owner_kp: &XfrKeyPair, amount: u64, validator: &str, -) -> Result { +) -> Result { let mut builder = utils::new_tx_builder().c(d!())?; utils::gen_transfer_op( diff --git a/src/components/finutils/src/common/utils.rs b/src/components/finutils/src/common/utils.rs index ee434fee1..3ea958c2a 100644 --- a/src/components/finutils/src/common/utils.rs +++ b/src/components/finutils/src/common/utils.rs @@ -6,14 +6,14 @@ use { crate::{ api::{DelegationInfo, ValidatorDetail}, common::get_serv_addr, - transaction::{BuildOperation, BuildTransaction}, txn_builder::{TransactionBuilder, TransferOperationBuilder}, }, globutils::{wallet, HashOf, SignatureOf}, ledger::{ data_model::{ - AssetType, AssetTypeCode, DefineAsset, StateCommitmentData, TransferType, - TxoRef, TxoSID, Utxo, ASSET_TYPE_FRA, BLACK_HOLE_PUBKEY, TX_FEE_MIN, + AssetType, AssetTypeCode, DefineAsset, Operation, StateCommitmentData, + Transaction, TransferType, TxoRef, TxoSID, Utxo, ASSET_TYPE_FRA, + BLACK_HOLE_PUBKEY, TX_FEE_MIN_V1, }, staking::{ init::get_inital_validators, StakerMemo, TendermintAddrRef, FRA_TOTAL_AMOUNT, @@ -56,7 +56,7 @@ pub fn new_tx_builder() -> Result { #[inline(always)] #[allow(missing_docs)] -pub fn send_tx(tx: &BuildTransaction) -> Result<()> { +pub fn send_tx(tx: &Transaction) -> Result<()> { let url = format!("{}:8669/submit_transaction", get_serv_addr().c(d!())?); let tx_bytes = serde_json::to_vec(tx).c(d!())?; @@ -150,7 +150,7 @@ pub fn gen_transfer_op( confidential_am: bool, confidential_ty: bool, balance_type: Option, -) -> Result { +) -> Result { gen_transfer_op_x( owner_kp, target_list, @@ -172,7 +172,7 @@ pub fn gen_transfer_op_x( confidential_am: bool, confidential_ty: bool, balance_type: Option, -) -> Result { +) -> Result { gen_transfer_op_xx( None, owner_kp, @@ -197,11 +197,11 @@ pub fn gen_transfer_op_xx( confidential_am: bool, confidential_ty: bool, balance_type: Option, -) -> Result { +) -> Result { let mut op_fee: u64 = 0; if auto_fee { - target_list.push((&*BLACK_HOLE_PUBKEY, TX_FEE_MIN, None)); - op_fee += TX_FEE_MIN; + target_list.push((&*BLACK_HOLE_PUBKEY, TX_FEE_MIN_V1, None)); + op_fee += TX_FEE_MIN_V1; } let asset_type = token_code.map(|code| code.val).unwrap_or(ASSET_TYPE_FRA); @@ -257,7 +257,7 @@ pub fn gen_transfer_op_xx( trans_builder .add_output( &AssetRecordTemplate::with_no_asset_tracing( - TX_FEE_MIN, + TX_FEE_MIN_V1, ASSET_TYPE_FRA, AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, *BLACK_HOLE_PUBKEY, @@ -309,7 +309,7 @@ pub fn gen_transfer_op_xx( /// for scenes that need to pay a standalone fee without other transfers #[inline(always)] #[allow(missing_docs)] -pub fn gen_fee_op(owner_kp: &XfrKeyPair) -> Result { +pub fn gen_fee_op(owner_kp: &XfrKeyPair) -> Result { gen_transfer_op(owner_kp, vec![], None, false, false, None).c(d!()) } @@ -810,7 +810,7 @@ pub fn get_evm_delegation_info( .c(d!())?; let ret = function.decode_output(&ret_data.0).c(d!())?; - let bound_amount = if let Some(Token::Uint(bound_amount)) = ret.get(0) { + let bound_amount = if let Some(Token::Uint(bound_amount)) = ret.first() { bound_amount } else { return Err(eg!("bound_amount not found")); @@ -876,7 +876,7 @@ pub fn get_reward_info( .c(d!())?; let ret = function.decode_output(&ret_data.0).c(d!())?; - let reward = if let Some(Token::Uint(reward)) = ret.get(0) { + let reward = if let Some(Token::Uint(reward)) = ret.first() { reward.div(U256::from(10_u64.pow(12))) } else { return Err(eg!("reward not found")); @@ -920,7 +920,7 @@ pub fn get_trigger_on_contract_address( .c(d!())?; let ret = function.decode_output(&ret_data.0).c(d!())?; - let address = if let Some(Token::Address(address)) = ret.get(0) { + let address = if let Some(Token::Address(address)) = ret.first() { address } else { return Err(eg!("staking address not found")); @@ -961,7 +961,7 @@ pub fn get_claim_on_contract_address(url: &str, staking_address: H160) -> Result .c(d!())?; let ret = function.decode_output(&ret_data.0).c(d!())?; - let address = if let Some(Token::Address(address)) = ret.get(0) { + let address = if let Some(Token::Address(address)) = ret.first() { address } else { return Err(eg!("reward address not found")); diff --git a/src/components/finutils/src/lib.rs b/src/components/finutils/src/lib.rs index 36c76adc8..238827abf 100644 --- a/src/components/finutils/src/lib.rs +++ b/src/components/finutils/src/lib.rs @@ -10,6 +10,3 @@ pub mod api; #[cfg(feature = "std")] pub mod common; pub mod txn_builder; - -#[allow(missing_docs)] -pub mod transaction; diff --git a/src/components/finutils/src/transaction.rs b/src/components/finutils/src/transaction.rs deleted file mode 100644 index 77d02a341..000000000 --- a/src/components/finutils/src/transaction.rs +++ /dev/null @@ -1,769 +0,0 @@ -use std::collections::HashMap; - -use globutils::{HashOf, SignatureOf}; -use ledger::{ - converter::ConvertAccount, - data_model::{ - CredentialProof, DefineAsset, IndexedSignature, IssueAsset, Memo, NoReplayToken, - Operation, Transaction, TransactionBody, TransferAsset, TransferAssetBody, - TransferType, TxOutput, TxnEffect, TxnSID, TxoRef, TxoSID, UpdateMemo, - XfrAddress, __trash__::TxnPolicyData, ASSET_TYPE_FRA, BLACK_HOLE_PUBKEY, - TX_FEE_MIN, - }, - staking::ops::{ - claim::ClaimOps, delegation::DelegationOps, - fra_distribution::FraDistributionOps, governance::GovernanceOps, - mint_fra::MintFraOps, replace_staker::ReplaceStakerOps, - undelegation::UnDelegationOps, update_staker::UpdateStakerOps, - update_validator::UpdateValidatorOps, - }, -}; -use rand_chacha::ChaChaRng; -use rand_core::{CryptoRng, RngCore, SeedableRng}; -use ruc::*; -use serde::{Deserialize, Serialize}; -use zei::xfr::{ - lib::{gen_xfr_body, XfrNotePolicies}, - sig::{XfrKeyPair, XfrPublicKey}, - structs::{ - AssetRecord, BlindAssetRecord, OwnerMemo, TracingPolicies, XfrAmount, - XfrAssetType, XfrBody, - }, -}; - -#[inline(always)] -fn is_default(x: &T) -> bool { - x == &T::default() -} - -#[allow(missing_docs)] -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -pub struct BuildTxOutput { - pub id: Option, - pub record: BlindAssetRecord, - #[serde(default)] - #[serde(skip_serializing_if = "is_default")] - pub lien: Option>>, - #[serde(skip_serializing_if = "is_default")] - pub memo: Option, -} -impl From for BuildTxOutput { - fn from(value: TxOutput) -> Self { - Self { - id: value.id, - record: value.record, - lien: value.lien, - memo: None, - } - } -} -impl From for TxOutput { - fn from(value: BuildTxOutput) -> Self { - Self { - id: value.id, - record: value.record, - lien: value.lien, - } - } -} - -/// The inner data of Transfer Operation -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -pub struct BuildTransferAssetBody { - /// Ledger address of inputs - pub inputs: Vec, - #[serde(default)] - #[serde(skip_serializing_if = "is_default")] - /// Transfer policies - pub policies: XfrNotePolicies, - /// A array of transaction outputs - pub outputs: Vec, - #[serde(default)] - #[serde(skip_serializing_if = "is_default")] - /// (inp_idx,out_idx,hash) triples signifying that the lien `hash` on - /// the input `inp_idx` gets assigned to the output `out_idx` - pub lien_assignments: Vec<(usize, usize, HashOf>)>, - /// TODO(joe): we probably don't need the whole XfrNote with input records - /// once it's on the chain - /// Encrypted transfer note - pub transfer: Box, - - /// Only Standard type supported - pub transfer_type: TransferType, -} -impl From for BuildTransferAssetBody { - fn from(value: TransferAssetBody) -> Self { - Self { - inputs: value.inputs, - policies: value.policies, - outputs: value.outputs.iter().map(|v| v.clone().into()).collect(), - lien_assignments: value.lien_assignments, - transfer: value.transfer, - transfer_type: value.transfer_type, - } - } -} -impl From for TransferAssetBody { - fn from(value: BuildTransferAssetBody) -> Self { - Self { - inputs: value.inputs, - policies: value.policies, - outputs: value.outputs.iter().map(|v| v.clone().into()).collect(), - lien_assignments: value.lien_assignments, - transfer: value.transfer, - transfer_type: value.transfer_type, - } - } -} - -impl BuildTransferAssetBody { - #[allow(missing_docs)] - #[allow(clippy::too_many_arguments)] - pub fn new( - prng: &mut R, - input_refs: Vec, - input_records: &[AssetRecord], - output_records: &[AssetRecord], - output_memos: &[Option], - policies: Option, - lien_assignments: Vec<(usize, usize, HashOf>)>, - transfer_type: TransferType, - ) -> Result { - let num_inputs = input_records.len(); - let num_outputs = output_records.len(); - - if num_inputs == 0 { - return Err(eg!()); - } - - // If no policies specified, construct set of empty policies - let policies = policies.unwrap_or_else(|| { - let no_policies = TracingPolicies::new(); - XfrNotePolicies::new( - vec![no_policies.clone(); num_inputs], - vec![None; num_inputs], - vec![no_policies; num_outputs], - vec![None; num_outputs], - ) - }); - - // Verify that for each input and output, there is a corresponding policy and credential commitment - if num_inputs != policies.inputs_tracing_policies.len() - || num_inputs != policies.inputs_sig_commitments.len() - || num_outputs != policies.outputs_tracing_policies.len() - || num_outputs != policies.outputs_sig_commitments.len() - { - return Err(eg!()); - } - - let transfer = - Box::new(gen_xfr_body(prng, input_records, output_records).c(d!())?); - let outputs = transfer - .outputs - .iter() - .zip(output_memos.iter()) - .map(|(rec, memo)| BuildTxOutput { - id: None, - record: rec.clone(), - lien: None, - memo: memo.clone(), - }) - .collect(); - Ok(Self { - inputs: input_refs, - outputs, - policies, - lien_assignments, - transfer, - transfer_type, - }) - } - /// Computes a body signature. A body signature represents consent to some part of the asset transfer. If an - /// input_idx is specified, the signature is a co-signature. - #[inline(always)] - pub fn compute_body_signature( - &self, - keypair: &XfrKeyPair, - input_idx: Option, - ) -> IndexedSignature { - let public_key = keypair.get_pk_ref(); - IndexedSignature { - signature: SignatureOf::new(keypair, &(self.clone().into(), input_idx)), - address: XfrAddress { key: *public_key }, - input_idx, - } - } -} /* - /// Verifies a body signature - #[inline(always)] - pub fn verify_body_signature( - &self, - signature: &IndexedSignature, - ) -> bool { - signature.verify(&self.into()) - } - } - */ -#[allow(missing_docs)] -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -pub struct BuildTransferAsset { - pub body: BuildTransferAssetBody, - pub body_signatures: Vec>, -} -impl From for BuildTransferAsset { - fn from(value: TransferAsset) -> Self { - Self { - body: value.body.into(), - body_signatures: value.body_signatures, - } - } -} -impl From for TransferAsset { - fn from(value: BuildTransferAsset) -> Self { - Self { - body: value.body.into(), - body_signatures: value.body_signatures, - } - } -} -impl BuildTransferAsset { - #[inline(always)] - #[allow(missing_docs)] - pub fn new(transfer_body: BuildTransferAssetBody) -> Result { - Ok(Self { - body: transfer_body, - body_signatures: Vec::new(), - }) - } - #[inline(always)] - #[allow(missing_docs)] - pub fn sign(&mut self, keypair: &XfrKeyPair) { - let sig = self.create_input_signature(keypair); - self.attach_signature(sig).unwrap() - } - - #[inline(always)] - #[allow(missing_docs)] - pub fn attach_signature( - &mut self, - sig: IndexedSignature, - ) -> Result<()> { - if !sig.verify(&self.body.clone().into()) { - return Err(eg!()); - } - self.body_signatures.push(sig); - Ok(()) - } - - #[inline(always)] - #[allow(missing_docs)] - pub fn create_input_signature( - &self, - keypair: &XfrKeyPair, - ) -> IndexedSignature { - self.body.compute_body_signature(keypair, None) - } - - #[inline(always)] - #[allow(missing_docs)] - pub fn get_owner_memos_ref(&self) -> Vec> { - self.body - .transfer - .owners_memos - .iter() - .map(|mem| mem.as_ref()) - .collect() - } -} /* - #[inline(always)] - #[allow(missing_docs)] - pub fn get_owner_addresses(&self) -> Vec { - self.body - .transfer - .inputs - .iter() - .map(|record| record.public_key) - .collect() - } - - #[inline(always)] - #[allow(missing_docs)] - pub fn get_outputs_ref(&self) -> Vec<&BuildTxOutput> { - self.body.outputs.iter().collect() - } - } - */ -/// Operation list supported in findora network -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -pub enum BuildOperation { - /// Transfer a findora asset, FRA or custom asset - TransferAsset(BuildTransferAsset), - /// Issue a custom asset in findora network - IssueAsset(IssueAsset), - /// Create a new asset for a findora account - DefineAsset(DefineAsset), - /// Update memo for a findora custom asset - UpdateMemo(UpdateMemo), - /// Add or remove validator from findora network - UpdateStaker(UpdateStakerOps), - /// Delegate FRA token to existed validator or self-delegation - Delegation(DelegationOps), - /// Withdraw FRA token from findora network - UnDelegation(Box), - /// Claim rewards - Claim(ClaimOps), - /// Update initial validator list - UpdateValidator(UpdateValidatorOps), - /// Findora network goverance operation - Governance(GovernanceOps), - /// Update FRA distribution - FraDistribution(FraDistributionOps), - /// Coinbase operation - MintFra(MintFraOps), - /// Convert UTXOs to EVM Account balance - ConvertAccount(ConvertAccount), - ///replace staker. - ReplaceStaker(ReplaceStakerOps), -} -impl From<&Operation> for BuildOperation { - fn from(value: &Operation) -> Self { - match value.clone() { - Operation::TransferAsset(op) => Self::TransferAsset(op.into()), - Operation::IssueAsset(op) => Self::IssueAsset(op), - Operation::DefineAsset(op) => Self::DefineAsset(op), - Operation::UpdateMemo(op) => Self::UpdateMemo(op), - Operation::UpdateStaker(op) => Self::UpdateStaker(op), - Operation::Delegation(op) => Self::Delegation(op), - Operation::UnDelegation(op) => Self::UnDelegation(op), - Operation::Claim(op) => Self::Claim(op), - Operation::UpdateValidator(op) => Self::UpdateValidator(op), - Operation::Governance(op) => Self::Governance(op), - Operation::FraDistribution(op) => Self::FraDistribution(op), - Operation::MintFra(op) => Self::MintFra(op), - Operation::ConvertAccount(op) => Self::ConvertAccount(op), - Operation::ReplaceStaker(op) => Self::ReplaceStaker(op), - } - } -} -impl From<&BuildOperation> for Operation { - fn from(value: &BuildOperation) -> Self { - match value.clone() { - BuildOperation::TransferAsset(op) => Self::TransferAsset(op.into()), - BuildOperation::IssueAsset(op) => Self::IssueAsset(op), - BuildOperation::DefineAsset(op) => Self::DefineAsset(op), - BuildOperation::UpdateMemo(op) => Self::UpdateMemo(op), - BuildOperation::UpdateStaker(op) => Self::UpdateStaker(op), - BuildOperation::Delegation(op) => Self::Delegation(op), - BuildOperation::UnDelegation(op) => Self::UnDelegation(op), - BuildOperation::Claim(op) => Self::Claim(op), - BuildOperation::UpdateValidator(op) => Self::UpdateValidator(op), - BuildOperation::Governance(op) => Self::Governance(op), - BuildOperation::FraDistribution(op) => Self::FraDistribution(op), - BuildOperation::MintFra(op) => Self::MintFra(op), - BuildOperation::ConvertAccount(op) => Self::ConvertAccount(op), - BuildOperation::ReplaceStaker(op) => Self::ReplaceStaker(op), - } - } -} - -#[allow(missing_docs)] -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, Default)] -pub struct BuildTransactionBody { - pub no_replay_token: NoReplayToken, - pub operations: Vec, - #[serde(default)] - #[serde(skip_serializing_if = "is_default")] - pub credentials: Vec, - #[serde(default)] - #[serde(skip_serializing_if = "is_default")] - pub policy_options: Option, - #[serde(default)] - #[serde(skip_serializing_if = "is_default")] - pub memos: Vec, -} - -impl From for BuildTransactionBody { - fn from(value: TransactionBody) -> Self { - Self { - no_replay_token: value.no_replay_token, - operations: value.operations.iter().map(|v| v.into()).collect(), - credentials: value.credentials, - policy_options: value.policy_options, - memos: value.memos, - } - } -} - -impl From for TransactionBody { - fn from(value: BuildTransactionBody) -> Self { - Self { - no_replay_token: value.no_replay_token, - operations: value.operations.iter().map(|v| v.into()).collect(), - credentials: value.credentials, - policy_options: value.policy_options, - memos: value.memos, - } - } -} - -impl BuildTransactionBody { - #[inline(always)] - fn from_token(no_replay_token: NoReplayToken) -> Self { - BuildTransactionBody { - no_replay_token, - ..Default::default() - } - } -} - -#[allow(missing_docs)] -#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] -pub struct BuildTransaction { - pub body: BuildTransactionBody, - #[serde(default)] - #[serde(skip_serializing_if = "is_default")] - pub signatures: Vec>, - #[serde(default)] - #[serde(skip_serializing_if = "HashMap::is_empty")] - pub pubkey_sign_map: HashMap>, -} - -impl From for BuildTransaction { - fn from(value: Transaction) -> Self { - Self { - body: value.body.into(), - signatures: value.signatures, - pubkey_sign_map: value.pubkey_sign_map, - } - } -} - -impl From for Transaction { - fn from(value: BuildTransaction) -> Self { - Self { - body: value.body.into(), - signatures: value.signatures, - pubkey_sign_map: value.pubkey_sign_map, - } - } -} - -impl BuildTransaction { - #[inline(always)] - #[allow(missing_docs)] - pub fn is_coinbase_tx(&self) -> bool { - self.body - .operations - .iter() - .any(|o| matches!(o, BuildOperation::MintFra(_))) - } - - // /// All-in-one checker - // #[inline(always)] - // pub fn valid_in_abci(&self) -> bool { - // self.check_fee() && !self.is_coinbase_tx() - // } - - /// A simple fee checker - /// - /// The check logic is as follows: - /// - Only `NonConfidential Operation` can be used as fee - /// - FRA code == [0; ASSET_TYPE_LENGTH] - /// - Fee destination == BLACK_HOLE_PUBKEY - /// - A transaction with an `Operation` of defining/issuing FRA need NOT fee - /// - A transaction with all addresses of inputs equal to BLACK_HOLE_PUBKEY need NOT fee - pub fn check_fee(&self) -> bool { - // This method can not completely solve the DOS risk, - // we should further limit the number of txo[s] in every operation. - // - // But it seems enough when we combine it with limiting - // the payload size of submission-server's http-requests. - self.is_coinbase_tx() - || self.body.operations.iter().any(|ops| { - if let BuildOperation::TransferAsset(ref x) = ops { - return x.body.outputs.iter().any(|o| { - if let XfrAssetType::NonConfidential(ty) = o.record.asset_type { - if ty == ASSET_TYPE_FRA - && *BLACK_HOLE_PUBKEY == o.record.public_key - { - if let XfrAmount::NonConfidential(am) = o.record.amount { - if am > (TX_FEE_MIN - 1) { - return true; - } - } - } - } - false - }); - } else if let BuildOperation::DefineAsset(ref x) = ops { - if x.body.asset.code.val == ASSET_TYPE_FRA { - return true; - } - } else if let BuildOperation::IssueAsset(ref x) = ops { - if x.body.code.val == ASSET_TYPE_FRA { - return true; - } - } else if matches!(ops, BuildOperation::UpdateValidator(_)) { - return true; - } - false - }) - } - - /// findora hash - #[inline(always)] - pub fn hash(&self, id: TxnSID) -> HashOf<(TxnSID, Transaction)> { - HashOf::new(&(id, self.clone().into())) - } - - // /// tendermint hash - // #[inline(always)] - // pub fn hash_tm(&self) -> HashOf { - // HashOf::new(self) - // } - - // #[inline(always)] - // #[allow(missing_docs)] - // pub fn hash_tm_rawbytes(&self) -> Vec { - // self.hash_tm().0.hash.as_ref().to_vec() - // } - - #[inline(always)] - #[allow(missing_docs)] - pub fn handle(&self) -> String { - let digest = self.hash(TxnSID(0)); - hex::encode(digest) - } - - /// Create a transaction from seq id - #[inline(always)] - pub fn from_seq_id(seq_id: u64) -> Self { - let mut prng = ChaChaRng::from_entropy(); - let no_replay_token = NoReplayToken::new(&mut prng, seq_id); - Self { - body: BuildTransactionBody::from_token(no_replay_token), - signatures: Vec::new(), - pubkey_sign_map: Default::default(), - } - } - - /// Create a transaction from a operation - // #[inline(always)] - // pub fn from_operation(op: Operation, seq_id: u64) -> Self { - // let mut tx = Transaction::from_seq_id(seq_id); - // tx.add_operation(op); - // tx - // } - - // /// Create a transaction from coinbase operation - // #[inline(always)] - // pub fn from_operation_coinbase_mint(op: Operation, seq_id: u64) -> Self { - // let mut tx = Transaction { - // body: TransactionBody::from_token(NoReplayToken::unsafe_new( - // seq_id.saturating_add(1357).saturating_mul(89), - // seq_id, - // )), - // signatures: Vec::new(), - // pubkey_sign_map: Default::default(), - // }; - // tx.add_operation(op); - // tx - // } - - #[inline(always)] - #[allow(missing_docs)] - pub fn add_operation(&mut self, mut op: BuildOperation) { - set_no_replay_token(&mut op, self.body.no_replay_token); - self.body.operations.push(op); - } - - #[inline(always)] - #[allow(missing_docs)] - pub fn sign(&mut self, keypair: &XfrKeyPair) { - self.signatures - .push(SignatureOf::new(keypair, &self.body.clone().into())); - } - - #[inline(always)] - #[allow(missing_docs)] - pub fn sign_to_map(&mut self, keypair: &XfrKeyPair) { - self.pubkey_sign_map.insert( - keypair.pub_key, - SignatureOf::new(keypair, &self.body.clone().into()), - ); - } - - #[inline(always)] - #[allow(missing_docs)] - pub fn check_signature( - &self, - public_key: &XfrPublicKey, - sig: &SignatureOf, - ) -> Result<()> { - sig.verify(public_key, &self.body.clone().into()).c(d!()) - } - - #[inline(always)] - #[allow(missing_docs)] - pub fn get_owner_memos_ref(&self) -> Vec> { - let mut memos = Vec::new(); - for op in self.body.operations.iter() { - match op { - BuildOperation::TransferAsset(xfr_asset) => { - memos.append(&mut xfr_asset.get_owner_memos_ref()); - } - BuildOperation::MintFra(mint_asset) => { - memos.append(&mut mint_asset.get_owner_memos_ref()); - } - BuildOperation::IssueAsset(issue_asset) => { - memos.append(&mut issue_asset.get_owner_memos_ref()); - } - _ => {} - } - } - memos - } - - /// Returns the outputs of a transaction. Internally spent outputs can be optionally included. - /// This will never panic on a well formed transaction, but may panic on a malformed one. - #[inline(always)] - pub fn get_outputs_ref(&self, include_spent: bool) -> Vec { - let eff = TxnEffect::compute_effect(self.clone().into()).unwrap(); - if !include_spent { - eff.txos.into_iter().flatten().collect() - } else { - let mut spent = eff.internally_spent_txos.into_iter(); - let mut ret = Vec::new(); - for txo in eff.txos.into_iter() { - if let Some(txo) = txo { - ret.push(txo); - } else { - ret.push(spent.next().unwrap()); - } - } - ret - } - } - - // /// NOTE: this does *not* guarantee that a private key affiliated with - // /// `public_key` has signed this transaction! If `public_key` is derived - // /// from `self` somehow, then it is infeasible for someone to forge a - // /// passing signature, but it is plausible for someone to generate an - // /// unrelated `public_key` which can pass this signature check! - // #[inline(always)] - // pub fn check_has_signature(&self, public_key: &XfrPublicKey) -> Result<()> { - // let serialized = Serialized::new(&self.body); - // for sig in self.signatures.iter() { - // match sig.0.verify(public_key, &serialized) { - // Err(_) => {} - // Ok(_) => { - // return Ok(()); - // } - // } - // } - // Err(eg!()) - // } - - // #[inline(always)] - // #[allow(missing_docs)] - // pub fn check_has_signature_from_map(&self, public_key: &XfrPublicKey) -> Result<()> { - // if let Some(sign) = self.pubkey_sign_map.get(public_key) { - // sign.0.verify(public_key, &Serialized::new(&self.body)) - // } else { - // Err(eg!( - // "the pubkey not match: {}", - // public_key_to_base64(public_key) - // )) - // } - // } - - // /// NOTE: This method is used to verify the signature in the transaction, - // /// when the user constructs the transaction not only needs to sign each `operation`, - // /// but also needs to sign the whole transaction, otherwise it will not be passed here - // #[inline(always)] - // pub fn check_tx(&self) -> Result<()> { - // let select_check = |tx: &Transaction, pk: &XfrPublicKey| -> Result<()> { - // if tx.signatures.is_empty() { - // tx.check_has_signature_from_map(pk) - // } else { - // tx.check_has_signature(pk) - // } - // }; - - // for operation in self.body.operations.iter() { - // match operation { - // Operation::TransferAsset(o) => { - // for pk in o.get_owner_addresses().iter() { - // select_check(self, pk).c(d!())?; - // } - // } - // Operation::IssueAsset(o) => { - // select_check(self, &o.pubkey.key).c(d!())?; - // } - // Operation::DefineAsset(o) => { - // select_check(self, &o.pubkey.key).c(d!())?; - // } - // Operation::UpdateMemo(o) => { - // select_check(self, &o.pubkey).c(d!())?; - // } - // Operation::UpdateStaker(o) => { - // select_check(self, &o.pubkey).c(d!())?; - // } - // Operation::Delegation(o) => { - // select_check(self, &o.pubkey).c(d!())?; - // } - // Operation::UnDelegation(o) => { - // select_check(self, &o.pubkey).c(d!())?; - // } - // Operation::Claim(o) => { - // select_check(self, &o.pubkey).c(d!())?; - // } - // Operation::UpdateValidator(_) => {} - // Operation::Governance(_) => {} - // Operation::FraDistribution(_) => {} - // Operation::MintFra(_) => {} - // Operation::ConvertAccount(o) => { - // select_check(self, &o.signer).c(d!())?; - // } - // Operation::ReplaceStaker(o) => { - // if !o.get_related_pubkeys().is_empty() { - // for pk in o.get_related_pubkeys() { - // select_check(self, &pk).c(Ok!())?; - // } - // } - // } - // } - // } - - // d(()) - // } -} -#[allow(missing_docs)] -pub fn set_no_replay_token(op: &mut BuildOperation, no_replay_token: NoReplayToken) { - match op { - BuildOperation::UpdateStaker(i) => { - i.set_nonce(no_replay_token); - } - BuildOperation::Delegation(i) => { - i.set_nonce(no_replay_token); - } - BuildOperation::UnDelegation(i) => { - i.set_nonce(no_replay_token); - } - BuildOperation::Claim(i) => { - i.set_nonce(no_replay_token); - } - BuildOperation::FraDistribution(i) => { - i.set_nonce(no_replay_token); - } - BuildOperation::UpdateValidator(i) => { - i.set_nonce(no_replay_token); - } - BuildOperation::Governance(i) => { - i.set_nonce(no_replay_token); - } - BuildOperation::UpdateMemo(i) => i.body.no_replay_token = no_replay_token, - BuildOperation::ConvertAccount(i) => i.set_nonce(no_replay_token), - _ => {} - } -} diff --git a/src/components/finutils/src/txn_builder/mod.rs b/src/components/finutils/src/txn_builder/mod.rs index d40d055c3..e793bcee9 100644 --- a/src/components/finutils/src/txn_builder/mod.rs +++ b/src/components/finutils/src/txn_builder/mod.rs @@ -5,10 +5,7 @@ #![deny(warnings)] #![allow(clippy::needless_borrow)] -use crate::transaction::{ - BuildOperation, BuildTransaction, BuildTransferAsset, BuildTransferAssetBody, -}; - +use ledger::data_model::{Operation, Transaction, TransferAsset, TX_FEE_MIN_V1}; //#[cfg(not(target_arch = "wasm32"))] use zei::serialization::ZeiFromToBytes; @@ -24,7 +21,7 @@ use { IndexedSignature, IssueAsset, IssueAssetBody, IssuerKeyPair, IssuerPublicKey, Memo, NoReplayToken, TransactionBody, TransferAssetBody, TransferType, TxOutput, TxoRef, UpdateMemo, UpdateMemoBody, ASSET_TYPE_FRA, - BLACK_HOLE_PUBKEY, TX_FEE_MIN, + BLACK_HOLE_PUBKEY, }, staking::{ is_valid_tendermint_addr, @@ -120,7 +117,7 @@ impl FeeInputs { /// An simple builder for findora transaction #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TransactionBuilder { - txn: BuildTransaction, + txn: Transaction, outputs: u64, #[allow(missing_docs)] pub no_replay_token: NoReplayToken, @@ -128,12 +125,12 @@ pub struct TransactionBuilder { impl TransactionBuilder { /// Convert builder to it's inner transaction - pub fn into_transaction(self) -> BuildTransaction { + pub fn into_transaction(self) -> Transaction { self.txn } /// Get reference of it's inner transaction - pub fn get_transaction(&self) -> &BuildTransaction { + pub fn get_transaction(&self) -> &Transaction { &self.txn } @@ -157,10 +154,10 @@ impl TransactionBuilder { .operations .iter() .flat_map(|new| match new { - BuildOperation::TransferAsset(d) => { + Operation::TransferAsset(d) => { seek!(d) } - BuildOperation::IssueAsset(d) => d + Operation::IssueAsset(d) => d .body .records .iter() @@ -182,7 +179,24 @@ impl TransactionBuilder { let mut opb = TransferOperationBuilder::default(); let outputs = self.get_relative_outputs(); - let mut am = TX_FEE_MIN; + let mut am = TX_FEE_MIN_V1; + for i in self.txn.body.operations.iter() { + if let Operation::TransferAsset(transfer) = i { + let len = transfer.body.outputs.len() as u64; + if len > 3 { + am += (len - 3) * 2_000_000; + } + let memo_len = transfer + .body + .outputs + .iter() + .filter(|v| v.memo.is_some()) + .collect::>() + .len() as u64; + am += memo_len * 2_000_000; + break; + } + } for (idx, (o, om)) in outputs.into_iter().enumerate() { if 0 < am { if let Ok(oar) = open_blind_asset_record(&o, &om, &kp) { @@ -200,7 +214,7 @@ impl TransactionBuilder { opb.add_output( &AssetRecordTemplate::with_no_asset_tracing( - TX_FEE_MIN, + am, ASSET_TYPE_FRA, AssetRecordType::from_flags(false, false), *BLACK_HOLE_PUBKEY, @@ -228,6 +242,25 @@ impl TransactionBuilder { let mut kps = vec![]; let mut opb = TransferOperationBuilder::default(); + let mut am = TX_FEE_MIN_V1; + for i in self.txn.body.operations.iter() { + if let Operation::TransferAsset(transfer) = i { + let len = transfer.body.outputs.len() as u64; + if len > 3 { + am += (len - 3) * 2_000_000; + } + let memo_len = transfer + .body + .outputs + .iter() + .filter(|v| v.memo.is_some()) + .collect::>() + .len() as u64; + am += memo_len * 2_000_000; + break; + } + } + for i in inputs.inner.into_iter() { open_blind_asset_record(&i.ar.record, &i.om, &i.kp) .c(d!()) @@ -242,7 +275,7 @@ impl TransactionBuilder { opb.add_output( &AssetRecordTemplate::with_no_asset_tracing( - TX_FEE_MIN, + am, ASSET_TYPE_FRA, AssetRecordType::from_flags(false, false), *BLACK_HOLE_PUBKEY, @@ -291,7 +324,7 @@ impl TransactionBuilder { let mut prng = ChaChaRng::from_entropy(); let no_replay_token = NoReplayToken::new(&mut prng, seq_id); TransactionBuilder { - txn: BuildTransaction::from_seq_id(seq_id), + txn: Transaction::from_seq_id(seq_id), outputs: 0, no_replay_token, } @@ -333,6 +366,7 @@ impl TransactionBuilder { id: None, record: ba, lien: None, + memo: None, }, owner_memo, )], @@ -341,12 +375,12 @@ impl TransactionBuilder { } #[allow(missing_docs)] - pub fn transaction(&self) -> &BuildTransaction { + pub fn transaction(&self) -> &Transaction { &self.txn } #[allow(missing_docs)] - pub fn take_transaction(self) -> BuildTransaction { + pub fn take_transaction(self) -> Transaction { self.txn } @@ -369,7 +403,7 @@ impl TransactionBuilder { None => AssetTypeCode::gen_random(), }; let iss_keypair = IssuerKeyPair { keypair: &key_pair }; - self.txn.add_operation(BuildOperation::DefineAsset( + self.txn.add_operation(Operation::DefineAsset( DefineAsset::new( DefineAssetBody::new( &token_code, @@ -399,7 +433,7 @@ impl TransactionBuilder { ) -> Result<&mut Self> { let iss_keypair = IssuerKeyPair { keypair: &key_pair }; - self.txn.add_operation(BuildOperation::IssueAsset( + self.txn.add_operation(Operation::IssueAsset( IssueAsset::new( IssueAssetBody::new(token_code, seq_num, &records_and_memos).c(d!())?, &iss_keypair, @@ -441,8 +475,8 @@ impl TransactionBuilder { ); } - let mut xfr = BuildTransferAsset::new( - BuildTransferAssetBody::new( + let mut xfr = TransferAsset::new( + TransferAssetBody::new( &mut prng, input_sids, &input_asset_records[..], @@ -457,7 +491,7 @@ impl TransactionBuilder { .c(d!())?; xfr.sign(&keys); - self.txn.add_operation(BuildOperation::TransferAsset(xfr)); + self.txn.add_operation(Operation::TransferAsset(xfr)); Ok(self) } @@ -478,7 +512,7 @@ impl TransactionBuilder { auth_key_pair, ); memo_update.pubkey = auth_key_pair.get_pk(); - let op = BuildOperation::UpdateMemo(memo_update); + let op = Operation::UpdateMemo(memo_update); self.txn.add_operation(op); self } @@ -499,7 +533,7 @@ impl TransactionBuilder { None, self.txn.body.no_replay_token, ); - self.add_operation(BuildOperation::Delegation(op)) + self.add_operation(Operation::Delegation(op)) } /// Add a operation to updating staker memo and commission_rate @@ -528,7 +562,7 @@ impl TransactionBuilder { self.txn.body.no_replay_token, ); - Ok(self.add_operation(BuildOperation::UpdateStaker(op))) + Ok(self.add_operation(Operation::UpdateStaker(op))) } /// Add a staking operation to add a tendermint node as a validator @@ -565,7 +599,7 @@ impl TransactionBuilder { self.txn.body.no_replay_token, ); - Ok(self.add_operation(BuildOperation::Delegation(op))) + Ok(self.add_operation(Operation::Delegation(op))) } /// Add a operation to reduce delegation amount of a findora account. @@ -577,7 +611,7 @@ impl TransactionBuilder { pu: Option, ) -> &mut Self { let op = UnDelegationOps::new(keypair, self.txn.body.no_replay_token, pu); - self.add_operation(BuildOperation::UnDelegation(Box::new(op))) + self.add_operation(Operation::UnDelegation(Box::new(op))) } /// Add a operation to claim all the rewards @@ -588,7 +622,7 @@ impl TransactionBuilder { am: Option, ) -> &mut Self { let op = ClaimOps::new(td_addr, keypair, am, self.txn.body.no_replay_token); - self.add_operation(BuildOperation::Claim(op)) + self.add_operation(Operation::Claim(op)) } #[allow(missing_docs)] @@ -599,7 +633,7 @@ impl TransactionBuilder { ) -> Result<&mut Self> { FraDistributionOps::new(kps, alloc_table, self.txn.body.no_replay_token) .c(d!()) - .map(move |op| self.add_operation(BuildOperation::FraDistribution(op))) + .map(move |op| self.add_operation(Operation::FraDistribution(op))) } #[allow(missing_docs)] @@ -618,7 +652,7 @@ impl TransactionBuilder { self.txn.body.no_replay_token, ) .c(d!()) - .map(move |op| self.add_operation(BuildOperation::Governance(op))) + .map(move |op| self.add_operation(Operation::Governance(op))) } /// Add a operation update the validator set at specified block height. @@ -630,7 +664,7 @@ impl TransactionBuilder { ) -> Result<&mut Self> { UpdateValidatorOps::new(kps, h, v_set, self.txn.body.no_replay_token) .c(d!()) - .map(move |op| self.add_operation(BuildOperation::UpdateValidator(op))) + .map(move |op| self.add_operation(Operation::UpdateValidator(op))) } /// Add an operation to replace the staker of validator. @@ -648,7 +682,7 @@ impl TransactionBuilder { td_addr, self.txn.body.no_replay_token, ); - self.add_operation(BuildOperation::ReplaceStaker(ops)); + self.add_operation(Operation::ReplaceStaker(ops)); Ok(self) } @@ -661,7 +695,7 @@ impl TransactionBuilder { asset: Option, lowlevel_data: Option>, ) -> Result<&mut Self> { - self.add_operation(BuildOperation::ConvertAccount(ConvertAccount { + self.add_operation(Operation::ConvertAccount(ConvertAccount { signer: kp.get_pk(), nonce: self.txn.body.no_replay_token, receiver: addr, @@ -673,7 +707,7 @@ impl TransactionBuilder { } #[allow(missing_docs)] - pub fn add_operation(&mut self, op: BuildOperation) -> &mut Self { + pub fn add_operation(&mut self, op: Operation) -> &mut Self { self.txn.add_operation(op); self } @@ -802,7 +836,7 @@ pub struct TransferOperationBuilder { outputs_tracing_policies: Vec, output_identity_commitments: Vec>, - transfer: Option, + transfer: Option, transfer_type: TransferType, auto_refund: bool, } @@ -1074,7 +1108,7 @@ impl TransferOperationBuilder { self.outputs_tracing_policies.clone(), vec![None; num_outputs], ); - let body = BuildTransferAssetBody::new( + let body = TransferAssetBody::new( &mut prng, self.input_sids.clone(), &self.input_records, @@ -1085,7 +1119,7 @@ impl TransferOperationBuilder { transfer_type, ) .c(d!())?; - self.transfer = Some(BuildTransferAsset::new(body).c(d!())?); + self.transfer = Some(TransferAsset::new(body).c(d!())?); Ok(self) } @@ -1136,13 +1170,11 @@ impl TransferOperationBuilder { } /// Return the transaction operation - pub fn transaction(&self) -> Result { + pub fn transaction(&self) -> Result { if self.transfer.is_none() { return Err(eg!(no_transfer_err!())); } - Ok(BuildOperation::TransferAsset( - self.transfer.clone().c(d!())?, - )) + Ok(Operation::TransferAsset(self.transfer.clone().c(d!())?)) } /// Checks to see whether all necessary signatures are present and valid @@ -1154,7 +1186,7 @@ impl TransferOperationBuilder { let trn = self.transfer.as_ref().c(d!())?; let mut sig_keys = HashSet::new(); for sig in &trn.body_signatures { - if !sig.verify(&trn.body.clone().into()) { + if !sig.verify(&trn.body) { return Err(eg!(("Invalid signature"))); } sig_keys.insert(sig.address.key.zei_to_bytes()); @@ -1174,8 +1206,7 @@ impl TransferOperationBuilder { mod tests { use { super::*, - ledger::data_model::{TxnEffect, TxoRef}, - ledger::store::{utils::fra_gen_initial_tx, LedgerState}, + ledger::data_model::TxoRef, rand_chacha::ChaChaRng, rand_core::SeedableRng, zei::setup::PublicParams, @@ -1392,140 +1423,4 @@ mod tests { .c(d!())?; Ok(()) } - - #[test] - fn test_check_fee_with_ledger() { - let mut ledger = LedgerState::tmp_ledger(); - let fra_owner_kp = XfrKeyPair::generate(&mut ChaChaRng::from_entropy()); - let bob_kp = XfrKeyPair::generate(&mut ChaChaRng::from_entropy()); - assert_eq!( - bob_kp.get_sk().into_keypair().zei_to_bytes(), - bob_kp.zei_to_bytes() - ); - - let mut tx = fra_gen_initial_tx(&fra_owner_kp); - assert!(tx.check_fee()); - - let effect = TxnEffect::compute_effect(tx.clone()).unwrap(); - let mut block = ledger.start_block().unwrap(); - let tmp_sid = ledger.apply_transaction(&mut block, effect).unwrap(); - let txo_sid = ledger - .finish_block(block) - .unwrap() - .remove(&tmp_sid) - .unwrap() - .1[0]; - - macro_rules! transfer_to_bob { - ($txo_sid: expr, $bob_pk: expr) => {{ - let output_bob_fra_template = AssetRecordTemplate::with_no_asset_tracing( - 100 * TX_FEE_MIN, - ASSET_TYPE_FRA, - NonConfidentialAmount_NonConfidentialAssetType, - $bob_pk, - ); - TransferOperationBuilder::new() - .add_input( - TxoRef::Absolute($txo_sid), - open_blind_asset_record( - &ledger.get_utxo_light($txo_sid).unwrap().utxo.0.record, - &None, - &fra_owner_kp, - ) - .unwrap(), - None, - None, - 100 * TX_FEE_MIN, - ) - .unwrap() - .add_output(&output_bob_fra_template, None, None, None, None) - .unwrap() - .balance(None) - .unwrap() - .create(TransferType::Standard) - .unwrap() - .sign(&fra_owner_kp) - .unwrap() - .transaction() - .unwrap() - }}; - } - - let mut tx2 = TransactionBuilder::from_seq_id(1); - tx2.add_operation(transfer_to_bob!(txo_sid, bob_kp.get_pk())) - .add_fee_relative_auto(&fra_owner_kp, None) - .unwrap(); - assert!(tx2.check_fee()); - - let effect = TxnEffect::compute_effect(tx2.into_transaction().into()).unwrap(); - let mut block = ledger.start_block().unwrap(); - let tmp_sid = ledger.apply_transaction(&mut block, effect).unwrap(); - // txo_sid[0]: fra_owner to bob - // txo_sid[1]: fra_owner to fee - // txo_sid[2]: balance to fra_owner - let txo_sid = ledger - .finish_block(block) - .unwrap() - .remove(&tmp_sid) - .unwrap() - .1; - - // (0) transfer first time - let mut fi = FeeInputs::new(); - let utxo = ledger.get_utxo_light(txo_sid[0]).unwrap(); - fi.append( - TX_FEE_MIN, - TxoRef::Absolute(txo_sid[0]), - utxo.utxo.0, - utxo.txn.txn.get_owner_memos_ref()[utxo.utxo_location.0].cloned(), - bob_kp.get_sk().into_keypair(), - ); - let mut tx3 = TransactionBuilder::from_seq_id(2); - pnk!(tx3 - .add_operation(transfer_to_bob!(txo_sid[2], bob_kp.get_pk())) - .add_fee(fi, None)); - assert!(tx3.check_fee()); - - let effect = TxnEffect::compute_effect(tx3.into_transaction().into()).unwrap(); - let mut block = ledger.start_block().unwrap(); - let tmp_sid = ledger.apply_transaction(&mut block, effect).unwrap(); - // txo_sid[0]: fra_owner to bob - // txo_sid[1]: balance to fra_owner - // txo_sid[2]: bob to fee - // txo_sid[3]: balance to bob - let txo_sid = ledger - .finish_block(block) - .unwrap() - .remove(&tmp_sid) - .unwrap() - .1; - - // (2) transfer second time - let mut fi = FeeInputs::new(); - let utxo = ledger.get_utxo_light(txo_sid[0]).unwrap(); - fi.append( - TX_FEE_MIN, - TxoRef::Absolute(txo_sid[0]), - utxo.utxo.0, - utxo.txn.txn.get_owner_memos_ref()[utxo.utxo_location.0].cloned(), - bob_kp.get_sk().into_keypair(), - ); - let mut tx4 = TransactionBuilder::from_seq_id(3); - tx4.add_operation(transfer_to_bob!(txo_sid[1], bob_kp.get_pk())) - .add_fee(fi, None) - .unwrap(); - assert!(tx4.check_fee()); - - let effect = TxnEffect::compute_effect(tx4.into_transaction().into()).unwrap(); - let mut block = ledger.start_block().unwrap(); - ledger.apply_transaction(&mut block, effect).unwrap(); - ledger.finish_block(block).unwrap(); - - // Ensure that FRA can only be defined only once. - tx.body.no_replay_token = - NoReplayToken::new(&mut ChaChaRng::from_entropy(), 100); - let effect = TxnEffect::compute_effect(tx).unwrap(); - let mut block = ledger.start_block().unwrap(); - assert!(ledger.apply_transaction(&mut block, effect).is_err()); - } } diff --git a/src/components/wallet_mobile/src/rust/crypto.rs b/src/components/wallet_mobile/src/rust/crypto.rs index 86059b624..7861044db 100644 --- a/src/components/wallet_mobile/src/rust/crypto.rs +++ b/src/components/wallet_mobile/src/rust/crypto.rs @@ -15,7 +15,7 @@ use globutils::wallet; use ledger::{ data_model::{ AssetTypeCode, ASSET_TYPE_FRA, BLACK_HOLE_PUBKEY, BLACK_HOLE_PUBKEY_STAKING, - TX_FEE_MIN, + TX_FEE_MIN_V1, }, staking::{MAX_DELEGATION_AMOUNT, MIN_DELEGATION_AMOUNT}, }; @@ -468,7 +468,7 @@ pub fn fra_get_asset_code() -> String { /// Fee smaller than this value will be denied. #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] pub fn fra_get_minimal_fee() -> u64 { - TX_FEE_MIN + TX_FEE_MIN_V1 } /// The destination for fee to be transfered to. diff --git a/src/components/wallet_mobile/src/rust/transaction.rs b/src/components/wallet_mobile/src/rust/transaction.rs index c55158554..99f6b8db0 100644 --- a/src/components/wallet_mobile/src/rust/transaction.rs +++ b/src/components/wallet_mobile/src/rust/transaction.rs @@ -146,6 +146,7 @@ impl TransactionBuilder { id: None, record: new.0, lien: None, + memo: None, }, }); base @@ -330,7 +331,7 @@ impl TransactionBuilder { /// Adds a serialized transfer asset operation to a transaction builder instance. pub fn add_transfer_operation(mut self, op: String) -> Result { let op = serde_json::from_str::(&op)?; - self.get_builder_mut().add_operation((&op).into()); + self.get_builder_mut().add_operation(op); Ok(self) } diff --git a/src/components/wasm/src/wasm.rs b/src/components/wasm/src/wasm.rs index 13b72c7a4..313969748 100644 --- a/src/components/wasm/src/wasm.rs +++ b/src/components/wasm/src/wasm.rs @@ -50,7 +50,7 @@ use { data_model::{ gen_random_keypair, AssetTypeCode, AssetTypePrefix, AuthenticatedTransaction, Operation, TransferType, TxOutput, ASSET_TYPE_FRA, - BLACK_HOLE_PUBKEY, BLACK_HOLE_PUBKEY_STAKING, TX_FEE_MIN, + BLACK_HOLE_PUBKEY, BLACK_HOLE_PUBKEY_STAKING, TX_FEE_MIN_V1, }, staking::{ td_addr_to_bytes, PartialUnDelegation, TendermintAddr, @@ -282,6 +282,7 @@ impl TransactionBuilder { id: None, record: new.0, lien: None, + memo: None, }, } .to_json() @@ -560,7 +561,7 @@ impl TransactionBuilder { mut self, op: String, ) -> Result { - let op = serde_json::from_str::(&op) + let op = serde_json::from_str::(&op) .c(d!()) .map_err(error_to_jsvalue)?; self.get_builder_mut().add_operation(op); @@ -1300,7 +1301,6 @@ pub fn trace_assets( use aes_gcm::aead::{generic_array::GenericArray, Aead, NewAead}; use aes_gcm::Aes256Gcm; -use finutils::transaction::BuildOperation; use rand::{thread_rng, Rng}; use ring::pbkdf2; use std::num::NonZeroU32; @@ -1510,7 +1510,7 @@ pub fn fra_get_asset_code() -> String { #[wasm_bindgen] /// Fee smaller than this value will be denied. pub fn fra_get_minimal_fee() -> u64 { - TX_FEE_MIN + TX_FEE_MIN_V1 } #[wasm_bindgen] diff --git a/src/ledger/src/data_model/effects.rs b/src/ledger/src/data_model/effects.rs index 491d0835d..d0269874f 100644 --- a/src/ledger/src/data_model/effects.rs +++ b/src/ledger/src/data_model/effects.rs @@ -262,7 +262,7 @@ impl TxnEffect { // (1), within this transaction //let v = vec![]; - let iss_nums = self.new_issuance_nums.entry(code).or_insert_with(Vec::new); + let iss_nums = self.new_issuance_nums.entry(code).or_default(); if let Some(last_num) = iss_nums.last() { if seq_num <= *last_num { @@ -296,6 +296,7 @@ impl TxnEffect { id: None, record: output.record.clone(), lien: None, + memo: None, }) { return Err(eg!()); @@ -475,6 +476,7 @@ impl TxnEffect { id: None, record: record.clone(), lien: lien.cloned(), + memo: None, }, ); } @@ -495,6 +497,7 @@ impl TxnEffect { id: None, record: out.clone(), lien: lien.cloned(), + memo: None, })); *txo_count += 1; } @@ -663,7 +666,7 @@ impl BlockEffect { if self.staking_simulator.cur_height > CFG.checkpoint.fix_check_replay && txn_effect.txn.body.operations.len() == 1 { - if let Some(Operation::MintFra(_)) = txn_effect.txn.body.operations.get(0) { + if let Some(Operation::MintFra(_)) = txn_effect.txn.body.operations.first() { flag = false; } } diff --git a/src/ledger/src/data_model/mod.rs b/src/ledger/src/data_model/mod.rs index f23eee11d..20b5810b7 100644 --- a/src/ledger/src/data_model/mod.rs +++ b/src/ledger/src/data_model/mod.rs @@ -9,11 +9,16 @@ pub mod __trash__; mod effects; mod test; +use std::sync::atomic::Ordering; + +use config::abci::global_cfg::CFG; pub use effects::{BlockEffect, TxnEffect}; use noah_algebra::bls12_381::BLSScalar; use noah_algebra::prelude::Scalar; use noah_crypto::basic::anemoi_jive::{AnemoiJive, AnemoiJive381}; +use crate::LEDGER_TENDERMINT_BLOCK_HEIGHT; + use { crate::converter::ConvertAccount, crate::staking::{ @@ -790,6 +795,8 @@ pub struct TxOutput { #[serde(default)] #[serde(skip_serializing_if = "is_default")] pub lien: Option>>, + #[serde(skip_serializing_if = "is_default")] + pub memo: Option, } #[allow(missing_docs)] @@ -889,6 +896,7 @@ impl TransferAssetBody { input_refs: Vec, input_records: &[AssetRecord], output_records: &[AssetRecord], + output_memos: &[Option], policies: Option, lien_assignments: Vec<(usize, usize, HashOf>)>, transfer_type: TransferType, @@ -925,10 +933,12 @@ impl TransferAssetBody { let outputs = transfer .outputs .iter() - .map(|rec| TxOutput { + .zip(output_memos.iter()) + .map(|(rec, memo)| TxOutput { id: None, record: rec.clone(), lien: None, + memo: memo.clone(), }) .collect(); Ok(TransferAssetBody { @@ -1672,7 +1682,10 @@ lazy_static! { } /// see [**mainnet-v0.1 defination**](https://www.notion.so/findora/Transaction-Fees-Analysis-d657247b70f44a699d50e1b01b8a2287) -pub const TX_FEE_MIN: u64 = 1_0000; +pub const TX_FEE_MIN_V0: u64 = 1_0000; + +/// 10fra +pub const TX_FEE_MIN_V1: u64 = 10_000_000; impl Transaction { #[inline(always)] @@ -1707,13 +1720,34 @@ impl Transaction { self.is_coinbase_tx() || self.body.operations.iter().any(|ops| { if let Operation::TransferAsset(ref x) = ops { + let fee = if LEDGER_TENDERMINT_BLOCK_HEIGHT.load(Ordering::Relaxed) + > CFG.checkpoint.utxo_fee_height + { + let mut fee = TX_FEE_MIN_V1; + + let len = x.body.outputs.len() as u64; + if len > 3 { + fee += (len - 3) * 2_000_000; + } + let mut memo_num = 0; + for it in x.body.outputs.iter() { + if it.memo.is_some() { + memo_num += 1; + } + } + fee += memo_num * 2_000_000; + fee + } else { + TX_FEE_MIN_V0 + }; + return x.body.outputs.iter().any(|o| { if let XfrAssetType::NonConfidential(ty) = o.record.asset_type { if ty == ASSET_TYPE_FRA && *BLACK_HOLE_PUBKEY == o.record.public_key { if let XfrAmount::NonConfidential(am) = o.record.amount { - if am > (TX_FEE_MIN - 1) { + if am >= fee { return true; } } diff --git a/src/ledger/src/data_model/test.rs b/src/ledger/src/data_model/test.rs index e08bf051a..45ab75926 100644 --- a/src/ledger/src/data_model/test.rs +++ b/src/ledger/src/data_model/test.rs @@ -238,7 +238,7 @@ fn gen_sample_tx() -> Transaction { assert_eq!(transaction.body.operations.len(), 3); assert_eq!( - transaction.body.operations.get(0), + transaction.body.operations.first(), Some(&Operation::TransferAsset(asset_transfer)) ); assert_eq!( @@ -284,6 +284,7 @@ fn gen_fee_operation( public_key: dest_pubkey, }, lien: None, + memo: None, }], lien_assignments: Vec::new(), transfer: Box::new(XfrBody { @@ -308,35 +309,35 @@ fn test_check_fee() { assert!(!tx.check_fee()); let invalid_confidential_type = - gen_fee_operation(Some(TX_FEE_MIN), None, *BLACK_HOLE_PUBKEY); + gen_fee_operation(Some(TX_FEE_MIN_V0), None, *BLACK_HOLE_PUBKEY); let invalid_confidential_amount = gen_fee_operation( None, Some(ZeiAssetType([0; ASSET_TYPE_LENGTH])), *BLACK_HOLE_PUBKEY, ); let invalid_nonconfidential_not_fra_code = gen_fee_operation( - Some(TX_FEE_MIN), + Some(TX_FEE_MIN_V0), Some(ZeiAssetType([9; ASSET_TYPE_LENGTH])), *BLACK_HOLE_PUBKEY, ); let invalid_nonconfidential_fee_too_little = gen_fee_operation( - Some(TX_FEE_MIN - 1), + Some(TX_FEE_MIN_V0 - 1), Some(ZeiAssetType([0; ASSET_TYPE_LENGTH])), *BLACK_HOLE_PUBKEY, ); let invalid_destination_not_black_hole = gen_fee_operation( - Some(TX_FEE_MIN), + Some(TX_FEE_MIN_V0), Some(ZeiAssetType([0; ASSET_TYPE_LENGTH])), XfrPublicKey::zei_from_bytes(&[9; ed25519_dalek::PUBLIC_KEY_LENGTH][..]) .unwrap(), ); let valid = gen_fee_operation( - Some(TX_FEE_MIN), + Some(TX_FEE_MIN_V0), Some(ZeiAssetType([0; ASSET_TYPE_LENGTH])), *BLACK_HOLE_PUBKEY, ); let valid2 = gen_fee_operation( - Some(TX_FEE_MIN + 999), + Some(TX_FEE_MIN_V0 + 999), Some(ZeiAssetType([0; ASSET_TYPE_LENGTH])), *BLACK_HOLE_PUBKEY, ); diff --git a/src/ledger/src/lib.rs b/src/ledger/src/lib.rs index 8d15bac66..0aed95bb1 100644 --- a/src/ledger/src/lib.rs +++ b/src/ledger/src/lib.rs @@ -2,7 +2,7 @@ //! The findora ledger core implementation //! -#![deny(warnings)] +//#![deny(warnings)] #![deny(missing_docs)] #![allow(clippy::needless_borrow)] diff --git a/src/ledger/src/staking/mod.rs b/src/ledger/src/staking/mod.rs index 3ec4585d3..1490d709b 100644 --- a/src/ledger/src/staking/mod.rs +++ b/src/ledger/src/staking/mod.rs @@ -809,7 +809,7 @@ impl Staking { self.delegation_info .end_height_map .entry(end_height) - .or_insert_with(BTreeSet::new) + .or_default() .insert(owner); // There should be no failure here !! @@ -903,7 +903,7 @@ impl Staking { self.delegation_info .end_height_map .entry(h + CFG.checkpoint.unbond_block_cnt) - .or_insert_with(BTreeSet::new) + .or_default() .insert(*addr); } @@ -995,7 +995,7 @@ impl Staking { self.delegation_info .end_height_map .entry(h + CFG.checkpoint.unbond_block_cnt) - .or_insert_with(BTreeSet::new) + .or_default() .insert(pu.new_delegator_id); // update delegator entries for pu target_validator @@ -1078,7 +1078,7 @@ impl Staking { self.delegation_info .end_height_map .entry(end_height) - .or_insert_with(BTreeSet::new) + .or_default() .insert(addr.to_owned()); Ok(()) } else { diff --git a/src/ledger/src/staking/ops/mint_fra.rs b/src/ledger/src/staking/ops/mint_fra.rs index 2738f3ff1..1791c2e3c 100644 --- a/src/ledger/src/staking/ops/mint_fra.rs +++ b/src/ledger/src/staking/ops/mint_fra.rs @@ -87,6 +87,7 @@ impl MintEntry { id: None, record: ba, lien: None, + memo: None, }; MintEntry { diff --git a/src/ledger/src/store/helpers.rs b/src/ledger/src/store/helpers.rs index 8f6a3cf6b..4facc75b5 100644 --- a/src/ledger/src/store/helpers.rs +++ b/src/ledger/src/store/helpers.rs @@ -177,6 +177,7 @@ pub fn create_issue_and_transfer_txn( id: None, record: ba.clone(), lien: None, + memo: None, }, None, )], @@ -211,6 +212,7 @@ pub fn create_issue_and_transfer_txn( open_blind_asset_record(&ba, &owner_memo, &issuer_keys).unwrap() )], &[ar.clone()], + &[None], None, vec![], TransferType::Standard, @@ -265,6 +267,7 @@ pub fn create_issue_and_transfer_txn_with_asset_tracing( id: None, record: ba.clone(), lien: None, + memo: None, }, None, )], @@ -305,6 +308,7 @@ pub fn create_issue_and_transfer_txn_with_asset_tracing( vec![TxoRef::Relative(0)], &[tar], &[ar.clone()], + &[None], Some(xfr_note_policies), vec![], TransferType::Standard, @@ -353,6 +357,7 @@ pub fn create_issuance_txn( id: None, record: ba, lien: None, + memo: None, }, None, )], diff --git a/src/ledger/src/store/mod.rs b/src/ledger/src/store/mod.rs index df4ffae74..e739c90d9 100644 --- a/src/ledger/src/store/mod.rs +++ b/src/ledger/src/store/mod.rs @@ -400,11 +400,11 @@ impl LedgerState { let utxo_map_path = format!("{}/{}utxo_map", basedir, &prefix); // These iterms will be set under ${BNC_DATA_DIR} - fs::create_dir_all(&basedir).c(d!())?; + fs::create_dir_all(basedir).c(d!())?; let snapshot_file = format!("{}ledger_status", &prefix); let snapshot_entries_dir = prefix.clone() + "ledger_status_subdata"; - env::set_var(LSSED_VAR, &snapshot_entries_dir); + env::set_var(LSSED_VAR, snapshot_entries_dir); let blocks_path = prefix.clone() + "blocks"; let tx_to_block_location_path = prefix.clone() + "tx_to_block_location"; @@ -801,7 +801,7 @@ impl LedgerState { let res = sids .into_iter() - .zip(aus.into_iter()) + .zip(aus) .filter_map(|(sid, au)| au.map(|au| (sid, au))) .map(|(sid, au)| { ( @@ -1372,8 +1372,9 @@ impl LedgerStatus { // Apply memo updates for (code, memo) in block.memo_updates.drain() { - let mut asset = self.asset_types.get_mut(&code).unwrap(); - asset.properties.memo = memo; + if let Some(ref mut asset) = self.asset_types.get_mut(&code) { + asset.properties.memo = memo; + } } for (code, amount) in block.issuance_amounts.drain() { diff --git a/src/ledger/src/store/test.rs b/src/ledger/src/store/test.rs index b6cb5cb56..7b95eface 100644 --- a/src/ledger/src/store/test.rs +++ b/src/ledger/src/store/test.rs @@ -6,7 +6,7 @@ use { crate::data_model::{ AssetRules, AssetTypeCode, IssueAsset, IssueAssetBody, Memo, Operation, Transaction, TransferAsset, TransferAssetBody, TxOutput, TxnEffect, TxoRef, - TxoSID, ASSET_TYPE_FRA, BLACK_HOLE_PUBKEY, TX_FEE_MIN, + TxoSID, ASSET_TYPE_FRA, BLACK_HOLE_PUBKEY, TX_FEE_MIN_V0, }, rand_core::SeedableRng, zei::{ @@ -193,6 +193,7 @@ fn test_asset_transfer() { id: None, record: ba, lien: None, + memo: None, }, None, ), @@ -201,6 +202,7 @@ fn test_asset_transfer() { id: None, record: second_ba, lien: None, + memo: None, }, None, ), @@ -264,6 +266,7 @@ fn test_asset_transfer() { vec![TxoRef::Absolute(txo_sid)], &[input_ar], &[output_ar], + &[None], None, vec![], TransferType::Standard, @@ -384,6 +387,7 @@ fn asset_issued() { id: None, record: ba, lien: None, + memo: None, }, None, )], @@ -531,6 +535,7 @@ pub fn test_transferable() { open_blind_asset_record(&bar, &None, &alice).unwrap(), )], &[record], + &[None], None, vec![], TransferType::Standard, @@ -568,6 +573,7 @@ pub fn test_transferable() { open_blind_asset_record(&bar, &None, &alice).unwrap(), )], &[record], + &[None], None, vec![], TransferType::Standard, @@ -613,6 +619,7 @@ pub fn test_transferable() { ar.open_asset_record, )], &[second_record], + &[None], None, vec![], TransferType::Standard, @@ -721,7 +728,7 @@ fn gen_fee_operation( let input_oar = open_blind_asset_record(&input_bar, &None, &fra_owner_kp).unwrap(); let output_template = AssetRecordTemplate::with_no_asset_tracing( - input_oar.amount - TX_FEE_MIN, + input_oar.amount - TX_FEE_MIN_V0, fra_code.val, AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, fra_owner_kp.get_pk(), @@ -733,7 +740,7 @@ fn gen_fee_operation( .unwrap(); let output_template = AssetRecordTemplate::with_no_asset_tracing( - TX_FEE_MIN, + TX_FEE_MIN_V0, fra_code.val, AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, *BLACK_HOLE_PUBKEY, @@ -752,6 +759,7 @@ fn gen_fee_operation( vec![TxoRef::Absolute(txo_sid)], &[input_ar], &[output_ar, output_ar_fee], + &[None, None], None, vec![], TransferType::Standard, diff --git a/src/ledger/src/store/utils.rs b/src/ledger/src/store/utils.rs index a7a1ed4ef..f062e13b8 100644 --- a/src/ledger/src/store/utils.rs +++ b/src/ledger/src/store/utils.rs @@ -73,6 +73,7 @@ pub fn fra_gen_initial_tx(fra_owner_kp: &XfrKeyPair) -> Transaction { id: None, record: ba, lien: None, + memo: None, }, None, )