From 2e6a2544de949f8dd288c89e392eda7777745c42 Mon Sep 17 00:00:00 2001 From: Harshad Patil Date: Thu, 17 Aug 2023 23:48:05 -0700 Subject: [PATCH 1/7] Anemoi upgrade and integration of platform-lib-noah (#1003) * Anemoi upgrade and integration of platform-lib-noah * fix lint * fix unit test failure * Update Cargo.toml * trigger Github action * trigger github action * trigger * fix query server API * fix derived asset code api --------- Co-authored-by: Weikeng Chen --- README.md | 2 + src/components/abciapp/Cargo.toml | 15 +- .../abciapp/src/abci/server/callback/mod.rs | 2 +- .../abciapp/src/abci/server/callback/utils.rs | 2 +- .../abciapp/src/abci/staking/mod.rs | 5 +- .../abciapp/src/abci/staking/test.rs | 23 ++- .../api/query_server/query_api/ledger_api.rs | 29 +++- .../src/api/query_server/query_api/mod.rs | 19 +-- .../src/api/query_server/query_api/server.rs | 2 +- src/components/config/Cargo.toml | 2 +- src/components/config/src/abci/mod.rs | 9 ++ src/components/contracts/baseapp/Cargo.toml | 8 +- .../contracts/baseapp/src/staking.rs | 13 +- .../contracts/modules/account/Cargo.toml | 8 +- .../contracts/modules/account/src/tests.rs | 2 +- .../contracts/modules/ethereum/Cargo.toml | 6 +- .../contracts/modules/ethereum/src/impls.rs | 2 +- .../contracts/modules/evm/Cargo.toml | 10 +- .../modules/evm/precompile/anemoi/Cargo.toml | 3 +- .../evm/precompile/anemoi/benches/anemoi.rs | 10 +- .../modules/evm/precompile/anemoi/src/lib.rs | 103 ++++++++++-- .../modules/evm/precompile/basic/Cargo.toml | 2 +- .../modules/evm/precompile/basic/src/lib.rs | 4 +- .../modules/evm/precompile/frc20/Cargo.toml | 2 +- .../modules/evm/precompile/modexp/Cargo.toml | 2 +- .../modules/evm/precompile/src/lib.rs | 9 +- .../evm/precompile/utils/macro/Cargo.toml | 2 +- .../evm/precompile/utils/macro/src/lib.rs | 4 +- .../contracts/modules/evm/src/lib.rs | 5 +- .../contracts/modules/evm/src/utils.rs | 16 +- .../contracts/primitives/core/Cargo.toml | 6 +- .../contracts/primitives/mocks/Cargo.toml | 6 +- .../contracts/primitives/mocks/src/lib.rs | 4 +- .../contracts/primitives/storage/Cargo.toml | 6 +- .../contracts/primitives/types/Cargo.toml | 12 +- .../primitives/types/src/actions/account.rs | 4 +- .../primitives/types/src/actions/xhub.rs | 3 +- .../contracts/primitives/types/src/crypto.rs | 61 ++++--- .../contracts/primitives/utils/Cargo.toml | 8 +- .../contracts/primitives/utils/src/ecdsa.rs | 1 + .../contracts/primitives/wasm/Cargo.toml | 2 +- .../contracts/primitives/wasm/src/wasm.rs | 2 +- src/components/contracts/rpc/Cargo.toml | 2 +- src/components/contracts/rpc/src/eth.rs | 6 +- src/components/contracts/rpc/src/web3.rs | 2 +- src/components/finutils/Cargo.toml | 16 +- .../finutils/src/bins/stt/init/mod.rs | 4 +- src/components/finutils/src/bins/stt/stt.rs | 18 +-- .../finutils/src/common/ddev/init.rs | 12 +- src/components/finutils/src/common/evm.rs | 7 +- src/components/finutils/src/common/mod.rs | 18 +-- src/components/finutils/src/common/utils.rs | 46 ++++-- .../finutils/src/txn_builder/mod.rs | 149 +++++++++++------- src/components/wallet_mobile/Cargo.toml | 16 +- .../wallet_mobile/src/android/constructor.rs | 4 +- .../wallet_mobile/src/android/evm.rs | 2 +- .../wallet_mobile/src/android/mod.rs | 2 +- .../wallet_mobile/src/android/transfer.rs | 8 +- .../wallet_mobile/src/android/tx_builder.rs | 19 ++- src/components/wallet_mobile/src/ios/evm.rs | 2 +- src/components/wallet_mobile/src/ios/mod.rs | 2 +- .../wallet_mobile/src/ios/tx_builder.rs | 9 +- .../wallet_mobile/src/ios/tx_op_builder.rs | 2 +- .../wallet_mobile/src/rust/account.rs | 4 +- .../wallet_mobile/src/rust/crypto.rs | 59 +++---- .../wallet_mobile/src/rust/data_model.rs | 85 ++++------ .../wallet_mobile/src/rust/transaction.rs | 27 ++-- .../wallet_mobile/src/rust/types.rs | 4 +- src/components/wallet_mobile/src/wasm/mod.rs | 4 +- src/components/wasm/Cargo.toml | 18 +-- src/components/wasm/src/wasm.rs | 95 ++++++----- src/components/wasm/src/wasm_data_model.rs | 76 +++------ src/ledger/Cargo.toml | 33 ++-- src/ledger/src/converter/mod.rs | 9 +- src/ledger/src/data_model/__trash__.rs | 4 +- src/ledger/src/data_model/effects.rs | 20 +-- src/ledger/src/data_model/mod.rs | 138 ++++++++++++---- src/ledger/src/data_model/test.rs | 55 ++++--- src/ledger/src/staking/cosig.rs | 6 +- src/ledger/src/staking/evm.rs | 2 +- src/ledger/src/staking/mod.rs | 11 +- src/ledger/src/staking/ops/claim.rs | 4 +- src/ledger/src/staking/ops/delegation.rs | 10 +- .../src/staking/ops/fra_distribution.rs | 2 +- src/ledger/src/staking/ops/governance.rs | 2 +- src/ledger/src/staking/ops/mint_fra.rs | 14 +- src/ledger/src/staking/ops/replace_staker.rs | 4 +- src/ledger/src/staking/ops/undelegation.rs | 4 +- src/ledger/src/staking/ops/update_staker.rs | 4 +- .../src/staking/ops/update_validator.rs | 2 +- src/ledger/src/store/api_cache.rs | 21 ++- src/ledger/src/store/helpers.rs | 90 ++++------- src/ledger/src/store/mod.rs | 37 +++-- src/ledger/src/store/test.rs | 122 +++++++------- src/ledger/src/store/utils.rs | 16 +- 95 files changed, 983 insertions(+), 781 deletions(-) diff --git a/README.md b/README.md index 1e2696eb3..167950ece 100644 --- a/README.md +++ b/README.md @@ -27,3 +27,5 @@ The primary license for Platform is the Business Source License 1.1 (`BUSL-1.1`) ### Exceptions - All files in `components/contracts` are licensed under `Apache-2.0` + + diff --git a/src/components/abciapp/Cargo.toml b/src/components/abciapp/Cargo.toml index e761d510d..5a0716399 100644 --- a/src/components/abciapp/Cargo.toml +++ b/src/components/abciapp/Cargo.toml @@ -15,18 +15,18 @@ path = "src/bins/abcid.rs" [dependencies] parking_lot = "0.12" -base64 = "0.12" +base64 = "0.13" bincode = "1.3.1" tracing = "0.1" rand = "0.8" -rand_chacha = "0.2" -rand_core = { version = "0.5", default-features = false, features = ["alloc"] } +rand_chacha = "0.3" +rand_core = { version = "0.6", default-features = false, features = ["alloc"] } attohttpc = { version = "0.23", default-features = false, features = ["compress", "json", "tls-rustls"] } serde = { version = "1.0.124", features = ["derive"] } serde_json = "1.0.40" lazy_static = "1.4.0" futures = { version = "0.3.16", features = ["thread-pool"] } -hex = "0.4.2" +hex = "0.4.3" ctrlc = { version = "=3.2.5", features = ["termination"] } protobuf = "2.16" toml = "0.5.8" @@ -41,15 +41,14 @@ percent-encoding = "2.1.0" nix = "0.22.1" -zei = { git = "https://github.com/FindoraNetwork/zei", branch = "stable-main" } +zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } ruc = { version = "1.0.5", default-features = false, features = ["compact"] } abci = { git = "https://github.com/FindoraNetwork/tendermint-abci", tag = "0.7.6" } config = { path = "../config"} ledger = { path = "../../ledger" } -globutils = { git = "https://github.com/FindoraNetwork/platform-lib-utils", tag = "v1.0.0" } -cryptohash = { git = "https://github.com/FindoraNetwork/platform-lib-cryptohash", tag = "v1.0.0" } - +globutils = { git = "https://github.com/FindoraNetwork/platform-lib-utils", branch = "develop" } +cryptohash = { git = "https://github.com/FindoraNetwork/platform-lib-cryptohash", branch = "develop" } finutils = { path = "../finutils" } tempfile = "3.1.0" diff --git a/src/components/abciapp/src/abci/server/callback/mod.rs b/src/components/abciapp/src/abci/server/callback/mod.rs index d0ae04da8..081c1d023 100644 --- a/src/components/abciapp/src/abci/server/callback/mod.rs +++ b/src/components/abciapp/src/abci/server/callback/mod.rs @@ -7,7 +7,7 @@ use ledger::{ data_model::ASSET_TYPE_FRA, staking::{FF_ADDR_EXTRA_120_0000, FF_ADDR_LIST}, }; -use zei::xfr::asset_record::AssetRecordType; +use zei::noah_api::xfr::asset_record::AssetRecordType; mod utils; diff --git a/src/components/abciapp/src/abci/server/callback/utils.rs b/src/components/abciapp/src/abci/server/callback/utils.rs index 109bf5ec2..767fe014e 100644 --- a/src/components/abciapp/src/abci/server/callback/utils.rs +++ b/src/components/abciapp/src/abci/server/callback/utils.rs @@ -6,7 +6,7 @@ use { protobuf::RepeatedField, serde::Serialize, std::time::SystemTime, - zei::xfr::structs::{XfrAmount, XfrAssetType}, + zei::noah_api::xfr::structs::{XfrAmount, XfrAssetType}, }; /// generate attr(tags) for index-ops of tendermint diff --git a/src/components/abciapp/src/abci/staking/mod.rs b/src/components/abciapp/src/abci/staking/mod.rs index d65de6ae3..4b0fd6422 100644 --- a/src/components/abciapp/src/abci/staking/mod.rs +++ b/src/components/abciapp/src/abci/staking/mod.rs @@ -39,6 +39,7 @@ use { ops::{Deref, DerefMut}, sync::atomic::Ordering, }, + zei::XfrPublicKey, }; // The top 50~ candidate validators @@ -365,7 +366,7 @@ pub fn system_prism_mint_pay( let atc = AssetTypeCode { val: mint.asset }; let at = if let Some(mut at) = la.get_asset_type(&atc) { at.properties.issuer = IssuerPublicKey { - key: *BLACK_HOLE_PUBKEY_STAKING, + key: XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY_STAKING), }; if mint.max_supply != 0 { at.properties.asset_rules.max_units = Some(mint.max_supply); @@ -375,7 +376,7 @@ pub fn system_prism_mint_pay( } else { let mut at = AssetType::default(); at.properties.issuer = IssuerPublicKey { - key: *BLACK_HOLE_PUBKEY_STAKING, + key: XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY_STAKING), }; if mint.max_supply != 0 { diff --git a/src/components/abciapp/src/abci/staking/test.rs b/src/components/abciapp/src/abci/staking/test.rs index b046ba6fb..d51880391 100644 --- a/src/components/abciapp/src/abci/staking/test.rs +++ b/src/components/abciapp/src/abci/staking/test.rs @@ -14,10 +14,12 @@ use { rand_chacha::ChaChaRng, rand_core::SeedableRng, ruc::*, - zei::xfr::{ - asset_record::{open_blind_asset_record, AssetRecordType}, - sig::{XfrKeyPair, XfrPublicKey}, - structs::{AssetRecordTemplate, XfrAmount}, + zei::{ + noah_api::xfr::{ + asset_record::{open_blind_asset_record, AssetRecordType}, + structs::{AssetRecordTemplate, XfrAmount}, + }, + {XfrKeyPair, XfrPublicKey}, }, }; @@ -51,7 +53,7 @@ fn check_block_rewards_rate() -> Result<()> { let tx = gen_transfer_tx( &ledger, &root_kp, - &FF_PK_LIST[random::() % FF_PK_LIST.len()], + &XfrPublicKey::from_noah(&FF_PK_LIST[random::() % FF_PK_LIST.len()]), FRA_PRE_ISSUE_AMOUNT / 200, seq_id, ) @@ -99,7 +101,8 @@ 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 binding = XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY); + let target_list = vec![(target_pk, am), (&binding, TX_FEE_MIN)]; let mut trans_builder = TransferOperationBuilder::new(); @@ -118,7 +121,11 @@ fn gen_transfer_tx( continue; } - open_blind_asset_record(&utxo.0.record, &owner_memo, owner_kp) + open_blind_asset_record( + &utxo.0.record.into_noah(), + &owner_memo.map(|o| o.into_noah()), + &owner_kp.into_noah(), + ) .c(d!()) .and_then(|ob| { trans_builder @@ -138,7 +145,7 @@ fn gen_transfer_tx( n, ASSET_TYPE_FRA, AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, - *pk, + pk.into_noah(), ) }); diff --git a/src/components/abciapp/src/api/query_server/query_api/ledger_api.rs b/src/components/abciapp/src/api/query_server/query_api/ledger_api.rs index f40706e47..9c45577a4 100644 --- a/src/components/abciapp/src/api/query_server/query_api/ledger_api.rs +++ b/src/components/abciapp/src/api/query_server/query_api/ledger_api.rs @@ -13,8 +13,8 @@ use { globutils::HashOf, ledger::{ data_model::{ - AssetType, AssetTypeCode, AuthenticatedUtxo, StateCommitmentData, TxnSID, - TxoSID, UnAuthenticatedUtxo, Utxo, + AssetType, AssetTypeCode, AssetTypePrefix, AuthenticatedUtxo, StateCommitmentData, + TxnSID, TxoSID, UnAuthenticatedUtxo, Utxo, }, staking::{ DelegationRwdDetail, DelegationState, Staking, TendermintAddr, @@ -25,7 +25,7 @@ use { ruc::*, serde::{Deserialize, Serialize}, std::{collections::BTreeMap, mem, sync::Arc}, - zei::xfr::{sig::XfrPublicKey, structs::OwnerMemo}, + zei::{OwnerMemo, XfrPublicKey}, }; /// Ping route to check for liveness of API @@ -149,6 +149,27 @@ pub async fn query_asset( } } +/// get_derived asset code according to `AssetTypeCode` +pub async fn get_derived_asset_code( + data: web::Data>>, + info: web::Path, +) -> actix_web::Result> { + let qs = data.read(); + if let Ok(token_code) = AssetTypeCode::new_from_base64(&info) { + let derived_asset_code = AssetTypeCode::from_prefix_and_raw_asset_type_code( + AssetTypePrefix::UserDefined, + &token_code, + &CFG.checkpoint, + qs.ledger_cloned.get_tendermint_height(), + ); + Ok(web::Json(derived_asset_code.to_base64())) + } else { + Err(actix_web::error::ErrorBadRequest( + "Invalid asset definition encoding.", + )) + } +} + /// query tx according to `TxnSID` pub async fn query_txn( data: web::Data>>, @@ -698,6 +719,7 @@ pub enum ApiRoutes { UtxoSidList, AssetIssuanceNum, AssetToken, + GetDerivedAssetCode, GlobalState, TxnSid, TxnSidLight, @@ -717,6 +739,7 @@ impl NetworkRoute for ApiRoutes { ApiRoutes::UtxoSidList => "utxo_sid_list", ApiRoutes::AssetIssuanceNum => "asset_issuance_num", ApiRoutes::AssetToken => "asset_token", + ApiRoutes::GetDerivedAssetCode => "get_derived_asset_code", ApiRoutes::GlobalState => "global_state", ApiRoutes::TxnSid => "txn_sid", ApiRoutes::TxnSidLight => "txn_sid_light", diff --git a/src/components/abciapp/src/api/query_server/query_api/mod.rs b/src/components/abciapp/src/api/query_server/query_api/mod.rs index e90d15ae2..325a078d1 100644 --- a/src/components/abciapp/src/api/query_server/query_api/mod.rs +++ b/src/components/abciapp/src/api/query_server/query_api/mod.rs @@ -33,10 +33,7 @@ use { sync::Arc, }, tracing::info, - zei::{ - serialization::ZeiFromToBytes, - xfr::{sig::XfrPublicKey, structs::OwnerMemo}, - }, + zei::{noah_algebra::serialization::NoahFromToBytes, OwnerMemo, XfrPublicKey}, }; /// Returns the git commit hash and commit date of this build @@ -160,7 +157,7 @@ pub async fn get_created_assets( info: web::Path, ) -> actix_web::Result>> { // Convert from base64 representation - let key: XfrPublicKey = XfrPublicKey::zei_from_bytes( + let key: XfrPublicKey = XfrPublicKey::noah_from_bytes( &b64dec(&*info) .c(d!()) .map_err(|e| error::ErrorBadRequest(e.to_string()))?, @@ -178,7 +175,7 @@ pub async fn get_issued_records( info: web::Path, ) -> actix_web::Result)>>> { // Convert from base64 representation - let key: XfrPublicKey = XfrPublicKey::zei_from_bytes( + let key: XfrPublicKey = XfrPublicKey::noah_from_bytes( &b64dec(&*info) .c(d!()) .map_err(|e| error::ErrorBadRequest(e.to_string()))?, @@ -388,7 +385,7 @@ pub async fn get_related_txns( info: web::Path, ) -> actix_web::Result>> { // Convert from base64 representation - let key: XfrPublicKey = XfrPublicKey::zei_from_bytes( + let key: XfrPublicKey = XfrPublicKey::noah_from_bytes( &b64dec(&*info) .c(d!()) .map_err(|e| error::ErrorBadRequest(e.to_string()))?, @@ -452,8 +449,8 @@ pub async fn get_total_supply( data: web::Data>>, ) -> actix_web::Result>, actix_web::error::Error> { let l = data.read(); - let burn_pubkey = *BLACK_HOLE_PUBKEY; - let extra_pubkey = *FF_PK_EXTRA_120_0000; + let burn_pubkey = XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY); + let extra_pubkey = XfrPublicKey::from_noah(&FF_PK_EXTRA_120_0000); let burn_balance = l .ledger_cloned @@ -596,6 +593,10 @@ impl QueryApi { &ApiRoutes::AssetToken.with_arg_template("code"), web::get().to(query_asset), ) + .route( + &ApiRoutes::GetDerivedAssetCode.with_arg_template("code"), + web::get().to(get_derived_asset_code), + ) .route( &ApiRoutes::GlobalState.route(), web::get().to(query_global_state), diff --git a/src/components/abciapp/src/api/query_server/query_api/server.rs b/src/components/abciapp/src/api/query_server/query_api/server.rs index f05e5ebf2..a1198a4d8 100644 --- a/src/components/abciapp/src/api/query_server/query_api/server.rs +++ b/src/components/abciapp/src/api/query_server/query_api/server.rs @@ -15,7 +15,7 @@ use { parking_lot::{Condvar, Mutex, RwLock}, ruc::*, std::{collections::HashSet, sync::Arc}, - zei::xfr::structs::OwnerMemo, + zei::OwnerMemo, }; lazy_static! { diff --git a/src/components/config/Cargo.toml b/src/components/config/Cargo.toml index ec2670aee..fc41b5e6b 100644 --- a/src/components/config/Cargo.toml +++ b/src/components/config/Cargo.toml @@ -16,7 +16,7 @@ serde_json = "1.0" serde-strz = "1.1.1" toml = "0.5.8" -globutils = { git = "https://github.com/FindoraNetwork/platform-lib-utils", tag = "v1.0.0" } +globutils = { git = "https://github.com/FindoraNetwork/platform-lib-utils", branch = "develop" } [target.'cfg(target_os= "linux")'.dependencies] btm = "0.1.6" diff --git a/src/components/config/src/abci/mod.rs b/src/components/config/src/abci/mod.rs index 66b6ec98b..9d92ac6ae 100644 --- a/src/components/config/src/abci/mod.rs +++ b/src/components/config/src/abci/mod.rs @@ -103,6 +103,9 @@ pub struct CheckPointConfig { #[serde(default = "def_utxo_asset_prefix_height")] pub utxo_asset_prefix_height: u64, + #[serde(default = "def_utxo_asset_prefix_height_2nd_update")] + pub utxo_asset_prefix_height_2nd_update: u64, + #[serde(default = "def_prismxx_inital_height")] pub prismxx_inital_height: i64, @@ -172,6 +175,10 @@ fn def_prismxx_inital_height() -> i64 { DEFAULT_CHECKPOINT_CONFIG.prismxx_inital_height } +fn def_utxo_asset_prefix_height_2nd_update() -> u64 { + DEFAULT_CHECKPOINT_CONFIG.utxo_asset_prefix_height_2nd_update +} + fn def_prism_bridge_address() -> String { DEFAULT_CHECKPOINT_CONFIG.prism_bridge_address.clone() } @@ -255,6 +262,7 @@ lazy_static! { check_signatures_num: 0, fix_deliver_tx_revert_nonce_height: 0, utxo_asset_prefix_height: 0, + utxo_asset_prefix_height_2nd_update: 0, prismxx_inital_height: 128, prism_bridge_address: "0x5f9552fEd754F20B636C996DaDB32806554Bb995".to_owned(), remove_fake_staking_hash: 0, @@ -302,6 +310,7 @@ lazy_static! { check_signatures_num: 4004430, fix_deliver_tx_revert_nonce_height: 4004430, utxo_asset_prefix_height: 4004430, + utxo_asset_prefix_height_2nd_update: 5000_0000, prismxx_inital_height: 4004430, prism_bridge_address: "0x4672372fDB139B7295Fc59b55b43EC5fF2761A0b".to_owned(), remove_fake_staking_hash: 4004430, diff --git a/src/components/contracts/baseapp/Cargo.toml b/src/components/contracts/baseapp/Cargo.toml index 5a2598c54..65cdd155b 100644 --- a/src/components/contracts/baseapp/Cargo.toml +++ b/src/components/contracts/baseapp/Cargo.toml @@ -22,10 +22,10 @@ protobuf = "2.16" ruc = "1.0" serde = {version = "1.0.124", features = ["derive"]} serde_json = "1.0.40" -storage = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.5" } -fin_db = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.5" } -sha3 = "0.8" -zei = { git = "https://github.com/FindoraNetwork/zei", branch = "stable-main" } +storage = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.6" } +fin_db = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.6" } +sha3 = "0.10" +zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } config = { path = "../../config"} diff --git a/src/components/contracts/baseapp/src/staking.rs b/src/components/contracts/baseapp/src/staking.rs index a99f360f2..74cfc7e97 100644 --- a/src/components/contracts/baseapp/src/staking.rs +++ b/src/components/contracts/baseapp/src/staking.rs @@ -15,7 +15,8 @@ use module_evm::{ use ruc::{d, Result, RucResult}; use sha3::{Digest, Keccak256}; use std::{collections::BTreeMap, str::FromStr}; -use zei::xfr::sig::XfrPublicKey; +use zei::noah_algebra::prelude::NoahFromToBytes; +use zei::XfrPublicKey; impl EVMStaking for BaseApp { fn import_validators( @@ -41,7 +42,7 @@ impl EVMStaking for BaseApp { memo: serde_json::to_string(&v.memo).c(d!())?, rate: mapping_rate(v.commission_rate), staker: mapping_address(&v.id), - staker_pk: v.id.as_bytes().to_vec(), + staker_pk: v.id.noah_to_bytes(), power: U256::from(v.td_power), begin_block: U256::from(begin_block), }); @@ -111,7 +112,7 @@ impl EVMStaking for BaseApp { delegators.push(DelegatorParam { validator: *validator_address, delegator: delegator_address, - delegator_pk: public_key.as_bytes().to_vec(), + delegator_pk: public_key.noah_to_bytes(), bound_amount, unbound_amount, }); @@ -182,7 +183,7 @@ impl EVMStaking for BaseApp { memo: String, rate: [u64; 2], ) -> Result<()> { - let staker_pk = staker.as_bytes().to_vec(); + let staker_pk = staker.noah_to_bytes(); let staker_address = mapping_address(staker); let amount = @@ -224,7 +225,7 @@ impl EVMStaking for BaseApp { amount: u64, td_addr: &[u8], ) -> Result<()> { - let delegator_pk = delegator.as_bytes().to_vec(); + let delegator_pk = delegator.noah_to_bytes(); let delegator_address = mapping_address(delegator); let amount = @@ -376,6 +377,6 @@ fn mapping_rate(rate: [u64; 2]) -> U256 { } pub fn mapping_address(pk: &XfrPublicKey) -> H160 { - let result = Keccak256::digest(pk.as_bytes()); + let result = Keccak256::digest(pk.noah_to_bytes()); H160::from_slice(&result.as_slice()[..20]) } diff --git a/src/components/contracts/modules/account/Cargo.toml b/src/components/contracts/modules/account/Cargo.toml index 5fedd1cad..41ab844e4 100644 --- a/src/components/contracts/modules/account/Cargo.toml +++ b/src/components/contracts/modules/account/Cargo.toml @@ -15,7 +15,7 @@ primitive-types = { version = "0.11.1", default-features = false, features = ["r ruc = "1.0" serde = { version = "1.0.124", features = ["derive"] } serde_json = "1.0.64" -storage = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.5" } +storage = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.6" } # primitives, don't depend on any modules fp-core = { path = "../../primitives/core" } @@ -26,7 +26,7 @@ enterprise-web3 = { path = "../../primitives/enterprise-web3" } config = { path = "../../../config"} [dev-dependencies] -rand_chacha = "0.2" +rand_chacha = "0.3" parking_lot = "0.12" -zei = { git = "https://github.com/FindoraNetwork/zei", branch = "stable-main" } -fin_db = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.5" } +zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } +fin_db = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.6" } diff --git a/src/components/contracts/modules/account/src/tests.rs b/src/components/contracts/modules/account/src/tests.rs index aa07f72f4..2ce7dbc7f 100644 --- a/src/components/contracts/modules/account/src/tests.rs +++ b/src/components/contracts/modules/account/src/tests.rs @@ -11,7 +11,7 @@ use rand_chacha::rand_core::SeedableRng; use rand_chacha::ChaChaRng; use std::{env::temp_dir, sync::Arc, time::SystemTime}; use storage::state::ChainState; -use zei::xfr::sig::XfrKeyPair; +use zei::XfrKeyPair; fn setup() -> Context { let time = SystemTime::now() diff --git a/src/components/contracts/modules/ethereum/Cargo.toml b/src/components/contracts/modules/ethereum/Cargo.toml index c40e523aa..ca374d979 100644 --- a/src/components/contracts/modules/ethereum/Cargo.toml +++ b/src/components/contracts/modules/ethereum/Cargo.toml @@ -19,7 +19,7 @@ rlp = "0.5" ruc = "1.0" serde = { version = "1.0.124", features = ["derive"] } serde_json = "1.0.64" -sha3 = "0.8" +sha3 = "0.10" lazy_static = "1.4.0" # primitives, don't depend on any modules @@ -37,8 +37,8 @@ enterprise-web3 = { path = "../../primitives/enterprise-web3" } baseapp = { path = "../../baseapp" } fp-mocks = { path = "../../primitives/mocks" } module-account = { path = "../account" } -storage = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.5" } -fin_db = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.5" } +storage = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.6" } +fin_db = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.6" } [features] default = [] diff --git a/src/components/contracts/modules/ethereum/src/impls.rs b/src/components/contracts/modules/ethereum/src/impls.rs index f28cde195..7c6d7567d 100644 --- a/src/components/contracts/modules/ethereum/src/impls.rs +++ b/src/components/contracts/modules/ethereum/src/impls.rs @@ -73,7 +73,7 @@ impl App { let pubkey = secp256k1_ecdsa_recover(&sig, &msg).ok()?; Some(H160::from(H256::from_slice( - Keccak256::digest(&pubkey).as_slice(), + Keccak256::digest(pubkey).as_slice(), ))) } diff --git a/src/components/contracts/modules/evm/Cargo.toml b/src/components/contracts/modules/evm/Cargo.toml index 4f57c3c6e..b865a7885 100644 --- a/src/components/contracts/modules/evm/Cargo.toml +++ b/src/components/contracts/modules/evm/Cargo.toml @@ -22,9 +22,9 @@ ruc = "1.0" serde = { version = "1.0.124", features = ["derive"] } serde_json = "1.0.64" sha3 = { version = "0.10", default-features = false } -hex = "0.4.2" +hex = "0.4.3" ethabi = "17.1.0" -zei = { git = "https://github.com/FindoraNetwork/zei", branch = "stable-main" } +zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } protobuf = "2.16" # primitives, don't depend on any modules @@ -35,8 +35,8 @@ fp-traits = { path = "../../primitives/traits" } fp-types = { path = "../../primitives/types" } fp-utils = { path = "../../primitives/utils" } config = { path = "../../../config"} -storage = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.5" } -fin_db = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.5" } +storage = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.6" } +fin_db = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.6" } ledger = { path = "../../../../ledger" } enterprise-web3 = { path = "../../primitives/enterprise-web3" } module-ethereum = { path = "../ethereum" } @@ -44,7 +44,7 @@ module-ethereum = { path = "../ethereum" } [dev-dependencies] baseapp = { path = "../../baseapp" } fp-mocks = { path = "../../primitives/mocks" } -hex = "0.4.2" +hex = "0.4.3" module-account = { path = "../account" } serde_json = "1.0.64" diff --git a/src/components/contracts/modules/evm/precompile/anemoi/Cargo.toml b/src/components/contracts/modules/evm/precompile/anemoi/Cargo.toml index 05897e824..c8e970ed0 100644 --- a/src/components/contracts/modules/evm/precompile/anemoi/Cargo.toml +++ b/src/components/contracts/modules/evm/precompile/anemoi/Cargo.toml @@ -16,8 +16,7 @@ evm-precompile-utils = { path = "../utils"} tracing = "0.1" module-evm = { path = "../../../../modules/evm"} num_enum = { version = "0.5.4", default-features = false } -noah-algebra = { git = "https://github.com/FindoraNetwork/noah", tag = "v0.4.3-1" } -noah-crypto = { git = "https://github.com/FindoraNetwork/noah", tag = "v0.4.3-1" } +platform-lib-noah = { git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } [dev-dependencies] baseapp = { path = "../../../../baseapp" } diff --git a/src/components/contracts/modules/evm/precompile/anemoi/benches/anemoi.rs b/src/components/contracts/modules/evm/precompile/anemoi/benches/anemoi.rs index a03a28479..98fdd54e2 100644 --- a/src/components/contracts/modules/evm/precompile/anemoi/benches/anemoi.rs +++ b/src/components/contracts/modules/evm/precompile/anemoi/benches/anemoi.rs @@ -1,4 +1,4 @@ -use evm_precompile_anemoi::Anemoi; +use evm_precompile_anemoi::Anemoi381; use noah_algebra::bls12_381::BLSScalar; use noah_algebra::prelude::Scalar; use std::time::Instant; @@ -19,10 +19,10 @@ fn main() { println!("Benchmarking 2 field elements for 1000 times"); let start = Instant::now(); for _ in 0..1000 { - _ = Anemoi::execute_with_input_and_gas(&data[0..64], None); + _ = Anemoi381::execute_with_input_and_gas(&data[0..64], None); } let time = start.elapsed().as_nanos() / 1000; - let gas = Anemoi::GAS_PER_PERM; + let gas = Anemoi381::GAS_PER_PERM; println!("Result = {} ns every time", time); println!("Cost = {} every time", gas); println!("NS per gas = {}", (time as f64) / (gas as f64)); @@ -30,10 +30,10 @@ fn main() { println!("Benchmarking 32 field elements for 1000 times"); let start = Instant::now(); for _ in 0..1000 { - _ = Anemoi::execute_with_input_and_gas(&data[0..1024], None); + _ = Anemoi381::execute_with_input_and_gas(&data[0..1024], None); } let time = start.elapsed().as_nanos() / 1000; - let gas = Anemoi::GAS_PER_PERM * 11; + let gas = Anemoi381::GAS_PER_PERM * 11; println!("Result = {} ns every time", time); println!("Cost = {} every time", gas); println!("NS per gas = {}", (time as f64) / (gas as f64)); diff --git a/src/components/contracts/modules/evm/precompile/anemoi/src/lib.rs b/src/components/contracts/modules/evm/precompile/anemoi/src/lib.rs index 49e824828..5204468aa 100644 --- a/src/components/contracts/modules/evm/precompile/anemoi/src/lib.rs +++ b/src/components/contracts/modules/evm/precompile/anemoi/src/lib.rs @@ -1,16 +1,21 @@ use evm::executor::stack::{PrecompileFailure, PrecompileOutput}; use evm::{Context, ExitError, ExitSucceed}; use module_evm::precompile::{FinState, Precompile, PrecompileId, PrecompileResult}; -use noah_algebra::bls12_381::BLSScalar; -use noah_algebra::prelude::Scalar; -use noah_crypto::basic::anemoi_jive::{AnemoiJive, AnemoiJive381}; +use platform_lib_noah::noah_algebra::{ + bls12_381::BLSScalar, bn254::BN254Scalar, prelude::Scalar, +}; +#[allow(deprecated)] +use platform_lib_noah::noah_crypto::anemoi_jive::{ + bls12_381_deprecated::AnemoiJive381Deprecated, AnemoiJive, AnemoiJive254, +}; -/// The Anemoi precompile -pub struct Anemoi; +/// The Anemoi precompile for BLS12-381 +pub struct Anemoi381; -impl Anemoi { +impl Anemoi381 { pub const GAS_PER_PERM: u64 = 125000; + #[allow(deprecated)] pub fn execute_with_input_and_gas( input: &[u8], target_gas: Option, @@ -55,7 +60,8 @@ impl Anemoi { } } - let mut res = AnemoiJive381::eval_variable_length_hash(&field_elems).to_bytes(); + let mut res = + AnemoiJive381Deprecated::eval_variable_length_hash(&field_elems).to_bytes(); res.reverse(); Ok(PrecompileOutput { @@ -67,13 +73,92 @@ impl Anemoi { } } -impl PrecompileId for Anemoi { +impl PrecompileId for Anemoi381 { fn contract_id() -> u64 { 0x2002 } } -impl Precompile for Anemoi { +impl Precompile for Anemoi381 { + fn execute( + input: &[u8], + target_gas: Option, + _context: &Context, + _state: &FinState, + ) -> PrecompileResult { + Self::execute_with_input_and_gas(input, target_gas) + } +} + +/// The Anemoi precompile for BN254 +pub struct Anemoi254; + +impl Anemoi254 { + pub const GAS_PER_PERM: u64 = 125000; + + pub fn execute_with_input_and_gas( + input: &[u8], + target_gas: Option, + ) -> PrecompileResult { + if input.len() % 32 != 0 { + return Err(PrecompileFailure::Error { + exit_status: ExitError::Other( + "input must be multiplies of 32 bytes".into(), + ), + }); + } + + let num_elems = input.len() / 32; + + let gas_cost = ((num_elems + 2) / 3) as u64 * Self::GAS_PER_PERM; + if let Some(gas_left) = target_gas { + if gas_left < gas_cost { + return Err(PrecompileFailure::Error { + exit_status: ExitError::OutOfGas, + }); + } + }; + + let mut field_elems = Vec::with_capacity(num_elems); + + for i in 0..num_elems { + let res = BN254Scalar::from_bytes( + &input[i * 32..(i + 1) * 32] + .iter() + .rev() + .copied() + .collect::>(), + ); + if let Ok(res) = res { + field_elems.push(res); + } else { + return Err(PrecompileFailure::Error { + exit_status: ExitError::Other( + "Cannot convert bytes to field elements".into(), + ), + }); + } + } + + let mut res = AnemoiJive254::eval_variable_length_hash(&field_elems).to_bytes(); + res.reverse(); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + cost: gas_cost, + output: res.to_vec(), + logs: Default::default(), + }) + } +} + +impl PrecompileId for Anemoi254 { + fn contract_id() -> u64 { + 0x2003 + } +} + +impl Precompile for Anemoi254 { fn execute( input: &[u8], target_gas: Option, diff --git a/src/components/contracts/modules/evm/precompile/basic/Cargo.toml b/src/components/contracts/modules/evm/precompile/basic/Cargo.toml index 5f60c3d6e..e8b9ad551 100644 --- a/src/components/contracts/modules/evm/precompile/basic/Cargo.toml +++ b/src/components/contracts/modules/evm/precompile/basic/Cargo.toml @@ -16,7 +16,7 @@ harness = false [dependencies] evm = { version = "0.35.0", default-features = false, features = ["with-serde"] } module-evm = { path = "../../../../modules/evm"} -ripemd160 = "0.9" +ripemd = "0.1" # primitives #fp-core = { path = "../../../../primitives/core" } diff --git a/src/components/contracts/modules/evm/precompile/basic/src/lib.rs b/src/components/contracts/modules/evm/precompile/basic/src/lib.rs index 4a8ebab8d..c1cf4662b 100644 --- a/src/components/contracts/modules/evm/precompile/basic/src/lib.rs +++ b/src/components/contracts/modules/evm/precompile/basic/src/lib.rs @@ -98,10 +98,10 @@ impl LinearCostPrecompile for Ripemd160 { input: &[u8], _cost: u64, ) -> core::result::Result<(ExitSucceed, Vec), PrecompileFailure> { - use ripemd160::Digest; + use ripemd::Digest; let mut ret = [0u8; 32]; - ret[12..32].copy_from_slice(&ripemd160::Ripemd160::digest(input)); + ret[12..32].copy_from_slice(&ripemd::Ripemd160::digest(input)); Ok((ExitSucceed::Returned, ret.to_vec())) } } diff --git a/src/components/contracts/modules/evm/precompile/frc20/Cargo.toml b/src/components/contracts/modules/evm/precompile/frc20/Cargo.toml index e5845d173..b4d318269 100644 --- a/src/components/contracts/modules/evm/precompile/frc20/Cargo.toml +++ b/src/components/contracts/modules/evm/precompile/frc20/Cargo.toml @@ -22,4 +22,4 @@ config = { path = "../../../../../config" } [dev-dependencies] baseapp = { path = "../../../../baseapp" } fp-mocks = { path = "../../../../primitives/mocks" } -sha3 = "0.8" +sha3 = "0.10" diff --git a/src/components/contracts/modules/evm/precompile/modexp/Cargo.toml b/src/components/contracts/modules/evm/precompile/modexp/Cargo.toml index 1e046763a..27630ce3b 100644 --- a/src/components/contracts/modules/evm/precompile/modexp/Cargo.toml +++ b/src/components/contracts/modules/evm/precompile/modexp/Cargo.toml @@ -15,5 +15,5 @@ num = { version = "0.4", features = ["alloc"] } ethereum-types = { version = "0.13.1", default-features = false } [dev-dependencies] -hex = "0.4.2" +hex = "0.4.3" fp-mocks = { path = "../../../../primitives/mocks" } diff --git a/src/components/contracts/modules/evm/precompile/src/lib.rs b/src/components/contracts/modules/evm/precompile/src/lib.rs index 994ec14ae..266b7d6aa 100644 --- a/src/components/contracts/modules/evm/precompile/src/lib.rs +++ b/src/components/contracts/modules/evm/precompile/src/lib.rs @@ -3,7 +3,7 @@ use evm::{executor::stack::PrecompileSet, Context}; use module_evm::precompile::{Precompile, PrecompileResult}; use std::marker::PhantomData; -use evm_precompile_anemoi::Anemoi; +use evm_precompile_anemoi::{Anemoi254, Anemoi381}; use evm_precompile_basic::{ECRecover, Identity, Ripemd160, Sha256}; use evm_precompile_blake2::Blake2F; use evm_precompile_bn128::{Bn128Add, Bn128Mul, Bn128Pairing}; @@ -76,8 +76,11 @@ where a if a == H160::from_low_u64_be(FRC20::::contract_id()) => { Some(FRC20::::execute(input, target_gas, context, ctx)) } - a if a == H160::from_low_u64_be(Anemoi::contract_id()) => { - Some(Anemoi::execute(input, target_gas, context, ctx)) + a if a == H160::from_low_u64_be(Anemoi381::contract_id()) => { + Some(Anemoi381::execute(input, target_gas, context, ctx)) + } + a if a == H160::from_low_u64_be(Anemoi254::contract_id()) => { + Some(Anemoi254::execute(input, target_gas, context, ctx)) } //a if a == H160::from_low_u64_be(EthPairing::contract_id()) => { // Some(EthPairing::execute(input, target_gas, context, ctx)) diff --git a/src/components/contracts/modules/evm/precompile/utils/macro/Cargo.toml b/src/components/contracts/modules/evm/precompile/utils/macro/Cargo.toml index e3eb436e3..f0e736630 100644 --- a/src/components/contracts/modules/evm/precompile/utils/macro/Cargo.toml +++ b/src/components/contracts/modules/evm/precompile/utils/macro/Cargo.toml @@ -15,5 +15,5 @@ path = "tests/tests.rs" [dependencies] quote = "1.0" proc-macro2 = "1.0" -sha3 = "0.8" +sha3 = "0.10" syn = { version = "1.0", features = ["full", "fold", "extra-traits", "visit"] } diff --git a/src/components/contracts/modules/evm/precompile/utils/macro/src/lib.rs b/src/components/contracts/modules/evm/precompile/utils/macro/src/lib.rs index d1aad50a5..cb5263844 100644 --- a/src/components/contracts/modules/evm/precompile/utils/macro/src/lib.rs +++ b/src/components/contracts/modules/evm/precompile/utils/macro/src/lib.rs @@ -64,9 +64,7 @@ pub fn generate_function_selector(_: TokenStream, input: TokenStream) -> TokenSt Some((_, Expr::Lit(ExprLit { lit, .. }))) => { if let Lit::Str(lit_str) = lit { let selector = u32::from_be_bytes( - Keccak256::digest(lit_str.value().as_ref())[..4] - .try_into() - .unwrap(), + Keccak256::digest(lit_str.value())[..4].try_into().unwrap(), ); ident_expressions.push(variant.ident); variant_expressions.push(Expr::Lit(ExprLit { diff --git a/src/components/contracts/modules/evm/src/lib.rs b/src/components/contracts/modules/evm/src/lib.rs index 60d6400d2..9ded144a5 100644 --- a/src/components/contracts/modules/evm/src/lib.rs +++ b/src/components/contracts/modules/evm/src/lib.rs @@ -50,7 +50,8 @@ use std::marker::PhantomData; use std::str::FromStr; use system_contracts::{SystemContracts, SYSTEM_ADDR}; use utils::parse_evm_staking_coinbase_mint_event; -use zei::xfr::sig::XfrPublicKey; +use zei::noah_algebra::serialization::NoahFromToBytes; +use zei::XfrPublicKey; use crate::utils::parse_evm_staking_mint_event; @@ -149,7 +150,7 @@ impl App { let asset = Token::FixedBytes(Vec::from(_asset)); - let from = Token::Bytes(from.as_bytes().to_vec()); + let from = Token::Bytes(from.noah_to_bytes()); let to = Token::Address(*to); diff --git a/src/components/contracts/modules/evm/src/utils.rs b/src/components/contracts/modules/evm/src/utils.rs index a10e5a9c8..8ff1898d3 100644 --- a/src/components/contracts/modules/evm/src/utils.rs +++ b/src/components/contracts/modules/evm/src/utils.rs @@ -7,11 +7,9 @@ use fp_types::actions::xhub::NonConfidentialOutput; use ledger::data_model::ASSET_TYPE_FRA; use ruc::*; use zei::{ - serialization::ZeiFromToBytes, - xfr::{ - sig::XfrPublicKey, - structs::{AssetType, ASSET_TYPE_LENGTH}, - }, + noah_algebra::serialization::NoahFromToBytes, + noah_api::xfr::structs::{AssetType, ASSET_TYPE_LENGTH}, + XfrPublicKey, }; pub fn deposit_asset_event() -> Event { @@ -72,7 +70,7 @@ pub fn parse_deposit_asset_event(data: Vec) -> Result .clone() .into_bytes() .unwrap_or_default(); - let target = XfrPublicKey::zei_from_bytes(receiver.as_slice()).c(d!())?; + let target = XfrPublicKey::noah_from_bytes(receiver.as_slice()).c(d!())?; let amount = result.params[2].value.clone().into_uint().c(d!())?; @@ -235,7 +233,8 @@ pub fn parse_evm_staking_mint_event( let result = event.parse_log(log).map_err(|e| eg!(e))?; let public_key_bytes = result.params[0].value.clone().into_bytes().c(d!())?; - let public_key = XfrPublicKey::zei_from_bytes(public_key_bytes.as_slice())?; + let public_key = + XfrPublicKey::noah_from_bytes(public_key_bytes.as_slice()).c(d!())?; let amount = result.params[1].value.clone().into_uint().c(d!())?.as_u64(); @@ -292,7 +291,8 @@ pub fn parse_evm_staking_coinbase_mint_event( if public_key_bytes.is_empty() { return Ok((delegator, None, amount)); } - let public_key = XfrPublicKey::zei_from_bytes(public_key_bytes.as_slice())?; + let public_key = + XfrPublicKey::noah_from_bytes(public_key_bytes.as_slice()).c(d!())?; Ok((delegator, Some(public_key), amount)) } diff --git a/src/components/contracts/primitives/core/Cargo.toml b/src/components/contracts/primitives/core/Cargo.toml index e265036a7..ce27fb03e 100644 --- a/src/components/contracts/primitives/core/Cargo.toml +++ b/src/components/contracts/primitives/core/Cargo.toml @@ -16,9 +16,9 @@ parking_lot = "0.12" primitive-types = { version = "0.11.1", default-features = false, features = ["rlp", "byteorder", "serde"] } ruc = "1.0" serde = { version = "1.0.124", features = ["derive"] } -storage = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.5", optional = true } -fin_db = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.5", optional = true } -serde_with = { version = "1.9.4"} +storage = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.6", optional = true } +fin_db = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.6", optional = true } +serde_with = { version = "2.0.1"} # primitives fp-types = { path = "../types" } diff --git a/src/components/contracts/primitives/mocks/Cargo.toml b/src/components/contracts/primitives/mocks/Cargo.toml index de327d5c9..681dc54b4 100644 --- a/src/components/contracts/primitives/mocks/Cargo.toml +++ b/src/components/contracts/primitives/mocks/Cargo.toml @@ -14,11 +14,11 @@ ethereum = { version = "0.12.0", default-features = false, features = ["with-ser lazy_static = "1.4.0" libsecp256k1 = { version = "0.7", features = ["static-context", "hmac"] } primitive-types = { version = "0.11.1", default-features = false, features = ["rlp", "byteorder", "serde"] } -rand_chacha = "0.2" +rand_chacha = "0.3" rlp = "0.5" serde_json = "1.0" -sha3 = "0.8" -zei = { git = "https://github.com/FindoraNetwork/zei", branch = "stable-main" } +sha3 = "0.10" +zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } # primitives fp-traits = { path = "../traits" } diff --git a/src/components/contracts/primitives/mocks/src/lib.rs b/src/components/contracts/primitives/mocks/src/lib.rs index 37819ccf9..687ae1a52 100644 --- a/src/components/contracts/primitives/mocks/src/lib.rs +++ b/src/components/contracts/primitives/mocks/src/lib.rs @@ -20,7 +20,7 @@ use std::env::temp_dir; use std::path::PathBuf; use std::sync::Mutex; use std::time::SystemTime; -use zei::xfr::sig::XfrKeyPair; +use zei::XfrKeyPair; lazy_static! { pub static ref BASE_APP: Mutex = Mutex::new( @@ -68,7 +68,7 @@ pub fn build_signed_transaction( let signer: Address = who.get_pk().into(); let msg = serde_json::to_vec(&(function.clone(), extra.clone())).unwrap(); - let sig = who.get_sk_ref().sign(msg.as_slice(), who.get_pk_ref()); + let sig = who.get_sk_ref().sign(msg.as_slice()).unwrap(); let signature = MultiSignature::from(sig); UncheckedTransaction::new_signed(function, signer, signature, extra) diff --git a/src/components/contracts/primitives/storage/Cargo.toml b/src/components/contracts/primitives/storage/Cargo.toml index bab9bfc4c..6dca51852 100644 --- a/src/components/contracts/primitives/storage/Cargo.toml +++ b/src/components/contracts/primitives/storage/Cargo.toml @@ -14,12 +14,12 @@ paste = "1.0" ruc = "1.0" serde = { version = "1.0.124", features = ["derive"] } serde_json = "1.0" -sha2 = "0.9.5" -storage = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.5" } +sha2 = "0.10" +storage = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.6" } # primitives fp-core = { path = "../core" } config = { path = "../../../config"} [dev-dependencies] -temp_db = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.5" } +temp_db = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.6" } diff --git a/src/components/contracts/primitives/types/Cargo.toml b/src/components/contracts/primitives/types/Cargo.toml index 8b974d520..23795d7ff 100644 --- a/src/components/contracts/primitives/types/Cargo.toml +++ b/src/components/contracts/primitives/types/Cargo.toml @@ -11,21 +11,21 @@ readme = "README.md" [dependencies] bech32 = "0.7.2" ethereum = { version = "0.12.0", default-features = false, features = ["with-serde"] } -hex = "0.4.2" +hex = "0.4.3" -globutils = { git = "https://github.com/FindoraNetwork/platform-lib-utils", tag = "v1.0.0" } +globutils = { git = "https://github.com/FindoraNetwork/platform-lib-utils", branch = "develop" } libsecp256k1 = { version = "0.7", features = ["static-context", "hmac"] } primitive-types = { version = "0.11.1", default-features = false, features = ["rlp", "byteorder", "serde"] } ruc = "1.0" serde = { version = "1.0.124", features = ["derive"] } serde_json = "1.0" -sha3 = "0.8" -zei = { git = "https://github.com/FindoraNetwork/zei", branch = "stable-main" } -fixed-hash = "0.7.0" +sha3 = "0.10" +zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } +fixed-hash = "0.8.0" # primitives fp-utils = { path = "../utils" } [dev-dependencies] -rand_chacha = "0.2" +rand_chacha = "0.3" diff --git a/src/components/contracts/primitives/types/src/actions/account.rs b/src/components/contracts/primitives/types/src/actions/account.rs index 701e091f9..dc608aa2a 100644 --- a/src/components/contracts/primitives/types/src/actions/account.rs +++ b/src/components/contracts/primitives/types/src/actions/account.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -use zei::xfr::sig::XfrPublicKey; -use zei::xfr::structs::AssetType; +use zei::XfrPublicKey; +use zei::noah_api::xfr::structs::AssetType; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum Action { diff --git a/src/components/contracts/primitives/types/src/actions/xhub.rs b/src/components/contracts/primitives/types/src/actions/xhub.rs index 622de4050..f74e53676 100644 --- a/src/components/contracts/primitives/types/src/actions/xhub.rs +++ b/src/components/contracts/primitives/types/src/actions/xhub.rs @@ -1,6 +1,5 @@ use serde::{Deserialize, Serialize}; -use zei::xfr::sig::XfrPublicKey; -use zei::xfr::structs::AssetType; +use zei::{noah_api::xfr::structs::AssetType, XfrPublicKey}; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum Action { diff --git a/src/components/contracts/primitives/types/src/crypto.rs b/src/components/contracts/primitives/types/src/crypto.rs index 7dcb34a4a..f29de6cb8 100644 --- a/src/components/contracts/primitives/types/src/crypto.rs +++ b/src/components/contracts/primitives/types/src/crypto.rs @@ -1,17 +1,19 @@ -use bech32::{FromBase32, ToBase32}; -use core::convert::TryFrom; -use core::fmt::Formatter; -use core::str::FromStr; -use fp_utils::{ecdsa, hashing::keccak_256}; -use globutils::wallet; -use hex::FromHex; -use primitive_types::{H160, H256}; -use ruc::{d, eg, RucResult}; -use serde::{Deserialize, Serialize}; -use sha3::{Digest, Keccak256}; -use std::ops::{Deref, DerefMut}; -use zei::serialization::ZeiFromToBytes; -use zei::xfr::sig::{XfrPublicKey, XfrSignature}; +use { + bech32::{FromBase32, ToBase32}, + core::convert::TryFrom, + core::fmt::Formatter, + core::str::FromStr, + fp_utils::{ecdsa, hashing::keccak_256}, + globutils::wallet, + hex::FromHex, + primitive_types::{H160, H256}, + ruc::{d, eg, RucResult}, + serde::{Deserialize, Serialize}, + sha3::{Digest, Keccak256}, + std::ops::{Deref, DerefMut}, + zei::noah_algebra::serialization::NoahFromToBytes, + zei::{XfrPublicKey, XfrSignature}, +}; /// An opaque 32-byte cryptographic identifier. #[derive( @@ -83,7 +85,7 @@ impl<'a> TryFrom<&'a [u8]> for Address32 { impl From for Address32 { fn from(k: XfrPublicKey) -> Self { - Address32::try_from(k.zei_to_bytes().as_slice()).unwrap() + Address32::try_from(k.noah_to_bytes().as_slice()).unwrap() } } @@ -205,7 +207,7 @@ pub trait Verify { /// Signature verify that can work with any known signature types.. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum MultiSignature { - /// An zei xfr signature. + /// An noah xfr signature. Xfr(XfrSignature), /// An ECDSA/SECP256k1 signature. Ecdsa(ecdsa::Signature), @@ -250,17 +252,14 @@ impl Verify for MultiSignature { fn verify(&self, msg: &[u8], signer: &Address32) -> bool { match self { - Self::Xfr(ref sig) => match XfrPublicKey::zei_from_bytes(signer.as_ref()) { - Ok(who) => sig.verify(msg, &who), - _ => false, - }, - // Self::Ecdsa(ref sig) => match sig.recover(msg) { - // Some(pubkey) => { - // &keccak_256(pubkey.as_ref()) - // == >::as_ref(signer) - // } - // _ => false, - // }, + Self::Xfr(ref sig) => { + let mut bytes = [0u8; 32]; + bytes[0..32].copy_from_slice(signer.as_ref()); + match XfrPublicKey::noah_from_bytes(&bytes) { + Ok(who) => sig.verify(msg, &who), + _ => false, + } + } Self::Ecdsa(ref sig) => { // let mut msg_hashed = [0u8; 32]; // msg_hashed.copy_from_slice(msg); @@ -269,7 +268,7 @@ impl Verify for MultiSignature { match secp256k1_ecdsa_recover(sig.as_ref(), &msg_hashed) { Ok(pubkey) => { Address32::from(H160::from(H256::from_slice( - Keccak256::digest(&pubkey).as_slice(), + Keccak256::digest(pubkey).as_slice(), ))) == signer.clone() } _ => false, @@ -281,7 +280,7 @@ impl Verify for MultiSignature { #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum MultiSigner { - /// An zei xfr identity. + /// An noah xfr identity. Xfr(XfrPublicKey), // /// An SECP256k1/ECDSA identity (actually, the keccak 256 hash of the compressed pub key). // Ecdsa(ecdsa::Public), @@ -434,13 +433,13 @@ mod tests { use super::*; use rand_chacha::rand_core::SeedableRng; use rand_chacha::ChaChaRng; - use zei::xfr::sig::XfrKeyPair; + use zei::XfrKeyPair; #[test] fn xfr_sign_verify_work() { let mut prng = ChaChaRng::from_entropy(); let alice = XfrKeyPair::generate(&mut prng); - let sig = alice.get_sk_ref().sign(b"hello", alice.get_pk_ref()); + let sig = alice.get_sk_ref().sign(b"hello").unwrap(); let signer = MultiSigner::from(alice.get_pk()); let sig = MultiSignature::from(sig); assert!( diff --git a/src/components/contracts/primitives/utils/Cargo.toml b/src/components/contracts/primitives/utils/Cargo.toml index 936d60bd9..98e9c2403 100644 --- a/src/components/contracts/primitives/utils/Cargo.toml +++ b/src/components/contracts/primitives/utils/Cargo.toml @@ -10,19 +10,19 @@ readme = "README.md" [dependencies] futures = "0.3.16" -base64 = "0.12" +base64 = "0.13" bip0039 = "0.8.0" blake2-rfc = "0.2.18" byteorder = "1.4.3" -hex = "0.4.2" +hex = "0.4.3" libsecp256k1 = { version = "0.7", features = ["static-context", "hmac"] } primitive-types = { version = "0.11.1", default-features = false, features = ["rlp", "byteorder", "serde"] } protobuf = "2.16" rand = "0.8" ruc = "1.0" serde = { version = "1.0.124", features = ["derive"] } -sha2 = "0.9.5" -sha3 = "0.8" +sha2 = "0.10" +sha3 = "0.10" bip32 = "0.2.1" tiny-keccak = { version = "2.0", features = ["keccak"] } twox-hash = "1.6.0" diff --git a/src/components/contracts/primitives/utils/src/ecdsa.rs b/src/components/contracts/primitives/utils/src/ecdsa.rs index b01ed4483..0cb896f26 100644 --- a/src/components/contracts/primitives/utils/src/ecdsa.rs +++ b/src/components/contracts/primitives/utils/src/ecdsa.rs @@ -356,6 +356,7 @@ impl SecpPair { } /// Ethereum address format. + #[allow(clippy::needless_borrow)] pub fn address(&self) -> H160 { let mut res = [0u8; 64]; res.copy_from_slice(&self.public.serialize()[1..65]); diff --git a/src/components/contracts/primitives/wasm/Cargo.toml b/src/components/contracts/primitives/wasm/Cargo.toml index 3e91916d9..106d875df 100644 --- a/src/components/contracts/primitives/wasm/Cargo.toml +++ b/src/components/contracts/primitives/wasm/Cargo.toml @@ -20,7 +20,7 @@ fp-types = { path = "../../primitives/types" } fp-utils = { path = "../../primitives/utils" } rlp = "0.5" ruc = "1.0" -sha3 = "0.8" +sha3 = "0.10" serde_json = "1.0" wasm-bindgen = { version = "=0.2.84", features = ["serde-serialize"] } diff --git a/src/components/contracts/primitives/wasm/src/wasm.rs b/src/components/contracts/primitives/wasm/src/wasm.rs index 7db2c4315..41c51ed99 100644 --- a/src/components/contracts/primitives/wasm/src/wasm.rs +++ b/src/components/contracts/primitives/wasm/src/wasm.rs @@ -29,7 +29,7 @@ pub fn recover_signer(transaction: &Transaction) -> Option { let pubkey = secp256k1_ecdsa_recover(&sig, &msg).ok()?; Some(H160::from(H256::from_slice( - Keccak256::digest(&pubkey).as_slice(), + Keccak256::digest(pubkey).as_slice(), ))) } diff --git a/src/components/contracts/rpc/Cargo.toml b/src/components/contracts/rpc/Cargo.toml index 3194801d3..10400b9c5 100644 --- a/src/components/contracts/rpc/Cargo.toml +++ b/src/components/contracts/rpc/Cargo.toml @@ -38,7 +38,7 @@ rustc-hex = { version = "2.1.0" } rustc_version = "0.4.0" semver = "1.0.4" serde_json = "1.0" -sha3 = "0.8" +sha3 = "0.10" tendermint = { git = "https://github.com/FindoraNetwork/tendermint-rs", tag = "v0.19.0a-fk" } tendermint-rpc = { git = "https://github.com/FindoraNetwork/tendermint-rs", features = ["http-client", "websocket-client"], tag = "v0.19.0a-fk" } tokio = { version = "1.10.1", features = ["full"] } diff --git a/src/components/contracts/rpc/src/eth.rs b/src/components/contracts/rpc/src/eth.rs index 7a4ffff85..75ce0a2a8 100644 --- a/src/components/contracts/rpc/src/eth.rs +++ b/src/components/contracts/rpc/src/eth.rs @@ -1437,7 +1437,7 @@ fn transaction_build( { match pubkey { Some(pk) => { - H160::from(H256::from_slice(Keccak256::digest(&pk).as_slice())) + H160::from(H256::from_slice(Keccak256::digest(pk).as_slice())) } _ => H160::default(), } @@ -1613,11 +1613,11 @@ fn dummy_block(height: u64, full: bool) -> Rich { let hash = if height == (CFG.checkpoint.evm_first_block_height as u64) - 1 { H256([0; 32]) } else { - H256::from_slice(&sha3::Keccak256::digest(&height.to_le_bytes())) + H256::from_slice(&sha3::Keccak256::digest(height.to_le_bytes())) }; let parent_hash = - H256::from_slice(&sha3::Keccak256::digest(&(height - 1).to_le_bytes())); + H256::from_slice(&sha3::Keccak256::digest((height - 1).to_le_bytes())); let transactions = if full { BlockTransactions::Full(vec![]) diff --git a/src/components/contracts/rpc/src/web3.rs b/src/components/contracts/rpc/src/web3.rs index 40237395d..3cba4b8ff 100644 --- a/src/components/contracts/rpc/src/web3.rs +++ b/src/components/contracts/rpc/src/web3.rs @@ -31,7 +31,7 @@ impl Web3Api for Web3ApiImpl { fn sha3(&self, input: Bytes) -> Result { Ok(H256::from_slice( - Keccak256::digest(&input.into_vec()).as_slice(), + Keccak256::digest(input.into_vec()).as_slice(), )) } } diff --git a/src/components/finutils/Cargo.toml b/src/components/finutils/Cargo.toml index d76cef1cd..d630f1a58 100644 --- a/src/components/finutils/Cargo.toml +++ b/src/components/finutils/Cargo.toml @@ -7,28 +7,28 @@ edition = "2021" [dependencies] -hex = "0.4.2" -base64 = "0.12" +hex = "0.4.3" +base64 = "0.13" clap = { version = "2.33.3", features = ["yaml"] } lazy_static = "1.4.0" attohttpc = { version = "0.23", default-features = false, features = ["compress", "json", "tls-rustls"] } serde_json = "1.0.40" serde = { version = "1.0.124", features = ["derive"] } rand = "0.8" -rand_core = { version = "0.5", default-features = false, features = ["alloc"] } -rand_chacha = "0.2" -curve25519-dalek = { version = "3.0", features = ["serde"] } +rand_core = { version = "0.6", default-features = false, features = ["alloc"] } +rand_chacha = "0.3" +noah-curve25519-dalek = { version = "4.0.0", features = ["serde"] } wasm-bindgen = { version = "=0.2.84", features = ["serde-serialize"] } sha2 = "0.10" -zei = { git = "https://github.com/FindoraNetwork/zei", branch = "stable-main" } +zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } ruc = "1.0" rucv4 = { package = "ruc", version = "4.0" } nix = "0.25" ledger = { path = "../../ledger" } -globutils = { git = "https://github.com/FindoraNetwork/platform-lib-utils", tag = "v1.0.0" } -credentials = { git = "https://github.com/FindoraNetwork/platform-lib-credentials", tag = "v1.0.0" } +globutils = { git = "https://github.com/FindoraNetwork/platform-lib-utils", branch = "develop" } +credentials = { git = "https://github.com/FindoraNetwork/platform-lib-credentials", branch = "develop" } eth_checksum = { version = "0.1.2", optional = true } fp-core = { path = "../contracts/primitives/core", default-features = false } diff --git a/src/components/finutils/src/bins/stt/init/mod.rs b/src/components/finutils/src/bins/stt/init/mod.rs index a5a372eb4..606f9931f 100644 --- a/src/components/finutils/src/bins/stt/init/mod.rs +++ b/src/components/finutils/src/bins/stt/init/mod.rs @@ -44,7 +44,7 @@ pub fn init(mut interval: u64, is_mainnet: bool, skip_validator: bool) -> Result .values() .map(|u| &u.pubkey) .chain(VALIDATOR_LIST.values().map(|v| &v.pubkey)) - .map(|pk| (pk, FRA_PRE_ISSUE_AMOUNT / 2_000)) + .map(|pk| (*pk, FRA_PRE_ISSUE_AMOUNT / 2_000)) .collect::>(); // Wallet Address: fra18xkez3fum44jq0zhvwq380rfme7u624cccn3z56fjeex6uuhpq6qv9e4g5 @@ -56,7 +56,7 @@ pub fn init(mut interval: u64, is_mainnet: bool, skip_validator: bool) -> Result let bank = pnk!(wallet::public_key_from_base64( "Oa2RRTzdayA8V2OBE7xp3n3NKrjGJxFTSZZybXOXCDQ=" )); - target_list.push((&bank, FRA_PRE_ISSUE_AMOUNT / 100 * 98)); + target_list.push((bank, FRA_PRE_ISSUE_AMOUNT / 100 * 98)); println!(">>> Transfer FRAs to validators ..."); common::utils::transfer_batch(&root_kp, target_list, None, true, true) diff --git a/src/components/finutils/src/bins/stt/stt.rs b/src/components/finutils/src/bins/stt/stt.rs index 84eb29643..082f61fe9 100644 --- a/src/components/finutils/src/bins/stt/stt.rs +++ b/src/components/finutils/src/bins/stt/stt.rs @@ -27,7 +27,7 @@ use { ruc::*, serde::Serialize, std::{collections::BTreeMap, env}, - zei::xfr::sig::{XfrKeyPair, XfrPublicKey}, + zei::{BlindAssetRecord, XfrKeyPair, XfrPublicKey}, }; lazy_static! { @@ -210,8 +210,8 @@ mod issue { }, rand_chacha::rand_core::SeedableRng, rand_chacha::ChaChaRng, - zei::setup::PublicParams, - zei::xfr::{ + zei::noah_algebra::ristretto::PedersenCommitmentRistretto, + zei::noah_api::xfr::{ asset_record::{build_blind_asset_record, AssetRecordType}, structs::AssetRecordTemplate, }, @@ -233,21 +233,21 @@ mod issue { FRA_PRE_ISSUE_AMOUNT / 2, ASSET_TYPE_FRA, AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, - root_kp.get_pk(), + root_kp.get_pk().into_noah(), ); - let params = PublicParams::default(); + let pc_gens = PedersenCommitmentRistretto::default(); let outputs = (0..2) .map(|_| { let (ba, _, _) = build_blind_asset_record( &mut ChaChaRng::from_entropy(), - ¶ms.pc_gens, + &pc_gens, &template, vec![], ); ( TxOutput { id: None, - record: ba, + record: BlindAssetRecord::from_noah(&ba), lien: None, }, None, @@ -271,7 +271,7 @@ mod issue { } mod delegate { - use {super::*, zei::xfr::asset_record::AssetRecordType}; + use {super::*, zei::noah_api::xfr::asset_record::AssetRecordType}; pub fn gen_tx( user: NameRef, @@ -291,7 +291,7 @@ mod delegate { common::utils::gen_transfer_op( owner_kp, - vec![(&BLACK_HOLE_PUBKEY_STAKING, amount)], + vec![(XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY_STAKING), amount)], None, false, false, diff --git a/src/components/finutils/src/common/ddev/init.rs b/src/components/finutils/src/common/ddev/init.rs index 3db94fca6..63261be3a 100644 --- a/src/components/finutils/src/common/ddev/init.rs +++ b/src/components/finutils/src/common/ddev/init.rs @@ -17,10 +17,8 @@ use ledger::{ }; use ruc::*; use serde::{Deserialize, Serialize}; -use zei::xfr::{ - asset_record::AssetRecordType, - sig::{XfrKeyPair, XfrPublicKey, XfrSecretKey}, -}; +use zei::noah_api::xfr::asset_record::AssetRecordType; +use zei::{XfrKeyPair, XfrPublicKey, XfrSecretKey}; #[derive(Deserialize)] struct TmValidators { @@ -102,7 +100,7 @@ pub(super) fn init(env: &mut Env) -> Result<()> { .custom_data .initial_validators .iter() - .map(|v| (v.xfr_keypair.get_pk_ref(), 500_0000 * FRA)) + .map(|v| (v.xfr_keypair.get_pk(), 500_0000 * FRA)) .collect::>(); println!("[ {} ] >>> Transfer FRAs to validators ...", &env.name); @@ -118,7 +116,7 @@ pub(super) fn init(env: &mut Env) -> Result<()> { gen_transfer_op_xx( Some(&gen_8668_endpoint(env)), &v.xfr_keypair, - vec![(&BLACK_HOLE_PUBKEY_STAKING, am)], + vec![(XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY_STAKING), am)], None, true, false, @@ -174,7 +172,7 @@ fn send_tx(env: &Env, tx: &Transaction) -> Result<()> { fn transfer_batch( env: &Env, owner_kp: &XfrKeyPair, - target_list: Vec<(&XfrPublicKey, u64)>, + target_list: Vec<(XfrPublicKey, u64)>, token_code: Option, confidential_am: bool, confidential_ty: bool, diff --git a/src/components/finutils/src/common/evm.rs b/src/components/finutils/src/common/evm.rs index 14dfde63e..6dd2ff291 100644 --- a/src/components/finutils/src/common/evm.rs +++ b/src/components/finutils/src/common/evm.rs @@ -29,7 +29,8 @@ use tendermint::block::Height; use tendermint_rpc::endpoint::abci_query::AbciQuery; use tendermint_rpc::{Client, HttpClient}; use tokio::runtime::Runtime; -use zei::xfr::{asset_record::AssetRecordType, sig::XfrKeyPair}; +use zei::noah_api::xfr::asset_record::AssetRecordType; +use zei::{XfrKeyPair, XfrPublicKey}; /// transfer utxo assets to account(ed25519 or ecdsa address) balance. pub fn transfer_to_account( @@ -51,7 +52,7 @@ pub fn transfer_to_account( let transfer_op = utils::gen_transfer_op( &kp, - vec![(&BLACK_HOLE_PUBKEY_STAKING, amount)], + vec![(XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY_STAKING), amount)], asset, false, false, @@ -94,7 +95,7 @@ impl Keypair { match self { Keypair::Ecdsa(kp) => MultiSignature::from(kp.sign(data)), Keypair::Ed25519(kp) => { - MultiSignature::from(kp.get_sk_ref().sign(data, kp.get_pk_ref())) + MultiSignature::from(kp.get_sk_ref().sign(data).unwrap()) } } } diff --git a/src/components/finutils/src/common/mod.rs b/src/components/finutils/src/common/mod.rs index 534364f6c..c460a7847 100644 --- a/src/components/finutils/src/common/mod.rs +++ b/src/components/finutils/src/common/mod.rs @@ -37,11 +37,8 @@ use { utils::{get_block_height, get_local_block_height, parse_td_validator_keys}, web3::types::H160, zei::{ - setup::PublicParams, - xfr::{ - asset_record::AssetRecordType, - sig::{XfrKeyPair, XfrPublicKey, XfrSecretKey}, - }, + noah_api::xfr::asset_record::AssetRecordType, XfrKeyPair, XfrPublicKey, + XfrSecretKey, }, }; @@ -151,7 +148,7 @@ pub fn stake( .c(d!())?; utils::gen_transfer_op( &kp, - vec![(&BLACK_HOLE_PUBKEY_STAKING, am)], + vec![(XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY_STAKING), am)], None, false, false, @@ -190,7 +187,7 @@ pub fn stake_append( builder.add_operation_delegation(&kp, am, td_addr); utils::gen_transfer_op( &kp, - vec![(&BLACK_HOLE_PUBKEY_STAKING, am)], + vec![(XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY_STAKING), am)], None, false, false, @@ -481,7 +478,7 @@ pub fn transfer_asset_batch_x( ) -> Result<()> { utils::transfer_batch( kp, - target_addr.iter().map(|addr| (addr, am)).collect(), + target_addr.iter().map(|addr| (*addr, am)).collect(), token_code, confidential_am, confidential_ty, @@ -699,7 +696,7 @@ fn gen_delegate_tx( utils::gen_transfer_op( owner_kp, - vec![(&BLACK_HOLE_PUBKEY_STAKING, amount)], + vec![(XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY_STAKING), amount)], None, false, false, @@ -753,7 +750,7 @@ pub fn create_asset_x( code: Option, ) -> Result { let code = code.unwrap_or_else(AssetTypeCode::gen_random); - let asset_code = AssetTypeCode::from_prefix_and_raw_asset_type_code( + let asset_code = AssetTypeCode::from_prefix_and_raw_asset_type_code_2nd_update( AssetTypePrefix::UserDefined, &code, ); @@ -806,7 +803,6 @@ pub fn issue_asset_x( builder.get_seq_id(), amount, confidentiality_flags, - &PublicParams::default(), ) .c(d!())?; utils::gen_fee_op(kp) diff --git a/src/components/finutils/src/common/utils.rs b/src/components/finutils/src/common/utils.rs index 9b0dfc99a..0849dbf2d 100644 --- a/src/components/finutils/src/common/utils.rs +++ b/src/components/finutils/src/common/utils.rs @@ -35,10 +35,12 @@ use { types::{BlockId, BlockNumber, Bytes, CallRequest, H160}, Web3, }, - zei::xfr::{ - asset_record::{open_blind_asset_record, AssetRecordType}, - sig::{XfrKeyPair, XfrPublicKey}, - structs::{AssetRecordTemplate, OwnerMemo}, + zei::{ + noah_api::xfr::{ + asset_record::{open_blind_asset_record, AssetRecordType}, + structs::{AssetRecordTemplate, OwnerMemo}, + }, + {XfrKeyPair, XfrPublicKey}, }, }; @@ -102,7 +104,7 @@ pub fn transfer( } transfer_batch( owner_kp, - vec![(target_pk, am)], + vec![(*target_pk, am)], token_code, confidential_am, confidential_ty, @@ -114,7 +116,7 @@ pub fn transfer( #[allow(missing_docs)] pub fn transfer_batch( owner_kp: &XfrKeyPair, - target_list: Vec<(&XfrPublicKey, u64)>, + target_list: Vec<(XfrPublicKey, u64)>, token_code: Option, confidential_am: bool, confidential_ty: bool, @@ -142,7 +144,7 @@ pub fn transfer_batch( #[inline(always)] pub fn gen_transfer_op( owner_kp: &XfrKeyPair, - target_list: Vec<(&XfrPublicKey, u64)>, + target_list: Vec<(XfrPublicKey, u64)>, token_code: Option, confidential_am: bool, confidential_ty: bool, @@ -163,7 +165,7 @@ pub fn gen_transfer_op( #[allow(missing_docs)] pub fn gen_transfer_op_x( owner_kp: &XfrKeyPair, - target_list: Vec<(&XfrPublicKey, u64)>, + target_list: Vec<(XfrPublicKey, u64)>, token_code: Option, auto_fee: bool, confidential_am: bool, @@ -188,7 +190,7 @@ pub fn gen_transfer_op_x( pub fn gen_transfer_op_xx( rpc_endpoint: Option<&str>, owner_kp: &XfrKeyPair, - mut target_list: Vec<(&XfrPublicKey, u64)>, + mut target_list: Vec<(XfrPublicKey, u64)>, token_code: Option, auto_fee: bool, confidential_am: bool, @@ -197,7 +199,7 @@ pub fn gen_transfer_op_xx( ) -> Result { let mut op_fee: u64 = 0; if auto_fee { - target_list.push((&*BLACK_HOLE_PUBKEY, TX_FEE_MIN)); + target_list.push((XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY), TX_FEE_MIN)); op_fee += TX_FEE_MIN; } let asset_type = token_code.map(|code| code.val).unwrap_or(ASSET_TYPE_FRA); @@ -217,8 +219,12 @@ pub fn gen_transfer_op_xx( .into_iter(); for (sid, (utxo, owner_memo)) in utxos { - let oar = - open_blind_asset_record(&utxo.0.record, &owner_memo, owner_kp).c(d!())?; + let oar = open_blind_asset_record( + &utxo.0.record.into_noah(), + &owner_memo, + &owner_kp.into_noah(), + ) + .c(d!())?; if oar.asset_type != asset_type && oar.asset_type != ASSET_TYPE_FRA { continue; @@ -278,7 +284,7 @@ pub fn gen_transfer_op_xx( n, token_code.map(|code| code.val).unwrap_or(ASSET_TYPE_FRA), art, - *pk, + pk.into_noah(), ) }); @@ -468,9 +474,13 @@ pub fn get_asset_balance(kp: &XfrKeyPair, asset: Option) -> Resul .c(d!())? .values() .map(|(utxo, owner_memo)| { - open_blind_asset_record(&utxo.0.record, owner_memo, kp) - .c(d!()) - .map(|obr| alt!(obr.asset_type == asset_type, obr.amount, 0)) + open_blind_asset_record( + &utxo.0.record.into_noah(), + owner_memo, + &kp.into_noah(), + ) + .c(d!()) + .map(|obr| alt!(obr.asset_type == asset_type, obr.amount, 0)) }) .collect::>>() .c(d!())? @@ -488,7 +498,9 @@ pub fn get_asset_all(kp: &XfrKeyPair) -> Result> { let mut set = BTreeMap::new(); for (_k, v) in info { - let res = open_blind_asset_record(&v.0 .0.record, &v.1, kp)?; + let res = + open_blind_asset_record(&v.0 .0.record.into_noah(), &v.1, &kp.into_noah()) + .c(d!())?; let code = AssetTypeCode { val: res.asset_type, diff --git a/src/components/finutils/src/txn_builder/mod.rs b/src/components/finutils/src/txn_builder/mod.rs index dc4e37c45..032a9ad9e 100644 --- a/src/components/finutils/src/txn_builder/mod.rs +++ b/src/components/finutils/src/txn_builder/mod.rs @@ -7,7 +7,6 @@ use { credentials::CredUserSecretKey, - curve25519_dalek::scalar::Scalar, fp_types::{crypto::MultiSigner, H160}, globutils::SignatureOf, ledger::{ @@ -36,6 +35,7 @@ use { TendermintAddr, Validator, }, }, + noah_curve25519_dalek::scalar::Scalar, rand_chacha::ChaChaRng, rand_core::{CryptoRng, RngCore, SeedableRng}, ruc::*, @@ -45,26 +45,26 @@ use { collections::{BTreeMap, HashSet}, }, tendermint::PrivateKey, - zei::{ - api::anon_creds::{ + zei::noah_algebra::prelude::*, + zei::noah_algebra::ristretto::PedersenCommitmentRistretto, + zei::noah_api::{ + anon_creds::{ ac_confidential_open_commitment, ACCommitment, ACCommitmentKey, ConfidentialAC, Credential, }, - serialization::ZeiFromToBytes, - setup::PublicParams, xfr::{ asset_record::{ build_blind_asset_record, build_open_asset_record, open_blind_asset_record, AssetRecordType, }, - lib::XfrNotePolicies, - sig::{XfrKeyPair, XfrPublicKey}, structs::{ - AssetRecord, AssetRecordTemplate, BlindAssetRecord, OpenAssetRecord, - OwnerMemo, TracingPolicies, TracingPolicy, + AssetRecord, AssetRecordTemplate, OpenAssetRecord, TracingPolicies, + TracingPolicy, }, + XfrNotePolicies, }, }, + zei::{BlindAssetRecord, OwnerMemo, XfrKeyPair, XfrPublicKey}, }; macro_rules! no_transfer_err { @@ -179,9 +179,13 @@ impl TransactionBuilder { let mut am = TX_FEE_MIN; for (idx, (o, om)) in outputs.into_iter().enumerate() { if 0 < am { - if let Ok(oar) = open_blind_asset_record(&o, &om, &kp) { + if let Ok(oar) = open_blind_asset_record( + &o.into_noah(), + &om.map(|o| o.into_noah()), + &kp.into_noah(), + ) { if ASSET_TYPE_FRA == oar.asset_type - && kp.get_pk_ref().as_bytes() == o.public_key.as_bytes() + && kp.get_pk_ref().to_bytes() == o.public_key.to_bytes() { let n = alt!(oar.amount > am, am, oar.amount); am = am.saturating_sub(oar.amount); @@ -214,24 +218,40 @@ impl TransactionBuilder { /// As the last operation of any transaction, /// add a static fee to the transaction. pub fn add_fee(&mut self, inputs: FeeInputs) -> Result<&mut TransactionBuilder> { + self.add_fee_custom(inputs, TX_FEE_MIN) + } + + /// As the last operation of any transaction, + /// add a static fee to the transaction. + pub fn add_fee_custom(&mut self, inputs: FeeInputs, fee: u64) -> Result<&mut TransactionBuilder> { let mut kps = vec![]; let mut opb = TransferOperationBuilder::default(); + let mut am = fee; for i in inputs.inner.into_iter() { - open_blind_asset_record(&i.ar.record, &i.om, &i.kp) - .c(d!()) - .and_then(|oar| { - opb.add_input(i.tr, oar, None, None, i.am) - .map(|_| { - kps.push(i.kp); - }) - .c(d!()) - })?; + open_blind_asset_record( + &i.ar.record.into_noah(), + &i.om.map(|o| o.into_noah()), + &i.kp.into_noah(), + ) + .c(d!()) + .and_then(|oar| { + if oar.asset_type != ASSET_TYPE_FRA { + return Err(eg!("Incorrect fee input asset_type, expected Findora AssetType record")); + } + let n = alt!(oar.amount > am, am, oar.amount); + am = am.saturating_sub(oar.amount); + opb.add_input(i.tr, oar, None, None, n) + .map(|_| { + kps.push(i.kp); + }) + .c(d!()) + })?; } opb.add_output( &AssetRecordTemplate::with_no_asset_tracing( - TX_FEE_MIN, + fee, ASSET_TYPE_FRA, AssetRecordType::from_flags(false, false), *BLACK_HOLE_PUBKEY, @@ -245,7 +265,7 @@ impl TransactionBuilder { .and_then(|o| o.create(TransferType::Standard).c(d!())) .and_then(|o| { let cmp = |a: &XfrKeyPair, b: &XfrKeyPair| { - a.get_pk().as_bytes().cmp(b.get_pk().as_bytes()) + a.get_pk().to_bytes().cmp(&b.get_pk().to_bytes()) }; kps.sort_by(cmp); kps.dedup_by(|a, b| matches!(cmp(a, b), Ordering::Equal)); @@ -300,18 +320,18 @@ impl TransactionBuilder { seq_num: u64, amount: u64, confidentiality_flags: AssetRecordType, - zei_params: &PublicParams, ) -> Result<&mut Self> { let mut prng = ChaChaRng::from_entropy(); let ar = AssetRecordTemplate::with_no_asset_tracing( amount, token_code.val, confidentiality_flags, - key_pair.get_pk(), + key_pair.get_pk().into_noah(), ); + let pc_gens = PedersenCommitmentRistretto::default(); let (ba, _, owner_memo) = - build_blind_asset_record(&mut prng, &zei_params.pc_gens, &ar, vec![]); + build_blind_asset_record(&mut prng, &pc_gens, &ar, vec![]); self.add_operation_issue_asset( key_pair, token_code, @@ -319,10 +339,10 @@ impl TransactionBuilder { &[( TxOutput { id: None, - record: ba, + record: BlindAssetRecord::from_noah(&ba), lien: None, }, - owner_memo, + owner_memo.map(|om| OwnerMemo::from_noah(&om).unwrap()), )], ) .c(d!()) @@ -741,10 +761,10 @@ pub(crate) fn build_record_and_get_blinds( } }; // 2. Use record template and ciphertexts to build open asset record - let params = PublicParams::default(); + let pc_gens = PedersenCommitmentRistretto::default(); let (open_asset_record, asset_tracing_memos, owner_memo) = build_open_asset_record( prng, - ¶ms.pc_gens, + &pc_gens, template, vec![attr_ctext.unwrap_or_default()], ); @@ -1129,11 +1149,11 @@ impl TransferOperationBuilder { if !sig.verify(&trn.body) { return Err(eg!(("Invalid signature"))); } - sig_keys.insert(sig.address.key.zei_to_bytes()); + sig_keys.insert(sig.address.key.noah_to_bytes()); } for record in &trn.body.transfer.inputs { - if !sig_keys.contains(&record.public_key.zei_to_bytes()) { + if !sig_keys.contains(&record.public_key.noah_to_bytes()) { return Err(eg!(("Not all signatures present"))); } } @@ -1150,10 +1170,11 @@ mod tests { ledger::store::{utils::fra_gen_initial_tx, LedgerState}, rand_chacha::ChaChaRng, rand_core::SeedableRng, - zei::setup::PublicParams, - zei::xfr::asset_record::AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, - zei::xfr::asset_record::{build_blind_asset_record, open_blind_asset_record}, - zei::xfr::sig::XfrKeyPair, + zei::noah_api::xfr::asset_record::{ + build_blind_asset_record, open_blind_asset_record, + AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, + }, + zei::XfrKeyPair, }; // Defines an asset type @@ -1183,7 +1204,7 @@ mod tests { fn test_transfer_op_builder_inner() -> Result<()> { let mut prng = ChaChaRng::from_entropy(); - let params = PublicParams::default(); + let pc_gens = PedersenCommitmentRistretto::default(); let code_1 = AssetTypeCode::gen_random(); let code_2 = AssetTypeCode::gen_random(); let alice = XfrKeyPair::generate(&mut prng); @@ -1195,18 +1216,18 @@ mod tests { 1000, code_1.val, NonConfidentialAmount_NonConfidentialAssetType, - alice.get_pk(), + alice.get_pk().into_noah(), ); let ar_2 = AssetRecordTemplate::with_no_asset_tracing( 1000, code_2.val, NonConfidentialAmount_NonConfidentialAssetType, - bob.get_pk(), + bob.get_pk().into_noah(), ); let (ba_1, _, memo1) = - build_blind_asset_record(&mut prng, ¶ms.pc_gens, &ar_1, vec![]); + build_blind_asset_record(&mut prng, &pc_gens, &ar_1, vec![]); let (ba_2, _, memo2) = - build_blind_asset_record(&mut prng, ¶ms.pc_gens, &ar_2, vec![]); + build_blind_asset_record(&mut prng, &pc_gens, &ar_2, vec![]); // Attempt to spend too much let mut invalid_outputs_transfer_op = TransferOperationBuilder::new(); @@ -1214,12 +1235,12 @@ mod tests { 25, code_1.val, NonConfidentialAmount_NonConfidentialAssetType, - bob.get_pk(), + bob.get_pk().into_noah(), ); let res = invalid_outputs_transfer_op .add_input( TxoRef::Relative(1), - open_blind_asset_record(&ba_1, &memo1, &alice).c(d!())?, + open_blind_asset_record(&ba_1, &memo1, &alice.into_noah()).c(d!())?, None, None, 20, @@ -1237,12 +1258,12 @@ mod tests { 20, code_1.val, NonConfidentialAmount_NonConfidentialAssetType, - bob.get_pk(), + bob.get_pk().into_noah(), ); let res = invalid_sig_op .add_input( TxoRef::Relative(1), - open_blind_asset_record(&ba_1, &memo1, &alice).c(d!())?, + open_blind_asset_record(&ba_1, &memo1, &alice.into_noah()).c(d!())?, None, None, 20, @@ -1265,12 +1286,12 @@ mod tests { 20, code_1.val, NonConfidentialAmount_NonConfidentialAssetType, - bob.get_pk(), + bob.get_pk().into_noah(), ); let res = missing_sig_op .add_input( TxoRef::Relative(1), - open_blind_asset_record(&ba_1, &memo1, &alice).c(d!())?, + open_blind_asset_record(&ba_1, &memo1, &alice.into_noah()).c(d!())?, None, None, 20, @@ -1291,42 +1312,42 @@ mod tests { 5, code_1.val, NonConfidentialAmount_NonConfidentialAssetType, - bob.get_pk(), + bob.get_pk().into_noah(), ); let output_charlie13_code1_template = AssetRecordTemplate::with_no_asset_tracing( 13, code_1.val, NonConfidentialAmount_NonConfidentialAssetType, - charlie.get_pk(), + charlie.get_pk().into_noah(), ); let output_ben2_code1_template = AssetRecordTemplate::with_no_asset_tracing( 2, code_1.val, NonConfidentialAmount_NonConfidentialAssetType, - ben.get_pk(), + ben.get_pk().into_noah(), ); let output_bob5_code2_template = AssetRecordTemplate::with_no_asset_tracing( 5, code_2.val, NonConfidentialAmount_NonConfidentialAssetType, - bob.get_pk(), + bob.get_pk().into_noah(), ); let output_charlie13_code2_template = AssetRecordTemplate::with_no_asset_tracing( 13, code_2.val, NonConfidentialAmount_NonConfidentialAssetType, - charlie.get_pk(), + charlie.get_pk().into_noah(), ); let output_ben2_code2_template = AssetRecordTemplate::with_no_asset_tracing( 2, code_2.val, NonConfidentialAmount_NonConfidentialAssetType, - ben.get_pk(), + ben.get_pk().into_noah(), ); let _valid_transfer_op = TransferOperationBuilder::new() .add_input( TxoRef::Relative(1), - open_blind_asset_record(&ba_1, &memo1, &alice).c(d!())?, + open_blind_asset_record(&ba_1, &memo1, &alice.into_noah()).c(d!())?, None, None, 20, @@ -1334,7 +1355,7 @@ mod tests { .c(d!())? .add_input( TxoRef::Relative(2), - open_blind_asset_record(&ba_2, &memo2, &bob).c(d!())?, + open_blind_asset_record(&ba_2, &memo2, &bob.into_noah()).c(d!())?, None, None, 20, @@ -1371,8 +1392,8 @@ mod tests { 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() + bob_kp.get_sk().into_keypair().noah_to_bytes(), + bob_kp.noah_to_bytes() ); let mut tx = fra_gen_initial_tx(&fra_owner_kp); @@ -1400,9 +1421,15 @@ mod tests { .add_input( TxoRef::Absolute($txo_sid), open_blind_asset_record( - &ledger.get_utxo_light($txo_sid).unwrap().utxo.0.record, + &ledger + .get_utxo_light($txo_sid) + .unwrap() + .utxo + .0 + .record + .into_noah(), &None, - &fra_owner_kp, + &fra_owner_kp.into_noah(), ) .unwrap(), None, @@ -1424,7 +1451,7 @@ mod tests { } let mut tx2 = TransactionBuilder::from_seq_id(1); - tx2.add_operation(transfer_to_bob!(txo_sid, bob_kp.get_pk())) + tx2.add_operation(transfer_to_bob!(txo_sid, bob_kp.get_pk().into_noah())) .add_fee_relative_auto(&fra_owner_kp) .unwrap(); assert!(tx2.check_fee()); @@ -1454,7 +1481,7 @@ mod tests { ); let mut tx3 = TransactionBuilder::from_seq_id(2); pnk!(tx3 - .add_operation(transfer_to_bob!(txo_sid[2], bob_kp.get_pk())) + .add_operation(transfer_to_bob!(txo_sid[2], bob_kp.get_pk().into_noah())) .add_fee(fi)); assert!(tx3.check_fee()); @@ -1483,7 +1510,7 @@ mod tests { 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())) + tx4.add_operation(transfer_to_bob!(txo_sid[1], bob_kp.get_pk().into_noah())) .add_fee(fi) .unwrap(); assert!(tx4.check_fee()); diff --git a/src/components/wallet_mobile/Cargo.toml b/src/components/wallet_mobile/Cargo.toml index 46ea6f1cd..e6f4cc228 100644 --- a/src/components/wallet_mobile/Cargo.toml +++ b/src/components/wallet_mobile/Cargo.toml @@ -16,30 +16,30 @@ crate-type = ["cdylib", "staticlib", "rlib"] wasm-opt = false [dependencies] -aes-gcm = "0.9.0" +aes-gcm = "^0.10.1" base64 = "0.13" bech32 = "0.7.2" ffi-support = "0.4" futures = "0.3.16" getrandom = { version = "0.2", features = ["js"] } -hex = "0.4.2" +hex = "0.4.3" js-sys = "0.3.27" rand = { version = "0.7", features = ["wasm-bindgen"] } -rand_chacha = "0.2.0" -rand_core = { version = "0.5", default-features = false, features = ["alloc"] } +rand_chacha = "0.3" +rand_core = { version = "0.6", default-features = false, features = ["alloc"] } ring = "0.16.19" ruc = "1.0" serde = { version = "1.0.124", features = ["derive"] } serde_derive = "1.0" serde_json = "1.0" -zei = { git = "https://github.com/FindoraNetwork/zei", branch = "stable-main" } +zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } finutils = { path = "../finutils", default-features = false, features = []} fp-types = { path = "../contracts/primitives/types" } fp-utils = { path = "../contracts/primitives/utils" } -globutils = { git = "https://github.com/FindoraNetwork/platform-lib-utils", tag = "v1.0.0" } -credentials = { git = "https://github.com/FindoraNetwork/platform-lib-credentials", tag = "v1.0.0" } -cryptohash = { git = "https://github.com/FindoraNetwork/platform-lib-cryptohash", tag = "v1.0.0" } +globutils = { git = "https://github.com/FindoraNetwork/platform-lib-utils", branch = "develop" } +credentials = { git = "https://github.com/FindoraNetwork/platform-lib-credentials", branch = "develop" } +cryptohash = { git = "https://github.com/FindoraNetwork/platform-lib-cryptohash", branch = "develop" } ledger = { path = "../../ledger" } diff --git a/src/components/wallet_mobile/src/android/constructor.rs b/src/components/wallet_mobile/src/android/constructor.rs index 4303b99c2..719501321 100644 --- a/src/components/wallet_mobile/src/android/constructor.rs +++ b/src/components/wallet_mobile/src/android/constructor.rs @@ -4,8 +4,8 @@ use jni::sys::{jbyteArray, jlong}; use jni::JNIEnv; use rand_chacha::ChaChaRng; use rand_core::SeedableRng; -use zei::xfr::sig::XfrKeyPair as RawXfrKeyPair; -use zei::xfr::structs::ASSET_TYPE_LENGTH; +use zei::noah_api::xfr::structs::ASSET_TYPE_LENGTH; +use zei::XfrKeyPair as RawXfrKeyPair; #[no_mangle] pub unsafe extern "system" fn Java_com_findora_JniApi_xfrKeyPairNew( diff --git a/src/components/wallet_mobile/src/android/evm.rs b/src/components/wallet_mobile/src/android/evm.rs index 0271a4903..ed038e5b7 100644 --- a/src/components/wallet_mobile/src/android/evm.rs +++ b/src/components/wallet_mobile/src/android/evm.rs @@ -2,7 +2,7 @@ use crate::rust::account::{get_serialized_address, EVMTransactionBuilder}; use jni::objects::{JClass, JString}; use jni::sys::{jlong, jstring}; use jni::JNIEnv; -use zei::xfr::sig::XfrPublicKey; +use zei::XfrPublicKey; use super::{jStringToString, parseU64}; diff --git a/src/components/wallet_mobile/src/android/mod.rs b/src/components/wallet_mobile/src/android/mod.rs index 5e41115c1..e68ec61f6 100644 --- a/src/components/wallet_mobile/src/android/mod.rs +++ b/src/components/wallet_mobile/src/android/mod.rs @@ -13,7 +13,7 @@ use jni::objects::{JClass, JString}; use jni::sys::{jboolean, jbyteArray, jint, jlong, jstring}; use jni::JNIEnv; use ledger::data_model::AssetTypeCode; -use zei::xfr::structs::ASSET_TYPE_LENGTH; +use zei::noah_api::xfr::structs::ASSET_TYPE_LENGTH; #[no_mangle] /// Returns the git commit hash and commit date of the commit this library was built against. pub extern "system" fn Java_com_findora_JniApi_buildId( diff --git a/src/components/wallet_mobile/src/android/transfer.rs b/src/components/wallet_mobile/src/android/transfer.rs index 05ddd9da9..ecb615882 100644 --- a/src/components/wallet_mobile/src/android/transfer.rs +++ b/src/components/wallet_mobile/src/android/transfer.rs @@ -3,8 +3,8 @@ use jni::objects::{JClass, JString}; use jni::sys::{jboolean, jint, jlong, jstring, jvalue, JNI_TRUE}; use jni::JNIEnv; use ledger::data_model::AssetType as PlatformAssetType; -use zei::xfr::sig::{XfrKeyPair, XfrPublicKey}; -use zei::xfr::structs::OwnerMemo as ZeiOwnerMemo; +use zei::OwnerMemo as NoahOwnerMemo; +use zei::{XfrKeyPair, XfrPublicKey}; use super::{jStringToString, parseU64}; @@ -189,8 +189,8 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_ownerMemoFromJson( .expect("Couldn't get java string!") .into(); - let zei_owner_memo: ZeiOwnerMemo = serde_json::from_str(val.as_str()).unwrap(); - Box::into_raw(Box::new(OwnerMemo::from_json(zei_owner_memo).unwrap())) as jlong + let noah_owner_memo: NoahOwnerMemo = serde_json::from_str(val.as_str()).unwrap(); + Box::into_raw(Box::new(OwnerMemo::from_json(noah_owner_memo).unwrap())) as jlong } #[no_mangle] diff --git a/src/components/wallet_mobile/src/android/tx_builder.rs b/src/components/wallet_mobile/src/android/tx_builder.rs index 264dac2fe..f935b75c5 100644 --- a/src/components/wallet_mobile/src/android/tx_builder.rs +++ b/src/components/wallet_mobile/src/android/tx_builder.rs @@ -4,7 +4,7 @@ use jni::objects::{JClass, JString}; use jni::sys::{jboolean, jint, jlong, jstring, JNI_TRUE}; use jni::JNIEnv; use ledger::data_model::AssetTypeCode; -use zei::xfr::sig::XfrKeyPair; +use zei::XfrKeyPair; #[no_mangle] /// # Safety /// @param kp: owner's XfrKeyPair @@ -285,9 +285,12 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddOpera .expect("Couldn't get java string!") .into(); let addr = td_addr.strip_prefix("0x").unwrap_or(&td_addr); - let td_address = hex::decode(addr) .expect("addr format error!"); + let td_address = hex::decode(addr).expect("addr format error!"); let keypair = &*(keypair as *mut XfrKeyPair); - let builder = builder.clone().add_operation_claim(td_address,keypair).unwrap(); + let builder = builder + .clone() + .add_operation_claim(td_address, keypair) + .unwrap(); Box::into_raw(Box::new(builder)) as jlong } @@ -305,14 +308,14 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddOpera let builder = &*(builder as *mut TransactionBuilder); let keypair = &*(keypair as *mut XfrKeyPair); let td_addr: String = env - .get_string(td_addr) - .expect("Couldn't get java string!") - .into(); + .get_string(td_addr) + .expect("Couldn't get java string!") + .into(); let addr = td_addr.strip_prefix("0x").unwrap_or(&td_addr); - let td_address = hex::decode(addr) .expect("addr format error!"); + let td_address = hex::decode(addr).expect("addr format error!"); let builder = builder .clone() - .add_operation_claim_custom(td_address,keypair, parseU64(env, am)) + .add_operation_claim_custom(td_address, keypair, parseU64(env, am)) .unwrap(); Box::into_raw(Box::new(builder)) as jlong } diff --git a/src/components/wallet_mobile/src/ios/evm.rs b/src/components/wallet_mobile/src/ios/evm.rs index 527c5e11b..f313ab63d 100644 --- a/src/components/wallet_mobile/src/ios/evm.rs +++ b/src/components/wallet_mobile/src/ios/evm.rs @@ -1,5 +1,5 @@ use std::os::raw::c_char; -use zei::xfr::sig::XfrPublicKey; +use zei::XfrPublicKey; use crate::rust::{ self, account::EVMTransactionBuilder, c_char_to_string, string_to_c_char, diff --git a/src/components/wallet_mobile/src/ios/mod.rs b/src/components/wallet_mobile/src/ios/mod.rs index 4212e5e0b..80e80b05a 100644 --- a/src/components/wallet_mobile/src/ios/mod.rs +++ b/src/components/wallet_mobile/src/ios/mod.rs @@ -13,7 +13,7 @@ use rand_core::SeedableRng; use std::ffi::{CStr, CString}; use std::os::raw::c_char; use std::ptr; -use zei::xfr::structs::ASSET_TYPE_LENGTH; +use zei::noah_api::xfr::structs::ASSET_TYPE_LENGTH; #[no_mangle] /// Returns the git commit hash and commit date of the commit this library was built against. diff --git a/src/components/wallet_mobile/src/ios/tx_builder.rs b/src/components/wallet_mobile/src/ios/tx_builder.rs index 13049fb38..2cba61ae0 100644 --- a/src/components/wallet_mobile/src/ios/tx_builder.rs +++ b/src/components/wallet_mobile/src/ios/tx_builder.rs @@ -5,7 +5,7 @@ use crate::rust::{ }; use ledger::data_model::AssetTypeCode; use std::os::raw::c_char; -use zei::xfr::sig::XfrKeyPair; +use zei::XfrKeyPair; #[no_mangle] /// @param kp: owner's XfrKeyPair @@ -219,7 +219,7 @@ pub extern "C" fn findora_ffi_transaction_builder_add_operation_claim( let td_addr = c_char_to_string(td_addr); let addr = td_addr.strip_prefix("0x").unwrap_or(&td_addr); let td_address = hex::decode(addr).expect("addr format error!"); - if let Ok(info) = builder.clone().add_operation_claim(td_address,keypair) { + if let Ok(info) = builder.clone().add_operation_claim(td_address, keypair) { Box::into_raw(Box::new(info)) } else { std::ptr::null_mut() @@ -237,7 +237,10 @@ pub extern "C" fn findora_ffi_transaction_builder_add_operation_claim_custom( let td_addr = c_char_to_string(td_addr); let addr = td_addr.strip_prefix("0x").unwrap_or(&td_addr); let td_address = hex::decode(addr).expect("addr format error!"); - if let Ok(info) = builder.clone().add_operation_claim_custom(td_address,keypair, am) { + if let Ok(info) = builder + .clone() + .add_operation_claim_custom(td_address, keypair, am) + { Box::into_raw(Box::new(info)) } else { std::ptr::null_mut() diff --git a/src/components/wallet_mobile/src/ios/tx_op_builder.rs b/src/components/wallet_mobile/src/ios/tx_op_builder.rs index 24a6fa28b..9f318d0d3 100644 --- a/src/components/wallet_mobile/src/ios/tx_op_builder.rs +++ b/src/components/wallet_mobile/src/ios/tx_op_builder.rs @@ -1,5 +1,5 @@ use std::os::raw::c_char; -use zei::xfr::sig::{XfrKeyPair, XfrPublicKey}; +use zei::{XfrKeyPair, XfrPublicKey}; use super::parse_u64; use crate::rust::TransferOperationBuilder; diff --git a/src/components/wallet_mobile/src/rust/account.rs b/src/components/wallet_mobile/src/rust/account.rs index 0c6588a54..963921863 100644 --- a/src/components/wallet_mobile/src/rust/account.rs +++ b/src/components/wallet_mobile/src/rust/account.rs @@ -1,7 +1,7 @@ use core::str::FromStr; use ledger::data_model::{AssetTypeCode, ASSET_TYPE_FRA}; use ruc::{d, Result, RucResult}; -use zei::xfr::sig::{XfrKeyPair, XfrPublicKey}; +use zei::{XfrKeyPair, XfrPublicKey}; use super::transaction::TransactionBuilder; @@ -29,7 +29,7 @@ impl Keypair { match self { Keypair::Ecdsa(kp) => MultiSignature::from(kp.sign(data)), Keypair::Ed25519(kp) => { - MultiSignature::from(kp.get_sk_ref().sign(data, kp.get_pk_ref())) + MultiSignature::from(kp.get_sk_ref().sign(data).unwrap()) } } } diff --git a/src/components/wallet_mobile/src/rust/crypto.rs b/src/components/wallet_mobile/src/rust/crypto.rs index 86059b624..390c0a4ea 100644 --- a/src/components/wallet_mobile/src/rust/crypto.rs +++ b/src/components/wallet_mobile/src/rust/crypto.rs @@ -2,7 +2,7 @@ use wasm_bindgen::prelude::*; use super::data_model::*; -use aes_gcm::aead::{generic_array::GenericArray, Aead, NewAead}; +use aes_gcm::aead::{generic_array::GenericArray, Aead, KeyInit}; use aes_gcm::Aes256Gcm; use credentials::{ credential_commit, credential_issuer_key_gen, credential_open_commitment, @@ -11,28 +11,32 @@ use credentials::{ CredUserPublicKey, CredUserSecretKey, Credential as PlatformCredential, }; use cryptohash::sha256; +use getrandom::getrandom; use globutils::wallet; use ledger::{ data_model::{ - AssetTypeCode, ASSET_TYPE_FRA, BLACK_HOLE_PUBKEY, BLACK_HOLE_PUBKEY_STAKING, + AssetTypeCode, ASSET_TYPE_FRA, BLACK_HOLE_PUBKEY_STAKING, TX_FEE_MIN, }, staking::{MAX_DELEGATION_AMOUNT, MIN_DELEGATION_AMOUNT}, }; -use rand::{thread_rng, Rng}; use rand_chacha::ChaChaRng; use rand_core::SeedableRng; use ring::pbkdf2; -use ruc::Result; +use ruc::{ + d, Result, RucResult +}; use std::num::NonZeroU32; use std::str; -use zei::serialization::ZeiFromToBytes; -use zei::xfr::asset_record::open_blind_asset_record as open_bar; -use zei::xfr::lib::trace_assets as zei_trace_assets; -use zei::xfr::sig::{XfrKeyPair, XfrPublicKey, XfrSecretKey}; -use zei::xfr::structs::{ - AssetType as ZeiAssetType, OpenAssetRecord, XfrBody, ASSET_TYPE_LENGTH, +use zei::noah_algebra::serialization::NoahFromToBytes; +use zei::noah_api::{ + xfr::{ + asset_record::open_blind_asset_record as open_bar, + structs::{AssetType as NoahAssetType, OpenAssetRecord, XfrBody, ASSET_TYPE_LENGTH}, + trace_assets as noah_trace_assets, + }, }; +use zei::{XfrKeyPair, XfrPublicKey, XfrSecretKey}; #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] /// Generates random Base64 encoded asset type as a Base64 string. Used in asset definitions. @@ -47,7 +51,7 @@ pub fn random_asset_type() -> String { /// Generates asset type as a Base64 string from given code. pub fn rs_asset_type_from_value(code: [u8; ASSET_TYPE_LENGTH]) -> String { AssetTypeCode { - val: ZeiAssetType(code), + val: NoahAssetType(code), } .to_base64() } @@ -57,7 +61,8 @@ pub fn rs_trace_assets( xfr_body: XfrBody, tracer_keypair: &AssetTracerKeyPair, ) -> Result> { - Ok(zei_trace_assets(&xfr_body, tracer_keypair.get_keys())? + Ok(noah_trace_assets(&xfr_body, tracer_keypair.get_keys()) + .c(d!())? .iter() .map(|(amt, asset_type, _, _)| { let asset_type_code = AssetTypeCode { val: *asset_type }; @@ -71,7 +76,7 @@ pub fn rs_trace_assets( /// Returns an address to use for cancelling debt tokens in a debt swap. /// @ignore pub fn get_null_pk() -> XfrPublicKey { - XfrPublicKey::zei_from_bytes(&[0; 32]).unwrap() + XfrPublicKey::noah_from_bytes(&[0; 32]).unwrap() } /// Returns a JavaScript object containing decrypted owner record information, @@ -82,10 +87,11 @@ pub fn rs_open_client_asset_record( keypair: &XfrKeyPair, ) -> Result { open_bar( - record.get_bar_ref(), + &record.get_bar_ref().into_noah(), &owner_memo.map(|memo| memo.get_memo_ref().clone()), - keypair, + &keypair.into_noah(), ) + .c(d!()) } #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] @@ -103,8 +109,8 @@ pub fn get_priv_key_str(key_pair: &XfrKeyPair) -> String { #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] /// Creates a new transfer key pair. pub fn new_keypair() -> XfrKeyPair { - let mut small_rng = rand::thread_rng(); - XfrKeyPair::generate(&mut small_rng) + let mut prng = ChaChaRng::from_entropy(); + XfrKeyPair::generate(&mut prng) } #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] @@ -131,14 +137,14 @@ pub fn rs_public_key_from_base64(pk: &str) -> Result { /// Expresses a transfer key pair as a hex-encoded string. /// To decode the string, use `keypair_from_str` function. pub fn keypair_to_str(key_pair: &XfrKeyPair) -> String { - hex::encode(key_pair.zei_to_bytes()) + hex::encode(key_pair.noah_to_bytes()) } #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] /// Constructs a transfer key pair from a hex-encoded string. /// The encode a key pair, use `keypair_to_str` function. pub fn keypair_from_str(str: String) -> XfrKeyPair { - XfrKeyPair::zei_from_bytes(&hex::decode(str).unwrap()).unwrap() + XfrKeyPair::noah_from_bytes(&hex::decode(str).unwrap()).unwrap() } /// Generates a new credential issuer key. @@ -167,7 +173,7 @@ pub fn rs_wasm_credential_verify_commitment( issuer_pub_key, commitment.get_ref(), pok.get_ref(), - xfr_pk.as_bytes(), + &xfr_pk.noah_to_bytes(), ) } @@ -248,7 +254,7 @@ pub fn rs_wasm_credential_commit( &mut prng, user_secret_key, credential.get_cred_ref(), - user_public_key.as_bytes(), + &user_public_key.noah_to_bytes(), )?; Ok(CredentialCommitmentData { commitment: CredentialCommitment { commitment }, @@ -319,10 +325,9 @@ pub fn encryption_pbkdf2_aes256gcm(key_pair: String, password: String) -> Vec Vec u64 { /// The destination for fee to be transfered to. #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] pub fn fra_get_dest_pubkey() -> XfrPublicKey { - *BLACK_HOLE_PUBKEY + XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY_STAKING) } /// The system address used to reveive delegation principals. @@ -486,13 +491,13 @@ pub fn get_delegation_target_address() -> String { #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] #[allow(missing_docs)] pub fn get_coinbase_address() -> String { - wallet::public_key_to_base64(&BLACK_HOLE_PUBKEY_STAKING) + wallet::public_key_to_base64(&XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY_STAKING)) } #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] #[allow(missing_docs)] pub fn get_coinbase_principal_address() -> String { - wallet::public_key_to_base64(&BLACK_HOLE_PUBKEY_STAKING) + wallet::public_key_to_base64(&XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY_STAKING)) } #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] diff --git a/src/components/wallet_mobile/src/rust/data_model.rs b/src/components/wallet_mobile/src/rust/data_model.rs index 12733a3f3..967e1fd3f 100644 --- a/src/components/wallet_mobile/src/rust/data_model.rs +++ b/src/components/wallet_mobile/src/rust/data_model.rs @@ -20,39 +20,15 @@ use rand_core::SeedableRng; use ruc::Result as RUCResult; use ruc::{d, err::RucResult}; use serde::{Deserialize, Serialize}; -use zei::setup::PublicParams as ZeiPublicParams; -use zei::xfr::sig::XfrPublicKey; -use zei::xfr::structs::{ - AssetTracerDecKeys, AssetTracerEncKeys, AssetTracerKeyPair as ZeiAssetTracerKeyPair, - BlindAssetRecord, IdentityRevealPolicy, OwnerMemo as ZeiOwnerMemo, - TracingPolicies as ZeiTracingPolicies, TracingPolicy as ZeiTracingPolicy, +use zei::noah_api::xfr::structs::{ + AssetTracerDecKeys, AssetTracerEncKeys, + AssetTracerKeyPair as NoahAssetTracerKeyPair, IdentityRevealPolicy, + OwnerMemo as NoahOwnerMemo, TracingPolicies as NoahTracingPolicies, + TracingPolicy as NoahTracingPolicy, +}; +use zei::{ + BlindAssetRecord, XfrPublicKey }; - -#[cfg_attr(target_arch = "wasm32", wasm_bindgen)] -/// Public parameters necessary for generating asset records. Generating this is expensive and -/// should be done as infrequently as possible. -/// @see {@link module:Findora-Wasm~TransactionBuilder#add_basic_issue_asset|add_basic_issue_asset} -/// for information using public parameters to create issuance asset records. -pub struct PublicParams { - pub(crate) params: ZeiPublicParams, -} - -#[allow(clippy::new_without_default)] -#[cfg_attr(target_arch = "wasm32", wasm_bindgen)] -impl PublicParams { - /// Generates a new set of parameters. - pub fn new() -> PublicParams { - PublicParams { - params: ZeiPublicParams::default(), - } - } -} - -impl PublicParams { - pub fn get_ref(&self) -> &ZeiPublicParams { - &self.params - } -} #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] /// Indicates whether the TXO ref is an absolute or relative value. @@ -238,7 +214,7 @@ impl ClientAssetRecord { /// @see {@link module:Findora-Wasm~AssetRules#add_tracing_policy|add_tracing_policy} for information about how to add a tracing policy to /// an asset definition. pub struct AssetTracerKeyPair { - pub(crate) keypair: ZeiAssetTracerKeyPair, + pub(crate) keypair: NoahAssetTracerKeyPair, } #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] @@ -247,7 +223,7 @@ impl AssetTracerKeyPair { pub fn new() -> Self { let mut small_rng = ChaChaRng::from_entropy(); AssetTracerKeyPair { - keypair: ZeiAssetTracerKeyPair::generate(&mut small_rng), + keypair: NoahAssetTracerKeyPair::generate(&mut small_rng), } } } @@ -266,7 +242,7 @@ impl AssetTracerKeyPair { &self.keypair.dec_key } - pub fn get_keys(&self) -> &ZeiAssetTracerKeyPair { + pub fn get_keys(&self) -> &NoahAssetTracerKeyPair { &self.keypair } } @@ -276,7 +252,7 @@ impl AssetTracerKeyPair { /// Asset owner memo. Contains information needed to decrypt an asset record. /// @see {@link module:Findora-Wasm.ClientAssetRecord|ClientAssetRecord} for more details about asset records. pub struct OwnerMemo { - pub(crate) memo: ZeiOwnerMemo, + pub(crate) memo: NoahOwnerMemo, } #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] @@ -293,29 +269,30 @@ impl OwnerMemo { /// "lock":{"ciphertext":[119,54,117,136,125,133,112,193],"encoded_rand":"8KDql2JphPB5WLd7-aYE1bxTQAcweFSmrqymLvPDntM="} /// } pub fn from_json(val: &JsValue) -> Result { - let zei_owner_memo: ZeiOwnerMemo = + let noah_owner_memo: NoahOwnerMemo = val.into_serde().c(d!()).map_err(error_to_jsvalue)?; Ok(OwnerMemo { - memo: ZeiOwnerMemo { - blind_share: zei_owner_memo.blind_share, - lock: zei_owner_memo.lock, + memo: NoahOwnerMemo { + blind_share: noah_owner_memo.blind_share, + lock: noah_owner_memo.lock, }, }) } #[cfg(not(target_arch = "wasm32"))] - pub fn from_json(zei_owner_memo: ZeiOwnerMemo) -> RUCResult { + pub fn from_json(noah_owner_memo: NoahOwnerMemo) -> RUCResult { Ok(OwnerMemo { - memo: ZeiOwnerMemo { - blind_share: zei_owner_memo.blind_share, - lock: zei_owner_memo.lock, + memo: NoahOwnerMemo { + key_type: noah_owner_memo.key_type, + blind_share_bytes: noah_owner_memo.blind_share_bytes, + lock_bytes: noah_owner_memo.lock_bytes, }, }) } } impl OwnerMemo { - pub fn get_memo_ref(&self) -> &ZeiOwnerMemo { + pub fn get_memo_ref(&self) -> &NoahOwnerMemo { &self.memo } } @@ -369,7 +346,7 @@ impl CredentialRevealSig { /// credential commitment. pub fn get_commitment(&self) -> CredentialCommitment { CredentialCommitment { - commitment: self.sig.sig_commitment.clone(), + commitment: self.sig.cm.clone(), } } /// Returns the underlying proof of knowledge that the credential is valid. @@ -377,7 +354,7 @@ impl CredentialRevealSig { /// credential commitment. pub fn get_pok(&self) -> CredentialPoK { CredentialPoK { - pok: self.sig.pok.clone(), + pok: self.sig.proof_open.clone(), } } } @@ -669,11 +646,11 @@ impl SignatureRules { /// A collection of tracing policies. Use this object when constructing asset transfers to generate /// the correct tracing proofs for traceable assets. pub struct TracingPolicies { - pub(crate) policies: ZeiTracingPolicies, + pub(crate) policies: NoahTracingPolicies, } impl TracingPolicies { - pub fn get_policies_ref(&self) -> &ZeiTracingPolicies { + pub fn get_policies_ref(&self) -> &NoahTracingPolicies { &self.policies } } @@ -682,13 +659,13 @@ impl TracingPolicies { /// Tracing policy for asset transfers. Can be configured to track credentials, the asset type and /// amount, or both. pub struct TracingPolicy { - pub(crate) policy: ZeiTracingPolicy, + pub(crate) policy: NoahTracingPolicy, } #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] impl TracingPolicy { pub fn new_with_tracing(tracing_key: &AssetTracerKeyPair) -> Self { - let policy = ZeiTracingPolicy { + let policy = NoahTracingPolicy { enc_keys: tracing_key.get_enc_key().clone(), asset_tracing: true, identity_tracing: None, @@ -710,7 +687,7 @@ impl TracingPolicy { cred_issuer_pub_key: cred_issuer_key.get_ref().clone(), reveal_map, }; - let policy = ZeiTracingPolicy { + let policy = NoahTracingPolicy { enc_keys: tracing_key.get_enc_key().clone(), asset_tracing: tracing, identity_tracing: Some(identity_policy), @@ -729,7 +706,7 @@ impl TracingPolicy { cred_issuer_pub_key: cred_issuer_key.get_ref().clone(), reveal_map, }; - let policy = ZeiTracingPolicy { + let policy = NoahTracingPolicy { enc_keys: tracing_key.get_enc_key().clone(), asset_tracing: tracing, identity_tracing: Some(identity_policy), @@ -739,7 +716,7 @@ impl TracingPolicy { } impl TracingPolicy { - pub fn get_ref(&self) -> &ZeiTracingPolicy { + pub fn get_ref(&self) -> &NoahTracingPolicy { &self.policy } } diff --git a/src/components/wallet_mobile/src/rust/transaction.rs b/src/components/wallet_mobile/src/rust/transaction.rs index a7c22f5be..575859c93 100644 --- a/src/components/wallet_mobile/src/rust/transaction.rs +++ b/src/components/wallet_mobile/src/rust/transaction.rs @@ -15,11 +15,13 @@ use ledger::{ }, staking::{td_addr_to_bytes, PartialUnDelegation, TendermintAddr}, }; -use ruc::{eg, Result as RucResult}; +use ruc::{d, eg, Result as RucResult, err::RucResult as NewRucResult}; use serde_json::Result; -use zei::xfr::asset_record::{open_blind_asset_record as open_bar, AssetRecordType}; -use zei::xfr::sig::{XfrKeyPair, XfrPublicKey}; -use zei::xfr::structs::AssetRecordTemplate; +use zei::noah_api::xfr::{ + asset_record::{open_blind_asset_record as open_bar, AssetRecordType}, + structs::AssetRecordTemplate, +}; +use zei::{OwnerMemo as NoahOwnerMemo, XfrKeyPair, XfrPublicKey}; /// Given a serialized state commitment and transaction, returns true if the transaction correctly /// hashes up to the state commitment and false otherwise. @@ -53,7 +55,7 @@ impl From for PlatformFeeInput { am: fi.am, tr: fi.tr.txo_ref, ar: fi.ar.txo, - om: fi.om.map(|om| om.memo), + om: fi.om.map(|om| NoahOwnerMemo::from_noah(&om.memo).unwrap()), kp: fi.kp, } } @@ -225,7 +227,6 @@ impl TransactionBuilder { seq_num: u64, amount: u64, conf_amount: bool, - zei_params: &PublicParams, ) -> RucResult { let asset_token = AssetTypeCode::new_from_base64(&code)?; @@ -239,7 +240,6 @@ impl TransactionBuilder { seq_num, amount, confidentiality_flags, - zei_params.get_ref(), )?; Ok(self) } @@ -362,7 +362,7 @@ impl TransactionBuilder { pub fn get_owner_memo(&self, idx: usize) -> Option { self.get_builder() .get_owner_memo_ref(idx) - .map(|memo| OwnerMemo { memo: memo.clone() }) + .map(|memo| OwnerMemo { memo: memo.into_noah() }) } } @@ -393,10 +393,11 @@ impl TransferOperationBuilder { amount: u64, ) -> RucResult { let oar = open_bar( - asset_record.get_bar_ref(), + &asset_record.get_bar_ref().into_noah(), &owner_memo.map(|memo| memo.get_memo_ref().clone()), - key, - )?; + &key.into_noah(), + ) + .c(d!())?; self.get_builder_mut().add_input( *txo_ref.get_txo(), oar, @@ -425,7 +426,7 @@ impl TransferOperationBuilder { amount, code.val, asset_record_type, - *recipient, + recipient.into_noah(), policies.get_policies_ref().clone(), ) } else { @@ -433,7 +434,7 @@ impl TransferOperationBuilder { amount, code.val, asset_record_type, - *recipient, + recipient.into_noah(), ) }; self.get_builder_mut().add_output( diff --git a/src/components/wallet_mobile/src/rust/types.rs b/src/components/wallet_mobile/src/rust/types.rs index 765072d30..71a26fe15 100644 --- a/src/components/wallet_mobile/src/rust/types.rs +++ b/src/components/wallet_mobile/src/rust/types.rs @@ -5,8 +5,8 @@ use credentials::{ CredUserSecretKey as PlatformCredUserSecretKey, }; use std::ops::{Deref, DerefMut}; -use zei::xfr::sig::{XfrKeyPair as ZeiXfrKeyPair, XfrPublicKey as ZeiXfrPublicKey}; -use zei::xfr::structs::OpenAssetRecord as ZeiOpenAssetRecord; +use zei::noah_api::xfr::structs::OpenAssetRecord as ZeiOpenAssetRecord; +use zei::{XfrKeyPair as ZeiXfrKeyPair, XfrPublicKey as ZeiXfrPublicKey}; //////////////////////////////////////////////////////////////////////////////// diff --git a/src/components/wallet_mobile/src/wasm/mod.rs b/src/components/wallet_mobile/src/wasm/mod.rs index 14a7fdf23..491c621a8 100644 --- a/src/components/wallet_mobile/src/wasm/mod.rs +++ b/src/components/wallet_mobile/src/wasm/mod.rs @@ -6,8 +6,8 @@ use credentials::{ }; use ruc::{d, err::RucResult}; use wasm_bindgen::prelude::*; -use zei::xfr::sig::{XfrKeyPair, XfrPublicKey}; -use zei::xfr::structs::ASSET_TYPE_LENGTH; +use zei::noah_api::xfr::structs::ASSET_TYPE_LENGTH; +use zei::{XfrKeyPair, XfrPublicKey}; #[wasm_bindgen] /// Generates asset type as a Base64 string from a JSON-serialized JavaScript value. diff --git a/src/components/wasm/Cargo.toml b/src/components/wasm/Cargo.toml index de2e9f212..2461fbd16 100644 --- a/src/components/wasm/Cargo.toml +++ b/src/components/wasm/Cargo.toml @@ -14,11 +14,11 @@ license = "" wasm-opt = false [dependencies] -base64 = "0.12" -hex = "0.4.2" +base64 = "0.13" +hex = "0.4.3" js-sys = "0.3.27" -rand_chacha = "0.2" -rand_core = { version = "0.5", default-features = false, features = ["alloc"] } +rand_chacha = "0.3" +rand_core = { version = "0.6", default-features = false, features = ["alloc"] } rand = { version = "0.7", features = ["wasm-bindgen"] } serde = { version = "1.0.124", features = ["derive"] } serde_json = "1.0" @@ -26,21 +26,21 @@ wasm-bindgen = { version = "=0.2.84", features = ["serde-serialize"] } fbnc = { version = "0.2.9", default-features = false} ring = "0.16.19" -aes-gcm = "0.9.0" +aes-gcm = "^0.10.1" bech32 = "0.7.2" # Must enable the "js"-feature, # OR the compiling will fail. getrandom = { version = "0.2", features = ["js"] } -zei = { git = "https://github.com/FindoraNetwork/zei", branch = "stable-main" } +zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } ruc = "1.0" finutils = { path = "../finutils", default-features = false } -globutils = { git = "https://github.com/FindoraNetwork/platform-lib-utils", tag = "v1.0.0" } -credentials = { git = "https://github.com/FindoraNetwork/platform-lib-credentials", tag = "v1.0.0" } -cryptohash = { git = "https://github.com/FindoraNetwork/platform-lib-cryptohash", tag = "v1.0.0" } +globutils = { git = "https://github.com/FindoraNetwork/platform-lib-utils", branch = "develop" } +credentials = { git = "https://github.com/FindoraNetwork/platform-lib-credentials", branch = "develop" } +cryptohash = { git = "https://github.com/FindoraNetwork/platform-lib-cryptohash", branch = "develop" } ledger = { path = "../../ledger" } diff --git a/src/components/wasm/src/wasm.rs b/src/components/wasm/src/wasm.rs index 4bf909c71..a9bfc7647 100644 --- a/src/components/wasm/src/wasm.rs +++ b/src/components/wasm/src/wasm.rs @@ -20,7 +20,7 @@ use { AttributeDefinition, ClientAssetRecord, Credential, CredentialCommitment, CredentialCommitmentData, CredentialCommitmentKey, CredentialIssuerKeyPair, CredentialPoK, CredentialRevealSig, CredentialSignature, CredentialUserKeyPair, - OwnerMemo, PublicParams, TracingPolicies, TxoRef, + OwnerMemo, TracingPolicies, TxoRef, }, credentials::{ credential_commit, credential_issuer_key_gen, credential_open_commitment, @@ -63,16 +63,19 @@ use { std::str::FromStr, wasm_bindgen::prelude::*, zei::{ - serialization::ZeiFromToBytes, - xfr::{ + noah_algebra::{ + prelude::{NoahFromToBytes, Scalar}, + ristretto::PedersenCommitmentRistretto, + }, + noah_api::xfr::{ asset_record::{open_blind_asset_record as open_bar, AssetRecordType}, - lib::trace_assets as zei_trace_assets, - sig::{XfrKeyPair, XfrPublicKey, XfrSecretKey}, structs::{ - AssetRecordTemplate, AssetType as ZeiAssetType, XfrBody, + AssetRecordTemplate, AssetType as NoahAssetType, ASSET_TYPE_LENGTH, }, + trace_assets as noah_trace_assets, }, + OwnerMemo as NoahOwnerMemo, XfrKeyPair, XfrPublicKey, XfrSecretKey, XfrBody }, }; @@ -99,28 +102,13 @@ pub fn random_asset_type() -> String { AssetTypeCode::gen_random().to_base64() } -#[wasm_bindgen] -/// Creates a new asset code with prefixing-hashing the original code to query the ledger. -pub fn hash_asset_code(asset_code_string: String) -> Result { - let original_asset_code = AssetTypeCode::new_from_base64(&asset_code_string) - .c(d!()) - .map_err(error_to_jsvalue)?; - - let derived_asset_code = AssetTypeCode::from_prefix_and_raw_asset_type_code( - AssetTypePrefix::UserDefined, - &original_asset_code, - ); - - Ok(derived_asset_code.to_base64()) -} - #[wasm_bindgen] /// Generates asset type as a Base64 string from a JSON-serialized JavaScript value. pub fn asset_type_from_jsvalue(val: &JsValue) -> Result { let code: [u8; ASSET_TYPE_LENGTH] = val.into_serde().c(d!()).map_err(error_to_jsvalue)?; Ok(AssetTypeCode { - val: ZeiAssetType(code), + val: NoahAssetType(code), } .to_base64()) } @@ -155,7 +143,7 @@ pub fn verify_authenticated_txn( #[wasm_bindgen] /// ... pub fn get_null_pk() -> XfrPublicKey { - XfrPublicKey::zei_from_bytes(&[0; 32]).unwrap() + XfrPublicKey::noah_from_bytes(&[0; 32]).unwrap() } #[wasm_bindgen] @@ -195,7 +183,7 @@ impl From for PlatformFeeInput { am: fi.am, tr: fi.tr.txo_ref, ar: fi.ar.txo, - om: fi.om.map(|om| om.memo), + om: fi.om.map(|om| NoahOwnerMemo::from_noah(&om.memo).unwrap()), kp: fi.kp, } } @@ -409,7 +397,6 @@ impl TransactionBuilder { seq_num, amount, confidentiality_flags, - PublicParams::new().get_ref(), ) .c(d!()) .map_err(error_to_jsvalue)?; @@ -607,7 +594,7 @@ impl TransactionBuilder { pub fn get_owner_memo(&self, idx: usize) -> Option { self.get_builder() .get_owner_memo_ref(idx) - .map(|memo| OwnerMemo { memo: memo.clone() }) + .map(|memo| OwnerMemo { memo: memo.into_noah() }) } } @@ -721,11 +708,11 @@ impl TransferOperationBuilder { amount: u64, ) -> Result { let oar = open_bar( - asset_record.get_bar_ref(), + &asset_record.get_bar_ref().into_noah(), &owner_memo.map(|memo| memo.get_memo_ref().clone()), - &key, + &key.into_noah(), ) - .c(d!()) + .c(d!()) .map_err(|e| { JsValue::from_str(&format!("Could not open asset record: {}", e)) })?; @@ -763,7 +750,7 @@ impl TransferOperationBuilder { amount, code.val, asset_record_type, - *recipient, + recipient.into_noah(), policies.get_policies_ref().clone(), ) } else { @@ -771,7 +758,7 @@ impl TransferOperationBuilder { amount, code.val, asset_record_type, - *recipient, + recipient.into_noah(), ) }; self.get_builder_mut() @@ -967,9 +954,9 @@ pub fn open_client_asset_record( keypair: &XfrKeyPair, ) -> Result { open_bar( - record.get_bar_ref(), + &record.get_bar_ref().into_noah(), &owner_memo.map(|memo| memo.get_memo_ref().clone()), - &keypair, + &keypair.into_noah(), ) .c(d!()) .map_err(|e| JsValue::from_str(&format!("Could not open asset record: {}", e))) @@ -1021,14 +1008,14 @@ pub fn public_key_from_base64(pk: &str) -> Result { /// Expresses a transfer key pair as a hex-encoded string. /// To decode the string, use `keypair_from_str` function. pub fn keypair_to_str(key_pair: &XfrKeyPair) -> String { - hex::encode(key_pair.zei_to_bytes()) + hex::encode(key_pair.noah_to_bytes()) } #[wasm_bindgen] /// Constructs a transfer key pair from a hex-encoded string. /// The encode a key pair, use `keypair_to_str` function. pub fn keypair_from_str(str: String) -> XfrKeyPair { - XfrKeyPair::zei_from_bytes(&hex::decode(str).unwrap()).unwrap() + XfrKeyPair::noah_from_bytes(&hex::decode(str).unwrap()).unwrap() } #[wasm_bindgen] @@ -1070,7 +1057,7 @@ pub fn wasm_credential_verify_commitment( issuer_pub_key, commitment.get_ref(), pok.get_ref(), - xfr_pk.as_bytes(), + &xfr_pk.to_bytes(), ) .c(d!()) .map_err(error_to_jsvalue) @@ -1182,7 +1169,7 @@ pub fn wasm_credential_commit( &mut prng, &user_secret_key, credential.get_cred_ref(), - &user_public_key.as_bytes(), + &user_public_key.to_bytes(), ) .c(d!()) .map_err(error_to_jsvalue)?; @@ -1262,15 +1249,16 @@ pub fn trace_assets( // let candidate_assets: Vec = // candidate_assets.into_serde().c(d!()).map_err(error_to_jsvalue)?; let xfr_body: XfrBody = xfr_body.into_serde().c(d!()).map_err(error_to_jsvalue)?; - // let candidate_assets: Vec = candidate_assets + // let candidate_assets: Vec = candidate_assets // .iter() // .map(|asset_type_str| { // AssetTypeCode::new_from_str(&asset_type_str.to_string()).val // }) // .collect(); - let record_data = zei_trace_assets(&xfr_body, tracer_keypair.get_keys()) - .c(d!()) - .map_err(error_to_jsvalue)?; + let record_data = + noah_trace_assets(&xfr_body.into_noah(), tracer_keypair.get_keys()) + .c(d!()) + .map_err(error_to_jsvalue)?; let record_data: Vec<(u64, String)> = record_data .iter() .map(|(amt, asset_type, _, _)| { @@ -1288,9 +1276,17 @@ pub fn trace_assets( // Author: Chao Ma, github.com/chaosma. // ////////////////////////////////////////// -use aes_gcm::aead::{generic_array::GenericArray, Aead, NewAead}; -use aes_gcm::Aes256Gcm; -use rand::{thread_rng, Rng}; +use aes_gcm::{ + aead::{generic_array::GenericArray, Aead, KeyInit}, + Aes256Gcm, +}; +use base64::URL_SAFE; +use fp_types::H160; +use getrandom::getrandom; +use js_sys::JsString; +use ledger::staking::Amount; + +use rand_core::{CryptoRng, RngCore}; use ring::pbkdf2; use std::num::NonZeroU32; use std::str; @@ -1329,10 +1325,9 @@ pub fn encryption_pbkdf2_aes256gcm(key_pair: String, password: String) -> Vec Vec u64 { #[wasm_bindgen] /// The destination for fee to be transfered to. pub fn fra_get_dest_pubkey() -> XfrPublicKey { - *BLACK_HOLE_PUBKEY + XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY) } #[wasm_bindgen] @@ -1517,13 +1512,13 @@ pub fn get_delegation_target_address() -> String { #[wasm_bindgen] #[allow(missing_docs)] pub fn get_coinbase_address() -> String { - wallet::public_key_to_base64(&BLACK_HOLE_PUBKEY_STAKING) + wallet::public_key_to_base64(&XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY_STAKING)) } #[wasm_bindgen] #[allow(missing_docs)] pub fn get_coinbase_principal_address() -> String { - wallet::public_key_to_base64(&BLACK_HOLE_PUBKEY_STAKING) + wallet::public_key_to_base64(&XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY_STAKING)) } #[wasm_bindgen] diff --git a/src/components/wasm/src/wasm_data_model.rs b/src/components/wasm/src/wasm_data_model.rs index 4b9666eb0..13eefd6fa 100644 --- a/src/components/wasm/src/wasm_data_model.rs +++ b/src/components/wasm/src/wasm_data_model.rs @@ -17,46 +17,20 @@ use { serde::{Deserialize, Serialize}, wasm_bindgen::prelude::*, zei::{ - setup::PublicParams as ZeiPublicParams, - xfr::{ - sig::XfrPublicKey, + noah_algebra::ristretto::PedersenCommitmentRistretto, + noah_api::xfr::{ structs::{ AssetTracerDecKeys, AssetTracerEncKeys, - AssetTracerKeyPair as ZeiAssetTracerKeyPair, BlindAssetRecord, - IdentityRevealPolicy, OwnerMemo as ZeiOwnerMemo, - TracingPolicies as ZeiTracingPolicies, - TracingPolicy as ZeiTracingPolicy, + AssetTracerKeyPair as NoahAssetTracerKeyPair, + IdentityRevealPolicy, OwnerMemo as NoahOwnerMemo, + TracingPolicies as NoahTracingPolicies, + TracingPolicy as NoahTracingPolicy, }, }, + XfrPublicKey, BlindAssetRecord, }, }; -#[wasm_bindgen] -/// Public parameters necessary for generating asset records. Generating this is expensive and -/// should be done as infrequently as possible. -/// @see {@link module:Findora-Wasm~TransactionBuilder#add_basic_issue_asset|add_basic_issue_asset} -/// for information using public parameters to create issuance asset records. -pub struct PublicParams { - pub(crate) params: ZeiPublicParams, -} - -#[wasm_bindgen] -#[allow(clippy::new_without_default)] -impl PublicParams { - /// Generates a new set of parameters. - pub fn new() -> PublicParams { - PublicParams { - params: ZeiPublicParams::default(), - } - } -} - -impl PublicParams { - pub fn get_ref(&self) -> &ZeiPublicParams { - &self.params - } -} - #[wasm_bindgen] /// Indicates whether the TXO ref is an absolute or relative value. #[derive(Copy, Clone)] @@ -204,7 +178,7 @@ impl ClientAssetRecord { /// @see {@link module:Findora-Wasm~AssetRules#add_tracing_policy|add_tracing_policy} for information about how to add a tracing policy to /// an asset definition. pub struct AssetTracerKeyPair { - pub(crate) keypair: ZeiAssetTracerKeyPair, + pub(crate) keypair: NoahAssetTracerKeyPair, } #[wasm_bindgen] @@ -213,7 +187,7 @@ impl AssetTracerKeyPair { pub fn new() -> Self { let mut small_rng = ChaChaRng::from_entropy(); AssetTracerKeyPair { - keypair: ZeiAssetTracerKeyPair::generate(&mut small_rng), + keypair: NoahAssetTracerKeyPair::generate(&mut small_rng), } } } @@ -232,7 +206,7 @@ impl AssetTracerKeyPair { &self.keypair.dec_key } - pub fn get_keys(&self) -> &ZeiAssetTracerKeyPair { + pub fn get_keys(&self) -> &NoahAssetTracerKeyPair { &self.keypair } } @@ -242,7 +216,7 @@ impl AssetTracerKeyPair { /// Asset owner memo. Contains information needed to decrypt an asset record. /// @see {@link module:Findora-Wasm.ClientAssetRecord|ClientAssetRecord} for more details about asset records. pub struct OwnerMemo { - pub(crate) memo: ZeiOwnerMemo, + pub(crate) memo: NoahOwnerMemo, } #[wasm_bindgen] @@ -257,12 +231,13 @@ impl OwnerMemo { /// "lock":{"ciphertext":[119,54,117,136,125,133,112,193],"encoded_rand":"8KDql2JphPB5WLd7-aYE1bxTQAcweFSmrqymLvPDntM="} /// } pub fn from_json(val: &JsValue) -> Result { - let zei_owner_memo: ZeiOwnerMemo = + let noah_owner_memo: NoahOwnerMemo = val.into_serde().c(d!()).map_err(error_to_jsvalue)?; Ok(OwnerMemo { - memo: ZeiOwnerMemo { - blind_share: zei_owner_memo.blind_share, - lock: zei_owner_memo.lock, + memo: NoahOwnerMemo { + key_type: noah_owner_memo.key_type, + blind_share_bytes: noah_owner_memo.blind_share_bytes, + lock_bytes: noah_owner_memo.lock_bytes, }, }) } @@ -276,11 +251,12 @@ impl OwnerMemo { } impl OwnerMemo { - pub fn get_memo_ref(&self) -> &ZeiOwnerMemo { + pub fn get_memo_ref(&self) -> &NoahOwnerMemo { &self.memo } } + #[derive(Serialize, Deserialize)] pub(crate) struct AttributeDefinition { pub name: String, @@ -330,7 +306,7 @@ impl CredentialRevealSig { /// credential commitment. pub fn get_commitment(&self) -> CredentialCommitment { CredentialCommitment { - commitment: self.sig.sig_commitment.clone(), + commitment: self.sig.cm.clone(), } } /// Returns the underlying proof of knowledge that the credential is valid. @@ -338,7 +314,7 @@ impl CredentialRevealSig { /// credential commitment. pub fn get_pok(&self) -> CredentialPoK { CredentialPoK { - pok: self.sig.pok.clone(), + pok: self.sig.proof_open.clone(), } } } @@ -576,11 +552,11 @@ impl SignatureRules { /// A collection of tracing policies. Use this object when constructing asset transfers to generate /// the correct tracing proofs for traceable assets. pub struct TracingPolicies { - pub(crate) policies: ZeiTracingPolicies, + pub(crate) policies: NoahTracingPolicies, } impl TracingPolicies { - pub fn get_policies_ref(&self) -> &ZeiTracingPolicies { + pub fn get_policies_ref(&self) -> &NoahTracingPolicies { &self.policies } } @@ -589,13 +565,13 @@ impl TracingPolicies { /// Tracing policy for asset transfers. Can be configured to track credentials, the asset type and /// amount, or both. pub struct TracingPolicy { - pub(crate) policy: ZeiTracingPolicy, + pub(crate) policy: NoahTracingPolicy, } #[wasm_bindgen] impl TracingPolicy { pub fn new_with_tracing(tracing_key: &AssetTracerKeyPair) -> Self { - let policy = ZeiTracingPolicy { + let policy = NoahTracingPolicy { enc_keys: tracing_key.get_enc_key().clone(), asset_tracing: true, identity_tracing: None, @@ -615,7 +591,7 @@ impl TracingPolicy { cred_issuer_pub_key: cred_issuer_key.get_ref().clone(), reveal_map, }; - let policy = ZeiTracingPolicy { + let policy = NoahTracingPolicy { enc_keys: tracing_key.get_enc_key().clone(), asset_tracing: tracing, identity_tracing: Some(identity_policy), @@ -625,7 +601,7 @@ impl TracingPolicy { } impl TracingPolicy { - pub fn get_ref(&self) -> &ZeiTracingPolicy { + pub fn get_ref(&self) -> &NoahTracingPolicy { &self.policy } } diff --git a/src/ledger/Cargo.toml b/src/ledger/Cargo.toml index 9ea5afd6c..5d37a3afb 100644 --- a/src/ledger/Cargo.toml +++ b/src/ledger/Cargo.toml @@ -6,22 +6,22 @@ edition = "2021" build = "build.rs" [dependencies] -base64 = "0.12" +base64 = "0.13" bincode = "1.3.1" byteorder = "1.0.0" -curve25519-dalek = { version = "3.0", features = ["serde"] } -ed25519-dalek = "1.0.0" -hex = "0.4.2" +curve25519-dalek = { package = "noah-curve25519-dalek", version = "4.0.0", default-features = false, features = ['serde'] } +ed25519-dalek = { package = "noah-ed25519-dalek", git = "https://github.com/FindoraNetwork/ed25519-dalek", tag = "v4.0.0" } +hex = "0.4.3" lazy_static = { version = "1.2.0" } tracing = "0.1" -rand = "=0.7.3" -rand_chacha = "0.2" -rand_core = { version = "0.5", default-features = false, features = ["alloc"] } +rand = "0.8" +rand_chacha = "0.3" +rand_core = { version = "0.6", default-features = false, features = ["alloc"] } serde = { version = "1.0.124", features = ["derive"] } serde_derive = "1.0" serde_json = "1.0" serde-strz = "1.1.1" -sha2 = "0.9.5" +sha2 = "0.10" unicode-normalization = "0.1.13" time = "0.3" tendermint = { git = "https://github.com/FindoraNetwork/tendermint-rs", tag = "v0.19.0a-fk" } @@ -30,21 +30,18 @@ config = { path = "../components/config" } fp-types = { path = "../components/contracts/primitives/types" } fp-utils = { path = "../components/contracts/primitives/utils" } ruc = "1.0" -zei = { git = "https://github.com/FindoraNetwork/zei", branch = "stable-main" } -zeiutils = { package = "utils", git = "https://github.com/FindoraNetwork/zei", branch = "stable-main" } +zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } bulletproofs = { package = "bulletproofs", git = "https://github.com/FindoraNetwork/bp", rev = "57633a", features = ["yoloproofs"] } -noah-algebra = { git = "https://github.com/FindoraNetwork/noah", tag = "v0.4.3-1" } -noah-crypto = { git = "https://github.com/FindoraNetwork/noah", tag = "v0.4.3-1" } fbnc = { version = "0.2.9", default-features = false} once_cell = "1" num-bigint = "0.4.3" -globutils = { git = "https://github.com/FindoraNetwork/platform-lib-utils", tag = "v1.0.0" } -bitmap = { git = "https://github.com/FindoraNetwork/platform-lib-bitmap", tag = "v1.0.0" } -cryptohash = { git = "https://github.com/FindoraNetwork/platform-lib-cryptohash", tag = "v1.0.0" } -credentials = { git = "https://github.com/FindoraNetwork/platform-lib-credentials", tag = "v1.0.0" } -merkle_tree = { git = "https://github.com/FindoraNetwork/platform-lib-merkle", tag = "v1.0.0" } -sliding_set = { git = "https://github.com/FindoraNetwork/platform-lib-slidingset", tag = "v1.0.0" } +globutils = { git = "https://github.com/FindoraNetwork/platform-lib-utils", branch = "develop" } +bitmap = { git = "https://github.com/FindoraNetwork/platform-lib-bitmap", branch = "develop" } +cryptohash = { git = "https://github.com/FindoraNetwork/platform-lib-cryptohash", branch = "develop" } +credentials = { git = "https://github.com/FindoraNetwork/platform-lib-credentials", branch = "develop" } +merkle_tree = { git = "https://github.com/FindoraNetwork/platform-lib-merkle", branch = "develop" } +sliding_set = { git = "https://github.com/FindoraNetwork/platform-lib-slidingset", branch = "develop" } [features] default = [] diff --git a/src/ledger/src/converter/mod.rs b/src/ledger/src/converter/mod.rs index 08526f293..802ecc9d9 100644 --- a/src/ledger/src/converter/mod.rs +++ b/src/ledger/src/converter/mod.rs @@ -13,9 +13,9 @@ use { ruc::*, serde::{Deserialize, Serialize}, std::sync::atomic::{AtomicI64, Ordering}, - zei::xfr::{ - sig::XfrPublicKey, - structs::{AssetType, XfrAmount, XfrAssetType}, + zei::{ + noah_api::xfr::structs::{AssetType, XfrAmount, XfrAssetType}, + XfrPublicKey, }, }; #[allow(missing_docs)] @@ -155,7 +155,8 @@ pub fn check_convert_account( )); } if let XfrAssetType::NonConfidential(ty) = o.record.asset_type { - if o.record.public_key == *BLACK_HOLE_PUBKEY_STAKING + if o.record.public_key + == XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY_STAKING) && ty == expected_asset { if let XfrAmount::NonConfidential(amount) = o.record.amount { diff --git a/src/ledger/src/data_model/__trash__.rs b/src/ledger/src/data_model/__trash__.rs index 54eb3a04b..ee27a584d 100644 --- a/src/ledger/src/data_model/__trash__.rs +++ b/src/ledger/src/data_model/__trash__.rs @@ -12,8 +12,8 @@ use { crate::data_model::AssetTypeCode, fixed::types::I20F12, serde::{Deserialize, Serialize}, - zei::xfr::sig::XfrPublicKey, - zei::xfr::structs::AssetType, + zei::noah_api::xfr::structs::AssetType, + zei::XfrPublicKey, }; #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)] diff --git a/src/ledger/src/data_model/effects.rs b/src/ledger/src/data_model/effects.rs index 491d0835d..09ccea520 100644 --- a/src/ledger/src/data_model/effects.rs +++ b/src/ledger/src/data_model/effects.rs @@ -1,3 +1,4 @@ +use zei::noah_api::parameters::bulletproofs::BulletproofParams; use { crate::{ data_model::{ @@ -28,21 +29,20 @@ use { sync::Arc, }, zei::{ - serialization::ZeiFromToBytes, - setup::PublicParams, - xfr::{ - lib::verify_xfr_body, - sig::XfrPublicKey, + noah_algebra::serialization::NoahFromToBytes, + noah_api::xfr::{ structs::{XfrAmount, XfrAssetType}, + verify_xfr_body, }, + XfrPublicKey, }, }; lazy_static! { static ref PRNG: Arc> = Arc::new(Mutex::new(ChaChaRng::from_entropy())); - static ref PARAMS: Arc> = - Arc::new(Mutex::new(PublicParams::default())); + static ref PARAMS: Arc> = + Arc::new(Mutex::new(BulletproofParams::default())); } /// Check operations in the context of a tx, partially. @@ -405,12 +405,12 @@ impl TxnEffect { if !trn.body.verify_body_signature(sig) { return Err(eg!()); } - input_keys.insert(sig.address.key.zei_to_bytes()); + input_keys.insert(sig.address.key.noah_to_bytes()); } // (1b) all input record owners have signed for record in trn.body.transfer.inputs.iter() { - if !input_keys.contains(&record.public_key.zei_to_bytes()) { + if !input_keys.contains(&record.public_key.noah_to_bytes()) { return Err(eg!()); } } @@ -418,7 +418,7 @@ impl TxnEffect { verify_xfr_body( prng, params, - &trn.body.transfer, + &trn.body.transfer.into_noah(), &trn.body.policies.to_ref(), ) .c(d!())?; diff --git a/src/ledger/src/data_model/mod.rs b/src/ledger/src/data_model/mod.rs index d3b2a54e7..22542b9fd 100644 --- a/src/ledger/src/data_model/mod.rs +++ b/src/ledger/src/data_model/mod.rs @@ -10,9 +10,6 @@ mod effects; mod test; 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::converter::ConvertAccount, @@ -28,6 +25,7 @@ use { }, __trash__::{Policy, PolicyGlobals, TxnPolicyData}, bitmap::SparseMap, + config::abci::CheckPointConfig, cryptohash::{sha256::Digest as BitDigest, HashValue}, fbnc::NumKey, globutils::wallet::public_key_to_base64, @@ -49,16 +47,23 @@ use { }, unicode_normalization::UnicodeNormalization, zei::{ - serialization::ZeiFromToBytes, - xfr::{ - lib::{gen_xfr_body, XfrNotePolicies}, - sig::{XfrKeyPair, XfrPublicKey}, - structs::{ - AssetRecord, AssetType as ZeiAssetType, BlindAssetRecord, OwnerMemo, - TracingPolicies, TracingPolicy, XfrAmount, XfrAssetType, XfrBody, - ASSET_TYPE_LENGTH, + noah_algebra::{ + bls12_381::BLSScalar, bn254::BN254Scalar, serialization::NoahFromToBytes, + traits::Scalar, + }, + noah_api::{ + keys::PublicKey as NoahXfrPublicKey, + xfr::{ + gen_xfr_body, + structs::{ + AssetRecord, AssetType as NoahAssetType, TracingPolicies, + TracingPolicy, XfrAmount, XfrAssetType, ASSET_TYPE_LENGTH, + }, + XfrNotePolicies, }, }, + noah_crypto::anemoi_jive::{AnemoiJive, AnemoiJive254}, + BlindAssetRecord, OwnerMemo, XfrBody, XfrKeyPair, XfrPublicKey, }, }; @@ -94,7 +99,7 @@ fn is_default(x: &T) -> bool { /// Findora asset type code pub struct AssetTypeCode { /// Internal asset type - pub val: ZeiAssetType, + pub val: NoahAssetType, } impl NumKey for AssetTypeCode { @@ -105,7 +110,7 @@ impl NumKey for AssetTypeCode { let mut b = b.to_owned(); b.resize(ASSET_TYPE_LENGTH, 0u8); Ok(Self { - val: ZeiAssetType( + val: NoahAssetType( <[u8; ASSET_TYPE_LENGTH]>::try_from(b.as_slice()).c(d!())?, ), }) @@ -119,7 +124,7 @@ impl Default for AssetTypeCode { #[inline(always)] fn default() -> Self { AssetTypeCode { - val: ZeiAssetType([255; ASSET_TYPE_LENGTH]), + val: NoahAssetType([255; ASSET_TYPE_LENGTH]), } } } @@ -147,7 +152,7 @@ impl AssetTypeCode { pub fn gen_random_with_rng(prng: &mut R) -> Self { let val: [u8; ASSET_TYPE_LENGTH] = prng.gen(); Self { - val: ZeiAssetType(val), + val: NoahAssetType(val), } } @@ -162,7 +167,7 @@ impl AssetTypeCode { pub fn new_from_vec(mut bytes: Vec) -> Self { bytes.resize(ASSET_TYPE_LENGTH, 0u8); Self { - val: ZeiAssetType( + val: NoahAssetType( <[u8; ASSET_TYPE_LENGTH]>::try_from(bytes.as_slice()).unwrap(), ), } @@ -226,7 +231,7 @@ impl AssetTypeCode { as_vec.resize(ASSET_TYPE_LENGTH, 0u8); let buf = <[u8; ASSET_TYPE_LENGTH]>::try_from(as_vec.as_slice()).unwrap(); Self { - val: ZeiAssetType(buf), + val: NoahAssetType(buf), } } @@ -240,7 +245,7 @@ impl AssetTypeCode { bin.resize(ASSET_TYPE_LENGTH, 0u8); let buf = <[u8; ASSET_TYPE_LENGTH]>::try_from(bin.as_slice()).c(d!())?; Ok(Self { - val: ZeiAssetType(buf), + val: NoahAssetType(buf), }) } Err(e) => Err(eg!((format!("Failed to deserialize base64 '{b64}': {e}",)))), @@ -261,13 +266,38 @@ impl AssetTypeCode { /// Generates the asset type code from the prefix and the Anemoi hash function #[inline(always)] - pub fn from_prefix_and_raw_asset_type_code( + pub fn from_prefix_and_raw_asset_type_code_2nd_update( prefix: AssetTypePrefix, raw_asset_type_code: &AssetTypeCode, ) -> Self { let mut f = Vec::with_capacity(3); f.push(prefix.to_field_element()); + let mut bytes = vec![0u8; 32]; + bytes[..31].copy_from_slice(&raw_asset_type_code.val.0[..31]); + f.push(BN254Scalar::from_bytes(&bytes).unwrap()); + + let mut bytes = vec![0u8; 32]; + bytes[0] = raw_asset_type_code.val.0[31]; + f.push(BN254Scalar::from_bytes(&bytes).unwrap()); + + let res = AnemoiJive254::eval_variable_length_hash(&f); + Self::new_from_vec(res.to_bytes()) + } + + /// Former version, now deprecated way to derive the asset code. + /// This version uses BLS12-381. + #[inline(always)] + #[deprecated] + pub fn from_prefix_and_raw_asset_type_code_1st_update( + prefix: AssetTypePrefix, + raw_asset_type_code: &AssetTypeCode, + ) -> Self { + let mut f = Vec::with_capacity(3); + + #[allow(deprecated)] + f.push(prefix.to_field_element_old()); + let mut bytes = vec![0u8; 32]; bytes[..31].copy_from_slice(&raw_asset_type_code.val.0[..31]); f.push(BLSScalar::from_bytes(&bytes).unwrap()); @@ -276,8 +306,42 @@ impl AssetTypeCode { bytes[0] = raw_asset_type_code.val.0[31]; f.push(BLSScalar::from_bytes(&bytes).unwrap()); - let res = AnemoiJive381::eval_variable_length_hash(&f); - Self::new_from_vec(res.to_bytes()) + #[allow(deprecated)] + { + use zei::noah_crypto::anemoi_jive::bls12_381_deprecated::AnemoiJive381Deprecated; + let res = AnemoiJive381Deprecated::eval_variable_length_hash(&f); + Self::new_from_vec(res.to_bytes()) + } + } + + /// Select the right asset code based on the global setting. + pub fn from_prefix_and_raw_asset_type_code( + prefix: AssetTypePrefix, + raw_asset_type_code: &AssetTypeCode, + checkpoint: &CheckPointConfig, + cur_height: u64, + ) -> Self { + if raw_asset_type_code.val == ASSET_TYPE_FRA + || core::cmp::min( + checkpoint.utxo_asset_prefix_height, + checkpoint.utxo_asset_prefix_height_2nd_update, + ) > cur_height + { + *raw_asset_type_code + } else if checkpoint.utxo_asset_prefix_height_2nd_update > cur_height + && checkpoint.utxo_asset_prefix_height <= cur_height + { + #[allow(deprecated)] + AssetTypeCode::from_prefix_and_raw_asset_type_code_1st_update( + prefix, + &raw_asset_type_code, + ) + } else { + AssetTypeCode::from_prefix_and_raw_asset_type_code_2nd_update( + prefix, + &raw_asset_type_code, + ) + } } } @@ -417,7 +481,7 @@ pub struct XfrAddress { impl XfrAddress { #[cfg(not(target_arch = "wasm32"))] pub(crate) fn to_base64(self) -> String { - b64enc(&self.key.as_bytes()) + b64enc(&self.key.to_bytes()) } // pub(crate) fn to_bytes(self) -> Vec { @@ -428,7 +492,7 @@ impl XfrAddress { impl Hash for XfrAddress { #[inline(always)] fn hash(&self, state: &mut H) { - self.key.as_bytes().hash(state); + self.key.to_bytes().hash(state); } } @@ -443,7 +507,7 @@ pub struct IssuerPublicKey { impl IssuerPublicKey { #[cfg(not(target_arch = "wasm32"))] pub(crate) fn to_base64(self) -> String { - b64enc(self.key.as_bytes()) + b64enc(&self.key.noah_to_bytes().as_slice()) } // pub(crate) fn to_bytes(&self) -> Vec { @@ -454,7 +518,7 @@ impl IssuerPublicKey { impl Hash for IssuerPublicKey { #[inline(always)] fn hash(&self, state: &mut H) { - self.key.as_bytes().hash(state); + self.key.to_bytes().hash(state); } } @@ -517,7 +581,7 @@ impl SignatureRules { let mut weight_map = HashMap::new(); // Convert to map for (key, weight) in self.weights.iter() { - weight_map.insert(key.as_bytes(), *weight); + weight_map.insert(key.to_bytes(), *weight); } // Calculate weighted sum for key in keyset.iter() { @@ -920,8 +984,9 @@ impl TransferAssetBody { return Err(eg!()); } - let transfer = - Box::new(gen_xfr_body(prng, input_records, output_records).c(d!())?); + let transfer = Box::new(XfrBody::from_noah( + &gen_xfr_body(prng, input_records, output_records).c(d!())?, + )); let outputs = transfer .outputs .iter() @@ -1083,7 +1148,13 @@ impl AssetTypePrefix { } #[allow(missing_docs)] - pub fn to_field_element(&self) -> BLSScalar { + pub fn to_field_element(&self) -> BN254Scalar { + BN254Scalar::from_bytes(&self.bytes()).unwrap() + } + + #[allow(missing_docs)] + #[deprecated] + pub fn to_field_element_old(&self) -> BLSScalar { BLSScalar::from_bytes(&self.bytes()).unwrap() } } @@ -1658,7 +1729,7 @@ impl FinalizedTransaction { } /// Use pure zero bytes(aka [0, 0, ... , 0]) to express FRA. -pub const ASSET_TYPE_FRA: ZeiAssetType = ZeiAssetType([0; ASSET_TYPE_LENGTH]); +pub const ASSET_TYPE_FRA: NoahAssetType = NoahAssetType([0; ASSET_TYPE_LENGTH]); /// FRA decimals pub const FRA_DECIMALS: u8 = 6; @@ -1666,9 +1737,9 @@ pub const FRA_DECIMALS: u8 = 6; lazy_static! { /// The destination of Fee is an black hole, /// all token transfered to it will be burned. - pub static ref BLACK_HOLE_PUBKEY: XfrPublicKey = pnk!(XfrPublicKey::zei_from_bytes(&[0; ed25519_dalek::PUBLIC_KEY_LENGTH][..])); + pub static ref BLACK_HOLE_PUBKEY: NoahXfrPublicKey = pnk!(NoahXfrPublicKey::noah_from_bytes(&[0; ed25519_dalek::PUBLIC_KEY_LENGTH][..])); /// BlackHole of Staking - pub static ref BLACK_HOLE_PUBKEY_STAKING: XfrPublicKey = pnk!(XfrPublicKey::zei_from_bytes(&[1; ed25519_dalek::PUBLIC_KEY_LENGTH][..])); + pub static ref BLACK_HOLE_PUBKEY_STAKING: NoahXfrPublicKey = pnk!(NoahXfrPublicKey::noah_from_bytes(&[1; ed25519_dalek::PUBLIC_KEY_LENGTH][..])); } /// see [**mainnet-v0.1 defination**](https://www.notion.so/findora/Transaction-Fees-Analysis-d657247b70f44a699d50e1b01b8a2287) @@ -1710,7 +1781,8 @@ impl Transaction { 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 + && XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY) + == o.record.public_key { if let XfrAmount::NonConfidential(am) = o.record.amount { if am > (TX_FEE_MIN - 1) { diff --git a/src/ledger/src/data_model/test.rs b/src/ledger/src/data_model/test.rs index e08bf051a..6476bba6c 100644 --- a/src/ledger/src/data_model/test.rs +++ b/src/ledger/src/data_model/test.rs @@ -6,12 +6,28 @@ use { rand_core::SeedableRng, std::cmp::min, zei::{ - ristretto, - xfr::structs::{AssetTypeAndAmountProof, XfrBody, XfrProofs}, + noah_api::{ + ristretto, + xfr::structs::{AssetTypeAndAmountProof, XfrProofs}, + }, + XfrBody }, - zeiutils::msg_eq, }; +#[macro_export] +macro_rules! msg_eq { + ($noah_err: expr, $ruc_err: expr $(,)?) => { + assert!($ruc_err.msg_has_overloop(ruc::eg!($noah_err).as_ref())); + }; + ($noah_err: expr, $ruc_err: expr, $msg: expr $(,)?) => { + assert!( + $ruc_err.msg_has_overloop(ruc::eg!($noah_err).as_ref()), + $msg + ); + }; +} + + const UTF8_ASSET_TYPES_WORK: bool = false; // This test may fail as it is a statistical test that sometimes fails (but very rarely) @@ -260,7 +276,7 @@ fn test_add_operation() { fn gen_fee_operation( amount: Option, - asset_type: Option, + asset_type: Option, dest_pubkey: XfrPublicKey, ) -> Operation { Operation::TransferAsset(TransferAsset { @@ -307,38 +323,41 @@ fn test_check_fee() { let mut tx = gen_sample_tx(); assert!(!tx.check_fee()); - let invalid_confidential_type = - gen_fee_operation(Some(TX_FEE_MIN), None, *BLACK_HOLE_PUBKEY); + let invalid_confidential_type = gen_fee_operation( + Some(TX_FEE_MIN), + None, + XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY), + ); let invalid_confidential_amount = gen_fee_operation( None, - Some(ZeiAssetType([0; ASSET_TYPE_LENGTH])), - *BLACK_HOLE_PUBKEY, + Some(NoahAssetType([0; ASSET_TYPE_LENGTH])), + XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY), ); let invalid_nonconfidential_not_fra_code = gen_fee_operation( Some(TX_FEE_MIN), - Some(ZeiAssetType([9; ASSET_TYPE_LENGTH])), - *BLACK_HOLE_PUBKEY, + Some(NoahAssetType([9; ASSET_TYPE_LENGTH])), + XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY), ); let invalid_nonconfidential_fee_too_little = gen_fee_operation( Some(TX_FEE_MIN - 1), - Some(ZeiAssetType([0; ASSET_TYPE_LENGTH])), - *BLACK_HOLE_PUBKEY, + Some(NoahAssetType([0; ASSET_TYPE_LENGTH])), + XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY), ); let invalid_destination_not_black_hole = gen_fee_operation( Some(TX_FEE_MIN), - Some(ZeiAssetType([0; ASSET_TYPE_LENGTH])), - XfrPublicKey::zei_from_bytes(&[9; ed25519_dalek::PUBLIC_KEY_LENGTH][..]) + Some(NoahAssetType([0; ASSET_TYPE_LENGTH])), + XfrPublicKey::noah_from_bytes(&[9; ed25519_dalek::PUBLIC_KEY_LENGTH][..]) .unwrap(), ); let valid = gen_fee_operation( Some(TX_FEE_MIN), - Some(ZeiAssetType([0; ASSET_TYPE_LENGTH])), - *BLACK_HOLE_PUBKEY, + Some(NoahAssetType([0; ASSET_TYPE_LENGTH])), + XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY), ); let valid2 = gen_fee_operation( Some(TX_FEE_MIN + 999), - Some(ZeiAssetType([0; ASSET_TYPE_LENGTH])), - *BLACK_HOLE_PUBKEY, + Some(NoahAssetType([0; ASSET_TYPE_LENGTH])), + XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY), ); // tx.add_operation(invalid_confidential_type.clone()); diff --git a/src/ledger/src/staking/cosig.rs b/src/ledger/src/staking/cosig.rs index f96b8c4d9..1d2cc50eb 100644 --- a/src/ledger/src/staking/cosig.rs +++ b/src/ledger/src/staking/cosig.rs @@ -17,7 +17,7 @@ use { collections::BTreeMap, fmt::{self, Debug}, }, - zei::xfr::sig::{XfrKeyPair, XfrPublicKey, XfrSignature}, + zei::{XfrKeyPair, XfrPublicKey, XfrSignature}, }; /// A common structure for data with co-signatures. @@ -53,7 +53,7 @@ where .c(d!()) .map(|msg| { let k = kp.get_pk(); - let v = CoSig::new(kp.get_pk(), kp.sign(&msg)); + let v = CoSig::new(kp.get_pk(), kp.sign(&msg).unwrap()); self.cosigs.insert(k, v); }) } @@ -64,7 +64,7 @@ where let msg = bincode::serialize(&(self.nonce, &self.data)).c(d!())?; kps.iter().for_each(|kp| { let k = kp.get_pk(); - let v = CoSig::new(kp.get_pk(), kp.sign(&msg)); + let v = CoSig::new(kp.get_pk(), kp.sign(&msg).unwrap()); self.cosigs.insert(k, v); }); Ok(()) diff --git a/src/ledger/src/staking/evm.rs b/src/ledger/src/staking/evm.rs index dd048d4fa..f6d5e8560 100644 --- a/src/ledger/src/staking/evm.rs +++ b/src/ledger/src/staking/evm.rs @@ -6,7 +6,7 @@ use once_cell::sync::{Lazy, OnceCell}; use parking_lot::{Mutex, RwLock}; use ruc::Result; use std::{collections::BTreeMap, sync::Arc}; -use zei::xfr::sig::XfrPublicKey; +use zei::XfrPublicKey; ///EVM staking interface pub static EVM_STAKING: OnceCell>> = OnceCell::new(); diff --git a/src/ledger/src/staking/mod.rs b/src/ledger/src/staking/mod.rs index 3ec4585d3..60633a796 100644 --- a/src/ledger/src/staking/mod.rs +++ b/src/ledger/src/staking/mod.rs @@ -51,7 +51,8 @@ use { Arc, }, }, - zei::xfr::sig::{XfrKeyPair, XfrPublicKey}, + zei::noah_api::keys::PublicKey as NoahXfrPublicKey, + zei::{XfrKeyPair, XfrPublicKey}, }; // height, reward rate @@ -80,14 +81,14 @@ lazy_static! { pub static ref KEEP_HIST: bool = env::var("FINDORAD_KEEP_HIST").is_ok(); /// Reserved accounts of EcoSystem. - pub static ref FF_PK_LIST: Vec = FF_ADDR_LIST + pub static ref FF_PK_LIST: Vec = FF_ADDR_LIST .iter() - .map(|addr| pnk!(wallet::public_key_from_bech32(addr))) + .map(|addr| pnk!(wallet::public_key_from_bech32(addr)).into_noah()) .collect(); /// Reserved accounts of Findora Foundation. - pub static ref FF_PK_EXTRA_120_0000: XfrPublicKey = - pnk!(wallet::public_key_from_bech32(FF_ADDR_EXTRA_120_0000)); + pub static ref FF_PK_EXTRA_120_0000: NoahXfrPublicKey = + pnk!(wallet::public_key_from_bech32(FF_ADDR_EXTRA_120_0000)).into_noah(); #[allow(missing_docs)] pub static ref CHAN_GLOB_RATE_HIST: GRHCP = chan!(); diff --git a/src/ledger/src/staking/ops/claim.rs b/src/ledger/src/staking/ops/claim.rs index bbdd9ce71..5a889b51a 100644 --- a/src/ledger/src/staking/ops/claim.rs +++ b/src/ledger/src/staking/ops/claim.rs @@ -12,7 +12,7 @@ use { config::abci::global_cfg::CFG, ruc::*, serde::{Deserialize, Serialize}, - zei::xfr::sig::{XfrKeyPair, XfrPublicKey, XfrSignature}, + zei::{XfrKeyPair, XfrPublicKey, XfrSignature}, }; /// Used as the inner object of a `Claim Operation`. @@ -81,7 +81,7 @@ impl ClaimOps { nonce: NoReplayToken, ) -> Self { let body = Data::new(amount, nonce); - let signature = keypair.sign(&body.to_bytes()); + let signature = keypair.sign(&body.to_bytes()).unwrap(); ClaimOps { body, pubkey: keypair.get_pk(), diff --git a/src/ledger/src/staking/ops/delegation.rs b/src/ledger/src/staking/ops/delegation.rs index 528a5eaaf..c0af11244 100644 --- a/src/ledger/src/staking/ops/delegation.rs +++ b/src/ledger/src/staking/ops/delegation.rs @@ -21,9 +21,9 @@ use { serde::{Deserialize, Serialize}, std::collections::HashSet, tendermint::{signature::Ed25519Signature, PrivateKey, PublicKey, Signature}, - zei::xfr::{ - sig::{XfrKeyPair, XfrPublicKey, XfrSignature}, - structs::{XfrAmount, XfrAssetType}, + zei::{ + noah_api::xfr::structs::{XfrAmount, XfrAssetType}, + {XfrKeyPair, XfrPublicKey, XfrSignature}, }, }; @@ -148,7 +148,7 @@ impl DelegationOps { nonce: NoReplayToken, ) -> Self { let body = Box::new(Data::new(validator, new_validator, amount, nonce)); - let signature = keypair.sign(&body.to_bytes()); + let signature = keypair.sign(&body.to_bytes()).unwrap(); let v_signature: Option = vltor_key .and_then(|pk| pk.ed25519_keypair().map(|k| k.sign(&body.to_bytes()))); DelegationOps { @@ -243,7 +243,7 @@ fn check_delegation_context_principal( tx: &Transaction, owner: (XfrPublicKey, Amount), ) -> Result { - let target_pk = *BLACK_HOLE_PUBKEY_STAKING; + let target_pk = XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY_STAKING); let am = tx .body diff --git a/src/ledger/src/staking/ops/fra_distribution.rs b/src/ledger/src/staking/ops/fra_distribution.rs index e82d401c9..2e517222f 100644 --- a/src/ledger/src/staking/ops/fra_distribution.rs +++ b/src/ledger/src/staking/ops/fra_distribution.rs @@ -14,7 +14,7 @@ use { ruc::*, serde::{Deserialize, Serialize}, std::collections::BTreeMap, - zei::xfr::sig::{XfrKeyPair, XfrPublicKey}, + zei::{XfrKeyPair, XfrPublicKey}, }; /// Used as the inner object of a `FraDistribution Operation`. diff --git a/src/ledger/src/staking/ops/governance.rs b/src/ledger/src/staking/ops/governance.rs index e5967586d..9b301aed7 100644 --- a/src/ledger/src/staking/ops/governance.rs +++ b/src/ledger/src/staking/ops/governance.rs @@ -16,7 +16,7 @@ use { ruc::*, serde::{Deserialize, Serialize}, std::collections::BTreeMap, - zei::xfr::sig::{XfrKeyPair, XfrPublicKey}, + zei::{XfrKeyPair, XfrPublicKey}, }; lazy_static! { diff --git a/src/ledger/src/staking/ops/mint_fra.rs b/src/ledger/src/staking/ops/mint_fra.rs index 2738f3ff1..33c86e2a3 100644 --- a/src/ledger/src/staking/ops/mint_fra.rs +++ b/src/ledger/src/staking/ops/mint_fra.rs @@ -14,12 +14,12 @@ use { rand_core::SeedableRng, serde::{Deserialize, Serialize}, zei::{ - setup::PublicParams, - xfr::{ + noah_algebra::ristretto::PedersenCommitmentRistretto, + noah_api::xfr::{ asset_record::{build_blind_asset_record, AssetRecordType}, - sig::XfrPublicKey, - structs::{AssetRecordTemplate, AssetType, OwnerMemo}, + structs::{AssetRecordTemplate, AssetType}, }, + BlindAssetRecord, OwnerMemo, XfrPublicKey, }, }; @@ -78,14 +78,14 @@ impl MintEntry { amount, asset_type, AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, - receiver_pk.unwrap_or(target_pk), + receiver_pk.unwrap_or(target_pk).into_noah(), ); - let pc_gens = PublicParams::default().pc_gens; + let pc_gens = PedersenCommitmentRistretto::default(); let (ba, _, _) = build_blind_asset_record(&mut prng, &pc_gens, &ar, vec![]); let utxo = TxOutput { id: None, - record: ba, + record: BlindAssetRecord::from_noah(&ba), lien: None, }; diff --git a/src/ledger/src/staking/ops/replace_staker.rs b/src/ledger/src/staking/ops/replace_staker.rs index b88b3b44b..b668074f5 100644 --- a/src/ledger/src/staking/ops/replace_staker.rs +++ b/src/ledger/src/staking/ops/replace_staker.rs @@ -12,7 +12,7 @@ use { fp_types::H160, ruc::*, serde::{Deserialize, Serialize}, - zei::xfr::sig::{XfrKeyPair, XfrPublicKey, XfrSignature}, + zei::{XfrKeyPair, XfrPublicKey, XfrSignature}, }; /// Used for `Staker Replace Operation`. @@ -39,7 +39,7 @@ impl ReplaceStakerOps { nonce, }; - let signature = keypair.sign(&body.to_bytes()); + let signature = keypair.sign(&body.to_bytes()).unwrap(); ReplaceStakerOps { body, diff --git a/src/ledger/src/staking/ops/undelegation.rs b/src/ledger/src/staking/ops/undelegation.rs index 9ccd6c1ea..414dee9fd 100644 --- a/src/ledger/src/staking/ops/undelegation.rs +++ b/src/ledger/src/staking/ops/undelegation.rs @@ -12,7 +12,7 @@ use { config::abci::global_cfg::CFG, ruc::*, serde::{Deserialize, Serialize}, - zei::xfr::sig::{XfrKeyPair, XfrPublicKey, XfrSignature}, + zei::{XfrKeyPair, XfrPublicKey, XfrSignature}, }; /// Used as the inner object of a `UnDelegation Operation`. @@ -82,7 +82,7 @@ impl UnDelegationOps { pu: Option, ) -> Self { let body = Data::new(nonce, pu); - let signature = keypair.sign(&body.to_bytes()); + let signature = keypair.sign(&body.to_bytes()).unwrap(); UnDelegationOps { body, pubkey: keypair.get_pk(), diff --git a/src/ledger/src/staking/ops/update_staker.rs b/src/ledger/src/staking/ops/update_staker.rs index b64d7a1d5..f5ab2798e 100644 --- a/src/ledger/src/staking/ops/update_staker.rs +++ b/src/ledger/src/staking/ops/update_staker.rs @@ -16,7 +16,7 @@ use { ruc::*, serde::{Deserialize, Serialize}, tendermint::{signature::Ed25519Signature, PrivateKey, PublicKey, Signature}, - zei::xfr::sig::{XfrKeyPair, XfrPublicKey, XfrSignature}, + zei::{XfrKeyPair, XfrPublicKey, XfrSignature}, }; /// Used as the inner object of a `Staker Update Operation`. @@ -105,7 +105,7 @@ impl UpdateStakerOps { nonce: NoReplayToken, ) -> Self { let body = Box::new(Data::new(validator, new_validator, nonce)); - let signature = keypair.sign(&body.to_bytes()); + let signature = keypair.sign(&body.to_bytes()).unwrap(); let v_signature: Option = vltor_key .ed25519_keypair() .map(|k| k.sign(&body.to_bytes())); diff --git a/src/ledger/src/staking/ops/update_validator.rs b/src/ledger/src/staking/ops/update_validator.rs index ddac83a82..576ef22c7 100644 --- a/src/ledger/src/staking/ops/update_validator.rs +++ b/src/ledger/src/staking/ops/update_validator.rs @@ -14,7 +14,7 @@ use { }, }, ruc::*, - zei::xfr::sig::{XfrKeyPair, XfrPublicKey}, + zei::{XfrKeyPair, XfrPublicKey}, }; /// Used as the inner object of a `UpdateValidator Operation`. diff --git a/src/ledger/src/store/api_cache.rs b/src/ledger/src/store/api_cache.rs index 465613efd..2479cbb59 100644 --- a/src/ledger/src/store/api_cache.rs +++ b/src/ledger/src/store/api_cache.rs @@ -6,7 +6,6 @@ use { data_model::{ AssetTypeCode, AssetTypePrefix, DefineAsset, IssueAsset, IssuerPublicKey, Operation, Transaction, TxOutput, TxnIDHash, TxnSID, TxoSID, XfrAddress, - ASSET_TYPE_FRA, }, staking::{ ops::mint_fra::MintEntry, Amount, BlockHeight, DelegationRwdDetail, @@ -20,7 +19,7 @@ use { ruc::*, serde::{Deserialize, Serialize}, std::collections::HashSet, - zei::xfr::{sig::XfrPublicKey, structs::OwnerMemo}, + zei::{OwnerMemo, XfrPublicKey}, }; type Issuances = Vec<(TxOutput, Option)>; @@ -115,16 +114,14 @@ impl ApiCache { #[inline(always)] pub fn add_created_asset(&mut self, creation: &DefineAsset, cur_height: u64) { let asset_code = creation.body.asset.code; - let code = if asset_code.val == ASSET_TYPE_FRA - || CFG.checkpoint.utxo_asset_prefix_height > cur_height - { - creation.body.asset.code - } else { - AssetTypeCode::from_prefix_and_raw_asset_type_code( - AssetTypePrefix::UserDefined, - &creation.body.asset.code, - ) - }; + + let code = AssetTypeCode::from_prefix_and_raw_asset_type_code( + AssetTypePrefix::UserDefined, + &asset_code, + &CFG.checkpoint, + cur_height, + ); + let prefix = self.prefix.clone(); let issuer = creation.pubkey; let mut tmp = creation.clone(); diff --git a/src/ledger/src/store/helpers.rs b/src/ledger/src/store/helpers.rs index 8f6a3cf6b..0ba1d196f 100644 --- a/src/ledger/src/store/helpers.rs +++ b/src/ledger/src/store/helpers.rs @@ -8,23 +8,22 @@ use { TransferType, XfrNotePolicies, }, crate::data_model::{ - Asset, AssetRules, AssetTypeCode, AssetTypePrefix, ConfidentialMemo, - DefineAsset, DefineAssetBody, IssueAsset, IssueAssetBody, Memo, Operation, - Transaction, TransferAsset, TransferAssetBody, TxOutput, TxnEffect, TxnSID, - TxoRef, TxoSID, ASSET_TYPE_FRA, + Asset, AssetRules, AssetTypeCode, ConfidentialMemo, DefineAsset, + DefineAssetBody, IssueAsset, IssueAssetBody, Memo, Operation, Transaction, + TransferAsset, TransferAssetBody, TxOutput, TxnEffect, TxnSID, TxoRef, TxoSID, }, globutils::SignatureOf, rand_core::{CryptoRng, RngCore}, ruc::*, std::fmt::Debug, zei::{ - setup::PublicParams, - xfr::{ + noah_algebra::ristretto::PedersenCommitmentRistretto, + noah_api::xfr::{ asset_record::AssetRecordType, asset_record::{build_blind_asset_record, open_blind_asset_record}, - sig::{XfrKeyPair, XfrPublicKey}, structs::{AssetRecord, AssetRecordTemplate}, }, + BlindAssetRecord, XfrKeyPair, XfrPublicKey, }, }; @@ -35,7 +34,7 @@ pub fn create_definition_transaction( asset_rules: AssetRules, memo: Option, seq_id: u64, -) -> Result<(Transaction, AssetTypeCode)> { +) -> Result { let issuer_key = IssuerPublicKey { key: *keypair.get_pk_ref(), }; @@ -44,18 +43,9 @@ pub fn create_definition_transaction( let asset_create = DefineAsset::new(asset_body, &IssuerKeyPair { keypair: &keypair }).c(d!())?; - let code = if code.val == ASSET_TYPE_FRA { - *code - } else { - AssetTypeCode::from_prefix_and_raw_asset_type_code( - AssetTypePrefix::UserDefined, - &code, - ) - }; - - Ok(( - Transaction::from_operation(Operation::DefineAsset(asset_create), seq_id), - code, + Ok(Transaction::from_operation( + Operation::DefineAsset(asset_create), + seq_id, )) } @@ -72,12 +62,7 @@ pub fn asset_creation_body( asset_rules: AssetRules, memo: Option, confidential_memo: Option, -) -> (DefineAssetBody, AssetTypeCode) { - let new_token_code = AssetTypeCode::from_prefix_and_raw_asset_type_code( - AssetTypePrefix::UserDefined, - token_code, - ); - +) -> DefineAssetBody { let mut token = Asset { code: *token_code, issuer: IssuerPublicKey { key: *issuer_key }, @@ -97,12 +82,9 @@ pub fn asset_creation_body( token.confidential_memo = ConfidentialMemo {}; } - ( - DefineAssetBody { - asset: Box::new(token), - }, - new_token_code, - ) + DefineAssetBody { + asset: Box::new(token), + } } #[allow(missing_docs)] @@ -148,7 +130,6 @@ pub fn apply_transaction( #[allow(missing_docs)] pub fn create_issue_and_transfer_txn( ledger: &mut LedgerState, - params: &PublicParams, code: &AssetTypeCode, amount: u64, issuer_keys: &XfrKeyPair, @@ -160,14 +141,11 @@ pub fn create_issue_and_transfer_txn( amount, code.val, AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, - issuer_keys.get_pk(), - ); - let (ba, _tracer_memo, owner_memo) = build_blind_asset_record( - &mut ledger.get_prng(), - ¶ms.pc_gens, - &ar_template, - vec![], + issuer_keys.get_pk().into_noah(), ); + let pc_gens = PedersenCommitmentRistretto::default(); + let (ba, _tracer_memo, owner_memo) = + build_blind_asset_record(&mut ledger.get_prng(), &pc_gens, &ar_template, vec![]); let asset_issuance_body = IssueAssetBody::new( &code, @@ -175,7 +153,7 @@ pub fn create_issue_and_transfer_txn( &[( TxOutput { id: None, - record: ba.clone(), + record: BlindAssetRecord::from_noah(&ba), lien: None, }, None, @@ -197,7 +175,7 @@ pub fn create_issue_and_transfer_txn( amount, code.val, AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, - *recipient_pk, + recipient_pk.into_noah(), ); let ar = AssetRecord::from_template_no_identity_tracing( &mut ledger.get_prng(), @@ -208,7 +186,7 @@ pub fn create_issue_and_transfer_txn( &mut ledger.get_prng(), vec![TxoRef::Relative(0)], &[AssetRecord::from_open_asset_record_no_asset_tracing( - open_blind_asset_record(&ba, &owner_memo, &issuer_keys).unwrap() + open_blind_asset_record(&ba, &owner_memo, &issuer_keys.into_noah()).unwrap() )], &[ar.clone()], None, @@ -227,7 +205,6 @@ pub fn create_issue_and_transfer_txn( #[allow(missing_docs)] pub fn create_issue_and_transfer_txn_with_asset_tracing( ledger: &mut LedgerState, - params: &PublicParams, code: &AssetTypeCode, amount: u64, issuer_keys: &XfrKeyPair, @@ -247,12 +224,13 @@ pub fn create_issue_and_transfer_txn_with_asset_tracing( amount, code.val, AssetRecordType::ConfidentialAmount_NonConfidentialAssetType, - issuer_keys.get_pk(), + issuer_keys.get_pk().into_noah(), tracing_policies.clone(), ); + let pc_gens = PedersenCommitmentRistretto::default(); let (ba, _tracer_memo, owner_memo) = build_blind_asset_record( &mut ledger.get_prng(), - ¶ms.pc_gens, + &pc_gens, &ar_template, vec![vec![]], ); @@ -263,7 +241,7 @@ pub fn create_issue_and_transfer_txn_with_asset_tracing( &[( TxOutput { id: None, - record: ba.clone(), + record: BlindAssetRecord::from_noah(&ba), lien: None, }, None, @@ -285,7 +263,7 @@ pub fn create_issue_and_transfer_txn_with_asset_tracing( amount, code.val, AssetRecordType::ConfidentialAmount_NonConfidentialAssetType, - *recipient_pk, + recipient_pk.into_noah(), tracing_policies.clone(), ); let ar = AssetRecord::from_template_no_identity_tracing( @@ -295,7 +273,7 @@ pub fn create_issue_and_transfer_txn_with_asset_tracing( .unwrap(); let tar = AssetRecord::from_open_asset_record_with_asset_tracing_but_no_identity( &mut ledger.get_prng(), - open_blind_asset_record(&ba, &owner_memo, &issuer_keys).unwrap(), + open_blind_asset_record(&ba, &owner_memo, &issuer_keys.into_noah()).unwrap(), tracing_policies, ) .unwrap(); @@ -324,7 +302,6 @@ pub fn create_issue_and_transfer_txn_with_asset_tracing( #[allow(missing_docs)] pub fn create_issuance_txn( ledger: &mut LedgerState, - params: &PublicParams, code: &AssetTypeCode, amount: u64, seq_num: u64, @@ -336,14 +313,11 @@ pub fn create_issuance_txn( amount, code.val, record_type, - issuer_keys.get_pk(), - ); - let (ba, _tracer_memo, _owner_memo) = build_blind_asset_record( - &mut ledger.get_prng(), - ¶ms.pc_gens, - &ar_template, - vec![], + issuer_keys.get_pk().into_noah(), ); + let pc_gens = PedersenCommitmentRistretto::default(); + let (ba, _tracer_memo, _owner_memo) = + build_blind_asset_record(&mut ledger.get_prng(), &pc_gens, &ar_template, vec![]); let asset_issuance_body = IssueAssetBody::new( &code, @@ -351,7 +325,7 @@ pub fn create_issuance_txn( &[( TxOutput { id: None, - record: ba, + record: BlindAssetRecord::from_noah(&ba), lien: None, }, None, diff --git a/src/ledger/src/store/mod.rs b/src/ledger/src/store/mod.rs index df4ffae74..c9ccf6660 100644 --- a/src/ledger/src/store/mod.rs +++ b/src/ledger/src/store/mod.rs @@ -17,7 +17,7 @@ use { BlockEffect, BlockSID, FinalizedBlock, FinalizedTransaction, IssuerKeyPair, IssuerPublicKey, OutputPosition, StateCommitmentData, Transaction, TransferType, TxnEffect, TxnSID, TxnTempSID, TxoSID, UnAuthenticatedUtxo, - Utxo, UtxoStatus, ASSET_TYPE_FRA, BLACK_HOLE_PUBKEY, + Utxo, UtxoStatus, BLACK_HOLE_PUBKEY, }, staking::{ Amount, Power, Staking, TendermintAddrRef, FF_PK_EXTRA_120_0000, FF_PK_LIST, @@ -47,10 +47,12 @@ use { ops::{Deref, DerefMut}, sync::Arc, }, - zei::xfr::{ - lib::XfrNotePolicies, - sig::XfrPublicKey, - structs::{OwnerMemo, TracingPolicies, TracingPolicy}, + zei::{ + noah_api::xfr::{ + structs::{TracingPolicies, TracingPolicy}, + XfrNotePolicies, + }, + OwnerMemo, XfrPublicKey, }, }; @@ -617,7 +619,12 @@ impl LedgerState { - FF_PK_LIST .iter() .chain(extras.iter()) - .map(|pk| self.staking_get_nonconfidential_balance(pk).unwrap_or(0)) + .map(|pk| { + self.staking_get_nonconfidential_balance(&XfrPublicKey::from_noah( + &pk, + )) + .unwrap_or(0) + }) .sum::() - s.coinbase_balance() } @@ -1330,17 +1337,13 @@ impl LedgerStatus { // This drains every field of `block` except `txns` and `temp_sids`. fn apply_block_effects(&mut self, block: &mut BlockEffect) -> (TmpSidMap, u64, u64) { let base_sid = self.next_txo.0; - let handle_asset_type_code = |code: AssetTypeCode| -> AssetTypeCode { - if CFG.checkpoint.utxo_asset_prefix_height > self.td_commit_height - || code.val == ASSET_TYPE_FRA - { - code - } else { - AssetTypeCode::from_prefix_and_raw_asset_type_code( - AssetTypePrefix::UserDefined, - &code, - ) - } + let handle_asset_type_code = |code: AssetTypeCode| { + AssetTypeCode::from_prefix_and_raw_asset_type_code( + AssetTypePrefix::UserDefined, + &code, + &CFG.checkpoint, + self.td_commit_height, + ) }; for no_replay_token in block.no_replay_tokens.iter() { let (rand, seq_id) = ( diff --git a/src/ledger/src/store/test.rs b/src/ledger/src/store/test.rs index b6cb5cb56..064b322ac 100644 --- a/src/ledger/src/store/test.rs +++ b/src/ledger/src/store/test.rs @@ -10,14 +10,14 @@ use { }, rand_core::SeedableRng, zei::{ - setup::PublicParams, - xfr::{ + noah_algebra::ristretto::PedersenCommitmentRistretto, + noah_api::xfr::{ asset_record::{ build_blind_asset_record, open_blind_asset_record, AssetRecordType, }, - sig::XfrKeyPair, structs::{AssetRecord, AssetRecordTemplate}, }, + BlindAssetRecord, XfrKeyPair, }, }; @@ -85,16 +85,19 @@ fn test_asset_creation_valid() { let keypair = build_keys(&mut prng); let code = AssetTypeCode::gen_random(); - let (asset_body, mut token_code) = asset_creation_body( + let asset_body = asset_creation_body( &code, keypair.get_pk_ref(), AssetRules::default(), None, None, ); - if CFG.checkpoint.utxo_asset_prefix_height > state.get_tendermint_height() { - token_code = code; - } + let token_code = AssetTypeCode::from_prefix_and_raw_asset_type_code( + AssetTypePrefix::UserDefined, + &code, + &CFG.checkpoint, + state.get_tendermint_height(), + ); let asset_create = asset_creation_operation(&asset_body, &keypair); let seq_id = state.get_block_commit_count(); let tx = Transaction::from_operation(Operation::DefineAsset(asset_create), seq_id); @@ -121,7 +124,7 @@ fn test_asset_creation_invalid_public_key() { // Create a valid asset creation operation. let mut prng = ChaChaRng::from_entropy(); let keypair = build_keys(&mut prng); - let (asset_body, _) = asset_creation_body( + let asset_body = asset_creation_body( &AssetTypeCode::gen_random(), keypair.get_pk_ref(), AssetRules::default(), @@ -143,14 +146,13 @@ fn test_asset_creation_invalid_public_key() { #[test] fn test_asset_transfer() { let mut ledger = LedgerState::tmp_ledger(); - let params = PublicParams::default(); let code = AssetTypeCode::gen_random(); let mut prng = ChaChaRng::from_entropy(); let key_pair = XfrKeyPair::generate(&mut prng); let key_pair_adversary = XfrKeyPair::generate(&mut ledger.get_prng()); - let (tx, mut new_code) = create_definition_transaction( + let tx = create_definition_transaction( &code, &key_pair, AssetRules::default(), @@ -158,9 +160,12 @@ fn test_asset_transfer() { ledger.get_block_commit_count(), ) .unwrap(); - if CFG.checkpoint.utxo_asset_prefix_height > ledger.get_tendermint_height() { - new_code = code; - } + let new_code = AssetTypeCode::from_prefix_and_raw_asset_type_code( + AssetTypePrefix::UserDefined, + &code, + &CFG.checkpoint, + ledger.get_tendermint_height(), + ); let effect = TxnEffect::compute_effect(tx).unwrap(); { let mut block = ledger.start_block().unwrap(); @@ -174,15 +179,15 @@ fn test_asset_transfer() { 100, new_code.val, art, - key_pair.get_pk(), + key_pair.get_pk().into_noah(), ); + let pc_gens = PedersenCommitmentRistretto::default(); let (ba, _, _) = build_blind_asset_record( &mut ledger.get_prng(), - ¶ms.pc_gens, + &pc_gens, &template, vec![], ); - let second_ba = ba.clone(); let asset_issuance_body = IssueAssetBody::new( &new_code, @@ -191,7 +196,7 @@ fn test_asset_transfer() { ( TxOutput { id: None, - record: ba, + record: BlindAssetRecord::from_noah(&ba), lien: None, }, None, @@ -199,7 +204,7 @@ fn test_asset_transfer() { ( TxOutput { id: None, - record: second_ba, + record: BlindAssetRecord::from_noah(&ba.clone()), lien: None, }, None, @@ -242,14 +247,16 @@ fn test_asset_transfer() { // Construct transfer operation let input_bar_proof = ledger.get_utxo(txo_sid).unwrap(); let input_bar = (input_bar_proof.clone().utxo.0).record; - let input_oar = open_blind_asset_record(&input_bar, &None, &key_pair).unwrap(); + let input_oar = + open_blind_asset_record(&input_bar.into_noah(), &None, &key_pair.into_noah()) + .unwrap(); assert!(input_bar_proof.is_valid(state_commitment)); let output_template = AssetRecordTemplate::with_no_asset_tracing( 100, new_code.val, art, - key_pair_adversary.get_pk(), + key_pair_adversary.get_pk().into_noah(), ); let output_ar = AssetRecord::from_template_no_identity_tracing( &mut ledger.get_prng(), @@ -317,7 +324,7 @@ fn test_asset_creation_invalid_signature() { let mut prng = ChaChaRng::from_entropy(); let keypair1 = build_keys(&mut prng); - let (asset_body, _) = asset_creation_body( + let asset_body = asset_creation_body( &AssetTypeCode::gen_random(), keypair1.get_pk_ref(), AssetRules::default(), @@ -340,13 +347,11 @@ fn test_asset_creation_invalid_signature() { fn asset_issued() { let mut ledger = LedgerState::tmp_ledger(); - let params = PublicParams::default(); - assert!(ledger.get_state_commitment() == (HashOf::new(&None), 0)); let token_code = AssetTypeCode::gen_random(); let keypair = build_keys(&mut ledger.get_prng()); let seq_id = ledger.get_block_commit_count(); - let (tx, mut new_token_code) = create_definition_transaction( + let tx = create_definition_transaction( &token_code, &keypair, AssetRules::default(), @@ -355,9 +360,12 @@ fn asset_issued() { ) .unwrap(); - if CFG.checkpoint.utxo_asset_prefix_height > ledger.get_tendermint_height() { - new_token_code = token_code; - } + let new_token_code = AssetTypeCode::from_prefix_and_raw_asset_type_code( + AssetTypePrefix::UserDefined, + &token_code, + &CFG.checkpoint, + ledger.get_tendermint_height(), + ); let effect = TxnEffect::compute_effect(tx).unwrap(); { @@ -371,18 +379,19 @@ fn asset_issued() { 100, new_token_code.val, art, - *keypair.get_pk_ref(), + keypair.get_pk_ref().into_noah(), ); + let pc_gens = PedersenCommitmentRistretto::default(); let (ba, _, _) = - build_blind_asset_record(&mut ledger.get_prng(), ¶ms.pc_gens, &ar, vec![]); + build_blind_asset_record(&mut ledger.get_prng(), &pc_gens, &ar, vec![]); let asset_issuance_body = IssueAssetBody::new( &new_token_code, 0, &[( TxOutput { id: None, - record: ba, + record: BlindAssetRecord::from_noah(&ba), lien: None, }, None, @@ -476,7 +485,6 @@ fn asset_issued() { #[test] pub fn test_transferable() { let mut ledger = LedgerState::tmp_ledger(); - let params = PublicParams::default(); let issuer = XfrKeyPair::generate(&mut ledger.get_prng()); let alice = XfrKeyPair::generate(&mut ledger.get_prng()); let bob = XfrKeyPair::generate(&mut ledger.get_prng()); @@ -484,7 +492,7 @@ pub fn test_transferable() { // Define fiat token let code = AssetTypeCode::gen_random(); let seq_id = ledger.get_block_commit_count(); - let (tx, mut new_code) = create_definition_transaction( + let tx = create_definition_transaction( &code, &issuer, AssetRules::default().set_transferable(false).clone(), @@ -492,13 +500,16 @@ pub fn test_transferable() { seq_id, ) .unwrap(); - if CFG.checkpoint.utxo_asset_prefix_height > ledger.get_tendermint_height() { - new_code = code; - } + let new_code = AssetTypeCode::from_prefix_and_raw_asset_type_code( + AssetTypePrefix::UserDefined, + &code, + &CFG.checkpoint, + ledger.get_tendermint_height(), + ); + apply_transaction(&mut ledger, tx); let (tx, _) = create_issue_and_transfer_txn( &mut ledger, - ¶ms, &new_code, 100, &issuer, @@ -514,7 +525,7 @@ pub fn test_transferable() { 100, new_code.val, AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, - bob.get_pk(), + bob.get_pk().into_noah(), ); let record = AssetRecord::from_template_no_identity_tracing( &mut ledger.get_prng(), @@ -528,7 +539,8 @@ pub fn test_transferable() { &mut ledger.get_prng(), vec![TxoRef::Absolute(sid)], &[AssetRecord::from_open_asset_record_no_asset_tracing( - open_blind_asset_record(&bar, &None, &alice).unwrap(), + open_blind_asset_record(&bar.into_noah(), &None, &alice.into_noah()) + .unwrap(), )], &[record], None, @@ -551,7 +563,7 @@ pub fn test_transferable() { 100, new_code.val, AssetRecordType::ConfidentialAmount_ConfidentialAssetType, - bob.get_pk(), + bob.get_pk().into_noah(), ); let record = AssetRecord::from_template_no_identity_tracing( &mut ledger.get_prng(), @@ -565,7 +577,8 @@ pub fn test_transferable() { &mut ledger.get_prng(), vec![TxoRef::Absolute(sid)], &[AssetRecord::from_open_asset_record_no_asset_tracing( - open_blind_asset_record(&bar, &None, &alice).unwrap(), + open_blind_asset_record(&bar.into_noah(), &None, &alice.into_noah()) + .unwrap(), )], &[record], None, @@ -589,7 +602,7 @@ pub fn test_transferable() { 100, new_code.val, AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, - bob.get_pk(), + bob.get_pk().into_noah(), ); let second_record = AssetRecord::from_template_no_identity_tracing( &mut ledger.get_prng(), @@ -598,7 +611,6 @@ pub fn test_transferable() { .unwrap(); let (mut tx, ar) = create_issue_and_transfer_txn( &mut ledger, - ¶ms, &new_code, 100, &issuer, @@ -630,14 +642,13 @@ pub fn test_transferable() { #[test] pub fn test_max_units() { let mut ledger = LedgerState::tmp_ledger(); - let params = PublicParams::default(); let issuer = XfrKeyPair::generate(&mut ledger.get_prng()); // Define fiat token let code = AssetTypeCode::gen_random(); let seq_id = ledger.get_block_commit_count(); - let (tx, mut new_code) = create_definition_transaction( + let tx = create_definition_transaction( &code, &issuer, AssetRules::default().set_max_units(Some(100)).clone(), @@ -645,13 +656,16 @@ pub fn test_max_units() { seq_id, ) .unwrap(); - if CFG.checkpoint.utxo_asset_prefix_height > ledger.get_tendermint_height() { - new_code = code; - } + let new_code = AssetTypeCode::from_prefix_and_raw_asset_type_code( + AssetTypePrefix::UserDefined, + &code, + &CFG.checkpoint, + ledger.get_tendermint_height(), + ); + apply_transaction(&mut ledger, tx); let tx = create_issuance_txn( &mut ledger, - ¶ms, &new_code, 50, 0, @@ -663,7 +677,6 @@ pub fn test_max_units() { // Ensure that a single overlfowing transaction fails let tx = create_issuance_txn( &mut ledger, - ¶ms, &new_code, 51, 1, @@ -679,7 +692,6 @@ pub fn test_max_units() { // Ensure that cap can be reached let tx = create_issuance_txn( &mut ledger, - ¶ms, &new_code, 50, 1, @@ -693,7 +705,6 @@ pub fn test_max_units() { // Cant try to exceed asset cap by issuing confidentially let tx = create_issuance_txn( &mut ledger, - ¶ms, &new_code, 1, 2, @@ -718,13 +729,18 @@ fn gen_fee_operation( let input_bar_proof = l.get_utxo_light(txo_sid).unwrap(); let input_bar = (input_bar_proof.utxo.0).record; - let input_oar = open_blind_asset_record(&input_bar, &None, &fra_owner_kp).unwrap(); + let input_oar = open_blind_asset_record( + &input_bar.into_noah(), + &None, + &fra_owner_kp.into_noah(), + ) + .unwrap(); let output_template = AssetRecordTemplate::with_no_asset_tracing( input_oar.amount - TX_FEE_MIN, fra_code.val, AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, - fra_owner_kp.get_pk(), + fra_owner_kp.get_pk().into_noah(), ); let output_ar = AssetRecord::from_template_no_identity_tracing( &mut l.get_prng(), diff --git a/src/ledger/src/store/utils.rs b/src/ledger/src/store/utils.rs index a7a1ed4ef..d1496c472 100644 --- a/src/ledger/src/store/utils.rs +++ b/src/ledger/src/store/utils.rs @@ -15,12 +15,12 @@ use { rand_core::SeedableRng, ruc::*, zei::{ - setup::PublicParams, - xfr::{ + noah_algebra::ristretto::PedersenCommitmentRistretto, + noah_api::xfr::{ asset_record::{build_blind_asset_record, AssetRecordType}, - sig::XfrKeyPair, structs::AssetRecordTemplate, }, + BlindAssetRecord, XfrKeyPair, }, }; @@ -35,7 +35,7 @@ pub fn fra_gen_initial_tx(fra_owner_kp: &XfrKeyPair) -> Transaction { val: ASSET_TYPE_FRA, }; - let (mut tx, _) = pnk!(helpers::create_definition_transaction( + let mut tx = pnk!(helpers::create_definition_transaction( &fra_code, fra_owner_kp, AssetRules { @@ -55,23 +55,23 @@ pub fn fra_gen_initial_tx(fra_owner_kp: &XfrKeyPair) -> Transaction { FRA_PRE_ISSUE_AMOUNT / 2, fra_code.val, AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, - fra_owner_kp.get_pk(), + fra_owner_kp.get_pk().into_noah(), ); - let params = PublicParams::default(); + let pc_gens = PedersenCommitmentRistretto::default(); let outputs = (0..2) .map(|_| { let (ba, _, _) = build_blind_asset_record( &mut ChaChaRng::from_entropy(), - ¶ms.pc_gens, + &pc_gens, &template, vec![], ); ( TxOutput { id: None, - record: ba, + record: BlindAssetRecord::from_noah(&ba), lien: None, }, None, From 4906c8a6273f708ca6b711da9cef495b9123ed0a Mon Sep 17 00:00:00 2001 From: Weikeng Chen Date: Sun, 20 Aug 2023 01:15:40 -0700 Subject: [PATCH 2/7] Remove unused Ethereum recover public key and SHA3 precompiles (#1005) * remove unused evm precompile * fix --- Cargo.toml | 1 - src/components/contracts/baseapp/Cargo.toml | 1 - src/components/contracts/baseapp/src/lib.rs | 3 - .../modules/evm/precompile/Cargo.toml | 1 - .../modules/evm/precompile/basic/src/lib.rs | 42 +---------- .../evm/precompile/sha3fips/Cargo.toml | 14 ---- .../evm/precompile/sha3fips/src/lib.rs | 69 ------------------- .../modules/evm/precompile/src/lib.rs | 4 +- 8 files changed, 3 insertions(+), 132 deletions(-) delete mode 100644 src/components/contracts/modules/evm/precompile/sha3fips/Cargo.toml delete mode 100644 src/components/contracts/modules/evm/precompile/sha3fips/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 57d92f5b6..58870478f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ members = [ "src/components/contracts/modules/evm/precompile/basic", "src/components/contracts/modules/evm/precompile/frc20", "src/components/contracts/modules/evm/precompile/modexp", - "src/components/contracts/modules/evm/precompile/sha3fips", "src/components/contracts/modules/evm/precompile/anemoi", "src/components/contracts/modules/evm/precompile/blake2", "src/components/contracts/modules/evm/precompile/bn128", diff --git a/src/components/contracts/baseapp/Cargo.toml b/src/components/contracts/baseapp/Cargo.toml index 65cdd155b..32483d3ba 100644 --- a/src/components/contracts/baseapp/Cargo.toml +++ b/src/components/contracts/baseapp/Cargo.toml @@ -48,7 +48,6 @@ evm-precompile = {path = "../modules/evm/precompile"} evm-precompile-basic = {path = "../modules/evm/precompile/basic"} evm-precompile-frc20 = {path = "../modules/evm/precompile/frc20"} evm-precompile-modexp = {path = "../modules/evm/precompile/modexp"} -evm-precompile-sha3fips = {path = "../modules/evm/precompile/sha3fips"} [features] abci_mock = [] diff --git a/src/components/contracts/baseapp/src/lib.rs b/src/components/contracts/baseapp/src/lib.rs index 19c0c42af..049c4ec9c 100644 --- a/src/components/contracts/baseapp/src/lib.rs +++ b/src/components/contracts/baseapp/src/lib.rs @@ -164,9 +164,6 @@ impl module_evm::Config for BaseApp { evm_precompile_basic::Ripemd160, evm_precompile_basic::Identity, evm_precompile_modexp::Modexp, - evm_precompile_basic::ECRecoverPublicKey, - evm_precompile_sha3fips::Sha3FIPS256, - evm_precompile_sha3fips::Sha3FIPS512, evm_precompile_frc20::FRC20, ); type PrecompilesType = FindoraPrecompiles; diff --git a/src/components/contracts/modules/evm/precompile/Cargo.toml b/src/components/contracts/modules/evm/precompile/Cargo.toml index 875e9a0cf..61af3152e 100644 --- a/src/components/contracts/modules/evm/precompile/Cargo.toml +++ b/src/components/contracts/modules/evm/precompile/Cargo.toml @@ -14,7 +14,6 @@ ethereum-types = "0.13.1" evm-precompile-basic = {path = "./basic"} evm-precompile-frc20 = {path = "./frc20"} evm-precompile-modexp = {path = "./modexp"} -evm-precompile-sha3fips = {path = "./sha3fips"} evm-precompile-anemoi = {path = "./anemoi"} evm-precompile-blake2 = {path = "./blake2"} evm-precompile-bn128 = {path = "./bn128"} diff --git a/src/components/contracts/modules/evm/precompile/basic/src/lib.rs b/src/components/contracts/modules/evm/precompile/basic/src/lib.rs index c1cf4662b..8dce50720 100644 --- a/src/components/contracts/modules/evm/precompile/basic/src/lib.rs +++ b/src/components/contracts/modules/evm/precompile/basic/src/lib.rs @@ -16,7 +16,7 @@ // limitations under the License. use core::cmp::min; -use evm::{executor::stack::PrecompileFailure, ExitError, ExitSucceed}; +use evm::{executor::stack::PrecompileFailure, ExitSucceed}; use module_evm::precompile::{LinearCostPrecompile, PrecompileId}; /// The identity precompile. @@ -127,43 +127,3 @@ impl LinearCostPrecompile for Sha256 { Ok((ExitSucceed::Returned, ret.to_vec())) } } - -/// The ECRecoverPublicKey precompile. -/// Similar to ECRecover, but returns the pubkey (not the corresponding Ethereum address) -pub struct ECRecoverPublicKey; - -impl PrecompileId for ECRecoverPublicKey { - fn contract_id() -> u64 { - 0x6 - } -} - -impl LinearCostPrecompile for ECRecoverPublicKey { - const BASE: u64 = 3000; - const WORD: u64 = 0; - - fn execute( - i: &[u8], - _: u64, - ) -> core::result::Result<(ExitSucceed, Vec), PrecompileFailure> { - let mut input = [0u8; 128]; - input[..min(i.len(), 128)].copy_from_slice(&i[..min(i.len(), 128)]); - - let mut msg = [0u8; 32]; - let mut sig = [0u8; 65]; - - msg[0..32].copy_from_slice(&input[0..32]); - sig[0..32].copy_from_slice(&input[64..96]); - sig[32..64].copy_from_slice(&input[96..128]); - sig[64] = input[63]; - - let pubkey = - fp_types::crypto::secp256k1_ecdsa_recover(&sig, &msg).map_err(|_| { - PrecompileFailure::Error { - exit_status: ExitError::Other("Public key recover failed".into()), - } - })?; - - Ok((ExitSucceed::Returned, pubkey.to_vec())) - } -} diff --git a/src/components/contracts/modules/evm/precompile/sha3fips/Cargo.toml b/src/components/contracts/modules/evm/precompile/sha3fips/Cargo.toml deleted file mode 100644 index 01c867e60..000000000 --- a/src/components/contracts/modules/evm/precompile/sha3fips/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "evm-precompile-sha3fips" -version = "0.1.0" -authors = ["FindoraNetwork"] -edition = "2021" -homepage = "https://findora.org/technology" -repository = "https://github.com/findoranetwork/platform/" -description = "SHA3 FIPS202 precompiles for EVM module." -readme = "README.md" - -[dependencies] -evm = { version = "0.35.0", default-features = false, features = ["with-serde"] } -module-evm = { path = "../../../../modules/evm"} -tiny-keccak = { version = "2.0", features = ["fips202"] } diff --git a/src/components/contracts/modules/evm/precompile/sha3fips/src/lib.rs b/src/components/contracts/modules/evm/precompile/sha3fips/src/lib.rs deleted file mode 100644 index e49880c72..000000000 --- a/src/components/contracts/modules/evm/precompile/sha3fips/src/lib.rs +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// This file is part of Frontier. -// -// Copyright (c) 2020 Parity Technologies (UK) Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use evm::executor::stack::PrecompileFailure; -use evm::ExitSucceed; -use module_evm::precompile::{LinearCostPrecompile, PrecompileId}; -use tiny_keccak::Hasher; - -pub struct Sha3FIPS256; - -impl PrecompileId for Sha3FIPS256 { - fn contract_id() -> u64 { - 0x7 - } -} - -impl LinearCostPrecompile for Sha3FIPS256 { - const BASE: u64 = 60; - const WORD: u64 = 12; - - fn execute( - input: &[u8], - _: u64, - ) -> core::result::Result<(ExitSucceed, Vec), PrecompileFailure> { - let mut output = [0; 32]; - let mut sha3 = tiny_keccak::Sha3::v256(); - sha3.update(input); - sha3.finalize(&mut output); - Ok((ExitSucceed::Returned, output.to_vec())) - } -} - -pub struct Sha3FIPS512; - -impl PrecompileId for Sha3FIPS512 { - fn contract_id() -> u64 { - 0x8 - } -} - -impl LinearCostPrecompile for Sha3FIPS512 { - const BASE: u64 = 60; - const WORD: u64 = 12; - - fn execute( - input: &[u8], - _: u64, - ) -> core::result::Result<(ExitSucceed, Vec), PrecompileFailure> { - let mut output = [0; 64]; - let mut sha3 = tiny_keccak::Sha3::v512(); - sha3.update(input); - sha3.finalize(&mut output); - Ok((ExitSucceed::Returned, output.to_vec())) - } -} diff --git a/src/components/contracts/modules/evm/precompile/src/lib.rs b/src/components/contracts/modules/evm/precompile/src/lib.rs index 266b7d6aa..0c4b3afa9 100644 --- a/src/components/contracts/modules/evm/precompile/src/lib.rs +++ b/src/components/contracts/modules/evm/precompile/src/lib.rs @@ -23,7 +23,7 @@ where Self(Default::default(), ctx) } pub fn used_addresses() -> std::vec::Vec { - std::vec![1, 2, 3, 4, 5, 1024, 1025] + std::vec![0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x1000, 0x2001, 0x2002] .into_iter() .map(hash) .collect() @@ -45,7 +45,7 @@ where let ctx = &self.1; match address { - // Ethereum precompiles : + // Ethereum precompiles: a if a == H160::from_low_u64_be(ECRecover::contract_id()) => { Some(ECRecover::execute(input, target_gas, context, ctx)) } From 1e800ceecc021661621691480b806234da334072 Mon Sep 17 00:00:00 2001 From: Harshad Patil Date: Tue, 22 Aug 2023 09:35:21 -0700 Subject: [PATCH 3/7] Add triple masking (#1004) * triple_masking * ledger add noah * components add noah * fix lint * update keypair * fix lint * remove is_address_fra * fix xfrboxy * signature.verify * update enable_triple_masking_height to enable_ed25519_triple_masking_height * fix OwnerMemo * fix test * update noah version * fix anon transfer batch --------- Co-authored-by: shaorongqiang triple_masking dependencies to develop (#926) * dependencies to develop * update wasm-bindgen * remove noah * strike build_record_and_get_blinds --------- Co-authored-by: shaorongqiang Co-authored-by: weikengchen Renew #935 for merging develop with main. (#937) * fix * Upgrade noah to v0.4.6 * update --------- Co-authored-by: weikeng Co-authored-by: Sun Co-authored-by: weikengchen Add noah init wasm (#941) Fix abar_to_ar params (#950) Let the Anemoi precompile use the platform-lib-noah library (#963) fix build (#977) Co-authored-by: Weikeng Chen Improve Noah secp support (#981) * Improve Noah secp support * update deps * update platform-lib-utils for testing * public key to bytes in data_model * fix * fix * Avoid lint bug * fix EVM XfrPublicKey deserialization * edit the dependency * fix error handling --------- Co-authored-by: weikengchen EIP 1962 is undecided (#984) Use BN254 Anemoi for asset ID mapping (#985) * Improve Noah secp support * update deps * update platform-lib-utils for testing * public key to bytes in data_model * fix * fix * Avoid lint bug * fix EVM XfrPublicKey deserialization * edit the dependency * fix error handling * update the asset code * fix --------- Co-authored-by: Harshad Patil add validator_whitelist v1 (#972) * fix timeout and checkpoint * add validator_whitelist v1 * add validator_whitelist add validator_whitelist_v2 (#976) * add validator_whitelist_v2 * update timeout_commit 10s * update validator_whitelist * bug fix * fix build validator whitelist v3 (#980) downgrade ctrlc (#973) update timeout_propose 3s (#974) update timeout_commit 10s (#975) Fix Fn_Check Bug (#970) android add execption (#979) validator whitelist v3 (#980) pr Adding checkpoint condition to AnemoiJive381 upgrade only use deprecated AnemoiJive381 for old precompiled contract query server API to get derived asset code fix build remo0ve unneeded sign in tx build fix Lint fmt fix build CLI test file test disable eth address transfer from EVM fix build enable eth-address in CLI fix lint update lib-noah branch update demo tests for triple masking fix CLI eth-address removed unrelated code changes remove some unrelated code review ledger package fix wallet_mobile build remove unneccesary refactoring fix some refactoring synced changes from platform-lib-noah removed testing scripts fmt & lint fix import statements remove unneeded refactoring fix conflicts * removed some non Triple masking related code * rename checkpoint config var * fix derived asset code API * trigger tests * trigger * Update src/components/abciapp/src/abci/server/callback/mod.rs * Update src/components/contracts/modules/evm/precompile/src/lib.rs * Update lib.rs * Update Cargo.toml * Apply suggestions from code review * minor fix in fn.yml * genkey * stake append * staker update * unstake and claim * delegate, undelegate * transfer and transfer_batch * wallet/create, wallet/show * asset * other edits on fn * fmt * undo bash script change * Update src/components/abciapp/src/api/query_server/query_api/ledger_api.rs * Update src/components/abciapp/src/api/query_server/query_api/server.rs * Update src/components/abciapp/src/api/query_server/query_api/mod.rs * Apply suggestions from code review * Update src/components/finutils/src/bins/fn.rs * additional consistency test for the asset code is not necessary * change apphash calculation --------- Co-authored-by: Weikeng Chen --- Cargo.toml | 30 +- src/components/abciapp/src/abci/mod.rs | 1 - .../abciapp/src/abci/server/callback/mod.rs | 119 +- .../abciapp/src/abci/server/callback/utils.rs | 62 +- .../abciapp/src/abci/staking/test.rs | 16 +- .../api/query_server/query_api/ledger_api.rs | 30 +- .../src/api/query_server/query_api/mod.rs | 151 +- .../src/api/query_server/query_api/server.rs | 85 +- src/components/config/src/abci/mod.rs | 12 +- src/components/contracts/baseapp/Cargo.toml | 6 +- src/components/contracts/baseapp/src/lib.rs | 6 + .../contracts/baseapp/src/staking.rs | 3 +- .../contracts/modules/account/Cargo.toml | 2 +- .../modules/evm/precompile/Cargo.toml | 1 + .../modules/evm/precompile/basic/Cargo.toml | 3 - .../evm/precompile/eth-pairings/src/lib.rs | 17 +- .../evm/precompile/eth-pairings/src/tests.rs | 29 + .../modules/evm/precompile/utils/Cargo.toml | 2 +- .../modules/evm/precompile/utils/src/data.rs | 5 + .../contracts/modules/evm/src/lib.rs | 10 +- .../contracts/modules/evm/src/precompile.rs | 5 +- .../contracts/primitives/core/src/module.rs | 11 +- .../contracts/primitives/types/Cargo.toml | 1 + .../primitives/types/src/actions/account.rs | 5 +- .../contracts/primitives/types/src/crypto.rs | 8 +- src/components/contracts/rpc/Cargo.toml | 6 +- src/components/finutils/Cargo.toml | 13 +- src/components/finutils/src/bins/fn.rs | 424 ++++- src/components/finutils/src/bins/fn.yml | 450 ++++- .../finutils/src/bins/key_generator.rs | 2 +- src/components/finutils/src/bins/stt/stt.rs | 18 +- .../finutils/src/common/ddev/init.rs | 33 +- src/components/finutils/src/common/evm.rs | 26 +- src/components/finutils/src/common/mod.rs | 800 ++++++++- src/components/finutils/src/common/utils.rs | 315 +++- .../finutils/src/txn_builder/mod.rs | 1526 ++++++++++++++++- src/components/wallet_mobile/Cargo.toml | 5 +- .../wallet_mobile/src/android/constructor.rs | 5 +- .../wallet_mobile/src/android/evm.rs | 9 +- .../wallet_mobile/src/android/mod.rs | 35 +- .../wallet_mobile/src/android/transfer.rs | 48 +- .../wallet_mobile/src/android/tx_builder.rs | 80 +- .../wallet_mobile/src/ios/tx_builder.rs | 5 +- .../wallet_mobile/src/rust/crypto.rs | 23 +- .../wallet_mobile/src/rust/data_model.rs | 19 +- .../wallet_mobile/src/rust/transaction.rs | 21 +- .../wallet_mobile/src/rust/types.rs | 30 +- src/components/wallet_mobile/src/rust/util.rs | 2 +- src/components/wallet_mobile/src/wasm/mod.rs | 18 +- src/components/wasm/Cargo.toml | 10 +- src/components/wasm/src/wasm.rs | 875 +++++++++- src/components/wasm/src/wasm_data_model.rs | 181 +- src/ledger/Cargo.toml | 16 +- src/ledger/src/data_model/__trash__.rs | 3 +- src/ledger/src/data_model/effects.rs | 219 ++- src/ledger/src/data_model/mod.rs | 512 +++++- src/ledger/src/data_model/test.rs | 3 +- src/ledger/src/lib.rs | 2 +- src/ledger/src/staking/mod.rs | 15 +- src/ledger/src/staking/ops/delegation.rs | 2 +- src/ledger/src/staking/ops/mint_fra.rs | 2 +- src/ledger/src/store/api_cache.rs | 163 +- src/ledger/src/store/helpers.rs | 8 +- src/ledger/src/store/mod.rs | 636 ++++++- src/ledger/src/store/test.rs | 137 +- src/ledger/src/store/utils.rs | 1 + tools/devnet/snapshot.sh | 1 + 67 files changed, 6576 insertions(+), 743 deletions(-) create mode 100644 src/components/contracts/modules/evm/precompile/eth-pairings/src/tests.rs mode change 100644 => 100755 src/ledger/src/data_model/test.rs mode change 100644 => 100755 src/ledger/src/store/test.rs diff --git a/Cargo.toml b/Cargo.toml index 58870478f..1978086b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,22 +36,34 @@ members = [ ] [profile.dev] -incremental = false +opt-level = 3 +lto = "thin" +incremental = true +debug-assertions = true +debug = true +panic = 'abort' overflow-checks = true [profile.release] +opt-level = 3 +lto = "thin" incremental = false overflow-checks = true +panic = 'abort' [profile.bench] +opt-level = 3 +debug = false +rpath = false +lto = "thin" codegen-units = 1 +incremental = true +debug-assertions = false overflow-checks = false -[profile.dev.package.curve25519-dalek] -opt-level = 1 -overflow-checks = false - -[patch.crates-io] -ed25519-dalek = { git = "https://github.com/FindoraNetwork/ed25519-dalek", rev = "ad461f" } -curve25519-dalek = { git = "https://github.com/FindoraNetwork/curve25519-dalek", rev = "a2df65" } -x25519-dalek = { git = "https://github.com/FindoraNetwork/x25519-dalek", rev = "53bb1a" } +[profile.test] +opt-level = 2 +lto = "off" +incremental = true +debug-assertions = true +debug = true \ No newline at end of file diff --git a/src/components/abciapp/src/abci/mod.rs b/src/components/abciapp/src/abci/mod.rs index 507078bd1..10ff8c609 100644 --- a/src/components/abciapp/src/abci/mod.rs +++ b/src/components/abciapp/src/abci/mod.rs @@ -94,7 +94,6 @@ pub fn run() -> Result<()> { "http://{}:{}", config.tendermint_host, config.tendermint_port ); - // keep them running in the background, // avoid being dropped by the jsonrpc crate. mem::forget(fc_rpc::start_web3_service( diff --git a/src/components/abciapp/src/abci/server/callback/mod.rs b/src/components/abciapp/src/abci/server/callback/mod.rs index 081c1d023..34a6e63a0 100644 --- a/src/components/abciapp/src/abci/server/callback/mod.rs +++ b/src/components/abciapp/src/abci/server/callback/mod.rs @@ -2,13 +2,6 @@ //! # Impl function of tendermint ABCI //! -use globutils::wallet; -use ledger::{ - data_model::ASSET_TYPE_FRA, - staking::{FF_ADDR_EXTRA_120_0000, FF_ADDR_LIST}, -}; -use zei::noah_api::xfr::asset_record::AssetRecordType; - mod utils; use { @@ -32,11 +25,15 @@ use { STATE_UPDATE_LIST, TXS, WEB3_SERVICE_START_HEIGHT, }, fp_storage::hash::{Sha256, StorageHasher}, + globutils::wallet, lazy_static::lazy_static, ledger::{ converter::is_convert_account, - data_model::Operation, - staking::{evm::EVM_STAKING, KEEP_HIST, VALIDATOR_UPDATE_BLOCK_ITV}, + data_model::{Operation, Transaction, ASSET_TYPE_FRA}, + staking::{ + evm::EVM_STAKING, FF_ADDR_EXTRA_120_0000, FF_ADDR_LIST, KEEP_HIST, + VALIDATOR_UPDATE_BLOCK_ITV, + }, store::{ api_cache, fbnc::{new_mapx, Mapx}, @@ -56,6 +53,7 @@ use { }, }, tracing::{error, info}, + zei::noah_api::xfr::asset_record::AssetRecordType, }; pub(crate) static TENDERMINT_BLOCK_HEIGHT: AtomicI64 = AtomicI64::new(0); @@ -100,9 +98,15 @@ pub fn info(s: &mut ABCISubmissionServer, req: &RequestInfo) -> ResponseInfo { && h < CFG.checkpoint.enable_frc20_height { resp.set_last_block_app_hash(la_hash); - } else { + } else if h < CFG.checkpoint.enable_triple_masking_height { let cs_hash = s.account_base_app.write().info(req).last_block_app_hash; resp.set_last_block_app_hash(app_hash("info", h, la_hash, cs_hash)); + } else { + let cs_hash = s.account_base_app.write().info(req).last_block_app_hash; + let tm_hash = state.get_anon_state_commitment().0; + resp.set_last_block_app_hash(app_hash_v2( + "info", h, la_hash, cs_hash, tm_hash, + )); } } @@ -140,6 +144,18 @@ pub fn check_tx(s: &mut ABCISubmissionServer, req: &RequestCheckTx) -> ResponseC TxCatalog::FindoraTx => { if matches!(req.field_type, CheckTxType::New) { if let Ok(tx) = convert_tx(req.get_tx()) { + for op in tx.body.operations.iter() { + if let Operation::TransferAnonAsset(op) = op { + let mut inputs = op.note.body.inputs.clone(); + inputs.sort(); + inputs.dedup(); + if inputs.len() != op.note.body.inputs.len() { + resp.log = "anon transfer input error".to_owned(); + resp.code = 1; + return resp; + } + } + } if td_height > CFG.checkpoint.check_signatures_num { for op in tx.body.operations.iter() { if let Operation::TransferAsset(op) = op { @@ -171,6 +187,11 @@ pub fn check_tx(s: &mut ABCISubmissionServer, req: &RequestCheckTx) -> ResponseC } else if TX_HISTORY.read().contains_key(&tx.hash_tm_rawbytes()) { resp.log = "Historical transaction".to_owned(); resp.code = 1; + } else if is_tm_transaction(&tx) + && td_height < CFG.checkpoint.enable_triple_masking_height + { + resp.code = 1; + resp.log = "Triple Masking is disabled".to_owned(); } } else { resp.log = "Invalid format".to_owned(); @@ -272,6 +293,18 @@ pub fn deliver_tx( match tx_catalog { TxCatalog::FindoraTx => { if let Ok(tx) = convert_tx(req.get_tx()) { + for op in tx.body.operations.iter() { + if let Operation::TransferAnonAsset(op) = op { + let mut inputs = op.note.body.inputs.clone(); + inputs.sort(); + inputs.dedup(); + if inputs.len() != op.note.body.inputs.len() { + resp.log = "anon Transfer input error".to_owned(); + resp.code = 1; + return resp; + } + } + } if td_height > CFG.checkpoint.check_signatures_num { for op in tx.body.operations.iter() { if let Operation::TransferAsset(op) = op { @@ -336,7 +369,7 @@ pub fn deliver_tx( if let Err(err) = s.account_base_app.write().deliver_findora_tx(&tx, &hash.0) { - info!(target: "abciapp", "deliver convert account tx failed: {err:?}"); + error!(target: "abciapp", "deliver convert account tx failed: {err:?}"); resp.code = 1; resp.log = @@ -375,6 +408,16 @@ pub fn deliver_tx( .db .write() .discard_session(); + } else if is_tm_transaction(&tx) + && td_height < CFG.checkpoint.enable_triple_masking_height + { + info!(target: "abciapp", + "Triple Masking transaction(FindoraTx) detected at early height {}: {:?}", + td_height, tx + ); + resp.code = 2; + resp.log = "Triple Masking is disabled".to_owned(); + return resp; } else if CFG.checkpoint.utxo_checktx_height < td_height { match tx.check_tx() { Ok(_) => { @@ -597,8 +640,11 @@ pub fn commit(s: &mut ABCISubmissionServer, req: &RequestCommit) -> ResponseComm && td_height < CFG.checkpoint.enable_frc20_height { r.set_data(la_hash); - } else { + } else if td_height < CFG.checkpoint.enable_triple_masking_height { r.set_data(app_hash("commit", td_height, la_hash, cs_hash)); + } else { + let tm_hash = state.get_anon_state_commitment().0; + r.set_data(app_hash_v2("commit", td_height, la_hash, cs_hash, tm_hash)); } IN_SAFE_ITV.store(false, Ordering::Release); @@ -728,3 +774,52 @@ fn app_hash( la_hash } } + +/// Combines ledger state hash and EVM chain state hash +/// and print app hashes for debugging +fn app_hash_v2( + when: &str, + height: i64, + mut la_hash: Vec, + cs_hash: Vec, + tm_hash: Vec, +) -> Vec { + info!(target: "abciapp", + "app_hash_{}: {}_{}_{}, height: {}", + when, + hex::encode(la_hash.clone()), + hex::encode(cs_hash.clone()), + hex::encode(tm_hash.clone()), + height + ); + + if !cs_hash.is_empty() { + la_hash.extend_from_slice(&cs_hash); + + if !tm_hash.is_empty() { + la_hash.extend_from_slice(&tm_hash); + } + + Sha256::hash(la_hash.as_slice()).to_vec() + } else if !tm_hash.is_empty() { + la_hash.extend([0u8; 32]); + la_hash.extend_from_slice(&tm_hash); + + Sha256::hash(la_hash.as_slice()).to_vec() + } else { + la_hash + } +} + +fn is_tm_transaction(tx: &Transaction) -> bool { + tx.body + .operations + .iter() + .try_for_each(|op| match op { + Operation::BarToAbar(_a) => None, + Operation::AbarToBar(_a) => None, + Operation::TransferAnonAsset(_a) => None, + _ => Some(()), + }) + .is_none() +} diff --git a/src/components/abciapp/src/abci/server/callback/utils.rs b/src/components/abciapp/src/abci/server/callback/utils.rs index 767fe014e..7f3e11946 100644 --- a/src/components/abciapp/src/abci/server/callback/utils.rs +++ b/src/components/abciapp/src/abci/server/callback/utils.rs @@ -39,8 +39,13 @@ pub fn gen_tendermint_attr(tx: &Transaction) -> RepeatedField { res.push(ev); let (from, to) = gen_tendermint_attr_addr(tx); + let (nullifiers, commitments) = gen_tendermint_attr_anon(tx); - if !from.is_empty() || !to.is_empty() { + if !from.is_empty() + || !to.is_empty() + || !nullifiers.is_empty() + || !commitments.is_empty() + { let mut ev = Event::new(); ev.set_field_type("addr".to_owned()); @@ -76,6 +81,8 @@ pub fn gen_tendermint_attr(tx: &Transaction) -> RepeatedField { index_addr!(from, "addr.from"); index_addr!(to, "addr.to"); + index_addr!(nullifiers, "nullifier.used"); + index_addr!(commitments, "commitment.created"); } RepeatedField::from_vec(res) @@ -126,6 +133,59 @@ fn gen_tendermint_attr_addr(tx: &Transaction) -> (Vec, Vec) { Operation::UpdateMemo(d) => { append_attr!(d); } + Operation::BarToAbar(d) => { + let mut attr = TagAttr::default(); + attr.addr = globutils::wallet::public_key_to_bech32( + &d.input_record().public_key, + ); + base.0.push(attr); + } + Operation::AbarToBar(d) => { + let mut attr = TagAttr::default(); + attr.addr = globutils::wallet::public_key_to_bech32( + &d.note.get_public_key(), + ); + base.1.push(attr); + } + _ => {} + } + + base + }) +} + +fn gen_tendermint_attr_anon(tx: &Transaction) -> (Vec, Vec) { + tx.body + .operations + .iter() + .fold((vec![], vec![]), |mut base, op| { + match op { + Operation::BarToAbar(d) => { + let mut attr = TagAttr::default(); + attr.addr = globutils::wallet::commitment_to_base58( + &d.output_record().commitment, + ); + base.1.push(attr); + } + Operation::AbarToBar(d) => { + let mut attr = TagAttr::default(); + attr.addr = + globutils::wallet::nullifier_to_base58(&d.note.get_input()); + base.0.push(attr); + } + Operation::TransferAnonAsset(d) => { + for ix in &d.note.body.inputs { + let mut attr = TagAttr::default(); + attr.addr = globutils::wallet::nullifier_to_base58(ix); + base.0.push(attr); + } + for ox in &d.note.body.outputs { + let mut attr = TagAttr::default(); + attr.addr = + globutils::wallet::commitment_to_base58(&ox.commitment); + base.1.push(attr); + } + } _ => {} } diff --git a/src/components/abciapp/src/abci/staking/test.rs b/src/components/abciapp/src/abci/staking/test.rs index d51880391..6dd104146 100644 --- a/src/components/abciapp/src/abci/staking/test.rs +++ b/src/components/abciapp/src/abci/staking/test.rs @@ -19,7 +19,7 @@ use { asset_record::{open_blind_asset_record, AssetRecordType}, structs::{AssetRecordTemplate, XfrAmount}, }, - {XfrKeyPair, XfrPublicKey}, + XfrKeyPair, XfrPublicKey, }, }; @@ -126,12 +126,12 @@ fn gen_transfer_tx( &owner_memo.map(|o| o.into_noah()), &owner_kp.into_noah(), ) - .c(d!()) - .and_then(|ob| { - trans_builder - .add_input(TxoRef::Absolute(sid), ob, None, None, i_am) - .c(d!()) - })?; + .c(d!()) + .and_then(|ob| { + trans_builder + .add_input(TxoRef::Absolute(sid), ob, None, None, i_am) + .c(d!()) + })?; alt!(0 == am, break); } @@ -166,5 +166,5 @@ fn gen_transfer_tx( .c(d!())?; tx_builder.add_operation(op); - Ok(tx_builder.take_transaction()) + tx_builder.build_and_take_transaction() } diff --git a/src/components/abciapp/src/api/query_server/query_api/ledger_api.rs b/src/components/abciapp/src/api/query_server/query_api/ledger_api.rs index 9c45577a4..bc6e38cfb 100644 --- a/src/components/abciapp/src/api/query_server/query_api/ledger_api.rs +++ b/src/components/abciapp/src/api/query_server/query_api/ledger_api.rs @@ -10,11 +10,12 @@ use { DelegationInfo, DelegatorInfo, DelegatorList, NetworkRoute, Validator, ValidatorDetail, ValidatorList, }, - globutils::HashOf, + globutils::{wallet, HashOf}, ledger::{ data_model::{ - AssetType, AssetTypeCode, AssetTypePrefix, AuthenticatedUtxo, StateCommitmentData, - TxnSID, TxoSID, UnAuthenticatedUtxo, Utxo, + ABARData, ATxoSID, AssetType, AssetTypeCode, AssetTypePrefix, + AuthenticatedUtxo, StateCommitmentData, TxnSID, TxoSID, UnAuthenticatedUtxo, + Utxo, }, staking::{ DelegationRwdDetail, DelegationState, Staking, TendermintAddr, @@ -222,8 +223,7 @@ pub async fn query_global_state( data: web::Data>>, ) -> web::Json<(HashOf>, u64, &'static str)> { let qs = data.read(); - let ledger = &qs.ledger_cloned; - let (hash, seq_id) = ledger.get_state_commitment(); + let (hash, seq_id) = qs.get_state_commitment_from_api_cache(); web::Json((hash, seq_id, "v4UVgkIBpj0eNYI1B1QhTTduJHCIHH126HcdesCxRdLkVGDKrVUPgwmNLCDafTVgC5e4oDhAGjPNt1VhUr6ZCQ==")) } @@ -712,6 +712,24 @@ pub async fn query_owned_utxos( .map(|pk| web::Json(pnk!(ledger.get_owned_utxos(&pk)))) } +// query utxos according to `commitment` +pub(super) async fn query_owned_abar( + data: web::Data>>, + com: web::Path, +) -> actix_web::Result>> { + let qs = data.read(); + let ledger = &qs.ledger_cloned; + globutils::wallet::commitment_from_base58(com.as_str()) + .c(d!()) + .map_err(|e| error::ErrorBadRequest(e.generate_log(None))) + .map(|com| { + web::Json(ledger.get_owned_abar(&com).map(|a| { + let c = wallet::commitment_to_base58(&com); + (a, ABARData { commitment: c }) + })) + }) +} + #[allow(missing_docs)] pub enum ApiRoutes { UtxoSid, @@ -725,6 +743,7 @@ pub enum ApiRoutes { TxnSidLight, GlobalStateVersion, OwnedUtxos, + OwnedAbars, ValidatorList, DelegationInfo, DelegatorList, @@ -749,6 +768,7 @@ impl NetworkRoute for ApiRoutes { ApiRoutes::DelegationInfo => "delegation_info", ApiRoutes::DelegatorList => "delegator_list", ApiRoutes::ValidatorDetail => "validator_detail", + ApiRoutes::OwnedAbars => "owned_abars", }; "/".to_owned() + endpoint } diff --git a/src/components/abciapp/src/api/query_server/query_api/mod.rs b/src/components/abciapp/src/api/query_server/query_api/mod.rs index 325a078d1..05aad71c7 100644 --- a/src/components/abciapp/src/api/query_server/query_api/mod.rs +++ b/src/components/abciapp/src/api/query_server/query_api/mod.rs @@ -16,8 +16,8 @@ use { globutils::wallet, ledger::{ data_model::{ - b64dec, AssetTypeCode, DefineAsset, IssuerPublicKey, Transaction, TxOutput, - TxnIDHash, TxnSID, TxoSID, XfrAddress, BLACK_HOLE_PUBKEY, + b64dec, ATxoSID, AssetTypeCode, DefineAsset, IssuerPublicKey, Transaction, + TxOutput, TxnIDHash, TxnSID, TxoSID, XfrAddress, BLACK_HOLE_PUBKEY, }, staking::{ ops::mint_fra::MintEntry, FF_PK_EXTRA_120_0000, FRA, FRA_TOTAL_AMOUNT, @@ -29,11 +29,15 @@ use { serde::{Deserialize, Serialize}, server::QueryServer, std::{ - collections::{BTreeMap, HashSet}, + collections::{BTreeMap, HashMap, HashSet}, sync::Arc, }, tracing::info, - zei::{noah_algebra::serialization::NoahFromToBytes, OwnerMemo, XfrPublicKey}, + zei::{ + noah_algebra::serialization::NoahFromToBytes, + noah_api::anon_xfr::structs::{AxfrOwnerMemo, Commitment, MTLeafInfo}, + OwnerMemo, XfrPublicKey, + }, }; /// Returns the git commit hash and commit date of this build @@ -91,6 +95,44 @@ pub async fn get_owner_memo_batch( Ok(web::Json(resp)) } +/// Returns the owner memo required to decrypt the asset record stored at given index, if it exists. +#[allow(clippy::unnecessary_wraps)] +async fn get_abar_memo( + data: web::Data>>, + info: web::Path, +) -> actix_web::Result>, actix_web::error::Error> { + let server = data.read(); + Ok(web::Json(server.get_abar_memo(ATxoSID(*info)))) +} + +/// Returns the owner memos required to decrypt the asset record stored at between start and end, +/// include start and end, limit 100. +async fn get_abar_memos( + data: web::Data>>, + query: web::Query>, +) -> actix_web::Result>, actix_web::error::Error> { + match (query.get("start"), query.get("end")) { + (Some(start), Some(end)) => { + if end < start || end - start > 100 { + // return limit 100 error. + return Err(actix_web::error::ErrorBadRequest("Limit 100")); + } + let server = data.read(); + Ok(web::Json(server.get_abar_memos(*start, *end))) + } + _ => Err(actix_web::error::ErrorBadRequest("Missing start and end")), + } +} + +/// Return the abar commitment by sid. +async fn get_abar_commitment( + data: web::Data>>, + info: web::Path, +) -> actix_web::Result>, actix_web::error::Error> { + let server = data.read(); + Ok(web::Json(server.get_abar_commitment(ATxoSID(*info)))) +} + /// Returns an array of the utxo sids currently spendable by a given address pub async fn get_owned_utxos( data: web::Data>>, @@ -112,6 +154,53 @@ pub async fn get_owned_utxos( Ok(web::Json(utxos)) } +/// Returns the ATxo Sid currently spendable by a given commitment +async fn get_owned_abar( + data: web::Data>>, + com: web::Path, +) -> actix_web::Result>> { + let qs = data.read(); + let ledger = &qs.ledger_cloned; + //let read = qs.state.as_ref().unwrap().read(); + globutils::wallet::commitment_from_base58(com.as_str()) + .c(d!()) + .map_err(|e| error::ErrorBadRequest(e.generate_log(None))) + .map(|com| web::Json(ledger.get_owned_abar(&com))) +} + +/// Returns the Merkle proof for anonymous transactions +async fn get_abar_proof( + data: web::Data>>, + info: web::Path, +) -> actix_web::Result>, actix_web::error::Error> { + let server = data.read(); + Ok(web::Json(server.get_abar_proof(ATxoSID(*info)))) +} + +/// Checks if a nullifier hash is present in nullifier set +async fn check_nullifier_hash( + data: web::Data>>, + info: web::Path, +) -> actix_web::Result>, actix_web::error::Error> { + let server = data.read(); + Ok(web::Json(server.check_nullifier_hash((*info).clone()))) +} + +async fn get_max_atxo_sid( + data: web::Data>>, +) -> actix_web::Result>, actix_web::error::Error> { + let server = data.read(); + Ok(web::Json(server.max_atxo_sid())) +} + +async fn get_max_atxo_sid_at_height( + data: web::Data>>, + info: web::Path, +) -> actix_web::Result>, actix_web::error::Error> { + let server = data.read(); + Ok(web::Json(server.max_atxo_sid_at_height(*info))) +} + /// Define interface type #[allow(missing_docs)] pub enum QueryServerRoutes { @@ -119,6 +208,14 @@ pub enum QueryServerRoutes { GetOwnerMemo, GetOwnerMemoBatch, GetOwnedUtxos, + GetOwnedAbars, + GetAbarCommitment, + GetAbarMemo, + GetAbarMemos, + GetAbarProof, + CheckNullifierHash, + GetMaxATxoSid, + GetMaxATxoSidAtHeight, GetCreatedAssets, GetIssuedRecords, GetIssuedRecordsByCode, @@ -137,8 +234,16 @@ impl NetworkRoute for QueryServerRoutes { QueryServerRoutes::GetRelatedTxns => "get_related_txns", QueryServerRoutes::GetRelatedXfrs => "get_related_xfrs", QueryServerRoutes::GetOwnedUtxos => "get_owned_utxos", + QueryServerRoutes::GetOwnedAbars => "get_owned_abar", QueryServerRoutes::GetOwnerMemo => "get_owner_memo", QueryServerRoutes::GetOwnerMemoBatch => "get_owner_memo_batch", + QueryServerRoutes::GetAbarCommitment => "get_abar_commitment", + QueryServerRoutes::GetAbarMemo => "get_abar_memo", + QueryServerRoutes::GetAbarMemos => "get_abar_memos", + QueryServerRoutes::GetAbarProof => "get_abar_proof", + QueryServerRoutes::CheckNullifierHash => "check_nullifier_hash", + QueryServerRoutes::GetMaxATxoSid => "get_max_atxo_sid", + QueryServerRoutes::GetMaxATxoSidAtHeight => "get_max_atxo_sid_at_height", QueryServerRoutes::GetCreatedAssets => "get_created_assets", QueryServerRoutes::GetIssuedRecords => "get_issued_records", QueryServerRoutes::GetIssuedRecordsByCode => "get_issued_records_by_code", @@ -519,6 +624,10 @@ impl QueryApi { &QueryServerRoutes::GetOwnedUtxos.with_arg_template("address"), web::get().to(get_owned_utxos), ) + .route( + &QueryServerRoutes::GetOwnedAbars.with_arg_template("commitment"), + web::get().to(get_owned_abar), + ) .route( &QueryServerRoutes::GetOwnerMemo.with_arg_template("txo_sid"), web::get().to(get_owner_memo), @@ -528,6 +637,36 @@ impl QueryApi { .with_arg_template("txo_sid_list"), web::get().to(get_owner_memo_batch), ) + .route( + &QueryServerRoutes::GetAbarCommitment.with_arg_template("atxo_sid"), + web::get().to(get_abar_commitment), + ) + .route( + &QueryServerRoutes::GetAbarMemo.with_arg_template("atxo_sid"), + web::get().to(get_abar_memo), + ) + .route( + &QueryServerRoutes::GetAbarMemos.route(), + web::get().to(get_abar_memos), + ) + .route( + &QueryServerRoutes::GetAbarProof.with_arg_template("atxo_sid"), + web::get().to(get_abar_proof), + ) + .route( + &QueryServerRoutes::CheckNullifierHash + .with_arg_template("null_hash"), + web::get().to(check_nullifier_hash), + ) + .route( + &QueryServerRoutes::GetMaxATxoSid.route(), + web::get().to(get_max_atxo_sid), + ) + .route( + &QueryServerRoutes::GetMaxATxoSidAtHeight + .with_arg_template("height"), + web::get().to(get_max_atxo_sid_at_height), + ) .route( &QueryServerRoutes::GetRelatedTxns.with_arg_template("address"), web::get().to(get_related_txns), @@ -617,6 +756,10 @@ impl QueryApi { &ApiRoutes::OwnedUtxos.with_arg_template("owner"), web::get().to(query_owned_utxos), ) + .route( + &ApiRoutes::OwnedAbars.with_arg_template("owner"), + web::get().to(query_owned_abar), + ) .route( &ApiRoutes::ValidatorList.route(), web::get().to(query_validators), diff --git a/src/components/abciapp/src/api/query_server/query_api/server.rs b/src/components/abciapp/src/api/query_server/query_api/server.rs index a1198a4d8..bca977019 100644 --- a/src/components/abciapp/src/api/query_server/query_api/server.rs +++ b/src/components/abciapp/src/api/query_server/query_api/server.rs @@ -3,11 +3,12 @@ //! use { + globutils::HashOf, lazy_static::lazy_static, ledger::{ data_model::{ - AssetTypeCode, DefineAsset, IssuerPublicKey, Transaction, TxOutput, - TxnIDHash, TxnSID, TxoSID, XfrAddress, + ATxoSID, AssetTypeCode, DefineAsset, IssuerPublicKey, StateCommitmentData, + Transaction, TxOutput, TxnIDHash, TxnSID, TxoSID, XfrAddress, }, staking::{ops::mint_fra::MintEntry, BlockHeight}, store::LedgerState, @@ -15,7 +16,10 @@ use { parking_lot::{Condvar, Mutex, RwLock}, ruc::*, std::{collections::HashSet, sync::Arc}, - zei::OwnerMemo, + zei::{ + noah_api::anon_xfr::structs::{AxfrOwnerMemo, Commitment, MTLeafInfo}, + OwnerMemo, + }, }; lazy_static! { @@ -300,6 +304,81 @@ impl QueryServer { .get(&txo_sid) } + /// Returns the abar owner memo required to decrypt the asset record stored at given index, if it exists. + #[inline(always)] + pub fn get_abar_memo(&self, atxo_sid: ATxoSID) -> Option { + self.ledger_cloned + .api_cache + .as_ref() + .and_then(|api| api.abar_memos.get(&atxo_sid)) + } + + /// Returns the owner memos required to decrypt the asset record stored at between start and end, + /// include start and end, limit 100. + #[inline(always)] + pub fn get_abar_memos(&self, start: u64, end: u64) -> Vec<(u64, AxfrOwnerMemo)> { + let mut memos = vec![]; + let cache = self.ledger_cloned.api_cache.as_ref().unwrap(); + for i in start..=end { + if let Some(memo) = cache.abar_memos.get(&ATxoSID(i)) { + memos.push((i, memo)); + } + } + memos + } + + #[inline(always)] + #[allow(missing_docs)] + pub fn get_state_commitment_from_api_cache( + &self, + ) -> (HashOf>, u64) { + let block_count = self.ledger_cloned.get_block_commit_count(); + let commitment = self + .ledger_cloned + .api_cache + .as_ref() + .unwrap() + .state_commitment_version + .clone() + .unwrap_or_else(|| HashOf::new(&None)); + (commitment, block_count) + } + + /// Returns the abar commitment by given index, if it exists. + pub fn get_abar_commitment(&self, atxo_sid: ATxoSID) -> Option { + self.ledger_cloned.get_abar(&atxo_sid) + } + + /// Returns the Merkle proof from the given ATxoSID + #[inline(always)] + pub fn get_abar_proof(&self, atxo_sid: ATxoSID) -> Option { + self.ledger_cloned.get_abar_proof(atxo_sid).ok() + } + + /// Returns a bool value from the given hash + #[inline(always)] + pub fn check_nullifier_hash(&self, null_hash: String) -> Option { + self.ledger_cloned.check_nullifier_hash(null_hash).ok() + } + + /// Returns an int value for the max ATxoSid + #[inline(always)] + pub fn max_atxo_sid(&self) -> Option { + self.ledger_cloned + .api_cache + .as_ref() + .and_then(|api| api.abar_memos.len().checked_sub(1)) + } + + /// Returns an int value for the max ATxoSid at a given block height + #[inline(always)] + pub fn max_atxo_sid_at_height(&self, height: BlockHeight) -> Option { + self.ledger_cloned + .api_cache + .as_ref() + .and_then(|api| api.height_to_max_atxo.get(&height).unwrap_or(None)) + } + /// retrieve block reward rate at specified block height #[inline(always)] pub fn query_block_rewards_rate(&self, height: &BlockHeight) -> Option<[u128; 2]> { diff --git a/src/components/config/src/abci/mod.rs b/src/components/config/src/abci/mod.rs index 9d92ac6ae..e06eb0468 100644 --- a/src/components/config/src/abci/mod.rs +++ b/src/components/config/src/abci/mod.rs @@ -92,6 +92,8 @@ pub struct CheckPointConfig { pub fix_exec_code: i64, + pub enable_triple_masking_height: i64, + #[serde(default = "def_check_signatures_num")] pub check_signatures_num: i64, @@ -171,14 +173,14 @@ fn def_utxo_asset_prefix_height() -> u64 { DEFAULT_CHECKPOINT_CONFIG.utxo_asset_prefix_height } -fn def_prismxx_inital_height() -> i64 { - DEFAULT_CHECKPOINT_CONFIG.prismxx_inital_height -} - fn def_utxo_asset_prefix_height_2nd_update() -> u64 { DEFAULT_CHECKPOINT_CONFIG.utxo_asset_prefix_height_2nd_update } +fn def_prismxx_inital_height() -> i64 { + DEFAULT_CHECKPOINT_CONFIG.prismxx_inital_height +} + fn def_prism_bridge_address() -> String { DEFAULT_CHECKPOINT_CONFIG.prism_bridge_address.clone() } @@ -259,6 +261,7 @@ lazy_static! { evm_substate_v2_height: 0, disable_delegate_frc20: 0, fix_exec_code: 0, + enable_triple_masking_height: 0, check_signatures_num: 0, fix_deliver_tx_revert_nonce_height: 0, utxo_asset_prefix_height: 0, @@ -307,6 +310,7 @@ lazy_static! { evm_substate_v2_height: 3351349, disable_delegate_frc20: 3401450, fix_exec_code: 3401450, + enable_triple_masking_height: 5000_0000, check_signatures_num: 4004430, fix_deliver_tx_revert_nonce_height: 4004430, utxo_asset_prefix_height: 4004430, diff --git a/src/components/contracts/baseapp/Cargo.toml b/src/components/contracts/baseapp/Cargo.toml index 32483d3ba..996605b1a 100644 --- a/src/components/contracts/baseapp/Cargo.toml +++ b/src/components/contracts/baseapp/Cargo.toml @@ -48,8 +48,12 @@ evm-precompile = {path = "../modules/evm/precompile"} evm-precompile-basic = {path = "../modules/evm/precompile/basic"} evm-precompile-frc20 = {path = "../modules/evm/precompile/frc20"} evm-precompile-modexp = {path = "../modules/evm/precompile/modexp"} +evm-precompile-blake2 = {path = "../modules/evm/precompile/blake2"} +evm-precompile-bn128 = {path = "../modules/evm/precompile/bn128"} +evm-precompile-anemoi = {path = "../modules/evm/precompile/anemoi"} + [features] abci_mock = [] benchmark = ["module-evm/benchmark","module-ethereum/benchmark"] -debug_env = [] \ No newline at end of file +debug_env = [] diff --git a/src/components/contracts/baseapp/src/lib.rs b/src/components/contracts/baseapp/src/lib.rs index 049c4ec9c..8caa73d15 100644 --- a/src/components/contracts/baseapp/src/lib.rs +++ b/src/components/contracts/baseapp/src/lib.rs @@ -164,7 +164,13 @@ impl module_evm::Config for BaseApp { evm_precompile_basic::Ripemd160, evm_precompile_basic::Identity, evm_precompile_modexp::Modexp, + evm_precompile_bn128::Bn128Add, + evm_precompile_bn128::Bn128Mul, + evm_precompile_bn128::Bn128Pairing, + evm_precompile_blake2::Blake2F, evm_precompile_frc20::FRC20, + evm_precompile_anemoi::Anemoi254, + evm_precompile_anemoi::Anemoi381, ); type PrecompilesType = FindoraPrecompiles; type PrecompilesValue = PrecompilesValue; diff --git a/src/components/contracts/baseapp/src/staking.rs b/src/components/contracts/baseapp/src/staking.rs index 74cfc7e97..b588ab99f 100644 --- a/src/components/contracts/baseapp/src/staking.rs +++ b/src/components/contracts/baseapp/src/staking.rs @@ -15,8 +15,7 @@ use module_evm::{ use ruc::{d, Result, RucResult}; use sha3::{Digest, Keccak256}; use std::{collections::BTreeMap, str::FromStr}; -use zei::noah_algebra::prelude::NoahFromToBytes; -use zei::XfrPublicKey; +use zei::{noah_algebra::prelude::NoahFromToBytes, XfrPublicKey}; impl EVMStaking for BaseApp { fn import_validators( diff --git a/src/components/contracts/modules/account/Cargo.toml b/src/components/contracts/modules/account/Cargo.toml index 41ab844e4..c12d7b5aa 100644 --- a/src/components/contracts/modules/account/Cargo.toml +++ b/src/components/contracts/modules/account/Cargo.toml @@ -24,9 +24,9 @@ fp-traits = { path = "../../primitives/traits" } fp-types = { path = "../../primitives/types" } enterprise-web3 = { path = "../../primitives/enterprise-web3" } config = { path = "../../../config"} +zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } [dev-dependencies] rand_chacha = "0.3" parking_lot = "0.12" -zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } fin_db = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.6" } diff --git a/src/components/contracts/modules/evm/precompile/Cargo.toml b/src/components/contracts/modules/evm/precompile/Cargo.toml index 61af3152e..943af994c 100644 --- a/src/components/contracts/modules/evm/precompile/Cargo.toml +++ b/src/components/contracts/modules/evm/precompile/Cargo.toml @@ -20,3 +20,4 @@ evm-precompile-bn128 = {path = "./bn128"} fp-core = {path = "../../../primitives/core"} module-evm = {path = "../../../modules/evm"} parking_lot = "0.12" +evm-precompile-eth-pairings = { path = "./eth-pairings" } diff --git a/src/components/contracts/modules/evm/precompile/basic/Cargo.toml b/src/components/contracts/modules/evm/precompile/basic/Cargo.toml index e8b9ad551..5aa4d2c9d 100644 --- a/src/components/contracts/modules/evm/precompile/basic/Cargo.toml +++ b/src/components/contracts/modules/evm/precompile/basic/Cargo.toml @@ -18,8 +18,5 @@ evm = { version = "0.35.0", default-features = false, features = ["with-serde"] module-evm = { path = "../../../../modules/evm"} ripemd = "0.1" -# primitives -#fp-core = { path = "../../../../primitives/core" } -#fp-evm = { path = "../../../../primitives/evm" } fp-types = { path = "../../../../primitives/types" } fp-utils = { path = "../../../../primitives/utils" } \ No newline at end of file diff --git a/src/components/contracts/modules/evm/precompile/eth-pairings/src/lib.rs b/src/components/contracts/modules/evm/precompile/eth-pairings/src/lib.rs index 66f28d8d3..470fec3c3 100644 --- a/src/components/contracts/modules/evm/precompile/eth-pairings/src/lib.rs +++ b/src/components/contracts/modules/evm/precompile/eth-pairings/src/lib.rs @@ -3,11 +3,7 @@ mod tests; use eth_pairings::public_interface::{perform_operation, ApiError, OperationType}; use evm::executor::stack::{PrecompileFailure, PrecompileOutput}; -use evm::{ - // Context, - ExitError, - ExitSucceed, -}; +use evm::{Context, ExitError, ExitSucceed}; use evm_precompile_utils::{EvmDataReader, EvmDataWriter, EvmResult, Gasometer}; use module_evm::precompile::{FinState, Precompile, PrecompileId, PrecompileResult}; use tracing::debug; @@ -29,12 +25,11 @@ pub enum Call { impl Precompile for EthPairing { fn execute( - handle: &mut impl PrecompileHandle, + input: &[u8], + target_gas: Option, + _context: &Context, _state: &FinState, ) -> PrecompileResult { - let input = handle.input(); - let target_gas = handle.gas_limit(); - let mut input = EvmDataReader::new(input); let selector = match input.read_selector::() { Ok(v) => v, @@ -91,11 +86,11 @@ impl EthPairing { Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - // cost: gasometer.used_gas(), + cost: gasometer.used_gas(), output: EvmDataWriter::new() .write_raw_bytes(result.as_slice()) .build(), - // logs: vec![], + logs: vec![], }) } } diff --git a/src/components/contracts/modules/evm/precompile/eth-pairings/src/tests.rs b/src/components/contracts/modules/evm/precompile/eth-pairings/src/tests.rs new file mode 100644 index 000000000..2ff06a41d --- /dev/null +++ b/src/components/contracts/modules/evm/precompile/eth-pairings/src/tests.rs @@ -0,0 +1,29 @@ +use crate::*; +use ethereum_types::H160; +use fp_mocks::*; + +// Test from eth-pairings (eip1962) repository https://github.com/FindoraNetwork/eip1962 +#[test] +fn test_bls12_pairing() { + use hex; + let hex_string = "07202912811758d871b77a9c3635c28570dc020576f9fc2719d8d0494439162b2b89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011603e65409b693c8a08aeb3478d10aa3732a6672ba06d12912811758d871b77a9c3635c28570dc020576f9fc2719d8d0494439162b2b84000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010206059efde42f3701020127ccb2831f0011c1d547c491b9dffbd4cfdb87598a4b370f5873ea62094a2f201faa6cb7f6fcca66de3f308a25776dac3f61edb792948fbe53e4d18a3d8aefbe011a7e9f75f3fdc77b83a97f7acd58326a0545f8aa37b69bfb32c52dc195763e8c17176e0ad4ee94d9c720e922d42688127c4b812cd7c2f8cf6126acd4c3d7568121e48b3fefe66c279f2ec71f0d6f8156a3343d1cfa54b808d747cd02419278290ad2d7d03f5de1e7b3c97732f53dbe1dfd42e51f9571f7fee3d9c1785d5a1ed6010b4f7f211a0a5f4425728e2df580196d3e3b85ef148ed769acd23e9be6e8440726cb40655787f48eaf46154cb740e2a58db5b96fa02d83fb9d0f94320da1471e0104ece4c46ac4f05a7c28ecda84292f15999747bb77c530c65448f1f837a47dd70e972c4065d0b39d40b5d550a55901516afa7f02b395963d1535fcba1705e31a117cb4beab1dc582198c4ab0c02e96a22f7bd10dde3bbbdbc9182a9596cb0ed32121616b692e8036437efb4c3816f018f11e643c6e0a049da431986a3a722b06"; + let data = hex::decode(hex_string).unwrap(); + + let output = EthPairing::execute( + &EvmDataWriter::new() + .write_selector(Call::ExecuteOperation) + .write_raw_bytes(&data) + .build(), + None, + &evm::Context { + address: H160::from_low_u64_be(2001), + caller: ALICE_ECDSA.address, + apparent_value: From::from(0), + }, + &BASE_APP.lock().unwrap().deliver_state, + ); + + assert!(output.is_ok()); + assert_eq!(output.as_ref().unwrap().cost, 164986); + assert_eq!(output.unwrap().output, vec![0x1]); +} diff --git a/src/components/contracts/modules/evm/precompile/utils/Cargo.toml b/src/components/contracts/modules/evm/precompile/utils/Cargo.toml index d525e8599..5a2091980 100644 --- a/src/components/contracts/modules/evm/precompile/utils/Cargo.toml +++ b/src/components/contracts/modules/evm/precompile/utils/Cargo.toml @@ -12,4 +12,4 @@ evm = { version = "0.35.0", default-features = false, features = ["with-serde"] tracing = "0.1" num_enum = { version = "0.5.3", default-features = false } precompile-utils-macro = { path = "macro" } -sha3 = { version = "0.8", default-features = false } +sha3 = { version = "0.10", default-features = false } diff --git a/src/components/contracts/modules/evm/precompile/utils/src/data.rs b/src/components/contracts/modules/evm/precompile/utils/src/data.rs index 99684f5f6..0958189bc 100644 --- a/src/components/contracts/modules/evm/precompile/utils/src/data.rs +++ b/src/components/contracts/modules/evm/precompile/utils/src/data.rs @@ -115,6 +115,11 @@ impl<'a> EvmDataReader<'a> { Ok(start..end) } + + /// Get slice from cursor to the end of buffer + pub fn get_slice(&mut self) -> &[u8] { + &self.input[self.cursor..] + } } /// Help build an EVM input/output data. diff --git a/src/components/contracts/modules/evm/src/lib.rs b/src/components/contracts/modules/evm/src/lib.rs index 9ded144a5..20ddb498b 100644 --- a/src/components/contracts/modules/evm/src/lib.rs +++ b/src/components/contracts/modules/evm/src/lib.rs @@ -16,8 +16,7 @@ use ethabi::Token; use ethereum::{ Log, ReceiptV0 as Receipt, TransactionAction, TransactionSignature, TransactionV0, }; -use ethereum_types::U256; -use ethereum_types::{Bloom, BloomInput, H160, H256}; +use ethereum_types::{Bloom, BloomInput, H160, H256, U256}; use evm::executor::stack::PrecompileSet as EvmPrecompileSet; use fp_core::{ context::Context, @@ -33,10 +32,10 @@ use fp_traits::{ account::AccountAsset, evm::{AddressMapping, BlockHashMapping, DecimalsMapping, FeeCalculator}, }; -use fp_types::crypto::HA256; + use fp_types::{ actions::evm::Action, - crypto::{Address, HA160}, + crypto::{Address, HA160, HA256}, }; use ledger::staking::evm::EVM_STAKING_MINTS; use ledger::staking::FRA_PRE_ISSUE_AMOUNT; @@ -50,8 +49,7 @@ use std::marker::PhantomData; use std::str::FromStr; use system_contracts::{SystemContracts, SYSTEM_ADDR}; use utils::parse_evm_staking_coinbase_mint_event; -use zei::noah_algebra::serialization::NoahFromToBytes; -use zei::XfrPublicKey; +use zei::{noah_algebra::serialization::NoahFromToBytes, XfrPublicKey}; use crate::utils::parse_evm_staking_mint_event; diff --git a/src/components/contracts/modules/evm/src/precompile.rs b/src/components/contracts/modules/evm/src/precompile.rs index ac28fe117..5eb302871 100644 --- a/src/components/contracts/modules/evm/src/precompile.rs +++ b/src/components/contracts/modules/evm/src/precompile.rs @@ -2,10 +2,7 @@ use crate::runtime::stack::FindoraStackState; use ethereum_types::H160; use evm::{ executor::stack::{PrecompileFailure, PrecompileOutput}, - Context, - // Context, - ExitError, - ExitSucceed, + Context, ExitError, ExitSucceed, }; use impl_trait_for_tuples::impl_for_tuples; diff --git a/src/components/contracts/primitives/core/src/module.rs b/src/components/contracts/primitives/core/src/module.rs index 7a7e843a4..cf0c284c7 100644 --- a/src/components/contracts/primitives/core/src/module.rs +++ b/src/components/contracts/primitives/core/src/module.rs @@ -1,6 +1,6 @@ use crate::context::Context; use abci::*; -use primitive_types::U256; +use fp_types::U256; use ruc::Result; /// AppModuleBasic is the standard form for basic non-dependant elements of an application module. @@ -45,4 +45,13 @@ pub trait AppModule: AppModuleBasic { ) -> (ResponseEndBlock, U256) { Default::default() } + + fn commit( + &mut self, + _ctx: &mut Context, + _height: U256, + _root_hash: &[u8], + ) -> Result<()> { + Ok(()) + } } diff --git a/src/components/contracts/primitives/types/Cargo.toml b/src/components/contracts/primitives/types/Cargo.toml index 23795d7ff..497e24d50 100644 --- a/src/components/contracts/primitives/types/Cargo.toml +++ b/src/components/contracts/primitives/types/Cargo.toml @@ -20,6 +20,7 @@ primitive-types = { version = "0.11.1", default-features = false, features = ["r ruc = "1.0" serde = { version = "1.0.124", features = ["derive"] } serde_json = "1.0" +serde-big-array = "0.4" sha3 = "0.10" zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } fixed-hash = "0.8.0" diff --git a/src/components/contracts/primitives/types/src/actions/account.rs b/src/components/contracts/primitives/types/src/actions/account.rs index dc608aa2a..4814f4b04 100644 --- a/src/components/contracts/primitives/types/src/actions/account.rs +++ b/src/components/contracts/primitives/types/src/actions/account.rs @@ -1,6 +1,7 @@ use serde::{Deserialize, Serialize}; -use zei::XfrPublicKey; -use zei::noah_api::xfr::structs::AssetType; +use zei::{ + noah_api::xfr::structs::AssetType, XfrPublicKey +}; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum Action { diff --git a/src/components/contracts/primitives/types/src/crypto.rs b/src/components/contracts/primitives/types/src/crypto.rs index f29de6cb8..6345fc11e 100644 --- a/src/components/contracts/primitives/types/src/crypto.rs +++ b/src/components/contracts/primitives/types/src/crypto.rs @@ -11,11 +11,10 @@ use { serde::{Deserialize, Serialize}, sha3::{Digest, Keccak256}, std::ops::{Deref, DerefMut}, - zei::noah_algebra::serialization::NoahFromToBytes, - zei::{XfrPublicKey, XfrSignature}, + zei::{noah_algebra::serialization::NoahFromToBytes, XfrPublicKey, XfrSignature}, }; -/// An opaque 32-byte cryptographic identifier. +/// An opaque 34-byte cryptographic identifier. #[derive( Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash, Serialize, Deserialize, Debug, )] @@ -261,9 +260,6 @@ impl Verify for MultiSignature { } } Self::Ecdsa(ref sig) => { - // let mut msg_hashed = [0u8; 32]; - // msg_hashed.copy_from_slice(msg); - let msg_hashed = keccak_256(msg); match secp256k1_ecdsa_recover(sig.as_ref(), &msg_hashed) { Ok(pubkey) => { diff --git a/src/components/contracts/rpc/Cargo.toml b/src/components/contracts/rpc/Cargo.toml index 10400b9c5..a7eef232f 100644 --- a/src/components/contracts/rpc/Cargo.toml +++ b/src/components/contracts/rpc/Cargo.toml @@ -26,7 +26,7 @@ jsonrpc-derive = { git = "https://github.com/FindoraNetwork/jsonrpc.git", packag jsonrpc-pubsub = { git = "https://github.com/FindoraNetwork/jsonrpc.git", package = "jsonrpc-pubsub" } jsonrpc-http-server = { git = "https://github.com/FindoraNetwork/jsonrpc.git", package = "jsonrpc-http-server" } jsonrpc-tcp-server = { git = "https://github.com/FindoraNetwork/jsonrpc.git", package = "jsonrpc-tcp-server" } -libsecp256k1 = { version = "0.5", features = ["static-context", "hmac"] } +libsecp256k1 = { version = "0.7", features = ["static-context", "hmac"] } lazy_static = "1.4.0" tracing = "0.1" rand = "0.8" @@ -39,8 +39,8 @@ rustc_version = "0.4.0" semver = "1.0.4" serde_json = "1.0" sha3 = "0.10" -tendermint = { git = "https://github.com/FindoraNetwork/tendermint-rs", tag = "v0.19.0a-fk" } -tendermint-rpc = { git = "https://github.com/FindoraNetwork/tendermint-rs", features = ["http-client", "websocket-client"], tag = "v0.19.0a-fk" } +tendermint = { git = "https://github.com/FindoraNetwork/tendermint-rs", tag = "v0.19.0c" } +tendermint-rpc = { git = "https://github.com/FindoraNetwork/tendermint-rs", features = ["http-client", "websocket-client"], tag = "v0.19.0c" } tokio = { version = "1.10.1", features = ["full"] } lru = "0.7" num_cpus = "1.13" diff --git a/src/components/finutils/Cargo.toml b/src/components/finutils/Cargo.toml index d630f1a58..4c427d9cb 100644 --- a/src/components/finutils/Cargo.toml +++ b/src/components/finutils/Cargo.toml @@ -17,16 +17,18 @@ serde = { version = "1.0.124", features = ["derive"] } rand = "0.8" rand_core = { version = "0.6", default-features = false, features = ["alloc"] } rand_chacha = "0.3" -noah-curve25519-dalek = { version = "4.0.0", features = ["serde"] } +curve25519-dalek = { package = "noah-curve25519-dalek", version = "4.0.0", default-features = false, features = ['serde'] } wasm-bindgen = { version = "=0.2.84", features = ["serde-serialize"] } sha2 = "0.10" +digest = '0.10' +parking_lot = "0.12" +getrandom = "0.2" zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } ruc = "1.0" rucv4 = { package = "ruc", version = "4.0" } nix = "0.25" -ledger = { path = "../../ledger" } - +ledger = { path = "../../ledger", default-features = false } globutils = { git = "https://github.com/FindoraNetwork/platform-lib-utils", branch = "develop" } credentials = { git = "https://github.com/FindoraNetwork/platform-lib-credentials", branch = "develop" } @@ -35,11 +37,10 @@ fp-core = { path = "../contracts/primitives/core", default-features = false } fp-utils = { path = "../contracts/primitives/utils" } fp-types = { path = "../contracts/primitives/types" } -tendermint = { git = "https://github.com/FindoraNetwork/tendermint-rs", tag = "v0.19.0a-fk" } -tendermint-rpc = { git = "https://github.com/FindoraNetwork/tendermint-rs", features = ["http-client", "websocket-client"], optional = true, tag = "v0.19.0a-fk" } +tendermint = { git = "https://github.com/FindoraNetwork/tendermint-rs", tag = "v0.19.0c" } +tendermint-rpc = { git = "https://github.com/FindoraNetwork/tendermint-rs", features = ["http-client", "websocket-client"], optional = true, tag = "v0.19.0c" } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -# chaindev = { path = "../../../../chaindev" } chaindev = { git = "https://github.com/FindoraNetwork/chaindev", branch = "platform", default-features = false, features = ["tendermint_based", "vsdb_sled_engine"] } web3 = "0.19.0" tokio = "1.10.1" diff --git a/src/components/finutils/src/bins/fn.rs b/src/components/finutils/src/bins/fn.rs index 40889dc9f..83c45275f 100644 --- a/src/components/finutils/src/bins/fn.rs +++ b/src/components/finutils/src/bins/fn.rs @@ -31,15 +31,16 @@ use fp_types::H160; use { clap::{crate_authors, load_yaml, App}, - finutils::common::{self, evm::*}, + finutils::common::{self, evm::*, get_keypair, utils}, fp_utils::ecdsa::SecpPair, globutils::wallet, ledger::{ - data_model::{AssetTypeCode, FRA_DECIMALS}, + data_model::{AssetTypeCode, ASSET_TYPE_FRA, FRA_DECIMALS}, staking::{StakerMemo, VALIDATORS_MIN}, }, ruc::*, std::{fmt, fs}, + zei::{noah_api::anon_xfr::structs::OpenAnonAssetRecordBuilder, XfrSecretKey}, }; fn main() { @@ -59,11 +60,13 @@ fn run() -> Result<()> { if matches.is_present("version") { println!("{}", env!("VERGEN_SHA")); - } else if matches.is_present("genkey") { - common::gen_key_and_print(); + } else if let Some(m) = matches.subcommand_matches("genkey") { + let gen_eth_address = m.is_present("gen-eth-address"); + common::gen_key_and_print(gen_eth_address); } else if let Some(m) = matches.subcommand_matches("wallet") { if m.is_present("create") { - common::gen_key_and_print(); + let is_address_eth = m.is_present("gen-eth-address"); + common::gen_key_and_print(is_address_eth); } else if m.is_present("show") { let seckey = match m.value_of("seckey") { Some(path) => { @@ -71,6 +74,8 @@ fn run() -> Result<()> { } None => None, }; + let is_address_eth = m.is_present("use-default-eth-address"); + // FRA asset is the default case let asset = if let Some(code) = m.value_of("asset") { match code.to_lowercase().as_str() { @@ -80,7 +85,7 @@ fn run() -> Result<()> { } else { None }; - common::show_account(seckey.as_deref(), asset).c(d!())?; + common::show_account(seckey.as_deref(), asset, is_address_eth).c(d!())?; } else { println!("{}", m.usage()); } @@ -94,16 +99,18 @@ fn run() -> Result<()> { let amount = m.value_of("amount"); let validator = m.value_of("validator"); let show_info = m.is_present("info"); + let is_address_eth = m.is_present("use-default-eth-address"); if amount.is_some() && validator.is_some() { common::delegate( seckey.as_deref(), amount.unwrap().parse::().c(d!())?, validator.unwrap(), + is_address_eth, ) .c(d!())?; } else if show_info { - common::show_delegations(seckey.as_deref()).c(d!())?; + common::show_delegations(seckey.as_deref(), is_address_eth).c(d!())?; } else { println!("{}", m.usage()); } @@ -116,6 +123,7 @@ fn run() -> Result<()> { }; let amount = m.value_of("amount"); let validator = m.value_of("validator"); + let is_address_eth = m.is_present("use-default-eth-address"); if (amount.is_none() && validator.is_some()) || (amount.is_some() && validator.is_none()) { @@ -127,21 +135,18 @@ fn run() -> Result<()> { } else { None }; - common::undelegate(seckey.as_deref(), param).c(d!())?; + common::undelegate(seckey.as_deref(), param, is_address_eth).c(d!())?; } else if let Some(m) = matches.subcommand_matches("asset") { if m.is_present("create") { - let seckey = match m.value_of("seckey") { - Some(path) => { - Some(fs::read_to_string(path).c(d!("Failed to read seckey file"))?) - } - None => None, - }; + let seckey = read_file_path(m.value_of("seckey")).c(d!())?; let memo = m.value_of("memo"); if memo.is_none() { println!("{}", m.usage()); return Ok(()); } let transferable = m.is_present("transferable"); + let is_address_eth = m.is_present("use-default-eth-address"); + let decimal = if let Some(num) = m.value_of("decimal") { num.parse::() .c(d!("decimal should be an 8-bits unsinged integer"))? @@ -164,6 +169,7 @@ fn run() -> Result<()> { max_units, transferable, token_code, + is_address_eth, ) .c(d!())?; } else if m.is_present("show") { @@ -192,12 +198,19 @@ fn run() -> Result<()> { .parse::() .c(d!("amount should be a 64-bits unsigned integer"))?; let hidden = m.is_present("hidden"); + let is_address_eth = m.is_present("use-default-eth-address"); - common::issue_asset(seckey.as_deref(), code.unwrap(), amount, hidden) - .c(d!())?; + common::issue_asset( + seckey.as_deref(), + code.unwrap(), + amount, + hidden, + is_address_eth, + ) + .c(d!())?; } else { let help = "fn asset [--create | --issue | --show]"; - println!("{help}"); + println!("{help}",); } } else if let Some(m) = matches.subcommand_matches("staker-update") { let vm = if let Some(memo) = m.value_of("validator-memo") { @@ -228,6 +241,7 @@ fn run() -> Result<()> { } } }; + let is_address_eth = m.is_present("use-eth-address"); let cr = m.value_of("commission-rate"); if vm.is_none() && cr.is_none() { @@ -236,7 +250,7 @@ fn run() -> Result<()> { "Tips: to update the information of your node, please specify commission-rate or memo" ); } else { - common::staker_update(cr, vm).c(d!())?; + common::staker_update(cr, vm, is_address_eth).c(d!())?; } } else if let Some(m) = matches.subcommand_matches("stake") { let am = m.value_of("amount"); @@ -248,22 +262,31 @@ fn run() -> Result<()> { None => None, }; let td_addr = m.value_of("validator-td-addr"); + let is_address_eth = m.is_present("use-default-eth-address"); if am.is_none() { println!("{}", m.usage()); } else { - common::stake_append(am.unwrap(), staker.as_deref(), td_addr).c(d!())?; + common::stake_append( + am.unwrap(), + staker.as_deref(), + td_addr, + is_address_eth, + ) + .c(d!())?; } } else { let cr = m.value_of("commission-rate"); let vm = m.value_of("validator-memo"); let force = m.is_present("force"); + let is_address_eth = m.is_present("use-default-eth-address"); if am.is_none() || cr.is_none() { println!("{}", m.usage()); println!( "Tips: if you want to raise the power of your node, please use `fn stake --append [OPTIONS]`" ); } else { - common::stake(am.unwrap(), cr.unwrap(), vm, force).c(d!())?; + common::stake(am.unwrap(), cr.unwrap(), vm, force, is_address_eth) + .c(d!())?; } } } else if let Some(m) = matches.subcommand_matches("unstake") { @@ -275,9 +298,11 @@ fn run() -> Result<()> { None => None, }; let td_addr = m.value_of("validator-td-addr"); - common::unstake(am, staker.as_deref(), td_addr).c(d!())?; + let is_address_eth = m.is_present("use-default-eth-address"); + common::unstake(am, staker.as_deref(), td_addr, is_address_eth).c(d!())?; } else if let Some(m) = matches.subcommand_matches("claim") { let am = m.value_of("amount"); + let is_address_eth = m.is_present("use-default-eth-address"); let seckey = match m.value_of("seckey") { Some(path) => { Some(fs::read_to_string(path).c(d!("Failed to read seckey file"))?) @@ -291,10 +316,11 @@ fn run() -> Result<()> { return Ok(()); } }; - common::claim(td_addr, am, seckey.as_deref()).c(d!())?; + common::claim(td_addr, am, seckey.as_deref(), is_address_eth).c(d!())?; } else if let Some(m) = matches.subcommand_matches("show") { let basic = m.is_present("basic"); - common::show(basic).c(d!())?; + let is_address_eth = m.is_present("eth-address"); + common::show(basic, is_address_eth).c(d!())?; } else if let Some(m) = matches.subcommand_matches("setup") { let sa = m.value_of("serv-addr"); let om = m.value_of("owner-mnemonic-path"); @@ -305,12 +331,7 @@ fn run() -> Result<()> { common::setup(sa, om, tp).c(d!())?; } } else if let Some(m) = matches.subcommand_matches("transfer") { - let f = match m.value_of("from-seckey") { - Some(path) => { - Some(fs::read_to_string(path).c(d!("Failed to read seckey file"))?) - } - None => None, - }; + let f = read_file_path(m.value_of("from-seckey")).c(d!())?; let asset = m.value_of("asset").unwrap_or("FRA"); let t = m .value_of("to-pubkey") @@ -322,6 +343,7 @@ fn run() -> Result<()> { }) })?; let am = m.value_of("amount"); + let is_address_eth = m.is_present("use-default-eth-address"); if am.is_none() { println!("{}", m.usage()); @@ -338,6 +360,7 @@ fn run() -> Result<()> { am.unwrap(), m.is_present("confidential-amount"), m.is_present("confidential-type"), + is_address_eth, ) .c(d!())?; } @@ -371,6 +394,7 @@ fn run() -> Result<()> { }) })?; let am = m.value_of("amount"); + let is_address_eth = m.is_present("use-default-eth-address"); if am.is_none() || t.is_empty() { println!("{}", m.usage()); @@ -382,6 +406,7 @@ fn run() -> Result<()> { am.unwrap(), m.is_present("confidential-amount"), m.is_present("confidential-type"), + is_address_eth, ) .c(d!())?; } @@ -396,26 +421,340 @@ fn run() -> Result<()> { ); } else if let Some(m) = matches.subcommand_matches("account") { let address = m.value_of("addr"); - let (account, info) = contract_account_info(address)?; - println!("AccountId: {account}\n{info:#?}\n"); + let sec_key = m.value_of("sec-key"); + let is_address_eth = m.is_present("use-default-eth-address"); + + // FRA asset is the default case + let asset = if let Some(code) = m.value_of("asset") { + match code.to_lowercase().as_str() { + "fra" => None, + _ => Some(code), + } + } else { + None + }; + if sec_key.is_some() { + // Asset defaults to fra + common::show_account(sec_key, asset, is_address_eth).c(d!())?; + } + if address.is_some() { + let (account, info) = contract_account_info(address, is_address_eth)?; + println!("AccountId: {account}\n{info:#?}\n"); + } } else if let Some(m) = matches.subcommand_matches("contract-deposit") { let amount = m.value_of("amount").c(d!())?; let address = m.value_of("addr"); let asset = m.value_of("asset"); let lowlevel_data = m.value_of("lowlevel-data"); + let is_address_eth = m.is_present("eth-address"); transfer_to_account( amount.parse::().c(d!())?, address, asset, lowlevel_data, - ) - .c(d!())? + is_address_eth, + )? } else if let Some(m) = matches.subcommand_matches("contract-withdraw") { let amount = m.value_of("amount").c(d!())?; let address = m.value_of("addr"); let eth_key = m.value_of("eth-key"); - transfer_from_account(amount.parse::().c(d!())?, address, eth_key) - .c(d!())? + let is_address_eth = m.is_present("eth-address"); + transfer_from_account( + amount.parse::().c(d!())?, + address, + eth_key, + is_address_eth, + )? + } else if let Some(m) = matches.subcommand_matches("convert-bar-to-abar") { + // sender Xfr secret key + let owner_sk = read_file_path(m.value_of("from-seckey")).c(d!())?; + + // the receiver Xfr address + let target_addr = m.value_of("to-address").c(d!())?; + + // The TxoSID to be spent for conversion to ABAR (Anon Blind Asset Record) + let txo_sid = m.value_of("txo-sid"); + let is_address_eth = m.is_present("use-default-eth-address"); + + if txo_sid.is_none() { + println!("{}", m.usage()); + } else { + // call the convert function to build and send transaction + // it takes owner Xfr secret key, Axfr address and TxoSID + let r = common::convert_bar2abar( + owner_sk.as_ref(), + target_addr, + txo_sid.unwrap(), + is_address_eth, + ) + .c(d!())?; + + // Print commitment to terminal + println!( + "\x1b[31;01m Commitment: {}\x1b[00m", + wallet::commitment_to_base58(&r) + ); + // write the commitment base64 form to the owned_commitments file + let mut file = fs::OpenOptions::new() + .append(true) + .create(true) + .open("owned_commitments") + .expect("cannot open commitments file"); + std::io::Write::write_all( + &mut file, + ("\n".to_owned() + &wallet::commitment_to_base58(&r)).as_bytes(), + ) + .expect("commitment write failed"); + } + } else if let Some(m) = matches.subcommand_matches("convert-abar-to-bar") { + let is_address_eth = m.is_present("use-default-eth-address"); + // sender Xfr secret key + let owner_sk = read_file_path(m.value_of("from-seckey")).c(d!())?; + + // get the BAR receiver address + let to = m + .value_of("to-pubkey") + .c(d!()) + .and_then(wallet::public_key_from_base64) + .or_else(|_| { + m.value_of("to-wallet-address").c(d!()).and_then(|addr| { + wallet::public_key_from_bech32(addr).c(d!("invalid wallet address")) + }) + })?; + + // get the commitments for abar conversion and anon_fee + let commitment = m.value_of("commitment"); + + if commitment.is_none() { + println!("{}", m.usage()); + } else { + // Build transaction and submit to network + common::convert_abar2bar( + owner_sk, + commitment.unwrap(), + &to, + m.is_present("confidential-amount"), + m.is_present("confidential-type"), + is_address_eth, + ) + .c(d!())?; + } + } else if let Some(m) = matches.subcommand_matches("owned-abars") { + let is_address_eth = m.is_present("use-default-eth-address"); + // sender Xfr secret key + let owner_sk = read_file_path(m.value_of("from-seckey")).c(d!())?; + // parse sender XfrSecretKey or generate from Mnemonic setup with wallet + let from = match owner_sk { + Some(str) => { + ruc::info!(serde_json::from_str::(&format!("\"{str}\""))) + .c(d!())? + .into_keypair() + } + None => get_keypair(is_address_eth).c(d!())?, + }; + + let commitments_list = m + .value_of("commitments") + .unwrap_or_else(|| panic!("Commitment list missing \n {}", m.usage())); + + common::get_owned_abars(from, commitments_list)?; + } else if let Some(m) = matches.subcommand_matches("anon-balance") { + let is_address_eth = m.is_present("use-default-eth-address"); + // Generates a list of owned Abars (both spent and unspent) + // sender Xfr secret key + let owner_sk = read_file_path(m.value_of("from-seckey")).c(d!())?; + // parse sender XfrSecretKey or generate from Mnemonic setup with wallet + let from = match owner_sk { + Some(str) => { + ruc::info!(serde_json::from_str::(&format!("\"{str}\""))) + .c(d!(str))? + .into_keypair() + } + None => get_keypair(is_address_eth).c(d!())?, + }; + let asset = m.value_of("asset"); + + let commitments_list = m + .value_of("commitments") + .unwrap_or_else(|| panic!("Commitment list missing \n {}", m.usage())); + + common::anon_balance(from, commitments_list, asset)?; + } else if let Some(m) = matches.subcommand_matches("owned-open-abars") { + let is_address_eth = m.is_present("use-default-eth-address"); + // sender Xfr secret key + let owner_sk = read_file_path(m.value_of("from-seckey")).c(d!())?; + // parse sender XfrSecretKey or generate from Mnemonic setup with wallet + let from = match owner_sk { + Some(str) => { + ruc::info!(serde_json::from_str::(&format!("\"{str}\""))) + .c(d!())? + .into_keypair() + } + None => get_keypair(is_address_eth).c(d!())?, + }; + let commitment_str = m.value_of("commitment"); + + // create derived public key + let commitment = wallet::commitment_from_base58(commitment_str.unwrap())?; + + // get results from query server and print + let (uid, abar) = utils::get_owned_abar(&commitment).c(d!())?; + let memo = utils::get_abar_memo(&uid).unwrap().unwrap(); + let oabar = + OpenAnonAssetRecordBuilder::from_abar(&abar, memo, &from.into_noah()) + .unwrap() + .build() + .unwrap(); + + println!( + "(AtxoSID, ABAR, OABAR) : {}", + serde_json::to_string(&(uid, abar, oabar)).c(d!())? + ); + } else if let Some(m) = matches.subcommand_matches("owned-utxos") { + // All assets are shown in the default case + let asset = m.value_of("asset"); + let is_address_eth = m.is_present("eth-address"); + + // fetch filtered list by asset + let list = common::get_owned_utxos(asset, is_address_eth)?; + let pk = wallet::public_key_to_base64( + get_keypair(is_address_eth).unwrap().get_pk_ref(), + ); + + // Print UTXO table + println!("Owned utxos for {pk:?}",); + println!("{:-^1$}", "", 100); + println!( + "{0: <8} | {1: <18} | {2: <45} ", + "ATxoSID", "Amount", "AssetType" + ); + for (a, b, c) in list.iter() { + let amt = b + .get_amount() + .map_or_else(|| "Confidential".to_string(), |a| a.to_string()); + let at = c.get_asset_type().map_or_else( + || "Confidential".to_string(), + |at| AssetTypeCode { val: at }.to_base64(), + ); + + println!("{0: <8} | {1: <18} | {2: <45} ", a.0, amt, at); + } + } else if let Some(m) = matches.subcommand_matches("anon-transfer") { + let is_eth_address = m.is_present("use-default-eth-address"); + // sender Xfr secret key + let owner_sk = read_file_path(m.value_of("from-seckey")).c(d!())?; + + // get commitments + let commitment = m.value_of("commitment"); + let fee_commitment = m.value_of("fra-commitment"); + + // get receiver keys and amount + let to_address = m.value_of("to-address"); + let amount = m.value_of("amount"); + + if commitment.is_none() || to_address.is_none() || amount.is_none() { + println!("{}", m.usage()); + } else { + // build transaction and submit + common::gen_anon_transfer_op( + owner_sk, + commitment.unwrap(), + fee_commitment, + amount.unwrap(), + to_address.unwrap(), + is_eth_address, + ) + .c(d!())?; + } + } else if let Some(m) = matches.subcommand_matches("anon-transfer-batch") { + let is_eth_address = m.is_present("use-default-eth-address"); + + // sender Xfr secret key + let owner_sk = read_file_path(m.value_of("from-seckey")).c(d!())?; + + let to_axfr_public_keys = + m.value_of("to-address-file").c(d!()).and_then(|f| { + fs::read_to_string(f).c(d!()).and_then(|pks| { + pks.lines() + .map(|pk| wallet::public_key_from_bech32(pk.trim())) + .collect::>>() + .c(d!("invalid file")) + }) + })?; + let mut commitments = m.value_of("commitment-file").c(d!()).and_then(|f| { + fs::read_to_string(f) + .c(d!()) + .map(|rms| rms.lines().map(String::from).collect::>()) + })?; + commitments.sort(); + commitments.dedup(); + let amounts = m.value_of("amount-file").c(d!()).and_then(|f| { + fs::read_to_string(f) + .c(d!()) + .map(|ams| ams.lines().map(String::from).collect::>()) + })?; + let assets = m.value_of("asset-file").c(d!()).and_then(|f| { + let token_code = |asset: &str| { + if asset.to_uppercase() == "FRA" { + AssetTypeCode { + val: ASSET_TYPE_FRA, + } + } else { + AssetTypeCode::new_from_base64(asset).unwrap_or(AssetTypeCode { + val: ASSET_TYPE_FRA, + }) + } + }; + fs::read_to_string(f) + .c(d!()) + .map(|ams| ams.lines().map(token_code).collect::>()) + })?; + + if to_axfr_public_keys.is_empty() + || commitments.is_empty() + || amounts.is_empty() + || assets.is_empty() + { + println!("{}", m.usage()); + } else { + common::gen_oabar_add_op_x( + owner_sk, + to_axfr_public_keys, + commitments, + amounts, + assets, + is_eth_address, + ) + .c(d!())?; + } + } else if let Some(m) = matches.subcommand_matches("anon-fetch-merkle-proof") { + let atxo_sid = m.value_of("atxo-sid"); + + if atxo_sid.is_none() { + println!("{}", m.usage()); + } else { + let mt_leaf_info = common::get_mtleaf_info(atxo_sid.unwrap()).c(d!())?; + println!("{:?}", serde_json::to_string_pretty(&mt_leaf_info)); + } + } else if let Some(m) = matches.subcommand_matches("check-abar-status") { + let is_address_eth = m.is_present("use-default-eth-address"); + // sender Xfr secret key + let owner_sk = read_file_path(m.value_of("from-seckey")).c(d!())?; + // parse sender XfrSecretKey or generate from Mnemonic setup with wallet + let from = match owner_sk { + Some(str) => { + ruc::info!(serde_json::from_str::(&format!("\"{str}\""))) + .c(d!())? + .into_keypair() + } + None => get_keypair(is_address_eth).c(d!())?, + }; + + let commitment_str = m.value_of("commitment"); + let commitment = wallet::commitment_from_base58(commitment_str.unwrap())?; + + let abar = utils::get_owned_abar(&commitment).c(d!())?; + common::check_abar_status(from, abar).c(d!())?; } else if let Some(m) = matches.subcommand_matches("replace_staker") { let target = m .value_of("target") @@ -428,7 +767,8 @@ fn run() -> Result<()> { return Ok(()); } }; - common::replace_staker(target, td_addr)?; + let is_address_eth = m.is_present("eth-address"); + common::replace_staker(target, td_addr, is_address_eth)?; } else if let Some(m) = matches.subcommand_matches("dev") { #[cfg(not(target_arch = "wasm32"))] { @@ -776,6 +1116,18 @@ fn run() -> Result<()> { Ok(()) } +fn read_file_path(path: Option<&str>) -> Result> { + Ok(match path { + Some(path) => Some( + fs::read_to_string(path) + .c(d!("Failed to read seckey file"))? + .trim() + .to_string(), + ), + None => None, + }) +} + fn tip_fail(e: impl fmt::Display) { eprintln!("\n\x1b[31;01mFAIL !!!\x1b[00m"); eprintln!( diff --git a/src/components/finutils/src/bins/fn.yml b/src/components/finutils/src/bins/fn.yml index 98a3a95b8..cbf96a6c3 100644 --- a/src/components/finutils/src/bins/fn.yml +++ b/src/components/finutils/src/bins/fn.yml @@ -10,19 +10,26 @@ args: subcommands: - genkey: - about: Generate a random Findora public key/private key Pair + about: Generate a new Findora key pair + args: + - gen-eth-address: + help: generate eth address + long: gen-eth-address - show: - about: View Validator status and accumulated rewards + about: View the validator status and accumulated rewards args: - basic: help: show basic account info short: b long: basic + - eth-address: + help: use the eth address + long: eth-address - setup: - about: Setup environment variables for staking transactions + about: Set up environment variables for staking transactions args: - serv-addr: - help: a node address of Findora Network + help: a node address of the Findora network short: S long: serv-addr takes_value: true @@ -40,7 +47,7 @@ subcommands: takes_value: true value_name: Path - stake: - about: Stake tokens (i.e. bond tokens) from a Findora account to a Validator + about: Stake tokens (i.e. bond tokens) from a Findora account to a validator args: - amount: help: how much `FRA unit`s you want to stake @@ -66,7 +73,7 @@ subcommands: short: a long: append - staker-priv-key: - help: the file which contains private key (in base64 format) of proposer + help: the file which contains the mnemonic of proposer short: S long: staker-priv-key takes_value: true @@ -80,6 +87,11 @@ subcommands: - force: help: ignore warning and stake FRAs to your target node long: force + - use-default-eth-address: + help: use a private key of the eth address if `staker-priv-key` is not provided + long: use-default-eth-address + conflicts_with: + - staker-priv-key groups: - staking-flags: args: @@ -119,11 +131,14 @@ subcommands: long: validator-memo-logo takes_value: true value_name: Logo + - use-eth-address: + help: use a private key of the eth address + long: use-eth-address - unstake: about: Unstake tokens (i.e. unbond tokens) from a Validator args: - staker-priv-key: - help: the file which contains private key (in base64 format) of proposer + help: the file which contains the mnemonic of proposer short: S long: staker-priv-key takes_value: true @@ -140,6 +155,11 @@ subcommands: long: amount takes_value: true value_name: Amount + - use-default-eth-address: + help: use a private key of the eth address if `staker-priv-key` is not provided + long: use-default-eth-address + conflicts-with: + - staker-priv-key - claim: about: Claim accumulated FRA rewards args: @@ -156,10 +176,15 @@ subcommands: takes_value: true value_name: Amount - seckey: - help: the file which contains base64-formated `XfrPrivateKey` of an existing wallet + help: the file which contains base64-formatted `XfrPrivateKey` of an existing wallet long: seckey takes_value: true value_name: SECRET KEY + - use-default-eth-address: + help: use a private key of the eth address if `seckey` is not provided + long: use-default-eth-address + conflicts-with: + - seckey - delegate: about: Delegating operations args: @@ -170,7 +195,7 @@ subcommands: takes_value: true value_name: AMOUNT - seckey: - help: the file which contains base64-formated `XfrPrivateKey` of an existing wallet + help: the file which contains base64-formatted `XfrPrivateKey` of an existing wallet long: seckey takes_value: true value_name: SECRET KEY @@ -185,6 +210,11 @@ subcommands: conflicts_with: - amount - validator + - use-default-eth-address: + help: use a private key of the eth address if `seckey` is not provided + long: use-default-eth-address + conflicts-with: + - seckey - undelegate: about: Undelegating operations args: @@ -195,7 +225,7 @@ subcommands: takes_value: true value_name: AMOUNT - seckey: - help: the file which contains base64-formated `XfrPrivateKey` of an existing wallet + help: the file which contains base64-formatted `XfrPrivateKey` of an existing wallet long: seckey takes_value: true value_name: SECRET KEY @@ -204,26 +234,33 @@ subcommands: long: validator takes_value: true value_name: VALIDATOR ADDRESS + - use-default-eth-address: + help: use a private key of the eth address if `seckey` is not provided + long: use-default-eth-address + conflicts-with: + - seckey - transfer: about: Transfer tokens from one address to another args: - asset: - help: asset code which you want to tansfer + help: asset code which you want to transfer long: asset takes_value: true value_name: ASSET + allow_hyphen_values: true - from-seckey: - help: the file which contains base64-formated `XfrPrivateKey` of the receiver + help: the file which contains base64-formatted `XfrPrivateKey` of the sender short: f long: from-seckey takes_value: true value_name: SecKey - to-pubkey: - help: base64-formated `XfrPublicKey` of the receiver + help: base64-formatted `XfrPublicKey` of the receiver short: t long: to-pubkey takes_value: true value_name: PubKey + allow_hyphen_values: true - to-wallet-address: help: fra prefixed address of FindoraNetwork short: T @@ -245,11 +282,16 @@ subcommands: - confidential-type: help: mask the asset type sent on the transaction log long: confidential-type + - use-default-eth-address: + help: use a private key of the eth address if `from-seckey` is not provided + long: use-default-eth-address + conflicts-with: + - from-seckey - transfer-batch: about: Transfer tokens from one address to many others args: - from-seckey: - help: the file which contains base64-formated `XfrPrivateKey` of the receiver + help: the file which contains base64-formatted `XfrPrivateKey` of the receiver short: f long: from-seckey takes_value: true @@ -279,6 +321,11 @@ subcommands: - confidential-type: help: mask the asset type sent on the transaction log long: confidential-type + - use-default-eth-address: + help: use a private key of the eth address if `from-seckey` is not provided + long: use-default-eth-address + conflicts-with: + - from-seckey - wallet: about: manipulates a findora wallet args: @@ -295,15 +342,29 @@ subcommands: long: asset takes_value: true value_name: ASSET + allow_hyphen_values: true conflicts_with: - create - seckey: - help: the file which contains base64-formated `XfrPrivateKey` of an existing wallet + help: the file which contains base64-formatted `XfrPrivateKey` of an existing wallet long: seckey takes_value: true value_name: SECRET KEY conflicts_with: - create + - gen-eth-address: + help: generate the keypair of an eth address + long: gen-eth-address + conflicts-with: + - show + - seckey + - asset + - use-default-eth-address: + help: use a private key of the eth address if `seckey` is not provided + long: use-default-eth-address + conflicts-with: + - seckey + - create - asset: about: manipulate custom asset groups: @@ -365,13 +426,14 @@ subcommands: long: code takes_value: true value_name: ASSET CODE + allow_hyphen_values: true - addr: help: Findora wallet address long: addr takes_value: true value_name: WALLET ADDRESS - seckey: - help: the file which contains base64-formated `XfrPrivateKey` of findora account + help: the file which contains base64-formatted `XfrPrivateKey` of findora account long: seckey takes_value: true value_name: SECRET KEY @@ -401,26 +463,13 @@ subcommands: - hidden: help: hidden asset amount when issuing asset on ledger long: hidden - #- history - # about: query operating history - # args: - # - coinbase: - # help: show coinbase history - # long: coinbase - # conflicts_with: - # - transaction - # - transaction: - # help: show transaction history - # conflicts_with: - # - coinbase - # - wallet: - # help: wallet nick name - # long: wallet - # takes_value: true - # value_name: WALLET - # required: true + - use-default-eth-address: + help: use a private key of the eth address if `seckey` is not provided + long: use-default-eth-address + conflicts-with: + - seckey - account: - about: Return user contract account information + about: Return user contract account information or the balance if secret key is provided args: - addr: help: findora account(eg:fra1rkv...) or Ethereum address(g:0xd3Bf...) @@ -428,19 +477,35 @@ subcommands: long: addr takes_value: true value_name: WALLET ADDRESS - required: true + - sec-key: + help: base64-formatted `XfrPrivateKey` + short: s + long: sec-key + takes_value: true + value_name: SECRET KEY + - asset: + help: code of asset, such as `fra` + long: asset + takes_value: true + value_name: ASSET + allow_hyphen_values: true + - use-default-eth-address: + help: use a private key of the eth address if `sec-key` is not provided + long: use-default-eth-address + conflicts-with: + - sec-key - contract-deposit: - about: Transfer FRA from a Findora account to the specified Ethereum address + about: Transfer an asset from the UTXO chain to the EVM chain args: - addr: - help: ethereum address to receive FRA, eg:0xd3Bf... + help: ethereum address to receive asset, eg:0xd3Bf... short: a long: addr takes_value: true value_name: WALLET ADDRESS required: true - amount: - help: deposit FRA amount + help: deposit asset amount short: n long: amount takes_value: true @@ -460,11 +525,14 @@ subcommands: takes_value: true value_name: LOWLEVEL required: false + - eth-address: + help: use the eth address + long: eth-address - contract-withdraw: about: Transfer FRA from an Ethereum address to the specified Findora account args: - addr: - help: findora account to receive FRA, eg:fra1rkv... + help: Findora account to receive FRA, eg:fra1rkv... short: a long: addr takes_value: true @@ -477,14 +545,297 @@ subcommands: value_name: AMOUNT required: true - eth-key: - help: ethereum account mnemonic phrase sign withdraw tx + help: mnemonic phrase for the EVM account to sign the withdraw tx short: e long: eth-key takes_value: true value_name: MNEMONIC required: true + - eth-address: + help: use the eth address + long: eth-address - gen-eth-key: about: Generate an Ethereum address + - owned-abars: + about: Get Anon UTXOs for a keypair using the commitment + args: + - commitments: + help: Commitment of the ABAR + short: c + long: commitments + takes_value: true + value_name: COMMITMENT + required: true + allow_hyphen_values: true + - from-seckey: + help: Xfr secret key file path of receiver + short: s + long: from-seckey + takes_value: true + value_name: SECRET KEY PATH + - asset: + help: code of asset, such as `fra` + long: asset + takes_value: true + value_name: ASSET + allow_hyphen_values: true + - use-default-eth-address: + help: use a private key of the eth address if `from-seckey` is not provided + long: use-default-eth-address + conflicts-with: + - from-seckey + - anon-balance: + about: List Anon balance and spending status for a public key and a list of commitments + args: + - commitments: + help: the list of commitments in base64 form. + short: c + long: commitments + takes_value: true + value_name: COMMITMENT + required: true + allow_hyphen_values: true + - from-seckey: + help: Xfr secret key file path of converter + short: s + long: from-seckey + takes_value: true + value_name: SECRET KEY PATH + required: true + - asset: + help: code of asset, such as `fra` + long: asset + takes_value: true + value_name: ASSET + allow_hyphen_values: true + - use-default-eth-address: + help: use a private key of the eth address if `from-seckey` is not provided + long: use-default-eth-address + conflicts-with: + - from-seckey + - owned-open-abars: + about: Get Open Anon UTXOs for a keypair using commitment + args: + - commitment: + help: The commitment of ABAR + short: c + long: commitment + takes_value: true + value_name: COMMITMENT + required: true + allow_hyphen_values: true + - from-seckey: + help: Xfr secret key file path of converter + short: s + long: from-seckey + takes_value: true + value_name: SECRET KEY PATH + required: true + - use-default-eth-address: + help: use a private key of the eth address if `from-seckey` is not provided + long: use-default-eth-address + conflicts-with: + - from-seckey + - owned-utxos: + about: List owned UTXOs for a public key + args: + - asset: + help: asset code which you want to tansfer + long: asset + takes_value: true + value_name: ASSET + allow_hyphen_values: true + - eth-address: + help: use the eth address + long: eth-address + - convert-bar-to-abar: + about: Convert a BAR to Anon BAR for yourself + args: + - from-seckey: + help: Xfr secret key file path of converter + short: s + long: from-seckey + takes_value: true + value_name: SECRET KEY PATH + - to-address: + help: bech32 address of receiver keys + short: a + long: to-address + takes_value: true + value_name: TO ADDRESS + required: true + - txo-sid: + help: Txo Sid of input to convert + short: t + long: txo-sid + takes_value: true + value_name: TXO SID + required: true + - use-default-eth-address: + help: use a private key of the eth address if `from-seckey` is not provided + long: use-default-eth-address + conflicts-with: + - from-seckey + - convert-abar-to-bar: + about: Convert an ABAR to BAR + args: + - from-seckey: + help: Xfr secret key file path of converter + short: s + long: from-seckey + takes_value: true + value_name: SECRET KEY PATH + - commitment: + help: Commitment for the input Anon BAR + short: c + long: commitment + takes_value: true + value_name: COMMITMENT + required: true + allow_hyphen_values: true + - to-pubkey: + help: base64-formatted `XfrPublicKey` of the receiver + short: t + long: to-pubkey + takes_value: true + value_name: PubKey + allow_hyphen_values: true + - to-wallet-address: + help: Xfr public key of the receiver + short: T + long: to-wallet-address + takes_value: true + value_name: XFR WALLET ADDRESS + conflicts_with: + - to-pubkey + - confidential-amount: + help: mask the amount sent on the transaction log + long: confidential-amount + - confidential-type: + help: mask the asset type sent on the transaction log + long: confidential-type + - use-default-eth-address: + help: use a private key of the eth address if `from-seckey` is not provided + long: use-default-eth-address + conflicts-with: + - from-seckey + - anon-transfer: + about: Perform an anonymous transfer + args: + - from-seckey: + help: Xfr secret key file path of sender + short: s + long: from-seckey + takes_value: true + value_name: SECRET KEY PATH + - commitment: + help: Commitment for the input Anon BAR + short: c + long: commitment + takes_value: true + value_name: COMMITMENT + required: true + allow_hyphen_values: true + - fra-commitment: + help: Commitment for the input FRA Anon BAR + long: fra-commitment + takes_value: true + value_name: FRA COMMITMENT + allow_hyphen_values: true + - to-address: + help: Address of the receiver + long: to-address + takes_value: true + value_name: ADDRESS + required: true + allow_hyphen_values: true + - amount: + help: how much units to transfer + short: n + long: amount + takes_value: true + value_name: Amount + required: true + - use-default-eth-address: + help: use a private key of the eth address if `from-seckey` is not provided + long: use-default-eth-address + conflicts-with: + - from-seckey + - anon-transfer-batch: + about: Anonymous Transfer of tokens from multiple inputs to multiple outputs + args: + - from-seckey: + help: Xfr secret key file path of sender + short: s + long: from-seckey + takes_value: true + value_name: SECRET KEY PATH + required: true + - commitment-file: + help: Commitments for the input Anon BARs + short: c + long: commitment-file + takes_value: true + value_name: COMMITMENT + required: true + - to-address-file: + help: Xfr public keys of the receivers + long: to-address-file + takes_value: true + value_name: PUBLIC KEY + required: true + - amount-file: + help: how much units to transfer for each receiver + short: n + long: amount-file + takes_value: true + value_name: Amount + required: true + - asset-file: + help: Relative asset code type. + short: a + long: asset-file + takes_value: true + value_name: Asset + required: true + - use-default-eth-address: + help: use a private key of the eth address if `from-seckey` is not provided + long: use-default-eth-address + conflicts-with: + - from-seckey + - anon-fetch-merkle-proof: + about: Query Merkle tree leaf info + args: + - atxo-sid: + help: ATXO SID of the ABAR + short: a + long: atxo-sid + takes_value: true + value_name: ATXO SID + required: true + - check-abar-status: + about: Check the spending status and balance of ABAR + args: + - commitment: + help: Commitment of the ABAR + short: c + long: commitment + takes_value: true + value_name: COMMITMENT + required: true + allow_hyphen_values: true + - from-seckey: + help: Xfr secret key file path of sender + short: s + long: from-seckey + takes_value: true + value_name: SECRET KEY PATH + required: true + - use-default-eth-address: + help: use a private key of the eth address if `from-seckey` is not provided + long: use-default-eth-address + conflicts-with: + - from-seckey - replace_staker: about: Replace the staker of the validator with target address args: @@ -501,6 +852,23 @@ subcommands: takes_value: true value_name: TARGET PUBLIC KEY required: true + allow_hyphen_values: true + - td_address: + help: the tendermint address that you may want to replace. + long: td_address + takes_value: true + value_name: TENDERMINT ADDRESS + required: false + - td_pubkey: + help: the tendermint public key that you may want to replace. + long: td_pubkey + takes_value: true + value_name: TENDERMINT PUBKEY + required: false + allow_hyphen_values: true + - eth-address: + help: use the eth address + long: eth-address - dev: about: Manage development clusters on your localhost args: diff --git a/src/components/finutils/src/bins/key_generator.rs b/src/components/finutils/src/bins/key_generator.rs index 71582f04c..c58945946 100644 --- a/src/components/finutils/src/bins/key_generator.rs +++ b/src/components/finutils/src/bins/key_generator.rs @@ -5,5 +5,5 @@ fn main() { .nth(1) .unwrap_or_else(|| "1".to_owned()) .parse::()); - (0..n).for_each(|_| gen_key_and_print()); + (0..n).for_each(|_| gen_key_and_print(false)); } diff --git a/src/components/finutils/src/bins/stt/stt.rs b/src/components/finutils/src/bins/stt/stt.rs index 082f61fe9..887f2bcc2 100644 --- a/src/components/finutils/src/bins/stt/stt.rs +++ b/src/components/finutils/src/bins/stt/stt.rs @@ -210,10 +210,12 @@ mod issue { }, rand_chacha::rand_core::SeedableRng, rand_chacha::ChaChaRng, - zei::noah_algebra::ristretto::PedersenCommitmentRistretto, - zei::noah_api::xfr::{ - asset_record::{build_blind_asset_record, AssetRecordType}, - structs::AssetRecordTemplate, + zei::{ + noah_algebra::ristretto::PedersenCommitmentRistretto, + noah_api::xfr::{ + asset_record::{build_blind_asset_record, AssetRecordType}, + structs::AssetRecordTemplate, + }, }, }; @@ -266,7 +268,7 @@ mod issue { IssueAsset::new(aib, &IssuerKeyPair { keypair: &root_kp }).c(d!())?; builder.add_operation(Operation::IssueAsset(asset_issuance_operation)); - Ok(builder.take_transaction()) + builder.build_and_take_transaction() } } @@ -303,7 +305,7 @@ mod delegate { builder.add_operation_delegation(owner_kp, amount, validator.to_owned()); })?; - let mut tx = builder.take_transaction(); + let mut tx = builder.build_and_take_transaction()?; tx.sign(owner_kp); Ok(tx) } @@ -341,7 +343,7 @@ mod undelegate { } })?; - Ok(builder.take_transaction()) + builder.build_and_take_transaction() } } @@ -358,7 +360,7 @@ mod claim { builder.add_operation_claim(None, owner_kp, amount); })?; - Ok(builder.take_transaction()) + builder.build_and_take_transaction() } } diff --git a/src/components/finutils/src/common/ddev/init.rs b/src/components/finutils/src/common/ddev/init.rs index 63261be3a..a6504448f 100644 --- a/src/components/finutils/src/common/ddev/init.rs +++ b/src/components/finutils/src/common/ddev/init.rs @@ -17,8 +17,9 @@ use ledger::{ }; use ruc::*; use serde::{Deserialize, Serialize}; -use zei::noah_api::xfr::asset_record::AssetRecordType; -use zei::{XfrKeyPair, XfrPublicKey, XfrSecretKey}; +use zei::{ + noah_api::xfr::asset_record::AssetRecordType, XfrKeyPair, XfrPublicKey, XfrSecretKey, +}; #[derive(Deserialize)] struct TmValidators { @@ -57,7 +58,7 @@ pub(super) fn init(env: &mut Env) -> Result<()> { .and_then(|b| serde_json::from_slice::(&b).c(d!()))?; tm_validators.result.validators.into_iter().for_each(|v| { - let xfr_key = common::gen_key(); + let xfr_key = common::gen_key(false); let iv = InitialValidator { tendermint_addr: v.address, tendermint_pubkey: v.pub_key.value, @@ -132,9 +133,13 @@ pub(super) fn init(env: &mut Env) -> Result<()> { v.tendermint_addr.clone(), ); })?; - let mut tx = builder.take_transaction(); - tx.sign(&v.xfr_keypair); - send_tx(env, &tx).c(d!())?; + builder + .build_and_take_transaction() + .c(d!()) + .and_then(|mut tx| { + tx.sign(&v.xfr_keypair); + send_tx(env, &tx).c(d!()) + })?; } println!("[ {} ] >>> Init work done !", &env.name); @@ -152,7 +157,10 @@ fn setup_initial_validators(env: &Env) -> Result<()> { .collect::>(); builder.add_operation_update_validator(&[], 1, vs).c(d!())?; - send_tx(env, &builder.take_transaction()).c(d!()) + builder + .build_and_take_transaction() + .c(d!()) + .and_then(|tx| send_tx(env, &tx).c(d!())) } fn send_tx(env: &Env, tx: &Transaction) -> Result<()> { @@ -191,10 +199,13 @@ fn transfer_batch( .c(d!())?; builder.add_operation(op); - let mut tx = builder.take_transaction(); - tx.sign(owner_kp); - - send_tx(env, &tx).c(d!()) + builder + .build_and_take_transaction() + .c(d!()) + .and_then(|mut tx| { + tx.sign(owner_kp); + send_tx(env, &tx).c(d!()) + }) } fn new_tx_builder(env: &Env) -> Result { diff --git a/src/components/finutils/src/common/evm.rs b/src/components/finutils/src/common/evm.rs index 6dd2ff291..586a23916 100644 --- a/src/components/finutils/src/common/evm.rs +++ b/src/components/finutils/src/common/evm.rs @@ -18,19 +18,15 @@ use fp_types::{ transaction::UncheckedTransaction, U256, }; -use fp_utils::ecdsa::SecpPair; -use fp_utils::tx::EvmRawTxWrapper; -use ledger::data_model::AssetTypeCode; -use ledger::data_model::ASSET_TYPE_FRA; -use ledger::data_model::BLACK_HOLE_PUBKEY_STAKING; +use fp_utils::{ecdsa::SecpPair, tx::EvmRawTxWrapper}; +use ledger::data_model::{AssetTypeCode, ASSET_TYPE_FRA, BLACK_HOLE_PUBKEY_STAKING}; use ruc::*; use std::str::FromStr; use tendermint::block::Height; use tendermint_rpc::endpoint::abci_query::AbciQuery; use tendermint_rpc::{Client, HttpClient}; use tokio::runtime::Runtime; -use zei::noah_api::xfr::asset_record::AssetRecordType; -use zei::{XfrKeyPair, XfrPublicKey}; +use zei::{noah_api::xfr::asset_record::AssetRecordType, XfrKeyPair, XfrPublicKey}; /// transfer utxo assets to account(ed25519 or ecdsa address) balance. pub fn transfer_to_account( @@ -38,10 +34,11 @@ pub fn transfer_to_account( address: Option<&str>, asset: Option<&str>, lowlevel_data: Option<&str>, + is_address_eth: bool, ) -> Result<()> { let mut builder = utils::new_tx_builder().c(d!())?; - let kp = get_keypair().c(d!())?; + let kp = get_keypair(is_address_eth).c(d!())?; let asset = if let Some(asset) = asset { let asset = AssetTypeCode::new_from_base64(asset)?; @@ -59,6 +56,7 @@ pub fn transfer_to_account( Some(AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType), ) .c(d!())?; + let target_address = match address { Some(s) => MultiSigner::from_str(s).c(d!())?, None => MultiSigner::Xfr(kp.get_pk()), @@ -77,7 +75,7 @@ pub fn transfer_to_account( .c(d!())? .sign(&kp); - let mut tx = builder.take_transaction(); + let mut tx = builder.build_and_take_transaction()?; tx.sign_to_map(&kp); utils::send_tx(&tx).c(d!()) @@ -106,8 +104,9 @@ pub fn transfer_from_account( amount: u64, address: Option<&str>, eth_phrase: Option<&str>, + is_address_eth: bool, ) -> Result<()> { - let fra_kp = get_keypair()?; + let fra_kp = get_keypair(is_address_eth)?; let target = match address { Some(s) => { @@ -205,8 +204,11 @@ fn one_shot_abci_query( } /// Query contract account info by abci/query -pub fn contract_account_info(address: Option<&str>) -> Result<(Address, SmartAccount)> { - let fra_kp = get_keypair()?; +pub fn contract_account_info( + address: Option<&str>, + is_address_eth: bool, +) -> Result<(Address, SmartAccount)> { + let fra_kp = get_keypair(is_address_eth)?; let address = match address { Some(s) => MultiSigner::from_str(s).c(d!())?, diff --git a/src/components/finutils/src/common/mod.rs b/src/components/finutils/src/common/mod.rs index c460a7847..573cc0159 100644 --- a/src/components/finutils/src/common/mod.rs +++ b/src/components/finutils/src/common/mod.rs @@ -17,12 +17,17 @@ pub mod utils; use { self::utils::{get_evm_staking_address, get_validator_memo_and_rate}, - crate::api::DelegationInfo, + crate::{ + api::DelegationInfo, + common::utils::{new_tx_builder, send_tx}, + txn_builder::TransactionBuilder, + }, globutils::wallet, lazy_static::lazy_static, ledger::{ data_model::{ - gen_random_keypair, AssetRules, AssetTypeCode, AssetTypePrefix, Transaction, + gen_random_keypair, get_abar_commitment, ATxoSID, AssetRules, AssetTypeCode, + AssetTypePrefix, Transaction, TxoSID, ASSET_TYPE_FRA, BLACK_HOLE_PUBKEY_STAKING, }, staking::{ @@ -31,14 +36,30 @@ use { TendermintAddrRef, }, }, + rand_chacha::ChaChaRng, + rand_core::SeedableRng, ruc::*, std::{env, fs}, tendermint::PrivateKey, utils::{get_block_height, get_local_block_height, parse_td_validator_keys}, web3::types::H160, zei::{ - noah_api::xfr::asset_record::AssetRecordType, XfrKeyPair, XfrPublicKey, - XfrSecretKey, + noah_api::{ + anon_xfr::{ + nullify, + structs::{ + AnonAssetRecord, Commitment, MTLeafInfo, OpenAnonAssetRecordBuilder, + }, + }, + xfr::{ + asset_record::{ + AssetRecordType, + AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, + }, + structs::{XfrAmount, XfrAssetType}, + }, + }, + XfrKeyPair, XfrPublicKey, XfrSecretKey, }, }; @@ -58,7 +79,11 @@ lazy_static! { } /// Updating the information of a staker includes commission_rate and staker_memo -pub fn staker_update(cr: Option<&str>, memo: Option) -> Result<()> { +pub fn staker_update( + cr: Option<&str>, + memo: Option, + is_address_eth: bool, +) -> Result<()> { let pub_key = get_td_pubkey() .map(|i| td_pubkey_to_td_addr_bytes(&i)) .c(d!())?; @@ -80,7 +105,7 @@ pub fn staker_update(cr: Option<&str>, memo: Option) -> Result<()> { let td_pubkey = get_td_pubkey().c(d!())?; - let kp = get_keypair().c(d!())?; + let kp = get_keypair(is_address_eth).c(d!())?; let vkp = get_td_privkey().c(d!())?; let mut builder = utils::new_tx_builder().c(d!())?; @@ -92,7 +117,7 @@ pub fn staker_update(cr: Option<&str>, memo: Option) -> Result<()> { .c(d!()) .map(|op| builder.add_operation(op))?; - let mut tx = builder.take_transaction(); + let mut tx = builder.build_and_take_transaction()?; tx.sign_to_map(&kp); utils::send_tx(&tx).c(d!()) @@ -105,6 +130,7 @@ pub fn stake( commission_rate: &str, memo: Option<&str>, force: bool, + is_address_eth: bool, ) -> Result<()> { let am = amount.parse::().c(d!("'amount' must be an integer"))?; check_delegation_amount(am, false).c(d!())?; @@ -114,7 +140,7 @@ pub fn stake( .and_then(|cr| convert_commission_rate(cr).c(d!()))?; let td_pubkey = get_td_pubkey().c(d!())?; - let kp = get_keypair().c(d!())?; + let kp = get_keypair(is_address_eth).c(d!())?; let vkp = get_td_privkey().c(d!())?; macro_rules! diff { @@ -157,7 +183,7 @@ pub fn stake( .c(d!()) .map(|principal_op| builder.add_operation(principal_op))?; - let mut tx = builder.take_transaction(); + let mut tx = builder.build_and_take_transaction()?; tx.sign_to_map(&kp); utils::send_tx(&tx).c(d!()) @@ -168,6 +194,7 @@ pub fn stake_append( amount: &str, staker: Option<&str>, td_addr: Option, + is_address_eth: bool, ) -> Result<()> { let am = amount.parse::().c(d!("'amount' must be an integer"))?; check_delegation_amount(am, true).c(d!())?; @@ -181,7 +208,7 @@ pub fn stake_append( let kp = staker .c(d!()) .and_then(|sk| wallet::restore_keypair_from_mnemonic_default(sk).c(d!())) - .or_else(|_| get_keypair().c(d!()))?; + .or_else(|_| get_keypair(is_address_eth).c(d!()))?; let mut builder = utils::new_tx_builder().c(d!())?; builder.add_operation_delegation(&kp, am, td_addr); @@ -195,7 +222,8 @@ pub fn stake_append( ) .c(d!()) .map(|principal_op| builder.add_operation(principal_op))?; - let mut tx = builder.take_transaction(); + + let mut tx = builder.build_and_take_transaction()?; tx.sign_to_map(&kp); utils::send_tx(&tx).c(d!()) @@ -206,6 +234,7 @@ pub fn unstake( am: Option<&str>, staker: Option<&str>, td_addr: Option, + is_address_eth: bool, ) -> Result<()> { let am = if let Some(i) = am { Some(i.parse::().c(d!("'amount' must be an integer"))?) @@ -216,7 +245,7 @@ pub fn unstake( let kp = staker .c(d!()) .and_then(|sk| wallet::restore_keypair_from_mnemonic_default(sk).c(d!())) - .or_else(|_| get_keypair().c(d!()))?; + .or_else(|_| get_keypair(is_address_eth).c(d!()))?; let td_addr_bytes = td_addr .c(d!()) .and_then(|ta| td_addr_to_bytes(ta).c(d!())) @@ -245,14 +274,19 @@ pub fn unstake( } })?; - let mut tx = builder.take_transaction(); + let mut tx = builder.build_and_take_transaction()?; tx.sign_to_map(&kp); utils::send_tx(&tx).c(d!()) } /// Claim rewards from findora network -pub fn claim(td_addr: &str, am: Option<&str>, sk_str: Option<&str>) -> Result<()> { +pub fn claim( + td_addr: &str, + am: Option<&str>, + sk_str: Option<&str>, + is_address_eth: bool, +) -> Result<()> { let td_addr = hex::decode(td_addr).c(d!())?; let am = if let Some(i) = am { @@ -261,7 +295,7 @@ pub fn claim(td_addr: &str, am: Option<&str>, sk_str: Option<&str>) -> Result<() None }; - let kp = restore_keypair_from_str_with_default(sk_str)?; + let kp = restore_keypair_from_str_with_default(sk_str, is_address_eth)?; let mut builder = utils::new_tx_builder().c(d!())?; @@ -270,7 +304,7 @@ pub fn claim(td_addr: &str, am: Option<&str>, sk_str: Option<&str>) -> Result<() builder.add_operation_claim(Some(td_addr), &kp, am); })?; - let mut tx = builder.take_transaction(); + let mut tx = builder.build_and_take_transaction()?; tx.sign_to_map(&kp); utils::send_tx(&tx).c(d!()) @@ -285,14 +319,14 @@ pub fn claim(td_addr: &str, am: Option<&str>, sk_str: Option<&str>) -> Result<() /// Delegation Information /// Validator Detail (if already staked) /// -pub fn show(basic: bool) -> Result<()> { - let kp = get_keypair().c(d!())?; +pub fn show(basic: bool, is_address_eth: bool) -> Result<()> { + let kp = get_keypair(is_address_eth).c(d!())?; let serv_addr = ruc::info!(get_serv_addr()).map(|i| { println!("\x1b[31;01mServer URL:\x1b[00m\n{i}\n"); }); - let xfr_account = ruc::info!(get_keypair()).map(|i| { + let xfr_account = ruc::info!(get_keypair(is_address_eth)).map(|i| { println!( "\x1b[31;01mFindora Address:\x1b[00m\n{}\n", wallet::public_key_to_bech32(&i.get_pk()) @@ -301,6 +335,10 @@ pub fn show(basic: bool) -> Result<()> { "\x1b[31;01mFindora Public Key:\x1b[00m\n{}\n", wallet::public_key_to_base64(&i.get_pk()) ); + println!( + "\x1b[31;01mFindora Public Key in hex:\x1b[00m\n{}\n", + wallet::public_key_to_hex(&i.get_pk()) + ); }); let self_balance = ruc::info!(utils::get_balance(&kp)).map(|i| { @@ -412,6 +450,7 @@ pub fn transfer_asset( am: &str, confidential_am: bool, confidential_ty: bool, + is_address_eth: bool, ) -> Result<()> { transfer_asset_batch( owner_sk, @@ -420,6 +459,7 @@ pub fn transfer_asset( am, confidential_am, confidential_ty, + is_address_eth, ) .c(d!()) } @@ -452,8 +492,9 @@ pub fn transfer_asset_batch( am: &str, confidential_am: bool, confidential_ty: bool, + is_address_eth: bool, ) -> Result<()> { - let from = restore_keypair_from_str_with_default(owner_sk)?; + let from = restore_keypair_from_str_with_default(owner_sk, is_address_eth)?; let am = am.parse::().c(d!("'amount' must be an integer"))?; transfer_asset_batch_x( @@ -502,15 +543,21 @@ pub fn get_serv_addr() -> Result<&'static str> { } /// Get keypair from config file -pub fn get_keypair() -> Result { +pub fn get_keypair(is_address_eth: bool) -> Result { if let Some(m_path) = MNEMONIC.as_ref() { fs::read_to_string(m_path) .c(d!("can not read mnemonic from 'owner-mnemonic-path'")) .and_then(|m| { let k = m.trim(); - wallet::restore_keypair_from_mnemonic_default(k) - .c(d!("invalid 'owner-mnemonic'")) - .or_else(|e| wallet::restore_keypair_from_seckey_base64(k).c(d!(e))) + let kp = if is_address_eth { + wallet::restore_keypair_from_mnemonic_secp256k1(k) + .c(d!("invalid 'owner-mnemonic'")) + } else { + wallet::restore_keypair_from_mnemonic_default(k) + .c(d!("invalid 'owner-mnemonic'")) + }; + + kp.or_else(|e| wallet::restore_keypair_from_seckey_base64(k).c(d!(e))) }) } else { Err(eg!("'owner-mnemonic-path' has not been set")) @@ -556,10 +603,15 @@ pub fn convert_commission_rate(cr: f64) -> Result<[u64; 2]> { } #[allow(missing_docs)] -pub fn gen_key() -> (String, String, String, XfrKeyPair) { +pub fn gen_key(is_address_eth: bool) -> (String, String, String, XfrKeyPair) { let (mnemonic, key, kp) = loop { let mnemonic = pnk!(wallet::generate_mnemonic_custom(24, "en")); - let kp = pnk!(wallet::restore_keypair_from_mnemonic_default(&mnemonic)); + let kp = if is_address_eth { + pnk!(wallet::restore_keypair_from_mnemonic_secp256k1(&mnemonic)) + } else { + pnk!(wallet::restore_keypair_from_mnemonic_default(&mnemonic)) + }; + if let Some(key) = serde_json::to_string_pretty(&kp) .ok() .filter(|s| s.matches("\": \"-").next().is_none()) @@ -574,26 +626,33 @@ pub fn gen_key() -> (String, String, String, XfrKeyPair) { } #[allow(missing_docs)] -pub fn gen_key_and_print() { - let (wallet_addr, mnemonic, key, _) = gen_key(); +pub fn gen_key_and_print(is_address_eth: bool) { + let (wallet_addr, mnemonic, key, _) = gen_key(is_address_eth); println!( "\n\x1b[31;01mWallet Address:\x1b[00m {wallet_addr}\n\x1b[31;01mMnemonic:\x1b[00m {mnemonic}\n\x1b[31;01mKey:\x1b[00m {key}\n", ); } -fn restore_keypair_from_str_with_default(sk_str: Option<&str>) -> Result { +fn restore_keypair_from_str_with_default( + sk_str: Option<&str>, + is_address_eth: bool, +) -> Result { if let Some(sk) = sk_str { serde_json::from_str::(&format!("\"{}\"", sk.trim())) .map(|sk| sk.into_keypair()) .c(d!("Invalid secret key")) } else { - get_keypair().c(d!()) + get_keypair(is_address_eth).c(d!()) } } /// Show the asset balance of a findora account -pub fn show_account(sk_str: Option<&str>, _asset: Option<&str>) -> Result<()> { - let kp = restore_keypair_from_str_with_default(sk_str)?; +pub fn show_account( + sk_str: Option<&str>, + _asset: Option<&str>, + is_address_eth: bool, +) -> Result<()> { + let kp = restore_keypair_from_str_with_default(sk_str, is_address_eth)?; // let token_code = asset // .map(|asset| AssetTypeCode::new_from_base64(asset).c(d!("Invalid asset code"))) // .transpose()?; @@ -614,8 +673,13 @@ pub fn show_account(sk_str: Option<&str>, _asset: Option<&str>) -> Result<()> { #[inline(always)] #[allow(missing_docs)] -pub fn delegate(sk_str: Option<&str>, amount: u64, validator: &str) -> Result<()> { - restore_keypair_from_str_with_default(sk_str) +pub fn delegate( + sk_str: Option<&str>, + amount: u64, + validator: &str, + is_address_eth: bool, +) -> Result<()> { + restore_keypair_from_str_with_default(sk_str, is_address_eth) .c(d!()) .and_then(|kp| delegate_x(&kp, amount, validator).c(d!())) } @@ -630,8 +694,12 @@ pub fn delegate_x(kp: &XfrKeyPair, amount: u64, validator: &str) -> Result<()> { #[inline(always)] #[allow(missing_docs)] -pub fn undelegate(sk_str: Option<&str>, param: Option<(u64, &str)>) -> Result<()> { - restore_keypair_from_str_with_default(sk_str) +pub fn undelegate( + sk_str: Option<&str>, + param: Option<(u64, &str)>, + is_address_eth: bool, +) -> Result<()> { + restore_keypair_from_str_with_default(sk_str, is_address_eth) .c(d!()) .and_then(|kp| undelegate_x(&kp, param).c(d!())) } @@ -645,8 +713,8 @@ pub fn undelegate_x(kp: &XfrKeyPair, param: Option<(u64, &str)>) -> Result<()> { } /// Display delegation information of a findora account -pub fn show_delegations(sk_str: Option<&str>) -> Result<()> { - let pk = restore_keypair_from_str_with_default(sk_str)?.get_pk(); +pub fn show_delegations(sk_str: Option<&str>, is_address_eth: bool) -> Result<()> { + let pk = restore_keypair_from_str_with_default(sk_str, is_address_eth)?.get_pk(); println!( "{}", @@ -681,7 +749,7 @@ fn gen_undelegate_tx( builder.add_operation_undelegation(owner_kp, None); } - let mut tx = builder.take_transaction(); + let mut tx = builder.build_and_take_transaction()?; tx.sign_to_map(owner_kp); Ok(tx) @@ -708,7 +776,7 @@ fn gen_delegate_tx( builder.add_operation_delegation(owner_kp, amount, validator.to_owned()); })?; - let mut tx = builder.take_transaction(); + let mut tx = builder.build_and_take_transaction()?; tx.sign_to_map(owner_kp); @@ -723,8 +791,9 @@ pub fn create_asset( max_units: Option, transferable: bool, token_code: Option<&str>, + is_address_eth: bool, ) -> Result<()> { - let kp = restore_keypair_from_str_with_default(sk_str)?; + let kp = restore_keypair_from_str_with_default(sk_str, is_address_eth)?; let code = if token_code.is_none() { AssetTypeCode::gen_random() @@ -768,7 +837,7 @@ pub fn create_asset_x( .c(d!()) .map(|op| builder.add_operation(op))?; - let mut tx = builder.take_transaction(); + let mut tx = builder.build_and_take_transaction()?; tx.sign_to_map(kp); utils::send_tx(&tx).map(|_| asset_code) @@ -780,8 +849,9 @@ pub fn issue_asset( asset: &str, amount: u64, hidden: bool, + is_address_eth: bool, ) -> Result<()> { - let kp = restore_keypair_from_str_with_default(sk_str)?; + let kp = restore_keypair_from_str_with_default(sk_str, is_address_eth)?; let code = AssetTypeCode::new_from_base64(asset).c(d!())?; issue_asset_x(&kp, &code, amount, hidden).c(d!()) } @@ -809,7 +879,7 @@ pub fn issue_asset_x( .c(d!()) .map(|op| builder.add_operation(op))?; - let mut tx = builder.take_transaction(); + let mut tx = builder.build_and_take_transaction()?; tx.sign_to_map(kp); utils::send_tx(&tx) @@ -827,15 +897,651 @@ pub fn show_asset(addr: &str) -> Result<()> { Ok(()) } +/// Builds a transaction for a BAR to ABAR conversion with fees and sends it to network +/// # Arguments +/// * owner_sk - Optional secret key Xfr in json form +/// * target_addr - ABAR receiving AXfr pub key after conversion in base64 +/// * TxoSID - sid of BAR to convert +pub fn convert_bar2abar( + owner_sk: Option<&String>, + target_addr: &str, + txo_sid: &str, + is_address_eth: bool, +) -> Result { + // parse sender XfrSecretKey or generate from Mnemonic setup with wallet + let from = match owner_sk { + Some(str) => { + ruc::info!(serde_json::from_str::(&format!("\"{str}\"",))) + .c(d!())? + .into_keypair() + } + None => get_keypair(is_address_eth).c(d!())?, + }; + // parse receiver AxfrPubKey + let to = + wallet::public_key_from_bech32(target_addr).c(d!("invalid 'target-addr'"))?; + let sid = txo_sid.parse::().c(d!("error parsing TxoSID"))?; + + // Get OpenAssetRecord from given Owner XfrKeyPair and TxoSID + let record = + utils::get_oar(&from, TxoSID(sid)).c(d!("error fetching open asset record"))?; + let is_bar_transparent = + record.1.get_record_type() == NonConfidentialAmount_NonConfidentialAssetType; + + // Generate the transaction and transmit it to network + let c = utils::generate_bar2abar_op( + &from, + &to, + TxoSID(sid), + &record.0, + is_bar_transparent, + ) + .c(d!("Bar to abar failed"))?; + + Ok(c) +} + +/// Convert an ABAR to a Blind Asset Record +/// # Arguments +/// * axfr_secret_key - the anon_secret_key in base64 +/// * com - commitment of ABAR in base64 +/// * to - Bar receiver's XfrPublicKey pointer +/// * com_fra - commitment of the FRA ABAR to pay fee in base64 +/// * confidential_am - if the output BAR should have confidential amount +/// * confidential_ty - if the output BAR should have confidential type +pub fn convert_abar2bar( + owner_sk: Option, + com: &str, + to: &XfrPublicKey, + confidential_am: bool, + confidential_ty: bool, + is_address_eth: bool, +) -> Result<()> { + let from = match owner_sk { + Some(str) => { + ruc::info!(serde_json::from_str::(&format!("\"{str}\""))) + .c(d!())? + .into_keypair() + } + None => get_keypair(is_address_eth).c(d!())?, + }; + // Get the owned ABAR from pub_key and commitment + let com = wallet::commitment_from_base58(com).c(d!())?; + let axtxo_abar = utils::get_owned_abar(&com).c(d!())?; + + // get OwnerMemo and Merkle Proof of ABAR + let owner_memo = utils::get_abar_memo(&axtxo_abar.0).c(d!())?.unwrap(); + let mt_leaf_info = utils::get_abar_proof(&axtxo_abar.0).c(d!())?.unwrap(); + let mt_leaf_uid = mt_leaf_info.uid; + + // Open ABAR with OwnerMemo & attach merkle proof + let oabar_in = OpenAnonAssetRecordBuilder::from_abar( + &axtxo_abar.1, + owner_memo, + &from.into_noah(), + ) + .unwrap() + .mt_leaf_info(mt_leaf_info) + .build() + .unwrap(); + + // check oabar is unspent. If already spent return error + // create nullifier + let n = nullify( + &from.into_noah(), + oabar_in.get_amount(), + oabar_in.get_asset_type().as_scalar(), + mt_leaf_uid, + ) + .c(d!())?; + let hash = wallet::nullifier_to_base58(&n.0); + // check if hash is present in nullifier set + let null_status = utils::check_nullifier_hash(&hash) + .c(d!())? + .ok_or(d!("The ABAR corresponding to this commitment is missing"))?; + if null_status { + return Err(eg!( + "The ABAR corresponding to this commitment is already spent" + )); + } + println!("Nullifier: {}", wallet::nullifier_to_base58(&n.0)); + + // Create New AssetRecordType for new BAR + let art = match (confidential_am, confidential_ty) { + (true, true) => AssetRecordType::ConfidentialAmount_ConfidentialAssetType, + (true, false) => AssetRecordType::ConfidentialAmount_NonConfidentialAssetType, + (false, true) => AssetRecordType::NonConfidentialAmount_ConfidentialAssetType, + _ => AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, + }; + + // Build AbarToBar Transaction and submit + utils::generate_abar2bar_op(&oabar_in, &from, to, art).c(d!())?; + + Ok(()) +} + +/// Generate OABAR and add anonymous transfer operation +/// # Arguments +/// * axfr_secret_key - AXfrKeyPair in base64 form +/// * com - Commitment in base64 form +/// * com_fra - Commitment for paying fee +/// * amount - amount to transfer +/// * to_axfr_public_key - AXfrPublicKey in base64 form +pub fn gen_anon_transfer_op( + owner_sk: Option, + com: &str, + com_fra: Option<&str>, + amount: &str, + to_address: &str, + is_address_eth: bool, +) -> Result<()> { + // parse sender keys + // parse sender XfrSecretKey or generate from Mnemonic setup with wallet + let from = match owner_sk { + Some(str) => { + ruc::info!(serde_json::from_str::(&format!("\"{str}\""))) + .c(d!())? + .into_keypair() + } + None => get_keypair(is_address_eth).c(d!())?, + }; + let axfr_amount = amount.parse::().c(d!("error parsing amount"))?; + + let to = wallet::public_key_from_bech32(to_address) + .c(d!("invalid 'to-xfr-public-key'"))?; + + let mut commitments = vec![com]; + if let Some(fra) = com_fra { + commitments.push(fra); + } + let mut inputs = vec![]; + // For each commitment add input to transfer operation + for com in commitments { + let c = wallet::commitment_from_base58(com).c(d!())?; + + // get unspent ABARs & their Merkle proof for commitment + let axtxo_abar = utils::get_owned_abar(&c).c(d!())?; + let owner_memo = utils::get_abar_memo(&axtxo_abar.0).c(d!())?.unwrap(); + let mt_leaf_info = utils::get_abar_proof(&axtxo_abar.0).c(d!())?.unwrap(); + let mt_leaf_uid = mt_leaf_info.uid; + + // Create Open ABAR from input information + let oabar_in = OpenAnonAssetRecordBuilder::from_abar( + &axtxo_abar.1, + owner_memo, + &from.into_noah(), + ) + .unwrap() + .mt_leaf_info(mt_leaf_info) + .build() + .unwrap(); + + // check oabar is unspent. + let n = nullify( + &from.into_noah(), + oabar_in.get_amount(), + oabar_in.get_asset_type().as_scalar(), + mt_leaf_uid, + ) + .c(d!())?; + let hash = wallet::nullifier_to_base58(&n.0); + let null_status = utils::check_nullifier_hash(&hash).c(d!())?.ok_or(d!( + "The ABAR corresponding to this commitment is missing {}", + com + ))?; + if null_status { + return Err(eg!( + "The ABAR corresponding to this commitment is already spent {}", + com + )); + } + + println!("Nullifier: {}", wallet::nullifier_to_base58(&n.0)); + inputs.push(oabar_in); + } + + // build output + let mut prng = ChaChaRng::from_entropy(); + let oabar_out = OpenAnonAssetRecordBuilder::new() + .amount(axfr_amount) + .asset_type(inputs[0].get_asset_type()) + .pub_key(&to.into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(); + + let mut builder: TransactionBuilder = new_tx_builder().c(d!())?; + let (_, note, rem_oabars) = builder + .add_operation_anon_transfer_fees_remainder(&inputs, &[oabar_out], &from) + .c(d!())?; + + send_tx(&builder.build_and_take_transaction()?).c(d!())?; + + let com_out = if !note.body.outputs.is_empty() { + Some(note.body.outputs[0].commitment) + } else { + None + }; + + if let Some(com) = com_out { + println!( + "\x1b[31;01m Commitment: {}\x1b[00m", + wallet::commitment_to_base58(&com) + ); + + // Append receiver's commitment to `sent_commitment` file + let mut file = fs::OpenOptions::new() + .append(true) + .create(true) + .open("sent_commitments") + .expect("cannot open commitments file"); + std::io::Write::write_all( + &mut file, + ("\n".to_owned() + &wallet::commitment_to_base58(&com)).as_bytes(), + ) + .expect("commitment write failed"); + } + + // Append sender's fee balance commitment to `owned_commitments` file + let mut file = fs::OpenOptions::new() + .append(true) + .create(true) + .open("owned_commitments") + .expect("cannot open commitments file"); + for rem_oabar in rem_oabars.iter() { + let c = get_abar_commitment(rem_oabar.clone()); + println!( + "\x1b[31;01m Remainder Commitment: {}\x1b[00m", + wallet::commitment_to_base58(&c) + ); + + std::io::Write::write_all( + &mut file, + ("\n".to_owned() + &wallet::commitment_to_base58(&c)).as_bytes(), + ) + .expect("commitment write failed"); + } + + println!("AxfrNote: {:?}", serde_json::to_string_pretty(¬e.body)); + Ok(()) +} + +/// Batch anon transfer - Generate OABAR and add anonymous transfer operation +/// Note - if multiple anon keys are used, we consider the last key in the list for remainder. +/// # Arguments +/// * axfr_secret_key - list of secret keys for senders' ABAR UTXOs +/// * to_axfr_public_keys - receiver AXfr Public keys +/// * to_enc_keys - List of receiver Encryption keys +/// * commitments - List of sender commitments in base64 format +/// * amounts - List of receiver amounts +/// * assets - List of receiver Asset Types +/// returns an error if Operation build fails +pub fn gen_oabar_add_op_x( + owner_sk: Option, + to_axfr_public_keys: Vec, + commitments: Vec, + amounts: Vec, + assets: Vec, + is_address_eth: bool, +) -> Result<()> { + let from = match owner_sk { + Some(str) => { + ruc::info!(serde_json::from_str::(&format!("\"{str}\""))) + .c(d!())? + .into_keypair() + } + None => get_keypair(is_address_eth).c(d!())?, + }; + let receiver_count = to_axfr_public_keys.len(); + + // check if input counts tally + if receiver_count != amounts.len() || receiver_count != assets.len() { + return Err(eg!( + "The Parameters: from-sk/dec-keys/commitments or to-pk/to-enc-keys not match!" + )); + } + + // Create Input Open Abars with input keys, radomizers and Owner memos + let mut oabars_in = Vec::new(); + for comm in commitments { + let c = wallet::commitment_from_base58(comm.as_str()).c(d!())?; + + // Get OwnerMemo + let axtxo_abar = utils::get_owned_abar(&c).c(d!())?; + let owner_memo = utils::get_abar_memo(&axtxo_abar.0).c(d!(comm))?.unwrap(); + // Get Merkle Proof + let mt_leaf_info = utils::get_abar_proof(&axtxo_abar.0).c(d!())?.unwrap(); + let mt_leaf_uid = mt_leaf_info.uid; + + // Build Abar + let oabar_in = OpenAnonAssetRecordBuilder::from_abar( + &axtxo_abar.1, + owner_memo, + &from.into_noah(), + ) + .unwrap() + .mt_leaf_info(mt_leaf_info) + .build() + .unwrap(); + + // check oabar is unspent. + let n = nullify( + &from.into_noah(), + oabar_in.get_amount(), + oabar_in.get_asset_type().as_scalar(), + mt_leaf_uid, + ) + .c(d!())?; + let hash = wallet::nullifier_to_base58(&n.0); + let null_status = utils::check_nullifier_hash(&hash) + .c(d!())? + .ok_or(d!("The ABAR corresponding to this commitment is missing"))?; + if null_status { + return Err(eg!( + "The ABAR corresponding to this commitment is already spent" + )); + } + println!("Nullifier: {}", wallet::nullifier_to_base58(&n.0)); + + oabars_in.push(oabar_in); + } + + // Create output Open ABARs + let mut oabars_out = Vec::new(); + for i in 0..receiver_count { + let mut prng = ChaChaRng::from_entropy(); + let to = to_axfr_public_keys[i]; + let axfr_amount = amounts[i].parse::().c(d!("error parsing amount"))?; + let asset_type = assets[i]; + + let oabar_out = OpenAnonAssetRecordBuilder::new() + .amount(axfr_amount) + .asset_type(asset_type.val) + .pub_key(&to.into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(); + + oabars_out.push(oabar_out); + } + + // Add a output for fees balance + let mut builder: TransactionBuilder = new_tx_builder().c(d!())?; + let (_, note, rem_oabars) = builder + .add_operation_anon_transfer_fees_remainder( + &oabars_in[..], + &oabars_out[..], + &from, + ) + .c(d!())?; + + // Send the transaction to the network + send_tx(&builder.build_and_take_transaction()?).c(d!())?; + + // Append receiver's commitment to `sent_commitments` file + let mut s_file = fs::OpenOptions::new() + .append(true) + .create(true) + .open("sent_commitments") + .expect("cannot open commitments file"); + for oabar_out in oabars_out { + let c_out = get_abar_commitment(oabar_out); + println!( + "\x1b[31;01m Commitment: {}\x1b[00m", + wallet::commitment_to_base58(&c_out) + ); + + std::io::Write::write_all( + &mut s_file, + ("\n".to_owned() + &wallet::commitment_to_base58(&c_out)).as_bytes(), + ) + .expect("commitment write failed"); + } + + let mut o_file = fs::OpenOptions::new() + .append(true) + .create(true) + .open("owned_commitments") + .expect("cannot open commitments file"); + for rem_oabar in rem_oabars.iter() { + let c_rem = get_abar_commitment(rem_oabar.clone()); + + println!( + "\x1b[31;01m Remainder Commitment: {}\x1b[00m", + wallet::commitment_to_base58(&c_rem) + ); + std::io::Write::write_all( + &mut o_file, + ("\n".to_owned() + &wallet::commitment_to_base58(&c_rem)).as_bytes(), + ) + .expect("commitment write failed"); + } + + println!("AxfrNote: {:?}", serde_json::to_string_pretty(¬e.body)); + Ok(()) +} + +/// Get merkle proof - Generate MTLeafInfo from ATxoSID +pub fn get_mtleaf_info(atxo_sid: &str) -> Result { + let asid = atxo_sid.parse::().c(d!("error parsing ATxoSID"))?; + let mt_leaf_info = utils::get_abar_proof(&ATxoSID(asid)) + .c(d!("error fetching abar proof"))? + .unwrap(); + Ok(mt_leaf_info) +} + +/// Fetches list of owned TxoSIDs from LedgerStatus +pub fn get_owned_utxos( + asset: Option<&str>, + is_address_eth: bool, +) -> Result> { + // get KeyPair from current setup wallet + let kp = get_keypair(is_address_eth).c(d!())?; + + // Parse Asset Type for filtering if provided + let mut asset_type = ASSET_TYPE_FRA; + if let Some(a) = asset { + asset_type = if a.to_uppercase() == "FRA" { + ASSET_TYPE_FRA + } else { + AssetTypeCode::new_from_base64(asset.unwrap()).unwrap().val + }; + } + + let list: Vec<(TxoSID, XfrAmount, XfrAssetType)> = + utils::get_owned_utxos(&kp.pub_key)? + .iter() + .filter(|a| { + // Filter by asset type if given or read all + if asset.is_none() { + true + } else { + match a.1.clone().0 .0.record.asset_type { + XfrAssetType::Confidential(_) => false, + XfrAssetType::NonConfidential(x) => asset_type == x, + } + } + }) + .map(|a| { + let record = a.1.clone().0 .0.record; + (*a.0, record.amount, record.asset_type) + }) + .collect(); + + Ok(list) +} + +/// Check the spending status of an ABAR from AnonKeys and commitment +pub fn check_abar_status( + from: XfrKeyPair, + axtxo_abar: (ATxoSID, AnonAssetRecord), +) -> Result<()> { + let owner_memo = utils::get_abar_memo(&axtxo_abar.0).c(d!())?.unwrap(); + let mt_leaf_info = utils::get_abar_proof(&axtxo_abar.0).c(d!())?.unwrap(); + let mt_leaf_uid = mt_leaf_info.uid; + + let oabar = OpenAnonAssetRecordBuilder::from_abar( + &axtxo_abar.1, + owner_memo, + &from.into_noah(), + ) + .unwrap() + .mt_leaf_info(mt_leaf_info) + .build() + .unwrap(); + + let n = nullify( + &from.into_noah(), + oabar.get_amount(), + oabar.get_asset_type().as_scalar(), + mt_leaf_uid, + ) + .c(d!())?; + let hash = wallet::nullifier_to_base58(&n.0); + let null_status = utils::check_nullifier_hash(&hash).c(d!())?.unwrap(); + if null_status { + println!("The ABAR corresponding to this commitment is already spent"); + } else { + println!("The ABAR corresponding to this commitment is unspent and has a balance {:?}", oabar.get_amount()); + } + Ok(()) +} + +/// Prints a dainty list of Abar info with spent status for a given AxfrKeyPair and a list of +/// commitments. +pub fn get_owned_abars( + axfr_secret_key: XfrKeyPair, + commitments_list: &str, +) -> Result<()> { + println!("Abar data for commitments: {commitments_list}",); + println!(); + println!( + "{0: <8} | {1: <18} | {2: <45} | {3: <9} | {4: <45}", + "ATxoSID", "Amount", "AssetType", "IsSpent", "Commitment" + ); + println!("{:-^1$}", "", 184); + commitments_list + .split(',') + .try_for_each(|com| -> ruc::Result<()> { + let commitment = wallet::commitment_from_base58(com).c(d!())?; + let (sid, abar) = utils::get_owned_abar(&commitment).c(d!())?; + let memo = utils::get_abar_memo(&sid).unwrap().unwrap(); + let oabar = OpenAnonAssetRecordBuilder::from_abar( + &abar, + memo, + &axfr_secret_key.into_noah(), + ) + .unwrap() + .build() + .unwrap(); + + let n = nullify( + &axfr_secret_key.into_noah(), + oabar.get_amount(), + oabar.get_asset_type().as_scalar(), + sid.0, + ) + .c(d!())?; + let hash = wallet::nullifier_to_base58(&n.0); + let null_status = utils::check_nullifier_hash(&hash).c(d!())?.unwrap(); + println!( + "{0: <8} | {1: <18} | {2: <45} | {3: <9} | {4: <45}", + sid.0, + oabar.get_amount(), + AssetTypeCode { + val: oabar.get_asset_type() + } + .to_base64(), + null_status, + com + ); + + Ok(()) + })?; + + Ok(()) +} + +/// Prints a dainty list of Abar info with spent status for a given AxfrKeyPair and a list of +/// commitments. +pub fn anon_balance( + axfr_secret_key: XfrKeyPair, + commitments_list: &str, + asset: Option<&str>, +) -> Result<()> { + // Parse Asset Type for filtering if provided + let mut asset_type = ASSET_TYPE_FRA; + if let Some(a) = asset { + asset_type = if a.to_uppercase() == "FRA" { + ASSET_TYPE_FRA + } else { + AssetTypeCode::new_from_base64(asset.unwrap()).unwrap().val + }; + } + + let mut balance = 0u64; + commitments_list + .split(',') + .try_for_each(|com| -> ruc::Result<()> { + let commitment = wallet::commitment_from_base58(com).c(d!())?; + + let result = utils::get_owned_abar(&commitment); + match result { + Err(e) => { + if e.msg_eq(eg!("missing abar").as_ref()) { + Ok(()) + } else { + Err(e) + } + } + Ok((sid, abar)) => { + let memo = utils::get_abar_memo(&sid).unwrap().unwrap(); + let oabar = OpenAnonAssetRecordBuilder::from_abar( + &abar, + memo, + &axfr_secret_key.into_noah(), + ) + .unwrap() + .build() + .unwrap(); + + let n = nullify( + &axfr_secret_key.into_noah(), + oabar.get_amount(), + oabar.get_asset_type().as_scalar(), + sid.0, + ) + .c(d!())?; + let hash = wallet::nullifier_to_base58(&n.0); + let is_spent = utils::check_nullifier_hash(&hash).c(d!())?.unwrap(); + if !is_spent && oabar.get_asset_type() == asset_type { + balance += oabar.get_amount(); + } + + Ok(()) + } + } + })?; + + println!("{}: {}", asset.unwrap_or("FRA"), balance); + Ok(()) +} + /// Return the built version. pub fn version() -> &'static str { concat!(env!("VERGEN_SHA"), " ", env!("VERGEN_BUILD_DATE")) } ///operation to replace the staker. -pub fn replace_staker(target_addr: fp_types::H160, td_addr: &str) -> Result<()> { +pub fn replace_staker( + target_addr: fp_types::H160, + td_addr: &str, + is_address_eth: bool, +) -> Result<()> { let td_addr = hex::decode(td_addr).c(d!())?; - let keypair = get_keypair()?; + let keypair = get_keypair(is_address_eth)?; let mut builder = utils::new_tx_builder().c(d!())?; @@ -844,7 +1550,7 @@ pub fn replace_staker(target_addr: fp_types::H160, td_addr: &str) -> Result<()> })?; builder.add_operation_replace_staker(&keypair, target_addr, td_addr)?; - let mut tx = builder.take_transaction(); + let mut tx = builder.build_and_take_transaction()?; tx.sign_to_map(&keypair); utils::send_tx(&tx).c(d!())?; diff --git a/src/components/finutils/src/common/utils.rs b/src/components/finutils/src/common/utils.rs index 0849dbf2d..0d794aa8a 100644 --- a/src/components/finutils/src/common/utils.rs +++ b/src/components/finutils/src/common/utils.rs @@ -11,9 +11,9 @@ use { globutils::{wallet, HashOf, SignatureOf}, ledger::{ data_model::{ - AssetType, AssetTypeCode, DefineAsset, Operation, StateCommitmentData, - Transaction, TransferType, TxoRef, TxoSID, Utxo, ASSET_TYPE_FRA, - BLACK_HOLE_PUBKEY, TX_FEE_MIN, + ABARData, ATxoSID, AssetType, AssetTypeCode, DefineAsset, Operation, + StateCommitmentData, Transaction, TransferType, TxoRef, TxoSID, Utxo, + ASSET_TYPE_FRA, BAR_TO_ABAR_TX_FEE_MIN, BLACK_HOLE_PUBKEY, TX_FEE_MIN, }, staking::{ init::get_inital_validators, StakerMemo, TendermintAddrRef, FRA_TOTAL_AMOUNT, @@ -36,11 +36,17 @@ use { Web3, }, zei::{ - noah_api::xfr::{ - asset_record::{open_blind_asset_record, AssetRecordType}, - structs::{AssetRecordTemplate, OwnerMemo}, + noah_api::{ + anon_xfr::structs::{ + AnonAssetRecord, AxfrOwnerMemo, Commitment, MTLeafInfo, + OpenAnonAssetRecord, + }, + xfr::{ + asset_record::{open_blind_asset_record, AssetRecordType}, + structs::{AssetRecordTemplate, OpenAssetRecord, OwnerMemo}, + }, }, - {XfrKeyPair, XfrPublicKey}, + BlindAssetRecord, XfrKeyPair, XfrPublicKey, }, }; @@ -83,7 +89,17 @@ pub fn set_initial_validators() -> Result<()> { let vs = get_inital_validators().c(d!())?; builder.add_operation_update_validator(&[], 1, vs).c(d!())?; - send_tx(&builder.take_transaction()).c(d!()) + send_tx(&builder.build_and_take_transaction()?).c(d!()) +} + +///load the tendermint key from the `priv_validator_key.json` file. +pub fn load_tendermint_priv_validator_key( + key_path: impl AsRef, +) -> Result { + let k = + std::fs::read_to_string(key_path).c(d!("can not read key file from path"))?; + let v_keys = parse_td_validator_keys(&k).c(d!())?; + Ok(v_keys) } #[inline(always)] @@ -133,7 +149,7 @@ pub fn transfer_batch( .c(d!())?; builder.add_operation(op); - let mut tx = builder.take_transaction(); + let mut tx = builder.build_and_take_transaction()?; tx.sign_to_map(owner_kp); send_tx(&tx).c(d!()) @@ -312,6 +328,92 @@ pub fn gen_fee_op(owner_kp: &XfrKeyPair) -> Result { gen_transfer_op(owner_kp, vec![], None, false, false, None).c(d!()) } +/// fee for bar to abar conversion +#[inline(always)] +pub fn gen_fee_bar_to_abar( + owner_kp: &XfrKeyPair, + avoid_input: TxoSID, +) -> Result { + let mut op_fee: u64 = BAR_TO_ABAR_TX_FEE_MIN; + let mut trans_builder = TransferOperationBuilder::new(); + trans_builder + .add_output( + &AssetRecordTemplate::with_no_asset_tracing( + BAR_TO_ABAR_TX_FEE_MIN, + ASSET_TYPE_FRA, + AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, + *BLACK_HOLE_PUBKEY, + ), + None, + None, + None, + ) + .c(d!())?; + + let utxos = get_owned_utxos(owner_kp.get_pk_ref()).c(d!())?.into_iter(); + for (sid, (utxo, owner_memo)) in utxos { + let oar = open_blind_asset_record( + &utxo.0.record.into_noah(), + &owner_memo, + &owner_kp.into_noah(), + ) + .c(d!())?; + + if op_fee == 0 { + break; + } + if oar.asset_type == ASSET_TYPE_FRA + && oar.get_record_type() + == AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType + && op_fee != 0 + && sid != avoid_input + { + let i_am = oar.amount; + if oar.amount <= op_fee { + op_fee -= i_am; + + trans_builder + .add_input(TxoRef::Absolute(sid), oar, None, None, i_am) + .c(d!())?; + } else { + trans_builder + .add_input(TxoRef::Absolute(sid), oar, None, None, i_am) + .c(d!())?; + + trans_builder + .add_output( + &AssetRecordTemplate::with_no_asset_tracing( + i_am - op_fee, + ASSET_TYPE_FRA, + AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, + owner_kp.pub_key.into_noah(), + ), + None, + None, + None, + ) + .c(d!())?; + + op_fee = 0; + } + } + } + + if op_fee != 0 { + return Err(eg!("Insufficient balance to pay Txn fees")); + } + + trans_builder + .balance(None) + .c(d!())? + .create(TransferType::Standard) + .c(d!())? + .sign(owner_kp) + .c(d!())? + .transaction() + .c(d!()) +} + ///////////////////////////////////////// // Part 2: utils for query infomations // ///////////////////////////////////////// @@ -516,7 +618,8 @@ pub fn get_asset_all(kp: &XfrKeyPair) -> Result> { Ok(set) } -fn get_owned_utxos( +#[allow(missing_docs)] +pub fn get_owned_utxos( addr: &XfrPublicKey, ) -> Result)>> { get_owned_utxos_x(None, addr).c(d!()) @@ -546,6 +649,33 @@ fn get_owned_utxos_x( }) } +/// Return the ABAR by commitment. +pub fn get_owned_abar(com: &Commitment) -> Result<(ATxoSID, AnonAssetRecord)> { + let url = format!( + "{}:8668/owned_abars/{}", + get_serv_addr().c(d!())?, + wallet::commitment_to_base58(com) + ); + + attohttpc::get(url) + .send() + .c(d!())? + .error_for_status() + .c(d!())? + .bytes() + .c(d!()) + .and_then(|b| { + serde_json::from_slice::>(&b) + .c(d!())? + .ok_or(eg!("missing abar")) + }) + .and_then(|(sid, data)| { + wallet::commitment_from_base58(&data.commitment) + .map(|commitment| (sid, AnonAssetRecord { commitment })) + .map_err(|_| eg!("commitment invalid")) + }) +} + #[inline(always)] fn get_seq_id() -> Result { type Resp = ( @@ -591,6 +721,61 @@ pub fn get_owner_memo_batch(ids: &[TxoSID]) -> Result>> { .and_then(|b| serde_json::from_slice(&b).c(d!())) } +#[inline(always)] +#[allow(missing_docs)] +pub fn get_abar_memo(id: &ATxoSID) -> Result> { + let id = id.0.to_string(); + let url = format!("{}:8667/get_abar_memo/{}", get_serv_addr().c(d!())?, id); + + attohttpc::get(url) + .send() + .c(d!())? + .error_for_status() + .c(d!())? + .bytes() + .c(d!()) + .and_then(|b| serde_json::from_slice(&b).c(d!())) +} + +#[inline(always)] +#[allow(missing_docs)] +pub fn get_abar_proof(atxo_sid: &ATxoSID) -> Result> { + let atxo_sid = atxo_sid.0.to_string(); + let url = format!( + "{}:8667/get_abar_proof/{}", + get_serv_addr().c(d!())?, + atxo_sid + ); + + attohttpc::get(url) + .send() + .c(d!())? + .error_for_status() + .c(d!())? + .bytes() + .c(d!()) + .and_then(|b| serde_json::from_slice(&b).c(d!())) +} + +#[inline(always)] +#[allow(missing_docs)] +pub fn check_nullifier_hash(null_hash: &str) -> Result> { + let url = format!( + "{}:8667/check_nullifier_hash/{}", + get_serv_addr().c(d!())?, + null_hash + ); + + attohttpc::get(url) + .send() + .c(d!())? + .error_for_status() + .c(d!())? + .bytes() + .c(d!()) + .and_then(|b| serde_json::from_slice(&b).c(d!())) +} + /// Delegation info(and staking info if `pk` is a validator). pub fn get_delegation_info(pk: &XfrPublicKey) -> Result { let url = format!( @@ -757,3 +942,113 @@ pub fn get_validator_memo_and_rate( }; Ok((memo, rate)) } + +#[inline(always)] +/// Generates a BarToAbar Operation and an accompanying FeeOP and sends it to the network and return the Randomizer +/// # Arguments +/// * `auth_key_pair` - XfrKeyPair of the owner BAR for conversion +/// * `abar_pub_key` - AXfrPubKey of the receiver ABAR after conversion +/// * `txo_sid` - TxoSID of the BAR to convert +/// * `input_record` - OpenAssetRecord of the BAR to convert +/// * `is_bar_transparent` - if transparent bar (ar) +pub fn generate_bar2abar_op( + auth_key_pair: &XfrKeyPair, + abar_pub_key: &XfrPublicKey, + txo_sid: TxoSID, + input_record: &OpenAssetRecord, + is_bar_transparent: bool, +) -> Result { + // add operation bar_to_abar in a new Tx Builder + + let mut seed = [0u8; 32]; + + getrandom::getrandom(&mut seed).c(d!())?; + + let mut builder: TransactionBuilder = new_tx_builder().c(d!())?; + let (_, c) = builder + .add_operation_bar_to_abar( + seed, + auth_key_pair, + abar_pub_key, + txo_sid, + input_record, + is_bar_transparent, + ) + .c(d!("Failed to generate operation bar to abar"))?; + + // Add a transparent fee operation for conversion which is required to process the bar + // In this step a transparent FRA AssetRecord is chosen from user owned UTXOs to pay the fee. + // If the user doesn't own such a UTXO then this method throws an error. + let feeop = + gen_fee_bar_to_abar(auth_key_pair, txo_sid).c(d!("Failed to generate fee"))?; + builder.add_operation(feeop); + + let mut tx = builder.build_and_take_transaction()?; + + tx.sign(auth_key_pair); + + // submit transaction to network + send_tx(&tx).c(d!("Failed to submit Bar to Abar txn"))?; + + Ok(c) +} + +#[inline(always)] +/// Create AbarToBar transaction with given Open ABAR & Open Bar and submit it to network +/// # Arguments +/// * oabar_in - Abar to convert in open form +/// * fee_oabar - Abar to pay anon fee in open form +/// * out_fee_oabar - Abar to get balance back after paying fee +/// * from - AXfrKeyPair of person converting ABAR +/// * to - XfrPublicKey of person receiving new BAR +/// * art - AssetRecordType of the new BAR +pub fn generate_abar2bar_op( + oabar_in: &OpenAnonAssetRecord, + from: &XfrKeyPair, + to: &XfrPublicKey, + art: AssetRecordType, +) -> Result<()> { + let mut builder: TransactionBuilder = new_tx_builder().c(d!())?; + // create and add AbarToBar Operation + builder + .add_operation_abar_to_bar(oabar_in, from, to, art) + .c(d!())?; + + // submit transaction + send_tx(&builder.build_and_take_transaction()?).c(d!())?; + Ok(()) +} + +#[inline(always)] +#[allow(missing_docs)] +pub fn get_oar( + owner_kp: &XfrKeyPair, + txo_sid: TxoSID, +) -> Result<(OpenAssetRecord, BlindAssetRecord)> { + let utxos = get_owned_utxos(owner_kp.get_pk_ref()).c(d!())?.into_iter(); + + for (sid, (utxo, owner_memo)) in utxos { + if sid != txo_sid { + continue; + } + + let oar = open_blind_asset_record( + &utxo.0.record.into_noah(), + &owner_memo, + &owner_kp.into_noah(), + ) + .c(d!())?; + + return Ok((oar, utxo.0.record)); + } + + Err(eg!("utxo not found")) +} + +#[inline(always)] +#[allow(missing_docs)] +pub fn get_abar_data(abar: AnonAssetRecord) -> ABARData { + ABARData { + commitment: wallet::commitment_to_base58(&abar.commitment), + } +} diff --git a/src/components/finutils/src/txn_builder/mod.rs b/src/components/finutils/src/txn_builder/mod.rs index 032a9ad9e..1bd6fc208 100644 --- a/src/components/finutils/src/txn_builder/mod.rs +++ b/src/components/finutils/src/txn_builder/mod.rs @@ -7,17 +7,20 @@ use { credentials::CredUserSecretKey, + curve25519_dalek::scalar::Scalar, + digest::Digest, fp_types::{crypto::MultiSigner, H160}, - globutils::SignatureOf, + globutils::{wallet, Serialized, SignatureOf}, ledger::{ converter::ConvertAccount, data_model::{ - AssetRules, AssetTypeCode, ConfidentialMemo, DefineAsset, DefineAssetBody, - IndexedSignature, IssueAsset, IssueAssetBody, IssuerKeyPair, - IssuerPublicKey, Memo, NoReplayToken, Operation, Transaction, + get_abar_commitment, AbarConvNote, AbarToBarOps, AnonTransferOps, + AssetRules, AssetTypeCode, BarAnonConvNote, BarToAbarOps, ConfidentialMemo, + DefineAsset, DefineAssetBody, IndexedSignature, IssueAsset, IssueAssetBody, + IssuerKeyPair, IssuerPublicKey, Memo, NoReplayToken, Operation, Transaction, TransactionBody, TransferAsset, TransferAssetBody, TransferType, TxOutput, - TxoRef, UpdateMemo, UpdateMemoBody, ASSET_TYPE_FRA, BLACK_HOLE_PUBKEY, - TX_FEE_MIN, + TxoRef, TxoSID, UpdateMemo, UpdateMemoBody, ASSET_TYPE_FRA, + BAR_TO_ABAR_TX_FEE_MIN, BLACK_HOLE_PUBKEY, FEE_CALCULATING_FUNC, TX_FEE_MIN, }, staking::{ is_valid_tendermint_addr, @@ -35,36 +38,51 @@ use { TendermintAddr, Validator, }, }, - noah_curve25519_dalek::scalar::Scalar, rand_chacha::ChaChaRng, - rand_core::{CryptoRng, RngCore, SeedableRng}, + rand_core::SeedableRng, ruc::*, serde::{Deserialize, Serialize}, + sha2::Sha512, std::{ cmp::Ordering, - collections::{BTreeMap, HashSet}, + collections::{BTreeMap, HashMap, HashSet}, }, tendermint::PrivateKey, - zei::noah_algebra::prelude::*, - zei::noah_algebra::ristretto::PedersenCommitmentRistretto, - zei::noah_api::{ - anon_creds::{ - ac_confidential_open_commitment, ACCommitment, ACCommitmentKey, - ConfidentialAC, Credential, - }, - xfr::{ - asset_record::{ - build_blind_asset_record, build_open_asset_record, - open_blind_asset_record, AssetRecordType, + zei::{ + noah_algebra::{prelude::*, ristretto::PedersenCommitmentRistretto}, + noah_api::{ + anon_creds::{ + ac_confidential_open_commitment, ACCommitment, ACCommitmentKey, + ConfidentialAC, Credential, + }, + anon_xfr::{ + abar_to_abar::{finish_anon_xfr_note, init_anon_xfr_note, AXfrPreNote}, + abar_to_ar::{ + finish_abar_to_ar_note, init_abar_to_ar_note, AbarToArPreNote, + }, + abar_to_bar::{ + finish_abar_to_bar_note, init_abar_to_bar_note, AbarToBarPreNote, + }, + ar_to_abar::gen_ar_to_abar_note, + bar_to_abar::gen_bar_to_abar_note, + structs::{Commitment, OpenAnonAssetRecord, OpenAnonAssetRecordBuilder}, }, - structs::{ - AssetRecord, AssetRecordTemplate, OpenAssetRecord, TracingPolicies, - TracingPolicy, + keys::SecretKey, + parameters::{AddressFormat, ProverParams}, + xfr::{ + asset_record::{ + build_blind_asset_record, build_open_asset_record, + open_blind_asset_record, AssetRecordType, + }, + structs::{ + AssetRecord, AssetRecordTemplate, AssetType, OpenAssetRecord, + TracingPolicies, TracingPolicy, + }, + XfrNotePolicies, }, - XfrNotePolicies, }, + BlindAssetRecord, OwnerMemo, XfrKeyPair, XfrPublicKey, }, - zei::{BlindAssetRecord, OwnerMemo, XfrKeyPair, XfrPublicKey}, }; macro_rules! no_transfer_err { @@ -119,6 +137,12 @@ pub struct TransactionBuilder { outputs: u64, #[allow(missing_docs)] pub no_replay_token: NoReplayToken, + #[serde(skip)] + abar_bar_cache: Vec, + #[serde(skip)] + abar_ar_cache: Vec, + #[serde(skip)] + abar_abar_cache: Vec, } impl TransactionBuilder { @@ -142,7 +166,7 @@ impl TransactionBuilder { .outputs .iter() .zip($d.body.transfer.owners_memos.iter()) - .map(|(r, om)| (r.clone(), om.clone())) + .map(|(r, om)| (r.clone(), om.clone().map(|it| it))) .collect() }; } @@ -221,32 +245,41 @@ impl TransactionBuilder { self.add_fee_custom(inputs, TX_FEE_MIN) } - /// As the last operation of any transaction, + /// As the last operation of bar_to_abar transaction, /// add a static fee to the transaction. - pub fn add_fee_custom(&mut self, inputs: FeeInputs, fee: u64) -> Result<&mut TransactionBuilder> { + pub fn add_fee_bar_to_abar( + &mut self, + inputs: FeeInputs, + ) -> Result<&mut TransactionBuilder> { + self.add_fee_custom(inputs, BAR_TO_ABAR_TX_FEE_MIN) + } + + /// As the last operation of any transaction, + /// add a custom static fee to the transaction. + pub fn add_fee_custom( + &mut self, + inputs: FeeInputs, + fee: u64, + ) -> Result<&mut TransactionBuilder> { let mut kps = vec![]; let mut opb = TransferOperationBuilder::default(); let mut am = fee; for i in inputs.inner.into_iter() { - open_blind_asset_record( - &i.ar.record.into_noah(), - &i.om.map(|o| o.into_noah()), - &i.kp.into_noah(), - ) - .c(d!()) - .and_then(|oar| { - if oar.asset_type != ASSET_TYPE_FRA { - return Err(eg!("Incorrect fee input asset_type, expected Findora AssetType record")); - } - let n = alt!(oar.amount > am, am, oar.amount); - am = am.saturating_sub(oar.amount); - opb.add_input(i.tr, oar, None, None, n) - .map(|_| { - kps.push(i.kp); - }) - .c(d!()) - })?; + open_blind_asset_record(&i.ar.record.into_noah(), &i.om.map(|o| o.into_noah()), &i.kp.into_noah()) + .c(d!()) + .and_then(|oar| { + if oar.asset_type != ASSET_TYPE_FRA { + return Err(eg!("Incorrect fee input asset_type, expected Findora AssetType record")); + } + let n = alt!(oar.amount > am, am, oar.amount); + am = am.saturating_sub(oar.amount); + opb.add_input(i.tr, oar, None, None, n) + .map(|_| { + kps.push(i.kp); + }) + .c(d!()) + })?; } opb.add_output( @@ -285,8 +318,8 @@ impl TransactionBuilder { } #[allow(missing_docs)] - pub fn get_owner_memo_ref(&self, idx: usize) -> Option<&OwnerMemo> { - self.txn.get_owner_memos_ref()[idx] + pub fn get_owner_memo_ref(&self, idx: usize) -> Option { + self.txn.get_owner_memos_ref()[idx].clone() } #[allow(missing_docs)] @@ -301,6 +334,9 @@ impl TransactionBuilder { TransactionBuilder { txn: Transaction::from_seq_id(seq_id), outputs: 0, + abar_abar_cache: vec![], + abar_bar_cache: vec![], + abar_ar_cache: vec![], no_replay_token, } } @@ -358,6 +394,157 @@ impl TransactionBuilder { self.txn } + #[allow(missing_docs)] + pub fn build_and_take_transaction(&mut self) -> Result { + self.build()?; + Ok(self.txn.clone()) + } + + /// Build a transaction from various pre-notes of operations + pub fn build(&mut self) -> Result<()> { + let mut prng = ChaChaRng::from_entropy(); + + // hasher txn. (IMPORTANT! KEEP THE same order) + let mut hasher = Sha512::new(); + let mut bytes = self.txn.body.digest(); + for i in &self.abar_abar_cache { + bytes.extend_from_slice(Serialized::new(&i.body).as_ref()); + } + for i in &self.abar_bar_cache { + bytes.extend_from_slice(Serialized::new(&i.body).as_ref()); + } + for i in &self.abar_ar_cache { + bytes.extend_from_slice(Serialized::new(&i.body).as_ref()); + } + hasher.update(bytes.as_slice()); + + // finish abar to abar + if !self.abar_abar_cache.is_empty() { + let mut params: HashMap<(usize, usize, u8), ProverParams> = HashMap::new(); + for pre_note in &self.abar_abar_cache { + let (af, ak) = match pre_note.input_keypair.get_sk_ref() { + SecretKey::Secp256k1(_) => (AddressFormat::SECP256K1, 0), + SecretKey::Ed25519(_) => (AddressFormat::ED25519, 1), + }; + let key = (pre_note.body.inputs.len(), pre_note.body.outputs.len(), ak); + let param = if let Some(key) = params.get(&key) { + key + } else { + let param = + ProverParams::gen_abar_to_abar(key.0, key.1, af).c(d!())?; + params.insert(key, param); + params.get(&key).unwrap() // safe, checked. + }; + + let note = finish_anon_xfr_note( + &mut prng, + param, + pre_note.clone(), + hasher.clone(), + ) + .c(d!())?; + + // Add operation + let inp = AnonTransferOps::new(note, self.no_replay_token).c(d!())?; + let op = Operation::TransferAnonAsset(Box::new(inp)); + self.txn.add_operation(op); + } + } + + // finish abar to bar + if !self.abar_bar_cache.is_empty() { + let mut abar_bar_params = [None, None]; + for pre_note in &self.abar_bar_cache { + let params = match pre_note.input_keypair.get_sk_ref() { + SecretKey::Secp256k1(_) => { + if abar_bar_params[0].is_none() { + abar_bar_params[0] = Some( + ProverParams::gen_abar_to_bar(AddressFormat::SECP256K1) + .c(d!())?, + ); + } + abar_bar_params[0].as_ref() + } + SecretKey::Ed25519(_) => { + if abar_bar_params[1].is_none() { + abar_bar_params[1] = Some( + ProverParams::gen_abar_to_bar(AddressFormat::ED25519) + .c(d!())?, + ); + } + abar_bar_params[1].as_ref() + } + }; + + let note = finish_abar_to_bar_note( + &mut prng, + params.unwrap(), + pre_note.clone(), + hasher.clone(), + ) + .c(d!())?; + + // Create operation + let conv = AbarToBarOps::new( + AbarConvNote::AbarToBar(Box::new(note)), + self.no_replay_token, + ) + .c(d!())?; + let op = Operation::AbarToBar(Box::from(conv)); + + // Add operation to transaction + self.txn.add_operation(op); + } + } + + // finish abar to ar + if !self.abar_ar_cache.is_empty() { + let mut abar_ar_params = [None, None]; + for pre_note in &self.abar_ar_cache { + let params = match pre_note.input_keypair.get_sk_ref() { + SecretKey::Secp256k1(_) => { + if abar_ar_params[0].is_none() { + abar_ar_params[0] = Some( + ProverParams::gen_abar_to_ar(AddressFormat::SECP256K1) + .c(d!())?, + ); + } + abar_ar_params[0].as_ref() + } + SecretKey::Ed25519(_) => { + if abar_ar_params[1].is_none() { + abar_ar_params[1] = Some( + ProverParams::gen_abar_to_ar(AddressFormat::ED25519) + .c(d!())?, + ); + } + abar_ar_params[1].as_ref() + } + }; + let note = finish_abar_to_ar_note( + &mut prng, + params.unwrap(), + pre_note.clone(), + hasher.clone(), + ) + .c(d!())?; + + // Create operation + let conv = AbarToBarOps::new( + AbarConvNote::AbarToAr(Box::new(note)), + self.no_replay_token, + ) + .c(d!())?; + let op = Operation::AbarToBar(Box::from(conv)); + + // Add operation to transaction + self.txn.add_operation(op); + } + } + + Ok(()) + } + /// Append a transaction memo pub fn add_memo(&mut self, memo: Memo) -> &mut Self { self.txn.body.memos.push(memo); @@ -489,7 +676,216 @@ impl TransactionBuilder { self } - /// Add a operation to delegating findora account to a tendermint validator. + /// Add an operation to convert a Blind Asset Record to a Anonymous record and return the Commitment + /// # Arguments + /// * `auth_key_pair` - XfrKeyPair of the owner BAR for conversion + /// * `abar_pub_key` - AXfrPubKey of the receiver ABAR after conversion + /// * `txo_sid` - TxoSID of the BAR to convert + /// * `input_record` - OpenAssetRecord of the BAR to convert + /// * `enc_key` - XPublicKey of OwnerMemo encryption of receiver + /// * `is_bar_transparent` - if transparent bar (ar) + #[allow(clippy::too_many_arguments)] + pub fn add_operation_bar_to_abar( + &mut self, + seed: [u8; 32], + auth_key_pair: &XfrKeyPair, + abar_pub_key: &XfrPublicKey, + txo_sid: TxoSID, + input_record: &OpenAssetRecord, + is_bar_transparent: bool, + ) -> Result<(&mut Self, Commitment)> { + // generate the BarToAbarNote with the ZKP + let (note, c) = gen_bar_conv_note( + seed, + input_record, + auth_key_pair, + abar_pub_key, + is_bar_transparent, + ) + .c(d!())?; + + // Create the BarToAbarOps + let bar_to_abar = BarToAbarOps::new(note, txo_sid, self.no_replay_token)?; + + // Add the generated operation to the transaction + let op = Operation::BarToAbar(Box::from(bar_to_abar)); + self.txn.add_operation(op); + Ok((self, c)) + } + + /// Create a new operation to convert from Anonymous record to Blind Asset Record + /// # Arguments + /// * input - ABAR to be converted + /// * input_keypair - owner keypair of ABAR to be converted + /// * bar_pub_key - Pubkey of the receiver of the new BAR + /// * asset_record_type - The type of confidentiality of new BAR + pub fn add_operation_abar_to_bar( + &mut self, + input: &OpenAnonAssetRecord, + input_keypair: &XfrKeyPair, + bar_pub_key: &XfrPublicKey, + asset_record_type: AssetRecordType, + ) -> Result<&mut Self> { + let mut prng = ChaChaRng::from_entropy(); + match asset_record_type { + AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType => { + let note = init_abar_to_ar_note( + &mut prng, + input, + &input_keypair.into_noah(), + &bar_pub_key.into_noah(), + ) + .c(d!())?; + self.abar_ar_cache.push(note); + } + _ => { + let note = init_abar_to_bar_note( + &mut prng, + input, + &input_keypair.into_noah(), + &bar_pub_key.into_noah(), + asset_record_type, + ) + .c(d!())?; + self.abar_bar_cache.push(note); + } + } + + Ok(self) + } + + /// Add an operation to transfer assets held in Anonymous Blind Asset Record. + /// Note - Input and output amounts should be balanced, including FRA implicit fee + /// Use op add_operation_anon_transfer_fees_remainder for automatic remainder and fee handling + /// # Arguments + /// * inputs - List of input ABARs to be used for the transfer + /// * outputs - List of output ABARs + /// * input_keypair - list of AXfrKeyPair of the sender + #[allow(dead_code)] + pub fn add_operation_anon_transfer( + &mut self, + inputs: &[OpenAnonAssetRecord], + outputs: &[OpenAnonAssetRecord], + input_keypair: &XfrKeyPair, + ) -> Result<(&mut Self, AXfrPreNote)> { + let fee = FEE_CALCULATING_FUNC(inputs.len() as u32, outputs.len() as u32); + + // generate anon transfer note + let note = init_anon_xfr_note(inputs, outputs, fee, &input_keypair.into_noah()) + .c(d!())?; + self.abar_abar_cache.push(note.clone()); + + Ok((self, note)) + } + + /// Create an operation for ABAR transfer and generates remainder abars for balance amounts + /// # Arguments + /// * inputs - List of input ABARs to be used for the transfer + /// * outputs - List of output ABARs + /// * input_keypair - list of AXfrKeyPair of the sender + /// * enc_key - The encryption key of the sender to send the remainder abar + pub fn add_operation_anon_transfer_fees_remainder( + &mut self, + inputs: &[OpenAnonAssetRecord], + outputs: &[OpenAnonAssetRecord], + input_keypair: &XfrKeyPair, + ) -> Result<(&mut Self, AXfrPreNote, Vec)> { + let mut prng = ChaChaRng::from_entropy(); + + let mut vec_outputs = outputs.to_vec(); + let mut vec_changes = vec![]; + let mut remainders = HashMap::new(); + let remainder_pk = input_keypair.get_pk(); + + // Create a remainders hashmap with remainder amount for each asset type + for input in inputs { + // add each input amount to the asset type entry + remainders + .entry(input.get_asset_type()) + .and_modify(|rem| *rem += input.get_amount() as i64) + .or_insert(input.get_amount() as i64); + } + for output in outputs { + // subtract each output amount from the asset type entry + remainders + .entry(output.get_asset_type()) + .and_modify(|rem| *rem -= output.get_amount() as i64) + .or_insert(-(output.get_amount() as i64)); + } + + // Check if at least one input is of FRA asset type + let fra_rem = remainders.remove(&ASSET_TYPE_FRA); + if fra_rem.is_none() { + return Err(eg!("Must include an FRA ABAR to pay FEE!")); + } + + // Create remainder OABARs for non-FRA asset types + for (asset_type, remainder) in remainders { + println!( + "Transaction Asset: {:?} Remainder Amount: {:?}", + base64::encode(&asset_type.0), + remainder + ); + + if remainder < 0 { + return Err(eg!("Transfer Asset token input less than output!")); + } + + if remainder > 0 { + let oabar_money_back = OpenAnonAssetRecordBuilder::new() + .amount(remainder as u64) + .asset_type(asset_type) + .pub_key(&remainder_pk.into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(); + + // Add the oabar to list of outputs and a list of new oabars created + vec_outputs.push(oabar_money_back.clone()); + vec_changes.push(oabar_money_back); + } + } + + // Calculate implicit fees that will get deducted and subtract from FRA remainder + let fees = + FEE_CALCULATING_FUNC(inputs.len() as u32, vec_outputs.len() as u32 + 1); + let fra_remainder = fra_rem.unwrap() - (fees as i64); // safe. checked. + if fra_remainder < 0 { + return Err(eg!("insufficient FRA to pay fees!")); + } + if fra_remainder > 0 { + println!("Transaction FRA Remainder Amount: {fra_remainder:?}",); + let oabar_money_back = OpenAnonAssetRecordBuilder::new() + .amount(fra_remainder as u64) + .asset_type(ASSET_TYPE_FRA) + .pub_key(&remainder_pk.into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(); + + // Add FRA remainder oabar to outputs + vec_outputs.push(oabar_money_back.clone()); + vec_changes.push(oabar_money_back); + } + + if vec_outputs.len() > 5 { + return Err(eg!( + "Total outputs (incl. remainders) cannot be greater than 5" + )); + } + + let note = + init_anon_xfr_note(inputs, &vec_outputs, fees, &input_keypair.into_noah()) + .c(d!())?; + self.abar_abar_cache.push(note.clone()); + + // return a list of all new remainder abars generated + Ok((self, note, vec_changes)) + } + + /// Add a operation to delegating finddra accmount to a tendermint validator. /// The transfer operation to BLACK_HOLE_PUBKEY_STAKING should be sent along with. pub fn add_operation_delegation( &mut self, @@ -792,6 +1188,49 @@ pub(crate) fn build_record_and_get_blinds( )) } +fn gen_bar_conv_note( + seed: [u8; 32], + input_record: &OpenAssetRecord, + auth_key_pair: &XfrKeyPair, + abar_pub_key: &XfrPublicKey, + is_bar_transparent: bool, +) -> Result<(BarAnonConvNote, Commitment)> { + // let mut prng = ChaChaRng::from_entropy(); + let mut prng = ChaChaRng::from_seed(seed); + + if is_bar_transparent { + let prover_params = ProverParams::gen_ar_to_abar().c(d!())?; + + // generate the BarToAbarNote with the ZKP + let note = gen_ar_to_abar_note( + &mut prng, + &prover_params, + input_record, + &auth_key_pair.into_noah(), + &abar_pub_key.into_noah(), + ) + .c(d!())?; + + let c = note.body.output.commitment; + Ok((BarAnonConvNote::ArNote(Box::new(note)), c)) + } else { + // generate params for Bar to Abar conversion + let prover_params = ProverParams::gen_bar_to_abar().c(d!())?; + + // generate the BarToAbarNote with the ZKP + let note = gen_bar_to_abar_note( + &mut prng, + &prover_params, + input_record, + &auth_key_pair.into_noah(), + &abar_pub_key.into_noah(), + ) + .c(d!())?; + let c = note.body.output.commitment; + Ok((BarAnonConvNote::BarNote(Box::new(note)), c)) + } +} + /// TransferOperationBuilder constructs transfer operations using the factory pattern /// Inputs and outputs are added iteratively before being signed by all input record owners #[derive(Clone, Serialize, Deserialize, Default)] @@ -961,7 +1400,6 @@ impl TransferOperationBuilder { } // Check if outputs and inputs are balanced - fn check_balance(&self) -> Result<()> { let input_total: u64 = self .input_records @@ -1161,20 +1599,439 @@ impl TransferOperationBuilder { } } +/// AnonTransferOperationBuilder builders anon transfer operation using the factory pattern. +/// This is used for the wasm interface in building a multi-input/output anon transfer operation. +#[derive(Default)] +pub struct AnonTransferOperationBuilder { + inputs: Vec, + outputs: Vec, + keypair: Option, + pre_note: Option, + commitments: Vec, + + nonce: NoReplayToken, + txn: Transaction, +} + +impl AnonTransferOperationBuilder { + /// default returns a fresh default builder + pub fn new_from_seq_id(seq_id: u64) -> Self { + let mut prng = ChaChaRng::from_entropy(); + let no_replay_token = NoReplayToken::new(&mut prng, seq_id); + + AnonTransferOperationBuilder { + inputs: Vec::default(), + outputs: Vec::default(), + keypair: None, + pre_note: None, + commitments: Vec::default(), + nonce: no_replay_token, + txn: Transaction::from_seq_id(seq_id), + } + } + + /// add_input is used for adding an input source to the Anon Transfer Operation factory, it takes + /// an ABAR and a Keypair as input + pub fn add_input(&mut self, abar: OpenAnonAssetRecord) -> Result<&mut Self> { + if self.inputs.len() >= 5 { + return Err(eg!("Total inputs (incl. fees) cannot be greater than 5")); + } + self.inputs.push(abar); + Ok(self) + } + + /// add_output is used to add a output record to the Anon Transfer factory + pub fn add_output(&mut self, abar: OpenAnonAssetRecord) -> Result<&mut Self> { + if self.outputs.len() >= 5 { + return Err(eg!( + "Total outputs (incl. remainders) cannot be greater than 5" + )); + } + self.commitments.push(get_abar_commitment(abar.clone())); + self.outputs.push(abar); + Ok(self) + } + + /// add_keypair is used to specify the input keypair for nullifier generation + pub fn add_keypair(&mut self, keypair: XfrKeyPair) -> &mut Self { + self.keypair = Some(keypair); + self + } + + #[allow(missing_docs)] + pub fn extra_fee_estimation(&self) -> Result { + if self.inputs.len() > 5 { + return Err(eg!("Total inputs (incl. fees) cannot be greater than 5")); + } + + let input_sums = + self.inputs + .iter() + .fold(HashMap::new(), |mut asset_amounts, i| { + let sum = asset_amounts.entry(i.get_asset_type()).or_insert(0u64); + *sum += i.get_amount(); + asset_amounts + }); + let output_sums = + self.outputs + .iter() + .fold(HashMap::new(), |mut asset_amounts, o| { + let sum = asset_amounts.entry(o.get_asset_type()).or_insert(0u64); + *sum += o.get_amount(); + asset_amounts + }); + + let fra_input_sum = *input_sums.get(&ASSET_TYPE_FRA).unwrap_or(&0u64); + let fra_output_sum = *output_sums.get(&ASSET_TYPE_FRA).unwrap_or(&0u64); + if output_sums.len() > input_sums.len() { + return Err(eg!("Output assets cannot be more than input assets")); + } + + let extra_remainders = input_sums.iter().try_fold( + 0usize, + |extra_remainders, (asset, inp_amount)| { + if *asset == ASSET_TYPE_FRA { + Ok(extra_remainders) + } else { + match output_sums.get(asset) { + None => Ok(extra_remainders + 1), + Some(op_sum) => match op_sum.cmp(inp_amount) { + Ordering::Equal => Ok(extra_remainders), + Ordering::Less => Ok(extra_remainders + 1), + Ordering::Greater => { + Err(eg!("Output cannot be greater than Input")) + } + }, + } + } + }, + )?; + + let estimated_fees_without_extra_fra_ip_op = FEE_CALCULATING_FUNC( + self.inputs.len() as u32, + (self.outputs.len() + extra_remainders) as u32, + ) as u64; + + let fra_extra_output_sum = + fra_output_sum + estimated_fees_without_extra_fra_ip_op; + match fra_input_sum.cmp(&fra_extra_output_sum) { + Ordering::Equal => Ok(0u64), + Ordering::Greater => { + let estimated_fees_with_fra_remainder = FEE_CALCULATING_FUNC( + self.inputs.len() as u32, + (self.outputs.len() + extra_remainders + 1) as u32, + ) as u64; + + if fra_input_sum >= (fra_output_sum + estimated_fees_with_fra_remainder) + { + Ok(0u64) + } else { + let estimated_fees_with_extra_input_and_remainder = + FEE_CALCULATING_FUNC( + (self.inputs.len() + 1) as u32, + (self.outputs.len() + extra_remainders + 1) as u32, + ) as u64; + + Ok( + fra_output_sum + estimated_fees_with_extra_input_and_remainder + - fra_input_sum, + ) + } + } + Ordering::Less => { + // case where input is insufficient + let estimated_fees_with_extra_input_and_remainder = FEE_CALCULATING_FUNC( + (self.inputs.len() + 1) as u32, + (self.outputs.len() + extra_remainders + 1) as u32, + ) + as u64; + Ok( + fra_output_sum + estimated_fees_with_extra_input_and_remainder + - fra_input_sum, + ) + } + } + } + + #[allow(missing_docs)] + pub fn get_total_fee_estimation(&self) -> Result { + let input_sums = + self.inputs + .iter() + .fold(HashMap::new(), |mut asset_amounts, i| { + let sum = asset_amounts.entry(i.get_asset_type()).or_insert(0u64); + *sum += i.get_amount(); + asset_amounts + }); + let output_sums = + self.outputs + .iter() + .fold(HashMap::new(), |mut asset_amounts, o| { + let sum = asset_amounts.entry(o.get_asset_type()).or_insert(0u64); + *sum += o.get_amount(); + asset_amounts + }); + + let fra_input_sum = *input_sums.get(&ASSET_TYPE_FRA).unwrap_or(&0u64); + let fra_output_sum = *output_sums.get(&ASSET_TYPE_FRA).unwrap_or(&0u64); + if output_sums.len() > input_sums.len() { + return Err(eg!("Output assets cannot be more than input assets")); + } + + let extra_remainders = input_sums.iter().try_fold( + 0usize, + |extra_remainders, (asset, inp_amount)| { + if *asset == ASSET_TYPE_FRA { + Ok(extra_remainders) + } else { + match output_sums.get(asset) { + None => Ok(extra_remainders + 1), + Some(op_sum) => match op_sum.cmp(inp_amount) { + Ordering::Equal => Ok(extra_remainders), + Ordering::Less => Ok(extra_remainders + 1), + Ordering::Greater => { + Err(eg!("Output cannot be greater than Input")) + } + }, + } + } + }, + )?; + + let estimated_fees_without_extra_fra_ip_op = FEE_CALCULATING_FUNC( + self.inputs.len() as u32, + (self.outputs.len() + extra_remainders) as u32, + ) as u64; + + let fra_extra_output_sum = + fra_output_sum + estimated_fees_without_extra_fra_ip_op; + match fra_input_sum.cmp(&fra_extra_output_sum) { + Ordering::Equal => Ok(fra_input_sum - fra_output_sum), + Ordering::Greater => { + let estimated_fees_with_fra_remainder = FEE_CALCULATING_FUNC( + self.inputs.len() as u32, + (self.outputs.len() + extra_remainders + 1) as u32, + ) as u64; + + if fra_input_sum >= (fra_output_sum + estimated_fees_with_fra_remainder) + { + Ok(estimated_fees_with_fra_remainder) + } else { + let estimated_fees_with_extra_input_and_remainder = + FEE_CALCULATING_FUNC( + (self.inputs.len() + 1) as u32, + (self.outputs.len() + extra_remainders + 1) as u32, + ) as u64; + + Ok(estimated_fees_with_extra_input_and_remainder) + } + } + Ordering::Less => { + // case where input is insufficient + let estimated_fees_with_extra_input_and_remainder = FEE_CALCULATING_FUNC( + (self.inputs.len() + 1) as u32, + (self.outputs.len() + extra_remainders + 1) as u32, + ) + as u64; + Ok(estimated_fees_with_extra_input_and_remainder) + } + } + } + + /// get_commitments fetches the commitments for the different outputs. + pub fn get_commitments(&self) -> Vec { + self.commitments.clone() + } + + /// get a hashmap of commitment, public key, asset, amount + pub fn get_commitment_map(&self) -> HashMap { + let mut commitment_map = HashMap::new(); + for out_abar in self.outputs.iter() { + let abar_rand = + wallet::commitment_to_base58(&get_abar_commitment(out_abar.clone())); + let abar_pkey = *out_abar.pub_key_ref(); + let abar_asset = out_abar.get_asset_type(); + let abar_amt = out_abar.get_amount(); + commitment_map.insert( + abar_rand, + (XfrPublicKey::from_noah(&abar_pkey), abar_asset, abar_amt), + ); + } + commitment_map + } + + /// build generates the anon transfer body with the Zero Knowledge Proof. + pub fn build(&mut self) -> Result<&mut Self> { + if self.inputs.len() > 5 { + return Err(eg!("Total inputs (incl. fees) cannot be greater than 5")); + } + if self.outputs.len() > 5 { + return Err(eg!( + "Total outputs (incl. remainders) cannot be greater than 5" + )); + } + + if self.keypair.is_none() { + return Err(eg!("keypair not set for build")); + } + let keypair = self.keypair.as_ref().unwrap(); + + let mut prng = ChaChaRng::from_entropy(); + let input_asset_list: HashSet = self + .inputs + .iter() + .map(|a| a.get_asset_type()) + .collect::>() + .drain(..) + .collect(); + let mut fees_in_fra = 0u32; + + for asset in input_asset_list { + let mut sum_input = 0; + let mut sum_output = 0; + for input in self.inputs.clone() { + if asset == input.get_asset_type() { + sum_input += input.get_amount(); + } + } + for output in self.outputs.clone() { + if asset == output.get_asset_type() { + sum_output += output.get_amount(); + } + } + + let fees = if asset == ASSET_TYPE_FRA { + fees_in_fra = FEE_CALCULATING_FUNC( + self.inputs.len() as u32, + self.outputs.len() as u32, + ); + fees_in_fra as u64 + } else { + 0u64 + }; + + if sum_output + fees > sum_input { + return if asset == ASSET_TYPE_FRA { + Err(eg!( + "Insufficient FRA balance to pay fees {} + {} > {}", + sum_output, + fees, + sum_input + )) + } else { + Err(eg!( + "Insufficient {:?} balance to pay fees {} + {} > {}", + asset, + sum_output, + fees, + sum_input + )) + }; + } + + let remainder = sum_input - sum_output - fees; + if remainder > 0 { + let oabar_money_back = OpenAnonAssetRecordBuilder::new() + .amount(remainder) + .asset_type(asset) + .pub_key(&keypair.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(); + + let commitment = get_abar_commitment(oabar_money_back.clone()); + self.outputs.push(oabar_money_back); + self.commitments.push(commitment); + } + } + + if self.outputs.len() > 5 { + return Err(eg!( + "Total outputs (incl. remainders) cannot be greater than 5" + )); + } + let note = init_anon_xfr_note( + self.inputs.as_slice(), + self.outputs.as_slice(), + fees_in_fra, + &keypair.into_noah(), + ) + .c(d!("error from init_anon_xfr_note"))?; + + self.pre_note = Some(note); + + Ok(self) + } + + /// Add operation to the transaction + pub fn build_txn(&mut self) -> Result<()> { + let mut prng = ChaChaRng::from_entropy(); + let pre_note = self.pre_note.clone().unwrap(); + let af = match pre_note.input_keypair.get_sk_ref() { + SecretKey::Secp256k1(_) => AddressFormat::SECP256K1, + SecretKey::Ed25519(_) => AddressFormat::ED25519, + }; + let param = + ProverParams::gen_abar_to_abar(self.inputs.len(), self.outputs.len(), af) + .c(d!())?; + + let mut hasher = Sha512::new(); + + let mut bytes = self.txn.body.digest(); + bytes.extend_from_slice(Serialized::new(&pre_note.body).as_ref()); + hasher.update(bytes); + + let note = finish_anon_xfr_note(&mut prng, ¶m, pre_note, hasher).c(d!())?; + + // Add operation + let inp = AnonTransferOps::new(note, self.nonce).c(d!())?; + let op = Operation::TransferAnonAsset(Box::new(inp)); + self.txn.add_operation(op); + + Ok(()) + } + + /// Calculates the Anon fee given the number of inputs and outputs + pub fn get_anon_fee(n_inputs: u32, n_outputs: u32) -> u32 { + FEE_CALCULATING_FUNC(n_inputs, n_outputs) + } + + /// transaction method wraps the anon transfer note in an Operation and returns it + pub fn serialize_str(&self) -> Result { + if self.pre_note.is_none() { + return Err(eg!("Anon transfer not built and signed")); + } + // Unwrap is safe because the underlying transaction is guaranteed to be serializable. + serde_json::to_string(&self.txn).c(d!()) + } +} + #[cfg(test)] #[allow(missing_docs)] mod tests { use { super::*, - ledger::data_model::{TxnEffect, TxoRef}, - ledger::store::{utils::fra_gen_initial_tx, LedgerState}, + ledger::{ + data_model::{ATxoSID, BlockEffect, TxnEffect, TxoRef}, + store::utils::fra_gen_initial_tx, + store::LedgerState, + }, rand_chacha::ChaChaRng, rand_core::SeedableRng, - zei::noah_api::xfr::asset_record::{ - build_blind_asset_record, open_blind_asset_record, - AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, + zei::{ + noah_algebra::ristretto::PedersenCommitmentRistretto, + noah_api::{ + anon_xfr::structs::{AnonAssetRecord, OpenAnonAssetRecordBuilder}, + xfr::{ + asset_record::{ + build_blind_asset_record, open_blind_asset_record, + AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, + }, + structs::AssetType as AT, + }, + }, }, - zei::XfrKeyPair, }; // Defines an asset type @@ -1476,7 +2333,7 @@ mod tests { TX_FEE_MIN, TxoRef::Absolute(txo_sid[0]), utxo.utxo.0, - utxo.txn.txn.get_owner_memos_ref()[utxo.utxo_location.0].cloned(), + utxo.txn.txn.get_owner_memos_ref()[utxo.utxo_location.0].clone(), bob_kp.get_sk().into_keypair(), ); let mut tx3 = TransactionBuilder::from_seq_id(2); @@ -1506,7 +2363,7 @@ mod tests { TX_FEE_MIN, TxoRef::Absolute(txo_sid[0]), utxo.utxo.0, - utxo.txn.txn.get_owner_memos_ref()[utxo.utxo_location.0].cloned(), + utxo.txn.txn.get_owner_memos_ref()[utxo.utxo_location.0].clone(), bob_kp.get_sk().into_keypair(), ); let mut tx4 = TransactionBuilder::from_seq_id(3); @@ -1527,4 +2384,557 @@ mod tests { let mut block = ledger.start_block().unwrap(); assert!(ledger.apply_transaction(&mut block, effect).is_err()); } + + #[test] + fn test_operation_bar_to_abar() { + let mut builder = TransactionBuilder::from_seq_id(1); + + let mut prng = ChaChaRng::from_seed([0u8; 32]); + let from = XfrKeyPair::generate(&mut prng); + let to = XfrKeyPair::generate(&mut prng).get_pk(); + + let ar = AssetRecordTemplate::with_no_asset_tracing( + 10u64, + AT([1u8; 32]), + AssetRecordType::ConfidentialAmount_ConfidentialAssetType, + from.get_pk().into_noah(), + ); + let pc_gens = PedersenCommitmentRistretto::default(); + let (bar, _, memo) = build_blind_asset_record(&mut prng, &pc_gens, &ar, vec![]); + let dummy_input = + open_blind_asset_record(&bar, &memo, &from.into_noah()).unwrap(); + + let mut seed = [0u8; 32]; + + getrandom::getrandom(&mut seed).unwrap(); + + let _ = builder + .add_operation_bar_to_abar( + seed, + &from, + &to, + TxoSID(123), + &dummy_input, + false, + ) + .is_ok(); + + let txn = builder.build_and_take_transaction().unwrap(); + + if let Operation::BarToAbar(note) = txn.body.operations[0].clone() { + let result = note.verify(); + assert!(result.is_ok()); + } + } + + #[test] + // This test calls multiple functions used in the anonymous transfer workflow + fn test_axfr_workflow() { + let mut prng = ChaChaRng::from_seed([0u8; 32]); + let amount = 6000000u64; + //let fee_amount = FEE_CALCULATING_FUNC(2, 1) as u64; + let amount_output = 1000000u64; + let asset_type = ASSET_TYPE_FRA; + + // simulate input abar + let (mut oabar, keypair_in) = gen_oabar_and_keys(&mut prng, amount, asset_type); + let abar = AnonAssetRecord::from_oabar(&oabar); + let _test_owner_memo = oabar.get_owner_memo().unwrap(); + + // simulate output abar + let (oabar_out, _keypair_out) = + gen_oabar_and_keys(&mut prng, amount_output, asset_type); + + // initialize ledger and add abars to merkle tree + let mut ledger_state = LedgerState::tmp_ledger(); + let _ledger_status = ledger_state.get_status(); + let uid = ledger_state.add_abar(&abar).unwrap(); + ledger_state.compute_and_append_txns_hash(&BlockEffect::default()); + ledger_state.compute_and_save_state_commitment_data(1); + + let mt_leaf_info = ledger_state.get_abar_proof(uid).unwrap(); + oabar.update_mt_leaf_info(mt_leaf_info); + + // build and submit transaction + let vec_inputs = vec![oabar]; + let vec_outputs = vec![oabar_out]; + + let mut builder = TransactionBuilder::from_seq_id(1); + let result = builder.add_operation_anon_transfer_fees_remainder( + &vec_inputs, + &vec_outputs, + &keypair_in, + ); + assert!(result.is_ok()); + + // post transaction steps test + let txn = builder.build_and_take_transaction().unwrap(); + let compute_effect = TxnEffect::compute_effect(txn).unwrap(); + let mut block = BlockEffect::default(); + let block_result = block.add_txn_effect(compute_effect); + assert!(block_result.is_ok()); + + // test nullifier functions + for n in block.new_nullifiers.iter() { + let _str = wallet::nullifier_to_base58(&n); + } + + let txn_sid_result = ledger_state.finish_block(block); + assert!(txn_sid_result.is_ok()); + } + + // Negative tests added + #[test] + #[ignore] + fn axfr_create_verify_unit_with_negative_tests() { + let mut prng = ChaChaRng::from_seed([0u8; 32]); + let amount = 10u64; + // Here the Asset Type is generated as a 32 byte and each of them are zero + let asset_type = AT::from_identical_byte(0); + + // simulate input abar + let (oabar, keypair_in) = gen_oabar_and_keys(&mut prng, amount, asset_type); + // simulate another oabar just to get new keypair + let (_, another_keypair) = gen_oabar_and_keys(&mut prng, amount, asset_type); + // negative test for input keypairs + assert_eq!(keypair_in.get_pk().into_noah(), *oabar.pub_key_ref()); + assert_ne!(keypair_in.get_pk(), another_keypair.get_pk()); + assert_ne!(another_keypair.get_pk().into_noah(), *oabar.pub_key_ref()); + + // Simulate output abar + let (oabar_out, _keypair_out) = + gen_oabar_and_keys(&mut prng, amount, asset_type); + let _abar_out = AnonAssetRecord::from_oabar(&oabar_out); + let mut builder = TransactionBuilder::from_seq_id(1); + + let wrong_key_result = builder.add_operation_anon_transfer( + &[oabar], + &[oabar_out], + &another_keypair, + ); + // negative test for keys + assert!(wrong_key_result.is_err()); + + // negative test for asset type + let wrong_asset_type_out = AT::from_identical_byte(1); + let (oabar, keypair_in) = gen_oabar_and_keys(&mut prng, amount, asset_type); + let (oabar_out, _keypair_out) = + gen_oabar_and_keys(&mut prng, amount, wrong_asset_type_out); + let wrong_asset_type_result = + builder.add_operation_anon_transfer(&[oabar], &[oabar_out], &keypair_in); + // Here we have an error due to the asset type input being unequal to the asset type output + assert!(wrong_asset_type_result.is_err()); + + // The happy path + let (mut oabar, keypair_in) = gen_oabar_and_keys(&mut prng, amount, asset_type); + let (oabar_out, _keypair_out) = + gen_oabar_and_keys(&mut prng, amount, asset_type); + let abar = AnonAssetRecord::from_oabar(&oabar); + + let owner_memo = oabar.get_owner_memo().unwrap(); + + // Trying to decrypt asset type and amount from owner memo using wrong keys + let new_xfrkeys = XfrKeyPair::generate(&mut prng); + let result_decrypt = owner_memo.decrypt(&new_xfrkeys.get_sk().into_noah()); + assert!(result_decrypt.is_err()); + + // initialize ledger and add abar to merkle tree + let mut ledger_state = LedgerState::tmp_ledger(); + let _ledger_status = ledger_state.get_status(); + let uid = ledger_state.add_abar(&abar).unwrap(); + ledger_state.compute_and_append_txns_hash(&BlockEffect::default()); + ledger_state.compute_and_save_state_commitment_data(1); + + // negative test for merkle tree proof + let mt_leaf_result_fail = ledger_state.get_abar_proof(ATxoSID(100u64)); + // 100 is not a valid uid, so we will catch an error + assert!(mt_leaf_result_fail.is_err()); + + let mt_leaf_info = ledger_state.get_abar_proof(uid).unwrap(); + oabar.update_mt_leaf_info(mt_leaf_info); + + let result = + builder.add_operation_anon_transfer(&[oabar], &[oabar_out], &keypair_in); + assert!(result.is_ok()); + + let txn = builder.build_and_take_transaction().unwrap(); + let compute_effect = TxnEffect::compute_effect(txn).unwrap(); + let mut block = BlockEffect::default(); + let block_result = block.add_txn_effect(compute_effect); + assert!(block_result.is_ok()); + + for n in block.new_nullifiers.iter() { + let _str = wallet::nullifier_to_base58(&n); + } + + let txn_sid_result = ledger_state.finish_block(block); + assert!(txn_sid_result.is_ok()); + } + + fn gen_oabar_and_keys( + prng: &mut R, + amount: u64, + asset_type: AT, + ) -> (OpenAnonAssetRecord, XfrKeyPair) { + let keypair = XfrKeyPair::generate(prng); + let oabar = OpenAnonAssetRecordBuilder::new() + .amount(amount) + .asset_type(asset_type) + .pub_key(&keypair.get_pk().into_noah()) + .finalize(prng) + .unwrap() + .build() + .unwrap(); + (oabar, keypair) + } + + #[test] + pub fn test_extra_fee_estimation_only_fra() { + let mut prng = ChaChaRng::from_seed([0u8; 32]); + let k = XfrKeyPair::generate(&mut prng); + { + let mut b = AnonTransferOperationBuilder::new_from_seq_id(0); + + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(1000000) + .asset_type(ASSET_TYPE_FRA) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let _fee = FEE_CALCULATING_FUNC(1, 1) as u64; + assert!(b.extra_fee_estimation().is_ok()); + assert_eq!(b.extra_fee_estimation().unwrap(), 0); + } + { + let mut b = AnonTransferOperationBuilder::new_from_seq_id(0); + + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(1000000) + .asset_type(ASSET_TYPE_FRA) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + + let _ = b.add_output( + OpenAnonAssetRecordBuilder::new() + .amount(1000000) + .asset_type(ASSET_TYPE_FRA) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + + let fee = FEE_CALCULATING_FUNC(2, 2) as u64; + assert!(b.extra_fee_estimation().is_ok()); + assert_eq!(b.extra_fee_estimation().unwrap(), fee); + } + { + // case with perfect balance for fee + let mut b = AnonTransferOperationBuilder::new_from_seq_id(0); + + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(1000000) + .asset_type(ASSET_TYPE_FRA) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + + let _ = b.add_output( + OpenAnonAssetRecordBuilder::new() + .amount(200000) + .asset_type(ASSET_TYPE_FRA) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + + assert!(b.extra_fee_estimation().is_ok()); + assert_eq!(b.extra_fee_estimation().unwrap(), 0); + } + { + // case where input is insufficient + let mut b = AnonTransferOperationBuilder::new_from_seq_id(0); + + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(10) + .asset_type(ASSET_TYPE_FRA) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let _ = b.add_output( + OpenAnonAssetRecordBuilder::new() + .amount(200000) + .asset_type(ASSET_TYPE_FRA) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + + let extra_fra = FEE_CALCULATING_FUNC(2, 2) as u64 + 200000 - 10; + assert!(b.extra_fee_estimation().is_ok()); + assert_eq!(b.extra_fee_estimation().unwrap(), extra_fra); + } + } + + #[test] + pub fn test_extra_fee_estimation_multi_asset() { + let mut prng = ChaChaRng::from_seed([0u8; 32]); + let k = XfrKeyPair::generate(&mut prng); + + let asset1 = AT::from_identical_byte(1u8); + let _asset2 = AT::from_identical_byte(2u8); + + { + let mut b = AnonTransferOperationBuilder::new_from_seq_id(0); + + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(1000000) + .asset_type(asset1) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let extra_fra = FEE_CALCULATING_FUNC(2, 2) as u64; + assert!(b.extra_fee_estimation().is_ok()); + assert_eq!(b.extra_fee_estimation().unwrap(), extra_fra); + } + { + let mut b = AnonTransferOperationBuilder::new_from_seq_id(0); + + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(1000000) + .asset_type(asset1) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(1100000) + .asset_type(ASSET_TYPE_FRA) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let extra_fra = FEE_CALCULATING_FUNC(2, 2) as u64 - 1100000; + assert!(b.extra_fee_estimation().is_ok()); + assert_eq!(b.extra_fee_estimation().unwrap(), extra_fra); + } + { + let mut b = AnonTransferOperationBuilder::new_from_seq_id(0); + + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(1000000) + .asset_type(asset1) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let _ = b.add_output( + OpenAnonAssetRecordBuilder::new() + .amount(1000000) + .asset_type(asset1) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(1100000) + .asset_type(ASSET_TYPE_FRA) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let extra_fra = FEE_CALCULATING_FUNC(2, 2) as u64 - 1100000; + assert!(b.extra_fee_estimation().is_ok()); + assert_eq!(b.extra_fee_estimation().unwrap(), extra_fra); + } + { + let mut b = AnonTransferOperationBuilder::new_from_seq_id(0); + + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(1000000) + .asset_type(asset1) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let _ = b.add_output( + OpenAnonAssetRecordBuilder::new() + .amount(1000000) + .asset_type(asset1) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let fee = FEE_CALCULATING_FUNC(2, 1) as u64; + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(fee) + .asset_type(ASSET_TYPE_FRA) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let extra_fra = FEE_CALCULATING_FUNC(2, 1) as u64 - fee; + assert!(b.extra_fee_estimation().is_ok()); + assert_eq!(b.extra_fee_estimation().unwrap(), extra_fra); + } + { + let mut b = AnonTransferOperationBuilder::new_from_seq_id(0); + + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(1000000) + .asset_type(asset1) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let _ = b.add_output( + OpenAnonAssetRecordBuilder::new() + .amount(900000) + .asset_type(asset1) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let fee = FEE_CALCULATING_FUNC(2, 2) as u64; + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(fee) + .asset_type(ASSET_TYPE_FRA) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let extra_fra = FEE_CALCULATING_FUNC(2, 2) as u64 - fee; + assert!(b.extra_fee_estimation().is_ok()); + assert_eq!(b.extra_fee_estimation().unwrap(), extra_fra); + } + { + let mut b = AnonTransferOperationBuilder::new_from_seq_id(0); + + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(800000) + .asset_type(asset1) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let _ = b.add_output( + OpenAnonAssetRecordBuilder::new() + .amount(900000) + .asset_type(asset1) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let fee = FEE_CALCULATING_FUNC(2, 2) as u64; + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(fee) + .asset_type(ASSET_TYPE_FRA) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + assert!(b.extra_fee_estimation().is_err()); + } + { + let mut b = AnonTransferOperationBuilder::new_from_seq_id(0); + + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(1000000) + .asset_type(asset1) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let _ = b.add_output( + OpenAnonAssetRecordBuilder::new() + .amount(900000) + .asset_type(asset1) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + let fee = FEE_CALCULATING_FUNC(2, 3) as u64; + let _ = b.add_input( + OpenAnonAssetRecordBuilder::new() + .amount(2 * fee) + .asset_type(ASSET_TYPE_FRA) + .pub_key(&k.get_pk().into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(), + ); + assert!(b.extra_fee_estimation().is_ok()); + assert_eq!(b.extra_fee_estimation().unwrap(), 0); + } + } } diff --git a/src/components/wallet_mobile/Cargo.toml b/src/components/wallet_mobile/Cargo.toml index e6f4cc228..78472bc71 100644 --- a/src/components/wallet_mobile/Cargo.toml +++ b/src/components/wallet_mobile/Cargo.toml @@ -30,7 +30,7 @@ rand_core = { version = "0.6", default-features = false, features = ["alloc"] } ring = "0.16.19" ruc = "1.0" serde = { version = "1.0.124", features = ["derive"] } -serde_derive = "1.0" +serde_derive = "^1.0.59" serde_json = "1.0" zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } @@ -66,5 +66,4 @@ safer-ffi = "0.0.10" [build-dependencies] cbindgen = "0.24" -vergen = "3.1.0" - +vergen = "3.1.0" \ No newline at end of file diff --git a/src/components/wallet_mobile/src/android/constructor.rs b/src/components/wallet_mobile/src/android/constructor.rs index 719501321..944fe10d4 100644 --- a/src/components/wallet_mobile/src/android/constructor.rs +++ b/src/components/wallet_mobile/src/android/constructor.rs @@ -4,8 +4,7 @@ use jni::sys::{jbyteArray, jlong}; use jni::JNIEnv; use rand_chacha::ChaChaRng; use rand_core::SeedableRng; -use zei::noah_api::xfr::structs::ASSET_TYPE_LENGTH; -use zei::XfrKeyPair as RawXfrKeyPair; +use zei::noah_api::{keys::KeyPair as RawXfrKeyPair, xfr::structs::ASSET_TYPE_LENGTH}; #[no_mangle] pub unsafe extern "system" fn Java_com_findora_JniApi_xfrKeyPairNew( @@ -17,7 +16,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_xfrKeyPairNew( let mut buf = [0u8; ASSET_TYPE_LENGTH]; buf.copy_from_slice(input.as_ref()); let mut prng = ChaChaRng::from_seed(buf); - let val = types::XfrKeyPair::from(RawXfrKeyPair::generate(&mut prng)); + let val = types::XfrKeyPair::from(RawXfrKeyPair::generate_ed25519(&mut prng)); Box::into_raw(Box::new(val)) as jlong } diff --git a/src/components/wallet_mobile/src/android/evm.rs b/src/components/wallet_mobile/src/android/evm.rs index ed038e5b7..7ac82504b 100644 --- a/src/components/wallet_mobile/src/android/evm.rs +++ b/src/components/wallet_mobile/src/android/evm.rs @@ -2,7 +2,7 @@ use crate::rust::account::{get_serialized_address, EVMTransactionBuilder}; use jni::objects::{JClass, JString}; use jni::sys::{jlong, jstring}; use jni::JNIEnv; -use zei::XfrPublicKey; +use zei::{noah_api::keys::PublicKey, XfrPublicKey}; use super::{jStringToString, parseU64}; @@ -27,10 +27,13 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transferToUtxoFromAccount( let sk = jStringToString(env, sk); - let recipient = *(recipient as *mut XfrPublicKey); + let recipient = *(recipient as *mut PublicKey); let ser_tx = EVMTransactionBuilder::new_transfer_to_utxo_from_account( - recipient, amount, sk, nonce, + XfrPublicKey::from_noah(&recipient).unwrap(), + amount, + sk, + nonce, ) .unwrap(); diff --git a/src/components/wallet_mobile/src/android/mod.rs b/src/components/wallet_mobile/src/android/mod.rs index e68ec61f6..e63880d29 100644 --- a/src/components/wallet_mobile/src/android/mod.rs +++ b/src/components/wallet_mobile/src/android/mod.rs @@ -13,7 +13,8 @@ use jni::objects::{JClass, JString}; use jni::sys::{jboolean, jbyteArray, jint, jlong, jstring}; use jni::JNIEnv; use ledger::data_model::AssetTypeCode; -use zei::noah_api::xfr::structs::ASSET_TYPE_LENGTH; +use zei::{noah_api::xfr::structs::ASSET_TYPE_LENGTH, XfrKeyPair, XfrPublicKey}; + #[no_mangle] /// Returns the git commit hash and commit date of the commit this library was built against. pub extern "system" fn Java_com_findora_JniApi_buildId( @@ -150,7 +151,7 @@ pub extern "system" fn Java_com_findora_JniApi_keypairFromStr( .get_string(text) .expect("Couldn't get java string!") .into(); - let val = types::XfrKeyPair::from(keypair_from_str(text)); + let val = types::XfrKeyPair::from(keypair_from_str(text).into_noah().unwrap()); Box::into_raw(Box::new(val)) as jlong } @@ -164,7 +165,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_publicKeyToBech32( xfr_public_key_ptr: jlong, ) -> jstring { let key = &*(xfr_public_key_ptr as *mut types::XfrPublicKey); - let res = public_key_to_bech32(key); + let res = public_key_to_bech32(&XfrPublicKey::from_noah(key).unwrap()); let output = env.new_string(res).expect("Couldn't create java string!"); **output } @@ -179,7 +180,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_getPubKeyStr( xfr_keypair_ptr: jlong, ) -> jstring { let key = &*(xfr_keypair_ptr as *mut types::XfrKeyPair); - let pubkey = get_pub_key_str(key); + let pubkey = get_pub_key_str(&XfrKeyPair::from_noah(key).unwrap()); let output = env .new_string(pubkey) .expect("Couldn't create java string!"); @@ -196,7 +197,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_getPrivKeyStr( xfr_keypair_ptr: jlong, ) -> jstring { let key = &*(xfr_keypair_ptr as *mut types::XfrKeyPair); - let prikey = get_priv_key_str(key); + let prikey = get_priv_key_str(&XfrKeyPair::from_noah(key).unwrap()); let output = env .new_string(prikey) .expect("Couldn't create java string!"); @@ -218,7 +219,9 @@ pub extern "system" fn Java_com_findora_JniApi_restoreKeypairFromMnemonicDefault .expect("Couldn't get java string!") .into(); if let Ok(keypair) = rs_restore_keypair_from_mnemonic_default(phrase.as_str()) { - Box::into_raw(Box::new(types::XfrKeyPair::from(keypair))) as jlong + Box::into_raw(Box::new(types::XfrKeyPair::from( + keypair.into_noah().unwrap(), + ))) as jlong } else { ::std::ptr::null_mut::<()>() as jlong } @@ -235,7 +238,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_keypairToStr( xfr_keypair_ptr: jlong, ) -> jstring { let key = &*(xfr_keypair_ptr as *mut types::XfrKeyPair); - let res = keypair_to_str(key); + let res = keypair_to_str(&XfrKeyPair::from_noah(key).unwrap()); let output = env.new_string(res).expect("Couldn't create java string!"); **output } @@ -251,7 +254,9 @@ pub extern "system" fn Java_com_findora_JniApi_createKeypairFromSecret( .expect("Couldn't get java string!") .into(); if let Some(keypair) = create_keypair_from_secret(sk) { - Box::into_raw(Box::new(types::XfrKeyPair::from(keypair))) as jlong + Box::into_raw(Box::new(types::XfrKeyPair::from( + keypair.into_noah().unwrap(), + ))) as jlong } else { ::std::ptr::null_mut::<()>() as jlong } @@ -266,8 +271,8 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_getPkFromKeypair( xfr_keypair_ptr: jlong, ) -> jlong { let kp = &*(xfr_keypair_ptr as *mut types::XfrKeyPair); - let pk = get_pk_from_keypair(kp); - Box::into_raw(Box::new(types::XfrPublicKey::from(pk))) as jlong + let pk = get_pk_from_keypair(&XfrKeyPair::from_noah(kp).unwrap()); + Box::into_raw(Box::new(types::XfrPublicKey::from(pk.into_noah().unwrap()))) as jlong } #[no_mangle] @@ -277,7 +282,9 @@ pub extern "system" fn Java_com_findora_JniApi_newKeypair( _: JClass, ) -> jlong { let keypair = new_keypair(); - Box::into_raw(Box::new(types::XfrKeyPair::from(keypair))) as jlong + Box::into_raw(Box::new(types::XfrKeyPair::from( + keypair.into_noah().unwrap(), + ))) as jlong } #[no_mangle] @@ -340,7 +347,11 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_openClientAssetRecord( let keypair = &*(keypair_ptr as *mut types::XfrKeyPair); let oar = throw_exception!( env, - rs_open_client_asset_record(record, owner_memo, keypair) + rs_open_client_asset_record( + record, + owner_memo, + &XfrKeyPair::from_noah(keypair).unwrap() + ) ); Box::into_raw(Box::new(types::OpenAssetRecord::from(oar))) as jlong } diff --git a/src/components/wallet_mobile/src/android/transfer.rs b/src/components/wallet_mobile/src/android/transfer.rs index ecb615882..613c07e95 100644 --- a/src/components/wallet_mobile/src/android/transfer.rs +++ b/src/components/wallet_mobile/src/android/transfer.rs @@ -3,8 +3,13 @@ use jni::objects::{JClass, JString}; use jni::sys::{jboolean, jint, jlong, jstring, jvalue, JNI_TRUE}; use jni::JNIEnv; use ledger::data_model::AssetType as PlatformAssetType; -use zei::OwnerMemo as NoahOwnerMemo; -use zei::{XfrKeyPair, XfrPublicKey}; +use zei::{ + noah_api::{ + keys::{KeyPair, PublicKey}, + xfr::structs::OwnerMemo as NoahOwnerMemo, + }, + XfrKeyPair, XfrPublicKey, +}; use super::{jStringToString, parseU64}; @@ -273,7 +278,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transferOperationBuilderAd Some(memo.clone()) }; let tracing_policies = &*(tracing_policies_ptr as *mut TracingPolicies); - let key = &*(key_ptr as *mut XfrKeyPair); + let key = &*(key_ptr as *mut KeyPair); let amount = parseU64(env, amount); let builder = builder @@ -283,7 +288,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transferOperationBuilderAd asset_record.clone(), owner_memo, tracing_policies, - key, + &XfrKeyPair::from_noah(key).unwrap(), amount, ) .unwrap(); @@ -328,12 +333,18 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transferOperationBuilderAd let memo = &*(owner_memo_ptr as *mut OwnerMemo); Some(memo.clone()) }; - let key = &*(key_ptr as *mut XfrKeyPair); + let key = &*(key_ptr as *mut KeyPair); let amount = parseU64(env, amount); let builder = builder .clone() - .add_input_no_tracing(txo_ref, asset_record, owner_memo, key, amount) + .add_input_no_tracing( + txo_ref, + asset_record, + owner_memo, + &XfrKeyPair::from_noah(key).unwrap(), + amount, + ) .unwrap(); Box::into_raw(Box::new(builder)) as jlong } @@ -369,7 +380,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transferOperationBuilderAd ) -> jlong { let builder = &*(builder as *mut TransferOperationBuilder); let tracing_policies = &*(tracing_policies_ptr as *mut TracingPolicies); - let recipient = &*(recipient as *mut XfrPublicKey); + let recipient = &*(recipient as *mut PublicKey); let amount = parseU64(env, amount); let code = jStringToString(env, code); @@ -377,7 +388,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transferOperationBuilderAd .clone() .add_output_with_tracing( amount, - recipient, + &XfrPublicKey::from_noah(recipient).unwrap(), tracing_policies, code, conf_amount == JNI_TRUE, @@ -413,7 +424,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transferOperationBuilderAd conf_type: jboolean, ) -> jlong { let builder = &*(builder as *mut TransferOperationBuilder); - let recipient = &*(recipient as *mut XfrPublicKey); + let recipient = &*(recipient as *mut PublicKey); let amount = parseU64(env, amount); let code = jStringToString(env, code); @@ -421,7 +432,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transferOperationBuilderAd .clone() .add_output_no_tracing( amount, - recipient, + &XfrPublicKey::from_noah(recipient).unwrap(), code, conf_amount == JNI_TRUE, conf_type == JNI_TRUE, @@ -459,7 +470,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transferOperationBuilderAd let policies = &*(tracing_policies_ptr as *mut TracingPolicies); Some(policies) }; - let key = &*(key_ptr as *mut XfrKeyPair); + let key = &*(key_ptr as *mut KeyPair); let builder = builder .clone() @@ -468,7 +479,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transferOperationBuilderAd asset_record, owner_memo, tracing_policies, - key, + &XfrKeyPair::from_noah(key).unwrap(), parseU64(env, amount), ) .unwrap(); @@ -496,7 +507,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transferOperationBuilderAd let policies = &*(tracing_policies_ptr as *mut TracingPolicies); Some(policies) }; - let recipient = &*(recipient as *mut XfrPublicKey); + let recipient = &*(recipient as *mut PublicKey); let code: String = env .get_string(code) .expect("Couldn't get java string!") @@ -506,7 +517,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transferOperationBuilderAd .clone() .add_output( parseU64(env, amount), - recipient, + &XfrPublicKey::from_noah(&recipient).unwrap(), tracing_policies, code, conf_amount == JNI_TRUE, @@ -562,9 +573,14 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transferOperationBuilderSi key_ptr: jlong, ) -> jlong { let builder = &*(builder as *mut TransferOperationBuilder); - let key = &*(key_ptr as *mut XfrKeyPair); + let key = &*(key_ptr as *mut KeyPair); - Box::into_raw(Box::new(builder.clone().sign(key).unwrap())) as jlong + Box::into_raw(Box::new( + builder + .clone() + .sign(&XfrKeyPair::from_noah(&key).unwrap()) + .unwrap(), + )) as jlong } #[no_mangle] diff --git a/src/components/wallet_mobile/src/android/tx_builder.rs b/src/components/wallet_mobile/src/android/tx_builder.rs index f935b75c5..c89a4b9e8 100644 --- a/src/components/wallet_mobile/src/android/tx_builder.rs +++ b/src/components/wallet_mobile/src/android/tx_builder.rs @@ -7,7 +7,7 @@ use ledger::data_model::AssetTypeCode; use zei::XfrKeyPair; #[no_mangle] /// # Safety -/// @param kp: owner's XfrKeyPair +/// @param kp: owner's KeyPair pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddFeeRelativeAuto( _env: JNIEnv, _: JClass, @@ -15,8 +15,11 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddFeeRe kp: jlong, ) -> jlong { let builder = &*(builder as *mut TransactionBuilder); - let kp = &*(kp as *mut XfrKeyPair); - let builder = builder.clone().add_fee_relative_auto(kp.clone()).unwrap(); + let kp = &*(kp as *mut KeyPair); + let builder = builder + .clone() + .add_fee_relative_auto(XfrKeyPair::from_noah(kp).unwrap()) + .unwrap(); Box::into_raw(Box::new(builder)) as jlong } @@ -91,7 +94,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderNew( /// console.log(err) /// } /// -/// @param {XfrKeyPair} key_pair - Issuer XfrKeyPair. +/// @param {KeyPair} key_pair - Issuer KeyPair. /// @param {string} memo - Text field for asset definition. /// @param {string} token_code - Optional Base64 string representing the token code of the asset to be issued. /// If empty, a token code will be chosen at random. @@ -107,7 +110,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddOpera asset_rules: jlong, ) -> jlong { let builder = &*(builder as *mut TransactionBuilder); - let key_pair = &*(key_pair as *mut XfrKeyPair); + let key_pair = &*(key_pair as *mut KeyPair); let memo: String = env .get_string(memo) .expect("Couldn't get java string!") @@ -119,7 +122,12 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddOpera let asset_rules = &*(asset_rules as *mut AssetRules); let builder = builder .clone() - .add_operation_create_asset(key_pair, memo, token_code, asset_rules.clone()) + .add_operation_create_asset( + &XfrKeyPair::from_noah(key_pair).unwrap(), + memo, + token_code, + asset_rules.clone(), + ) .unwrap(); Box::into_raw(Box::new(builder)) as jlong } @@ -130,13 +138,12 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddOpera /// /// Use this function for simple one-shot issuances. /// -/// @param {XfrKeyPair} key_pair - Issuer XfrKeyPair. +/// @param {KeyPair} key_pair - Issuer KeyPair. /// and types of traced assets. /// @param {string} code - base64 string representing the token code of the asset to be issued. /// @param {BigInt} seq_num - Issuance sequence number. Every subsequent issuance of a given asset type must have a higher sequence number than before. /// @param {BigInt} amount - Amount to be issued. /// @param {boolean} conf_amount - `true` means the asset amount is confidential, and `false` means it's nonconfidential. -/// @param {PublicParams} zei_params - Public parameters necessary to generate asset records. pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddBasicIssueAsset( env: JNIEnv, _: JClass, @@ -146,24 +153,21 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddBasic seq_num: jlong, amount: JString, conf_amount: jboolean, - zei_params: jlong, ) -> jlong { let builder = &*(builder as *mut TransactionBuilder); - let key_pair = &*(key_pair as *mut XfrKeyPair); + let key_pair = &*(key_pair as *mut KeyPair); let code: String = env .get_string(code) .expect("Couldn't get java string!") .into(); - let zei_params = &*(zei_params as *mut PublicParams); let builder = builder .clone() .add_basic_issue_asset( - key_pair, + &XfrKeyPair::from_noah(key_pair).unwrap(), code, seq_num as u64, parseU64(env, amount), conf_amount == JNI_TRUE, - zei_params, ) .unwrap(); Box::into_raw(Box::new(builder)) as jlong @@ -173,7 +177,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddBasic /// # Safety /// Adds an operation to the transaction builder that adds a hash to the ledger's custom data /// store. -/// @param {XfrKeyPair} auth_key_pair - Asset creator key pair. +/// @param {KeyPair} auth_key_pair - Asset creator key pair. /// @param {String} code - base64 string representing token code of the asset whose memo will be updated. /// transaction validates. /// @param {String} new_memo - The new asset memo. @@ -188,7 +192,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddOpera new_memo: JString, ) -> jlong { let builder = &*(builder as *mut TransactionBuilder); - let auth_key_pair = &*(auth_key_pair as *mut XfrKeyPair); + let auth_key_pair = &*(auth_key_pair as *mut KeyPair); let code: String = env .get_string(code) .expect("Couldn't get java string!") @@ -199,7 +203,11 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddOpera .into(); let builder = builder .clone() - .add_operation_update_memo(auth_key_pair, code, new_memo) + .add_operation_update_memo( + &XfrKeyPair::from_noah(auth_key_pair).unwrap(), + code, + new_memo, + ) .unwrap(); Box::into_raw(Box::new(builder)) as jlong } @@ -216,7 +224,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddOpera validator: JString, ) -> jlong { let builder = &*(builder as *mut TransactionBuilder); - let keypair = &*(keypair as *mut XfrKeyPair); + let keypair = &*(keypair as *mut KeyPair); let validator: String = env .get_string(validator) .expect("Couldn't get java string!") @@ -224,7 +232,11 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddOpera let builder = builder .clone() - .add_operation_delegate(keypair, parseU64(env, amount), validator) + .add_operation_delegate( + &XfrKeyPair::from_noah(keypair).unwrap(), + parseU64(env, amount), + validator, + ) .unwrap(); Box::into_raw(Box::new(builder)) as jlong } @@ -239,8 +251,11 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddOpera keypair: jlong, ) -> jlong { let builder = &*(builder as *mut TransactionBuilder); - let keypair = &*(keypair as *mut XfrKeyPair); - let builder = builder.clone().add_operation_undelegate(keypair).unwrap(); + let keypair = &*(keypair as *mut KeyPair); + let builder = builder + .clone() + .add_operation_undelegate(&XfrKeyPair::from_noah(keypair).unwrap()) + .unwrap(); Box::into_raw(Box::new(builder)) as jlong } @@ -256,7 +271,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddOpera validator: JString, ) -> jlong { let builder = &*(builder as *mut TransactionBuilder); - let keypair = &*(keypair as *mut XfrKeyPair); + let keypair = &*(keypair as *mut KeyPair); let validator: String = env .get_string(validator) @@ -264,7 +279,11 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddOpera .into(); let builder = builder .clone() - .add_operation_undelegate_partially(keypair, parseU64(env, am), validator) + .add_operation_undelegate_partially( + &XfrKeyPair::from_noah(keypair).unwrap(), + parseU64(env, am), + validator, + ) .unwrap(); Box::into_raw(Box::new(builder)) as jlong } @@ -306,7 +325,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddOpera am: JString, ) -> jlong { let builder = &*(builder as *mut TransactionBuilder); - let keypair = &*(keypair as *mut XfrKeyPair); + let keypair = &*(keypair as *mut KeyPair); let td_addr: String = env .get_string(td_addr) .expect("Couldn't get java string!") @@ -347,7 +366,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddTrans /// /// Adds a serialized transfer-account operation to transaction builder instance. /// @param {string} amount - amount to transfer. -/// @param {XfrKeyPair} keypair - FRA account key pair. +/// @param {KeyPair} keypair - FRA account key pair. /// @param {String} address - FRA account key pair. /// @throws Will throw an error if `address` is invalid. pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddOperationConvertAccount( @@ -366,7 +385,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddOpera .expect("Couldn't get java string!") .into(); - let fra_kp = &*(keypair as *mut XfrKeyPair); + let fra_kp = &*(keypair as *mut KeyPair); let asset_str: String = env .get_string(asset) @@ -393,7 +412,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderAddOpera .add_transfer_to_account_operation( parseU64(env, amount), Some(addr), - fra_kp, + &XfrKeyPair::from_noah(fra_kp).unwrap(), asset, lowlevel_data, ) @@ -411,8 +430,11 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderSign( kp: jlong, ) -> jlong { let builder = &*(builder as *mut TransactionBuilder); - let kp = &*(kp as *mut XfrKeyPair); - let builder = builder.clone().sign(kp).unwrap(); + let kp = &*(kp as *mut KeyPair); + let builder = builder + .clone() + .sign(&XfrKeyPair::from_noah(kp).unwrap()) + .unwrap(); Box::into_raw(Box::new(builder)) as jlong } @@ -425,7 +447,7 @@ pub unsafe extern "system" fn Java_com_findora_JniApi_transactionBuilderTransact _: JClass, builder: jlong, ) -> jstring { - let builder = &*(builder as *mut TransactionBuilder); + let builder = &mut *(builder as *mut TransactionBuilder); let output = env .new_string(builder.transaction()) .expect("Couldn't create java string!"); diff --git a/src/components/wallet_mobile/src/ios/tx_builder.rs b/src/components/wallet_mobile/src/ios/tx_builder.rs index 2cba61ae0..9d3a05c9d 100644 --- a/src/components/wallet_mobile/src/ios/tx_builder.rs +++ b/src/components/wallet_mobile/src/ios/tx_builder.rs @@ -1,7 +1,7 @@ use super::parse_u64; use crate::rust::{ c_char_to_string, string_to_c_char, AssetRules, ClientAssetRecord, FeeInputs, - OwnerMemo, PublicParams, TransactionBuilder, + OwnerMemo, TransactionBuilder, }; use ledger::data_model::AssetTypeCode; use std::os::raw::c_char; @@ -108,7 +108,6 @@ pub extern "C" fn findora_ffi_transaction_builder_add_operation_create_asset( /// @param {BigInt} seq_num - Issuance sequence number. Every subsequent issuance of a given asset type must have a higher sequence number than before. /// @param {BigInt} amount - Amount to be issued. /// @param {boolean} conf_amount - `true` means the asset amount is confidential, and `false` means it's nonconfidential. -/// @param {PublicParams} zei_params - Public parameters necessary to generate asset records. #[no_mangle] pub extern "C" fn findora_ffi_transaction_builder_add_basic_issue_asset( builder: &TransactionBuilder, @@ -117,7 +116,6 @@ pub extern "C" fn findora_ffi_transaction_builder_add_basic_issue_asset( seq_num: u64, amount: *const c_char, conf_amount: bool, - zei_params: &PublicParams, ) -> *mut TransactionBuilder { let amount = parse_u64(amount); if let Ok(info) = builder.clone().add_basic_issue_asset( @@ -126,7 +124,6 @@ pub extern "C" fn findora_ffi_transaction_builder_add_basic_issue_asset( seq_num, amount, conf_amount, - zei_params, ) { Box::into_raw(Box::new(info)) } else { diff --git a/src/components/wallet_mobile/src/rust/crypto.rs b/src/components/wallet_mobile/src/rust/crypto.rs index 390c0a4ea..98d31ddca 100644 --- a/src/components/wallet_mobile/src/rust/crypto.rs +++ b/src/components/wallet_mobile/src/rust/crypto.rs @@ -14,29 +14,26 @@ use cryptohash::sha256; use getrandom::getrandom; use globutils::wallet; use ledger::{ - data_model::{ - AssetTypeCode, ASSET_TYPE_FRA, BLACK_HOLE_PUBKEY_STAKING, - TX_FEE_MIN, - }, + data_model::{AssetTypeCode, ASSET_TYPE_FRA, BLACK_HOLE_PUBKEY_STAKING, TX_FEE_MIN}, staking::{MAX_DELEGATION_AMOUNT, MIN_DELEGATION_AMOUNT}, }; use rand_chacha::ChaChaRng; use rand_core::SeedableRng; use ring::pbkdf2; -use ruc::{ - d, Result, RucResult -}; +use ruc::{d, Result, RucResult}; use std::num::NonZeroU32; use std::str; -use zei::noah_algebra::serialization::NoahFromToBytes; -use zei::noah_api::{ - xfr::{ +use zei::{ + noah_algebra::serialization::NoahFromToBytes, + noah_api::xfr::{ asset_record::open_blind_asset_record as open_bar, - structs::{AssetType as NoahAssetType, OpenAssetRecord, XfrBody, ASSET_TYPE_LENGTH}, + structs::{ + AssetType as NoahAssetType, OpenAssetRecord, XfrBody, ASSET_TYPE_LENGTH, + }, trace_assets as noah_trace_assets, }, + XfrKeyPair, XfrPublicKey, XfrSecretKey, }; -use zei::{XfrKeyPair, XfrPublicKey, XfrSecretKey}; #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] /// Generates random Base64 encoded asset type as a Base64 string. Used in asset definitions. @@ -91,7 +88,7 @@ pub fn rs_open_client_asset_record( &owner_memo.map(|memo| memo.get_memo_ref().clone()), &keypair.into_noah(), ) - .c(d!()) + .c(d!()) } #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] diff --git a/src/components/wallet_mobile/src/rust/data_model.rs b/src/components/wallet_mobile/src/rust/data_model.rs index 967e1fd3f..d630af796 100644 --- a/src/components/wallet_mobile/src/rust/data_model.rs +++ b/src/components/wallet_mobile/src/rust/data_model.rs @@ -20,14 +20,14 @@ use rand_core::SeedableRng; use ruc::Result as RUCResult; use ruc::{d, err::RucResult}; use serde::{Deserialize, Serialize}; -use zei::noah_api::xfr::structs::{ - AssetTracerDecKeys, AssetTracerEncKeys, - AssetTracerKeyPair as NoahAssetTracerKeyPair, IdentityRevealPolicy, - OwnerMemo as NoahOwnerMemo, TracingPolicies as NoahTracingPolicies, - TracingPolicy as NoahTracingPolicy, -}; use zei::{ - BlindAssetRecord, XfrPublicKey + noah_api::xfr::structs::{ + AssetTracerDecKeys, AssetTracerEncKeys, + AssetTracerKeyPair as NoahAssetTracerKeyPair, IdentityRevealPolicy, + OwnerMemo as NoahOwnerMemo, TracingPolicies as NoahTracingPolicies, + TracingPolicy as NoahTracingPolicy, + }, + BlindAssetRecord, XfrPublicKey, }; #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] @@ -272,10 +272,7 @@ impl OwnerMemo { let noah_owner_memo: NoahOwnerMemo = val.into_serde().c(d!()).map_err(error_to_jsvalue)?; Ok(OwnerMemo { - memo: NoahOwnerMemo { - blind_share: noah_owner_memo.blind_share, - lock: noah_owner_memo.lock, - }, + memo: noah_owner_memo, }) } diff --git a/src/components/wallet_mobile/src/rust/transaction.rs b/src/components/wallet_mobile/src/rust/transaction.rs index 575859c93..03a637404 100644 --- a/src/components/wallet_mobile/src/rust/transaction.rs +++ b/src/components/wallet_mobile/src/rust/transaction.rs @@ -15,13 +15,15 @@ use ledger::{ }, staking::{td_addr_to_bytes, PartialUnDelegation, TendermintAddr}, }; -use ruc::{d, eg, Result as RucResult, err::RucResult as NewRucResult}; +use ruc::{d, eg, err::RucResult as NewRucResult, Result as RucResult}; use serde_json::Result; -use zei::noah_api::xfr::{ - asset_record::{open_blind_asset_record as open_bar, AssetRecordType}, - structs::AssetRecordTemplate, +use zei::{ + noah_api::xfr::{ + asset_record::{open_blind_asset_record as open_bar, AssetRecordType}, + structs::AssetRecordTemplate, + }, + OwnerMemo as NoahOwnerMemo, XfrKeyPair, XfrPublicKey, }; -use zei::{OwnerMemo as NoahOwnerMemo, XfrKeyPair, XfrPublicKey}; /// Given a serialized state commitment and transaction, returns true if the transaction correctly /// hashes up to the state commitment and false otherwise. @@ -340,7 +342,8 @@ impl TransactionBuilder { } /// Extracts the serialized form of a transaction. - pub fn transaction(&self) -> String { + pub fn transaction(&mut self) -> String { + self.get_builder_mut().build().unwrap(); self.get_builder().serialize_str() } @@ -362,7 +365,9 @@ impl TransactionBuilder { pub fn get_owner_memo(&self, idx: usize) -> Option { self.get_builder() .get_owner_memo_ref(idx) - .map(|memo| OwnerMemo { memo: memo.into_noah() }) + .map(|memo| OwnerMemo { + memo: memo.into_noah(), + }) } } @@ -397,7 +402,7 @@ impl TransferOperationBuilder { &owner_memo.map(|memo| memo.get_memo_ref().clone()), &key.into_noah(), ) - .c(d!())?; + .c(d!())?; self.get_builder_mut().add_input( *txo_ref.get_txo(), oar, diff --git a/src/components/wallet_mobile/src/rust/types.rs b/src/components/wallet_mobile/src/rust/types.rs index 71a26fe15..d63b50e0a 100644 --- a/src/components/wallet_mobile/src/rust/types.rs +++ b/src/components/wallet_mobile/src/rust/types.rs @@ -5,21 +5,23 @@ use credentials::{ CredUserSecretKey as PlatformCredUserSecretKey, }; use std::ops::{Deref, DerefMut}; -use zei::noah_api::xfr::structs::OpenAssetRecord as ZeiOpenAssetRecord; -use zei::{XfrKeyPair as ZeiXfrKeyPair, XfrPublicKey as ZeiXfrPublicKey}; +use zei::noah_api::{ + keys::{KeyPair as NoahXfrKeyPair, PublicKey as NoahXfrPublicKey}, + xfr::structs::OpenAssetRecord as NoahOpenAssetRecord, +}; //////////////////////////////////////////////////////////////////////////////// -pub struct XfrPublicKey(ZeiXfrPublicKey); +pub struct XfrPublicKey(NoahXfrPublicKey); -impl From for XfrPublicKey { - fn from(v: ZeiXfrPublicKey) -> XfrPublicKey { +impl From for XfrPublicKey { + fn from(v: NoahXfrPublicKey) -> XfrPublicKey { XfrPublicKey(v) } } impl Deref for XfrPublicKey { - type Target = ZeiXfrPublicKey; + type Target = NoahXfrPublicKey; fn deref(&self) -> &Self::Target { &self.0 @@ -35,16 +37,16 @@ impl DerefMut for XfrPublicKey { //////////////////////////////////////////////////////////////////////////////// #[derive(Clone)] -pub struct XfrKeyPair(ZeiXfrKeyPair); +pub struct XfrKeyPair(NoahXfrKeyPair); -impl From for XfrKeyPair { - fn from(v: ZeiXfrKeyPair) -> XfrKeyPair { +impl From for XfrKeyPair { + fn from(v: NoahXfrKeyPair) -> XfrKeyPair { XfrKeyPair(v) } } impl Deref for XfrKeyPair { - type Target = ZeiXfrKeyPair; + type Target = NoahXfrKeyPair; fn deref(&self) -> &Self::Target { &self.0 @@ -60,16 +62,16 @@ impl DerefMut for XfrKeyPair { //////////////////////////////////////////////////////////////////////////////// #[derive(Clone)] -pub struct OpenAssetRecord(ZeiOpenAssetRecord); +pub struct OpenAssetRecord(NoahOpenAssetRecord); -impl From for OpenAssetRecord { - fn from(v: ZeiOpenAssetRecord) -> OpenAssetRecord { +impl From for OpenAssetRecord { + fn from(v: NoahOpenAssetRecord) -> OpenAssetRecord { OpenAssetRecord(v) } } impl Deref for OpenAssetRecord { - type Target = ZeiOpenAssetRecord; + type Target = NoahOpenAssetRecord; fn deref(&self) -> &Self::Target { &self.0 diff --git a/src/components/wallet_mobile/src/rust/util.rs b/src/components/wallet_mobile/src/rust/util.rs index b81986a94..7f101e254 100644 --- a/src/components/wallet_mobile/src/rust/util.rs +++ b/src/components/wallet_mobile/src/rust/util.rs @@ -21,6 +21,6 @@ pub fn string_to_c_char(r_string: String) -> *mut c_char { #[cfg(target_arch = "wasm32")] #[inline(always)] -pub fn error_to_jsvalue(e: T) -> JsVal { +pub fn error_to_jsvalue(e: T) -> JsValue { JsValue::from_str(&e.to_string()) } diff --git a/src/components/wallet_mobile/src/wasm/mod.rs b/src/components/wallet_mobile/src/wasm/mod.rs index 491c621a8..1361fcd5b 100644 --- a/src/components/wallet_mobile/src/wasm/mod.rs +++ b/src/components/wallet_mobile/src/wasm/mod.rs @@ -6,8 +6,7 @@ use credentials::{ }; use ruc::{d, err::RucResult}; use wasm_bindgen::prelude::*; -use zei::noah_api::xfr::structs::ASSET_TYPE_LENGTH; -use zei::{XfrKeyPair, XfrPublicKey}; +use zei::{noah_api::xfr::structs::ASSET_TYPE_LENGTH, XfrKeyPair, XfrPublicKey}; #[wasm_bindgen] /// Generates asset type as a Base64 string from a JSON-serialized JavaScript value. @@ -163,7 +162,6 @@ impl TransactionBuilder { /// @param {BigInt} seq_num - Issuance sequence number. Every subsequent issuance of a given asset type must have a higher sequence number than before. /// @param {BigInt} amount - Amount to be issued. /// @param {boolean} conf_amount - `true` means the asset amount is confidential, and `false` means it's nonconfidential. - /// @param {PublicParams} zei_params - Public parameters necessary to generate asset records. pub fn add_basic_issue_asset( self, key_pair: &XfrKeyPair, @@ -171,18 +169,10 @@ impl TransactionBuilder { seq_num: u64, amount: u64, conf_amount: bool, - zei_params: &PublicParams, ) -> Result { let builder = self .0 - .add_basic_issue_asset( - key_pair, - code, - seq_num, - amount, - conf_amount, - zei_params, - ) + .add_basic_issue_asset(key_pair, code, seq_num, amount, conf_amount) .c(d!()) .map_err(error_to_jsvalue)?; @@ -234,7 +224,7 @@ impl TransactionBuilder { } /// Extracts the serialized form of a transaction. - pub fn transaction(&self) -> String { + pub fn transaction(&mut self) -> String { self.0.transaction() } @@ -403,7 +393,7 @@ impl TransferOperationBuilder { /// @throws Will throw an error if the transaction cannot be balanced. pub fn balance(self) -> Result { let builder = - self.0.balance().c(d!()).map_err(|e| { + self.0.balance(None).c(d!()).map_err(|e| { JsValue::from_str(&format!("Error balancing txn: {}", e)) })?; Ok(TransferOperationBuilder(builder)) diff --git a/src/components/wasm/Cargo.toml b/src/components/wasm/Cargo.toml index 2461fbd16..6feae46eb 100644 --- a/src/components/wasm/Cargo.toml +++ b/src/components/wasm/Cargo.toml @@ -19,22 +19,23 @@ hex = "0.4.3" js-sys = "0.3.27" rand_chacha = "0.3" rand_core = { version = "0.6", default-features = false, features = ["alloc"] } -rand = { version = "0.7", features = ["wasm-bindgen"] } serde = { version = "1.0.124", features = ["derive"] } serde_json = "1.0" wasm-bindgen = { version = "=0.2.84", features = ["serde-serialize"] } +wasm-bindgen-futures = "^0.4.34" fbnc = { version = "0.2.9", default-features = false} ring = "0.16.19" aes-gcm = "^0.10.1" bech32 = "0.7.2" +ruc = "1.0" +bs58 = "0.4" # Must enable the "js"-feature, # OR the compiling will fail. getrandom = { version = "0.2", features = ["js"] } zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } -ruc = "1.0" finutils = { path = "../finutils", default-features = false } @@ -68,9 +69,12 @@ features = [ serde = "1.0.124" serde_json = "1.0.41" vergen = "=3.1.0" -wasm-bindgen = { version = "=0.2.84", features = ["serde-serialize"] } [dev-dependencies] # Must enable the "js"-feature, # OR the compiling will fail. getrandom = { version = "0.2", features = ["js"] } +wasm-bindgen-test = "0.3.0" + +[features] +lightweight = ["zei/lightweight"] # Minimize size for only AR2ABAR and ABAR2AR. diff --git a/src/components/wasm/src/wasm.rs b/src/components/wasm/src/wasm.rs index a9bfc7647..6e477d542 100644 --- a/src/components/wasm/src/wasm.rs +++ b/src/components/wasm/src/wasm.rs @@ -16,12 +16,14 @@ mod wasm_data_model; use { crate::wasm_data_model::{ - error_to_jsvalue, AssetRules, AssetTracerKeyPair, AttributeAssignment, - AttributeDefinition, ClientAssetRecord, Credential, CredentialCommitment, - CredentialCommitmentData, CredentialCommitmentKey, CredentialIssuerKeyPair, - CredentialPoK, CredentialRevealSig, CredentialSignature, CredentialUserKeyPair, + error_to_jsvalue, AssetRules, AssetTracerKeyPair, AssetType, + AttributeAssignment, AttributeDefinition, AxfrOwnerMemo, AxfrOwnerMemoInfo, + ClientAssetRecord, Credential, CredentialCommitment, CredentialCommitmentData, + CredentialCommitmentKey, CredentialIssuerKeyPair, CredentialPoK, + CredentialRevealSig, CredentialSignature, CredentialUserKeyPair, MTLeafInfo, OwnerMemo, TracingPolicies, TxoRef, }, + core::str::FromStr, credentials::{ credential_commit, credential_issuer_key_gen, credential_open_commitment, credential_reveal, credential_sign, credential_user_key_gen, credential_verify, @@ -31,6 +33,7 @@ use { cryptohash::sha256, fbnc::NumKey, finutils::txn_builder::{ + AnonTransferOperationBuilder as PlatformAnonTransferOperationBuilder, FeeInput as PlatformFeeInput, FeeInputs as PlatformFeeInputs, TransactionBuilder as PlatformTransactionBuilder, TransferOperationBuilder as PlatformTransferOperationBuilder, @@ -48,7 +51,7 @@ use { globutils::{wallet, HashOf}, ledger::{ data_model::{ - gen_random_keypair, AssetTypeCode, AssetTypePrefix, + gen_random_keypair, get_abar_commitment, AssetTypeCode, AssetTypePrefix, AuthenticatedTransaction, Operation, TransferType, TxOutput, ASSET_TYPE_FRA, BLACK_HOLE_PUBKEY, BLACK_HOLE_PUBKEY_STAKING, TX_FEE_MIN, }, @@ -59,23 +62,36 @@ use { }, rand_chacha::ChaChaRng, rand_core::SeedableRng, - ruc::{d, err::RucResult}, - std::str::FromStr, + ruc::{d, eg, err::RucResult}, + serde::{Deserialize, Serialize}, + std::convert::From, wasm_bindgen::prelude::*, zei::{ noah_algebra::{ + bn254::BN254Scalar, prelude::{NoahFromToBytes, Scalar}, - ristretto::PedersenCommitmentRistretto, }, - noah_api::xfr::{ - asset_record::{open_blind_asset_record as open_bar, AssetRecordType}, - structs::{ - AssetRecordTemplate, AssetType as NoahAssetType, - ASSET_TYPE_LENGTH, + noah_api::{ + anon_xfr::{ + decrypt_memo, nullify, parse_memo, + structs::{ + AnonAssetRecord, Commitment, OpenAnonAssetRecord, + OpenAnonAssetRecordBuilder, + }, + }, + xfr::{ + asset_record::{ + open_blind_asset_record as open_bar, AssetRecordType, + AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, + }, + structs::{ + AssetRecordTemplate, AssetType as NoahAssetType, ASSET_TYPE_LENGTH, + }, + trace_assets as noah_trace_assets, }, - trace_assets as noah_trace_assets, }, - OwnerMemo as NoahOwnerMemo, XfrKeyPair, XfrPublicKey, XfrSecretKey, XfrBody + noah_crypto::hybrid_encryption::{XPublicKey, XSecretKey}, + OwnerMemo as NoahOwnerMemo, XfrBody, XfrKeyPair, XfrPublicKey, XfrSecretKey, }, }; @@ -83,6 +99,13 @@ use { /// against. const BUILD_ID: &str = concat!(env!("VERGEN_SHA_SHORT"), " ", env!("VERGEN_BUILD_DATE")); +/// Init noah anon xfr +#[cfg(target_arch = "wasm32")] +#[wasm_bindgen] +pub async fn init_noah() -> Result<(), JsValue> { + zei::noah_api::anon_xfr::init_anon_xfr().await +} + #[wasm_bindgen] /// Returns the git commit hash and commit date of the commit this library was built against. pub fn build_id() -> String { @@ -146,10 +169,17 @@ pub fn get_null_pk() -> XfrPublicKey { XfrPublicKey::noah_from_bytes(&[0; 32]).unwrap() } +/// struct to return list of commitment strings +#[derive(Serialize, Deserialize)] +pub struct CommitmentStringArray { + commitments: Vec, +} + #[wasm_bindgen] /// Structure that allows users to construct arbitrary transactions. pub struct TransactionBuilder { transaction_builder: PlatformTransactionBuilder, + commitments: Vec, } impl TransactionBuilder { @@ -209,7 +239,7 @@ impl FeeInputs { #[allow(missing_docs)] pub fn new() -> Self { FeeInputs { - inner: Vec::with_capacity(1), + inner: Vec::with_capacity(10), } } @@ -232,9 +262,15 @@ impl FeeInputs { tr: TxoRef, ar: ClientAssetRecord, om: Option, - kp: XfrKeyPair, + kp: &XfrKeyPair, ) -> Self { - self.inner.push(FeeInput { am, tr, ar, om, kp }); + self.inner.push(FeeInput { + am, + tr, + ar, + om, + kp: kp.clone(), + }); self } } @@ -288,6 +324,19 @@ impl TransactionBuilder { Ok(self) } + /// As the last operation of BarToAbar transaction, + /// add a static fee to the transaction. + pub fn add_fee_bar_to_abar( + mut self, + inputs: FeeInputs, + ) -> Result { + self.transaction_builder + .add_fee_bar_to_abar(inputs.into()) + .c(d!()) + .map_err(error_to_jsvalue)?; + Ok(self) + } + /// A simple fee checker for mainnet v1.0. /// /// SEE [check_fee](ledger::data_model::Transaction::check_fee) @@ -300,9 +349,20 @@ impl TransactionBuilder { pub fn new(seq_id: u64) -> Self { TransactionBuilder { transaction_builder: PlatformTransactionBuilder::from_seq_id(seq_id), + commitments: Default::default(), } } + /// Deserialize transaction builder from string. + pub fn from_string(s: String) -> Result { + let transaction_builder = serde_json::from_str(&s).map_err(error_to_jsvalue)?; + + Ok(TransactionBuilder { + transaction_builder, + commitments: Default::default(), + }) + } + /// Wraps around TransactionBuilder to add an asset definition operation to a transaction builder instance. /// @example Error handling /// try { @@ -373,7 +433,6 @@ impl TransactionBuilder { /// @param {BigInt} seq_num - Issuance sequence number. Every subsequent issuance of a given asset type must have a higher sequence number than before. /// @param {BigInt} amount - Amount to be issued. /// @param {boolean} conf_amount - `true` means the asset amount is confidential, and `false` means it's nonconfidential. - /// @param {PublicParams} zei_params - Public parameters necessary to generate asset records. pub fn add_basic_issue_asset( mut self, key_pair: &XfrKeyPair, @@ -427,6 +486,208 @@ impl TransactionBuilder { Ok(self) } + /// Adds an operation to the transaction builder that converts a bar to abar. + /// + /// @param {XfrKeyPair} auth_key_pair - input bar owner key pair + /// @param {AXfrPubKey} abar_pubkey - abar receiver's public key + /// @param {TxoSID} input_sid - txo sid of input bar + /// @param {ClientAssetRecord} input_record - + pub fn add_operation_bar_to_abar( + mut self, + seed: String, + auth_key_pair: &XfrKeyPair, + abar_pubkey: &XfrPublicKey, + txo_sid: u64, + input_record: &ClientAssetRecord, + owner_memo: Option, + ) -> Result { + use hex::FromHex; + + let oar = open_bar( + &input_record.get_bar_ref().into_noah(), + &owner_memo.map(|memo| memo.get_memo_ref().clone()), + &auth_key_pair.into_noah(), + ) + .c(d!()) + .map_err(|e| { + JsValue::from_str(&format!("Could not open asset record: {}", e)) + })?; + let is_bar_transparent = + oar.get_record_type() == NonConfidentialAmount_NonConfidentialAssetType; + + let mut seed = <[u8; 32]>::from_hex(seed).c(d!()).map_err(|e| { + JsValue::from_str(&format!("Failed to parse seed from hex: {}", e)) + })?; + + let (_, c) = self + .get_builder_mut() + .add_operation_bar_to_abar( + seed, + &auth_key_pair.clone(), + &abar_pubkey.clone(), + TxoSID(txo_sid), + &oar, + is_bar_transparent, + ) + .c(d!()) + .map_err(|e| { + JsValue::from_str(&format!("Could not add operation: {}", e)) + })?; + + self.commitments.push(c); + Ok(self) + } + + /// Adds an operation to transaction builder which converts an abar to a bar. + /// + /// @param {AnonAssetRecord} input - the ABAR to be converted + /// @param {AxfrOwnerMemo} axfr owner_memo - the corresponding owner_memo of the ABAR to be converted + /// @param {MTLeafInfo} mt_leaf_info - the Merkle Proof of the ABAR + /// @param {AXfrKeyPair} from_keypair - the owners Anon Key pair + /// @param {XfrPublic} recipient - the BAR owner public key + /// @param {bool} conf_amount - whether the BAR amount should be confidential + /// @param {bool} conf_type - whether the BAR asset type should be confidential + pub fn add_operation_abar_to_bar( + mut self, + input: AnonAssetRecord, + owner_memo: AxfrOwnerMemo, + mt_leaf_info: MTLeafInfo, + from_keypair: &XfrKeyPair, + recipient: &XfrPublicKey, + conf_amount: bool, + conf_type: bool, + ) -> Result { + let oabar = OpenAnonAssetRecordBuilder::from_abar( + &input, + owner_memo.memo, + &from_keypair.into_noah(), + ) + .c(d!()) + .map_err(|e| { + JsValue::from_str(&format!( + "Builder from_abar error: {}", + e.get_lowest_msg() + )) + })? + .mt_leaf_info(mt_leaf_info.get_noah_mt_leaf_info().clone()) + .build() + .c(d!()) + .map_err(|e| { + JsValue::from_str(&format!("Builder build error: {}", e.get_lowest_msg())) + })?; + + let art = match (conf_amount, conf_type) { + (true, true) => AssetRecordType::ConfidentialAmount_ConfidentialAssetType, + (true, false) => { + AssetRecordType::ConfidentialAmount_NonConfidentialAssetType + } + (false, true) => { + AssetRecordType::NonConfidentialAmount_ConfidentialAssetType + } + _ => AssetRecordType::NonConfidentialAmount_NonConfidentialAssetType, + }; + + self.get_builder_mut() + .add_operation_abar_to_bar( + &oabar, + &from_keypair.clone(), + &recipient.clone(), + art, + ) + .c(d!()) + .map_err(|e| { + JsValue::from_str(&format!( + "builder add_operation_abar_to_bar error: {}", + e.get_lowest_msg() + )) + })?; + + Ok(self) + } + + /// Returns a list of commitment base64 strings as json + pub fn get_commitments(&self) -> JsValue { + let r = CommitmentStringArray { + commitments: self + .commitments + .iter() + .map(wallet::commitment_to_base58) + .collect(), + }; + + JsValue::from_serde(&r).unwrap() + } + + /// Adds an operation to transaction builder which transfer a Anon Blind Asset Record + /// + /// @param {AnonAssetRecord} input - input abar + /// @param {AxfrOwnerMemo} axfr owner_memo - input owner memo + /// @param {AXfrKeyPair} from_keypair - abar sender's private key + /// @param {AXfrPubKey} to_pub_key - receiver's Anon public key + /// @param {u64} to_amount - amount to send to receiver + #[allow(clippy::too_many_arguments)] + pub fn add_operation_anon_transfer( + mut self, + input: AnonAssetRecord, + owner_memo: AxfrOwnerMemo, + mt_leaf_info: MTLeafInfo, + from_keypair: &XfrKeyPair, + to_pub_key: &XfrPublicKey, + to_amount: u64, + ) -> Result { + let mut prng = ChaChaRng::from_entropy(); + let input_oabar = OpenAnonAssetRecordBuilder::from_abar( + &input, + owner_memo.memo, + &from_keypair.into_noah(), + ) + .c(d!()) + .map_err(|e| JsValue::from_str(&format!("Could not add operation: {}", e)))? + .mt_leaf_info(mt_leaf_info.get_noah_mt_leaf_info().clone()) + .build() + .c(d!()) + .map_err(|e| JsValue::from_str(&format!("Could not add operation: {}", e)))?; + + if input_oabar.get_amount() <= to_amount { + return Err(JsValue::from_str(&format!( + "Insufficient amount for the input abar: {}", + input_oabar.get_amount() + ))); + } + + let output_oabar = OpenAnonAssetRecordBuilder::new() + .amount(to_amount) + .asset_type(input_oabar.get_asset_type()) + .pub_key(&to_pub_key.into_noah()) + .finalize(&mut prng) + .c(d!()) + .map_err(|e| JsValue::from_str(&format!("Could not add operation: {}", e)))? + .build() + .map_err(|e| { + JsValue::from_str(&format!("Could not add operation: {}", e)) + })?; + let r1 = get_abar_commitment(output_oabar.clone()); + self.commitments.push(r1); + + let (_, note, rem_oabars) = self + .get_builder_mut() + .add_operation_anon_transfer_fees_remainder( + &[input_oabar], + &[output_oabar], + &from_keypair.clone(), + ) + .c(d!()) + .map_err(|e| { + JsValue::from_str(&format!("Could not add operation: {}", e)) + })?; + + for rem_oabar in rem_oabars { + self.commitments.push(get_abar_commitment(rem_oabar)); + } + + Ok(self) + } + #[allow(missing_docs)] pub fn add_operation_delegate( mut self, @@ -549,8 +810,12 @@ impl TransactionBuilder { Ok(self) } - /// Do nothing, compatible with frontend + /// Builds the anon operations from pre-notes pub fn build(mut self) -> Result { + self.get_builder_mut() + .build() + .c(d!()) + .map_err(error_to_jsvalue)?; Ok(self) } @@ -572,7 +837,7 @@ impl TransactionBuilder { } /// Extracts the serialized form of a transaction. - pub fn transaction(&self) -> String { + pub fn transaction(&mut self) -> String { self.get_builder().serialize_str() } @@ -594,7 +859,9 @@ impl TransactionBuilder { pub fn get_owner_memo(&self, idx: usize) -> Option { self.get_builder() .get_owner_memo_ref(idx) - .map(|memo| OwnerMemo { memo: memo.into_noah() }) + .map(|memo| OwnerMemo { + memo: memo.into_noah(), + }) } } @@ -614,6 +881,11 @@ pub fn transfer_to_utxo_from_account( sk: String, nonce: u64, ) -> Result { + if !recipient.is_ed25519() { + return Err(eg!("recipient can only be ed25519 address")) + .map_err(error_to_jsvalue); + } + let seed = hex::decode(sk).map_err(error_to_jsvalue)?; let mut s = [0u8; 32]; s.copy_from_slice(&seed); @@ -677,6 +949,93 @@ pub fn get_serialized_address(address: String) -> Result { String::from_utf8(sa).map_err(error_to_jsvalue) } +/// Get balance for an Anonymous Blind Asset Record +/// @param {AnonAssetRecord} abar - ABAR for which balance needs to be queried +/// @param {AxfrOwnerMemo} memo - memo corresponding to the abar +/// @param keypair {AXfrKeyPair} - AXfrKeyPair of the ABAR owner +/// @param MTLeafInfo {mt_leaf_info} - the Merkle proof of the ABAR from commitment tree +/// @throws Will throw an error if abar fails to open +#[wasm_bindgen] +pub fn get_anon_balance( + abar: AnonAssetRecord, + memo: AxfrOwnerMemo, + keypair: XfrKeyPair, + mt_leaf_info: MTLeafInfo, +) -> Result { + let oabar = + OpenAnonAssetRecordBuilder::from_abar(&abar, memo.memo, &keypair.into_noah()) + .c(d!()) + .map_err(error_to_jsvalue)? + .mt_leaf_info(mt_leaf_info.get_noah_mt_leaf_info().clone()) + .build() + .c(d!()) + .map_err(error_to_jsvalue)?; + + Ok(oabar.get_amount()) +} + +/// Get OABAR (Open ABAR) using the ABAR, OwnerMemo and MTLeafInfo +/// @param {AnonAssetRecord} abar - ABAR which needs to be opened +/// @param {AxfrOwnerMemo} memo - memo corresponding to the abar +/// @param keypair {AXfrKeyPair} - AXfrKeyPair of the ABAR owner +/// @param MTLeafInfo {mt_leaf_info} - the Merkle proof of the ABAR from commitment tree +/// @throws Will throw an error if abar fails to open +#[wasm_bindgen] +pub fn get_open_abar( + abar: AnonAssetRecord, + memo: AxfrOwnerMemo, + keypair: XfrKeyPair, + mt_leaf_info: MTLeafInfo, +) -> Result { + let oabar = + OpenAnonAssetRecordBuilder::from_abar(&abar, memo.memo, &keypair.into_noah()) + .c(d!()) + .map_err(error_to_jsvalue)? + .mt_leaf_info(mt_leaf_info.get_noah_mt_leaf_info().clone()) + .build() + .c(d!()) + .map_err(error_to_jsvalue)?; + + let json = JsValue::from_serde(&oabar) + .c(d!()) + .map_err(error_to_jsvalue)?; + Ok(json) +} + +/// Generate nullifier hash using ABAR, OwnerMemo and MTLeafInfo +/// @param {AnonAssetRecord} abar - ABAR for which balance needs to be queried +/// @param {AxfrOwnerMemo} memo - memo corresponding to the abar +/// @param keypair {AXfrKeyPair} - AXfrKeyPair of the ABAR owner +/// @param MTLeafInfo {mt_leaf_info} - the Merkle proof of the ABAR from commitment tree +/// @throws Will throw an error if abar fails to open +#[wasm_bindgen] +pub fn gen_nullifier_hash( + abar: AnonAssetRecord, + memo: AxfrOwnerMemo, + keypair: XfrKeyPair, + mt_leaf_info: MTLeafInfo, +) -> Result { + let oabar = + OpenAnonAssetRecordBuilder::from_abar(&abar, memo.memo, &keypair.into_noah()) + .c(d!()) + .map_err(error_to_jsvalue)? + .mt_leaf_info(mt_leaf_info.get_noah_mt_leaf_info().clone()) + .build() + .c(d!()) + .map_err(error_to_jsvalue)?; + + let n = nullify( + &keypair.into_noah(), + oabar.get_amount(), + oabar.get_asset_type().as_scalar(), + mt_leaf_info.get_noah_mt_leaf_info().uid, + ) + .c(d!()) + .map_err(error_to_jsvalue)?; + let hash = wallet::nullifier_to_base58(&n.0); + Ok(hash) +} + #[wasm_bindgen] #[derive(Default)] /// Structure that enables clients to construct complex transfers. @@ -712,7 +1071,7 @@ impl TransferOperationBuilder { &owner_memo.map(|memo| memo.get_memo_ref().clone()), &key.into_noah(), ) - .c(d!()) + .c(d!()) .map_err(|e| { JsValue::from_str(&format!("Could not open asset record: {}", e)) })?; @@ -927,6 +1286,12 @@ impl TransferOperationBuilder { serde_json::to_string(self.get_builder()).unwrap() } + #[allow(missing_docs)] + pub fn from_string(s: String) -> Result { + let op_builder = serde_json::from_str(&s).c(d!()).map_err(error_to_jsvalue)?; + Ok(TransferOperationBuilder { op_builder }) + } + /// Wraps around TransferOperationBuilder to extract an operation expression as JSON. pub fn transaction(&self) -> Result { let op = self @@ -938,6 +1303,167 @@ impl TransferOperationBuilder { } } +#[wasm_bindgen] +/// Structure that enables clients to construct complex transfers. +pub struct AnonTransferOperationBuilder { + op_builder: PlatformAnonTransferOperationBuilder, +} + +impl AnonTransferOperationBuilder { + #[allow(missing_docs)] + pub fn get_builder(&self) -> &PlatformAnonTransferOperationBuilder { + &self.op_builder + } + + #[allow(missing_docs)] + pub fn get_builder_mut(&mut self) -> &mut PlatformAnonTransferOperationBuilder { + &mut self.op_builder + } +} + +#[wasm_bindgen] +impl AnonTransferOperationBuilder { + /// new is a constructor for AnonTransferOperationBuilder + pub fn new(seq_id: u64) -> Self { + AnonTransferOperationBuilder { + op_builder: PlatformAnonTransferOperationBuilder::new_from_seq_id(seq_id), + } + } + + /// add_input is used to add a new input source for Anon Transfer + /// @param {AnonAssetRecord} abar - input ABAR to transfer + /// @param {AxfrOwnerMemo} memo - memo corresponding to the input abar + /// @param keypair {AXfrKeyPair} - AXfrKeyPair of the ABAR owner + /// @param MTLeafInfo {mt_leaf_info} - the Merkle proof of the ABAR from commitment tree + /// @throws Will throw an error if abar fails to open, input fails to get added to Operation + pub fn add_input( + mut self, + abar: &AnonAssetRecord, + memo: &AxfrOwnerMemo, + keypair: &XfrKeyPair, + mt_leaf_info: MTLeafInfo, + ) -> Result { + let oabar = OpenAnonAssetRecordBuilder::from_abar( + &abar.clone(), + memo.memo.clone(), + &keypair.into_noah(), + ) + .c(d!()) + .map_err(error_to_jsvalue)? + .mt_leaf_info(mt_leaf_info.get_noah_mt_leaf_info().clone()) + .build() + .c(d!()) + .map_err(error_to_jsvalue)?; + + self.get_builder_mut() + .add_input(oabar) + .c(d!()) + .map_err(error_to_jsvalue)?; + + Ok(self) + } + + /// add_output is used to add a output to the Anon Transfer + /// @param amount {u64} - amount to be sent to the receiver + /// @param to {AXfrPubKey} - original pub key of receiver + /// @throws error if ABAR fails to be built + pub fn add_output( + mut self, + amount: u64, + asset_type: String, + to: XfrPublicKey, + ) -> Result { + let mut prng = ChaChaRng::from_entropy(); + + let at = AssetTypeCode::new_from_base64(asset_type.as_str()) + .map_err(error_to_jsvalue)?; + + let oabar_out = OpenAnonAssetRecordBuilder::new() + .amount(amount) + .asset_type(at.val) + .pub_key(&to.into_noah()) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(); + + self.get_builder_mut() + .add_output(oabar_out) + .c(d!()) + .map_err(error_to_jsvalue)?; + + Ok(self) + } + + /// add_keypair is used to add the sender's keypair for the nullifier generation + /// @param to {AXfrKeyPair} - original keypair of sender + /// @throws error if ABAR fails to be built + pub fn add_keypair(mut self, keypair: &XfrKeyPair) -> AnonTransferOperationBuilder { + self.get_builder_mut().add_keypair(keypair.clone()); + + self + } + + /// get_expected_fee is used to gather extra FRA that needs to be spent to make the transaction + /// have enough fees. + pub fn get_expected_fee(&self) -> Result { + self.get_builder() + .extra_fee_estimation() + .map_err(error_to_jsvalue) + } + + /// get_total_fee_estimate + pub fn get_total_fee_estimate(&self) -> Result { + self.get_builder() + .get_total_fee_estimation() + .map_err(error_to_jsvalue) + } + + /// get_commitments returns a list of all the commitments for receiver public keys + pub fn get_commitments(&self) -> JsValue { + let r = CommitmentStringArray { + commitments: self + .get_builder() + .get_commitments() + .iter() + .map(wallet::commitment_to_base58) + .collect(), + }; + + JsValue::from_serde(&r).unwrap() + } + + /// get_commitment_map returns a hashmap of all the commitments mapped to public key, asset, amount + pub fn get_commitment_map(&self) -> JsValue { + let commitment_map = self.get_builder().get_commitment_map(); + JsValue::from_serde(&commitment_map).unwrap() + } + + /// build is used to build proof the Transfer Operation + pub fn build(mut self) -> Result { + self.get_builder_mut() + .build() + .c(d!("error in txn_builder: build")) + .map_err(error_to_jsvalue)?; + + self.get_builder_mut() + .build_txn() + .c(d!()) + .map_err(error_to_jsvalue)?; + + Ok(self) + } + + /// transaction returns the prepared Anon Transfer Operation + /// @param nonce {NoReplayToken} - nonce of the txn to be added to the operation + pub fn transaction(self) -> Result { + self.get_builder() + .serialize_str() + .c(d!()) + .map_err(error_to_jsvalue) + } +} + ///////////// CRYPTO ////////////////////// #[wasm_bindgen] /// Returns a JavaScript object containing decrypted owner record information, @@ -975,12 +1501,35 @@ pub fn get_priv_key_str(key_pair: &XfrKeyPair) -> String { serde_json::to_string(key_pair.get_sk_ref()).unwrap() } +#[wasm_bindgen] +/// +pub fn get_priv_key_hex_str_by_mnemonic( + phrase: &str, + num: u32, +) -> Result { + let key_pair = wallet::restore_keypair_from_mnemonic_cus(phrase, 0, 0, num) + .map_err(error_to_jsvalue)?; + let data = key_pair.get_sk_ref().to_bytes(); + Ok(format!("0x{}", hex::encode(&data[1..]))) +} + +#[wasm_bindgen] +/// Extracts the private key as a string from a transfer key pair. +pub fn get_priv_key_str_old(key_pair: &XfrKeyPair) -> String { + base64::encode_config(&key_pair.get_sk_ref().to_bytes(), base64::URL_SAFE) +} + #[wasm_bindgen] /// Creates a new transfer key pair. pub fn new_keypair() -> XfrKeyPair { gen_random_keypair() } +#[wasm_bindgen] +/// Creates a new transfer key pair. +pub fn new_keypair_old() -> XfrKeyPair { + XfrKeyPair::generate(&mut ChaChaRng::from_entropy()) +} #[wasm_bindgen] /// Generates a new keypair deterministically from a seed string and an optional name. pub fn new_keypair_from_seed(seed_str: String, name: Option) -> XfrKeyPair { @@ -1249,12 +1798,7 @@ pub fn trace_assets( // let candidate_assets: Vec = // candidate_assets.into_serde().c(d!()).map_err(error_to_jsvalue)?; let xfr_body: XfrBody = xfr_body.into_serde().c(d!()).map_err(error_to_jsvalue)?; - // let candidate_assets: Vec = candidate_assets - // .iter() - // .map(|asset_type_str| { - // AssetTypeCode::new_from_str(&asset_type_str.to_string()).val - // }) - // .collect(); + let record_data = noah_trace_assets(&xfr_body.into_noah(), tracer_keypair.get_keys()) .c(d!()) @@ -1276,6 +1820,7 @@ pub fn trace_assets( // Author: Chao Ma, github.com/chaosma. // ////////////////////////////////////////// +use crate::wasm_data_model::{AmountAssetType, AnonKeys}; use aes_gcm::{ aead::{generic_array::GenericArray, Aead, KeyInit}, Aes256Gcm, @@ -1284,6 +1829,7 @@ use base64::URL_SAFE; use fp_types::H160; use getrandom::getrandom; use js_sys::JsString; +use ledger::data_model::{ABARData, TxoSID, BAR_TO_ABAR_TX_FEE_MIN}; use ledger::staking::Amount; use rand_core::{CryptoRng, RngCore}; @@ -1312,6 +1858,13 @@ pub fn bech32_to_base64(pk: &str) -> Result { Ok(public_key_to_base64(&pub_key)) } +#[wasm_bindgen] +#[allow(missing_docs)] +pub fn bech32_to_base64_old(pk: &str) -> Result { + public_key_from_bech32(pk) + .map(|pk| base64::encode_config(&pk.to_bytes(), base64::URL_SAFE)) +} + #[wasm_bindgen] #[allow(missing_docs)] pub fn base64_to_bech32(pk: &str) -> Result { @@ -1319,6 +1872,17 @@ pub fn base64_to_bech32(pk: &str) -> Result { Ok(public_key_to_bech32(&pub_key)) } +#[wasm_bindgen] +#[allow(missing_docs)] +pub fn base64_to_base58(data: &str) -> Result { + let byts = base64::decode_config(data, URL_SAFE) + .c(d!()) + .map_err(error_to_jsvalue)?; + + let dat = bs58::encode(byts).into_string(); + Ok(dat) +} + #[wasm_bindgen] #[allow(missing_docs)] pub fn encryption_pbkdf2_aes256gcm(key_pair: String, password: String) -> Vec { @@ -1386,10 +1950,12 @@ pub fn decryption_pbkdf2_aes256gcm(enc_key_pair: Vec, password: String) -> S #[wasm_bindgen] #[allow(missing_docs)] -pub fn create_keypair_from_secret(sk_str: String) -> Option { - serde_json::from_str::(&sk_str) - .map(|sk| sk.into_keypair()) - .ok() +pub fn create_keypair_from_secret(sk_str: String) -> Result { + let sk = serde_json::from_str::(&sk_str) + .c(d!()) + .map_err(error_to_jsvalue)?; + + Ok(sk.into_keypair()) } #[wasm_bindgen] @@ -1456,6 +2022,28 @@ pub fn restore_keypair_from_mnemonic_default( .map_err(error_to_jsvalue) } +#[wasm_bindgen] +/// Restore the XfrKeyPair from a mnemonic with a default bip44-path, +/// that is "m/44'/917'/0'/0/0" ("m/44'/coin'/account'/change/address"). +pub fn restore_keypair_from_mnemonic_ed25519( + phrase: &str, +) -> Result { + wallet::restore_keypair_from_mnemonic_ed25519(phrase) + .c(d!()) + .map_err(error_to_jsvalue) +} + +#[wasm_bindgen] +/// Restore the XfrKeyPair from a mnemonic with a default bip44-path, +/// that is "m/44'/917'/0'/0/0" ("m/44'/coin'/account'/change/address"). +pub fn restore_keypair_from_mnemonic_secp256k1( + phrase: &str, +) -> Result { + wallet::restore_keypair_from_mnemonic_secp256k1(phrase) + .c(d!()) + .map_err(error_to_jsvalue) +} + #[wasm_bindgen] /// Restore the XfrKeyPair from a mnemonic with custom params, /// in bip44 form. @@ -1497,8 +2085,20 @@ pub fn fra_get_minimal_fee() -> u64 { TX_FEE_MIN } +/// Fee smaller than this value will be denied. +#[wasm_bindgen] +pub fn fra_get_minimal_fee_for_bar_to_abar() -> u64 { + BAR_TO_ABAR_TX_FEE_MIN +} + +/// Anon fee for a given number of inputs & outputs #[wasm_bindgen] +pub fn get_anon_fee(n_inputs: u32, n_outputs: u32) -> u32 { + PlatformAnonTransferOperationBuilder::get_anon_fee(n_inputs, n_outputs) +} + /// The destination for fee to be transfered to. +#[wasm_bindgen] pub fn fra_get_dest_pubkey() -> XfrPublicKey { XfrPublicKey::from_noah(&BLACK_HOLE_PUBKEY) } @@ -1533,10 +2133,197 @@ pub fn get_delegation_max_amount() -> u64 { MAX_DELEGATION_AMOUNT } +#[wasm_bindgen] +#[allow(missing_docs)] +pub fn x_pubkey_from_string(key_str: &str) -> Result { + wallet::x_public_key_from_base64(key_str) + .c(d!()) + .map_err(error_to_jsvalue) +} + +#[wasm_bindgen] +#[allow(missing_docs)] +pub fn x_secretkey_from_string(key_str: &str) -> Result { + wallet::x_secret_key_from_base64(key_str) + .c(d!()) + .map_err(error_to_jsvalue) +} + +#[wasm_bindgen] +#[allow(missing_docs)] +pub fn abar_from_json(json: JsValue) -> Result { + let abar: ABARData = json.into_serde().c(d!()).map_err(error_to_jsvalue)?; + let c = wallet::commitment_from_base58(abar.commitment.as_str()) + .c(d!()) + .map_err(error_to_jsvalue)?; + + Ok(AnonAssetRecord { commitment: c }) +} + +#[wasm_bindgen] +/// Decrypts an ABAR with owner memo and decryption key +pub fn open_abar( + abar: AnonAssetRecord, + memo: AxfrOwnerMemo, + keypair: &XfrKeyPair, +) -> Result { + let oabar = + OpenAnonAssetRecordBuilder::from_abar(&abar, memo.memo, &keypair.into_noah()) + .map_err(error_to_jsvalue)? + .build() + .map_err(error_to_jsvalue)?; + + let at = AssetTypeCode { + val: oabar.get_asset_type(), + }; + + Ok(AmountAssetType { + amount: oabar.get_amount(), + asset_type: at.to_base64(), + }) +} + +#[wasm_bindgen] +/// Decrypts the owner anon memo. +/// * `memo` - Owner anon memo to decrypt +/// * `key_pair` - Owner anon keypair +/// * `abar` - Associated anonymous blind asset record to check memo info against. +/// Return Error if memo info does not match the commitment or public key. +/// Return Ok(amount, asset_type, blinding) otherwise. +pub fn decrypt_axfr_memo( + memo: &AxfrOwnerMemo, + key_pair: &XfrKeyPair, + abar: &AnonAssetRecord, +) -> Result { + let (amount, asset_type, blind) = + decrypt_memo(&memo.memo, &key_pair.into_noah(), abar) + .c(d!()) + .map_err(error_to_jsvalue)?; + Ok(AxfrOwnerMemoInfo { + amount, + blind, + asset_type: AssetTypeCode { val: asset_type }.to_base64(), + }) +} + +#[wasm_bindgen] +/// Try to decrypt the owner memo to check if it is own. +/// * `memo` - Owner anon memo need to decrypt. +/// * `key_pair` - the memo bytes. +/// Return Ok(amount, asset_type, blinding) if memo is own. +pub fn try_decrypt_axfr_memo( + memo: &AxfrOwnerMemo, + key_pair: &XfrKeyPair, +) -> Result, JsValue> { + let secret_key = key_pair.get_sk_ref().into_noah(); + let res = memo + .get_memo_ref() + .decrypt(&secret_key) + .c(d!()) + .map_err(error_to_jsvalue)?; + Ok(res) +} + +#[wasm_bindgen] +/// Parse the owner memo from bytes. +/// * `bytes` - the memo plain bytes. +/// * `key_pair` - the memo bytes. +/// * `abar` - Associated anonymous blind asset record to check memo info against. +/// Return Error if memo info does not match the commitment. +/// Return Ok(amount, asset_type, blinding) otherwise. +pub fn parse_axfr_memo( + bytes: &[u8], + key_pair: &XfrKeyPair, + abar: &AnonAssetRecord, +) -> Result { + let (amount, asset_type, blind) = parse_memo(bytes, &key_pair.into_noah(), abar) + .c(d!()) + .map_err(error_to_jsvalue)?; + Ok(AxfrOwnerMemoInfo { + amount, + blind, + asset_type: AssetTypeCode { val: asset_type }.to_base64(), + }) +} + +#[wasm_bindgen] +/// Convert Commitment to AnonAssetRecord. +pub fn commitment_to_aar(commitment: Commitment) -> AnonAssetRecord { + AnonAssetRecord { commitment } +} + #[cfg(test)] #[allow(missing_docs)] mod test { use super::*; + use wasm_bindgen_test::*; + + #[wasm_bindgen_test] + //This contains only the positive tests with the fees included + fn extra_fee_test() { + let mut prng = ChaChaRng::from_seed([0u8; 32]); + + let amount = 6000000000u64; + + //let amount_output = amount / 3; + let amount_output = amount; + + let asset_type = ASSET_TYPE_FRA; + + // simulate input abar + let (mut oabar, keypair_in) = gen_oabar_and_keys(&mut prng, amount, asset_type); + + let asset_type_out = ASSET_TYPE_FRA; + + //Simulate output abar + let (mut oabar_out, _keypair_out) = + gen_oabar_and_keys(&mut prng, amount_output, asset_type_out); + + let mut ts = AnonTransferOperationBuilder::new(1); + + ts.get_builder_mut().add_input(oabar); + + ts.get_builder_mut().add_output(oabar_out); + + /* + Extra_fee_estimation works as follows + 1.- compute estimated_fees + 2.- compute FRA_excess + fra_excess = fra_input_sum - fra_output_sum; + if (fra_excess >= estimated_fees) => 0 + else (estimated_fees > fra_excess) => new_fees_estimation(n + 1 inputs, m + 1 outputs) + */ + + let estimated_fees_gt_fra_excess = ts.get_expected_fee(); + + assert!(estimated_fees_gt_fra_excess.unwrap() > 0); + + let (mut oabar_2, keypair_in_2) = + gen_oabar_and_keys(&mut prng, 2 * amount, asset_type); + + ts.get_builder_mut().add_input(oabar_2); + + let fra_excess_gt_fees_estimation = ts.get_expected_fee(); + + assert_eq!(fra_excess_gt_fees_estimation, Ok(0)); + } + + fn gen_oabar_and_keys( + prng: &mut R, + amount: u64, + asset_type: NoahAssetType, + ) -> (OpenAnonAssetRecord, XfrKeyPair) { + let keypair = XfrKeyPair::generate(prng); + let oabar = OpenAnonAssetRecordBuilder::new() + .amount(u64::from(amount)) + .asset_type(asset_type) + .pub_key(&keypair.get_pk().into_noah()) + .finalize(prng) + .unwrap() + .build() + .unwrap(); + (oabar, keypair) + } #[test] fn t_keypair_conversion() { @@ -1624,4 +2411,26 @@ mod test { serde_json::from_str::(&actual_serialized_json).unwrap(); assert_eq!(res.max_units, None); } + + #[test] + fn test_keypair_from_mnemonic() { + let phrase1 = "museum combine night carry artefact actress sugar amount kitchen change ill room walk potato beef similar claw fossil gate chalk domain chronic utility engage"; + let phrase2 = "museum combine night carry artefact actress sugar amount kitchen change ill room walk potato beef similar claw fossil gate chalk domain chronic utility engage"; + + let kp1 = restore_keypair_from_mnemonic_default(phrase1).unwrap(); + println!( + "{} {}", + serde_json::to_string_pretty(&kp1).unwrap(), + wallet::public_key_to_bech32(kp1.get_pk_ref()) + ); + + let kp2 = restore_keypair_from_mnemonic_default(phrase2).unwrap(); + println!( + "{} {}", + serde_json::to_string_pretty(&kp2).unwrap(), + wallet::public_key_to_bech32(kp2.get_pk_ref()) + ); + + assert_eq!(kp1.get_sk(), kp2.get_sk()); + } } diff --git a/src/components/wasm/src/wasm_data_model.rs b/src/components/wasm/src/wasm_data_model.rs index 13eefd6fa..cb3eaed5e 100644 --- a/src/components/wasm/src/wasm_data_model.rs +++ b/src/components/wasm/src/wasm_data_model.rs @@ -6,6 +6,7 @@ use { Credential as PlatformCredential, }, globutils::{wallet, HashOf}, + js_sys::JsString, ledger::data_model::{ AssetRules as PlatformAssetRules, AssetType as PlatformAssetType, AuthenticatedUtxo, SignatureRules as PlatformSignatureRules, TxOutput, @@ -17,17 +18,20 @@ use { serde::{Deserialize, Serialize}, wasm_bindgen::prelude::*, zei::{ - noah_algebra::ristretto::PedersenCommitmentRistretto, - noah_api::xfr::{ - structs::{ + noah_algebra::{bn254::BN254Scalar, ristretto::PedersenCommitmentRistretto}, + noah_api::{ + anon_xfr::structs::{ + AnonAssetRecord, AxfrOwnerMemo as NoahAxfrOwnerMemo, + MTLeafInfo as NoahMTLeafInfo, + }, + xfr::structs::{ AssetTracerDecKeys, AssetTracerEncKeys, - AssetTracerKeyPair as NoahAssetTracerKeyPair, - IdentityRevealPolicy, OwnerMemo as NoahOwnerMemo, - TracingPolicies as NoahTracingPolicies, + AssetTracerKeyPair as NoahAssetTracerKeyPair, IdentityRevealPolicy, + OwnerMemo as NoahOwnerMemo, TracingPolicies as NoahTracingPolicies, TracingPolicy as NoahTracingPolicy, }, }, - XfrPublicKey, BlindAssetRecord, + BlindAssetRecord, XfrPublicKey, }, }; @@ -157,7 +161,10 @@ impl ClientAssetRecord { /// fetch an asset record from the ledger server. pub fn from_json(val: &JsValue) -> Result { Ok(ClientAssetRecord { - txo: val.into_serde().c(d!()).map_err(error_to_jsvalue)?, + txo: val + .into_serde() + .c(d!()) + .map_err(|_| JsValue::from_str("format json error"))?, }) } @@ -256,6 +263,73 @@ impl OwnerMemo { } } +#[wasm_bindgen] +#[derive(Deserialize, Clone)] +/// Asset owner memo. Contains information needed to decrypt an asset record. +/// @see {@link module:Findora-Wasm.ClientAssetRecord|ClientAssetRecord} for more details about asset records. +pub struct AxfrOwnerMemo { + pub(crate) memo: NoahAxfrOwnerMemo, +} + +#[wasm_bindgen] +impl AxfrOwnerMemo { + /// Builds an owner memo from a JSON-serialized JavaScript value. + /// @param {JsValue} val - JSON owner memo fetched from query server with the `get_owner_memo/{sid}` route, + /// where `sid` can be fetched from the query server with the `get_owned_utxos/{address}` route. See the example below. + /// + /// @example + /// { + /// "blind_share":[91,251,44,28,7,221,67,155,175,213,25,183,70,90,119,232,212,238,226,142,159,200,54,19,60,115,38,221,248,202,74,248], + /// "lock":{"ciphertext":[119,54,117,136,125,133,112,193],"encoded_rand":"8KDql2JphPB5WLd7-aYE1bxTQAcweFSmrqymLvPDntM="} + /// } + pub fn from_json(val: &JsValue) -> Result { + let noah_owner_memo: NoahAxfrOwnerMemo = + val.into_serde().c(d!()).map_err(error_to_jsvalue)?; + Ok(AxfrOwnerMemo { + memo: noah_owner_memo, + }) + } + + /// Creates a clone of the owner memo. + pub fn clone(&self) -> Self { + AxfrOwnerMemo { + memo: self.memo.clone(), + } + } +} + +impl AxfrOwnerMemo { + pub fn get_memo_ref(&self) -> &NoahAxfrOwnerMemo { + &self.memo + } +} + +#[wasm_bindgen] +/// Asset owner memo decrypted info. contains amount, asset_type and blind. +pub struct AxfrOwnerMemoInfo { + pub(crate) amount: u64, + pub(crate) asset_type: String, + pub(crate) blind: BN254Scalar, +} + +#[wasm_bindgen] +#[allow(missing_docs)] +impl AxfrOwnerMemoInfo { + #[wasm_bindgen(getter)] + pub fn amount(&self) -> u64 { + self.amount + } + + #[wasm_bindgen(getter)] + pub fn asset_type(&self) -> String { + self.asset_type.clone() + } + + #[wasm_bindgen(getter)] + pub fn blind(&self) -> BN254Scalar { + self.blind + } +} #[derive(Serialize, Deserialize)] pub(crate) struct AttributeDefinition { @@ -695,3 +769,94 @@ impl AssetRules { pub(crate) fn error_to_jsvalue(e: T) -> JsValue { JsValue::from_str(&e.to_string()) } + +#[wasm_bindgen] +#[derive(Default, Clone)] +pub struct MTLeafInfo { + object: NoahMTLeafInfo, +} + +impl MTLeafInfo { + pub fn get_noah_mt_leaf_info(&self) -> &NoahMTLeafInfo { + &self.object + } +} + +#[wasm_bindgen] +impl MTLeafInfo { + pub fn from_json(json: &JsValue) -> Result { + let mt_leaf_info: NoahMTLeafInfo = json + .into_serde() + .c(d!()) + .map_err(|_| JsValue::from_str("format json error"))?; + Ok(MTLeafInfo { + object: mt_leaf_info, + }) + } + + pub fn to_json(&self) -> Result { + serde_json::to_string(&self.object) + .map(|s| JsValue::from_str(&s)) + .c(d!()) + .map_err(error_to_jsvalue) + } +} + +#[wasm_bindgen] +pub struct AmountAssetType { + pub amount: u64, + pub(crate) asset_type: String, +} + +#[wasm_bindgen] +impl AmountAssetType { + #[wasm_bindgen(getter)] + pub fn asset_type(&self) -> String { + self.asset_type.clone() + } +} + +/// AnonKeys is used to store keys for Anon proofs +#[wasm_bindgen] +#[derive(Serialize, Deserialize)] +pub struct AnonKeys { + pub(crate) secret_key: String, + pub(crate) pub_key: String, +} + +/// AnonKeys is a struct to store keys required for anon transfer +#[wasm_bindgen] +#[allow(missing_docs)] +impl AnonKeys { + pub fn from_json(json: &JsValue) -> Result { + let anon_keys: AnonKeys = json.into_serde().c(d!()).map_err(error_to_jsvalue)?; + Ok(anon_keys) + } + + pub fn to_json(&self) -> Result { + serde_json::to_string(&self) + .map(|s| JsValue::from_str(&s)) + .c(d!()) + .map_err(error_to_jsvalue) + } + + #[wasm_bindgen(getter)] + pub fn secret_key(&self) -> String { + self.secret_key.clone() + } + + #[wasm_bindgen(setter)] + pub fn set_secret_key(&mut self, secret_key: String) { + self.secret_key = secret_key; + } + + #[wasm_bindgen(getter)] + pub fn pub_key(&self) -> String { + self.pub_key.clone() + } + + #[wasm_bindgen(setter)] + pub fn set_pub_key(&mut self, pub_key: String) { + self.pub_key = pub_key; + } +} diff --git a/src/ledger/Cargo.toml b/src/ledger/Cargo.toml index 5d37a3afb..3fb8a1e77 100644 --- a/src/ledger/Cargo.toml +++ b/src/ledger/Cargo.toml @@ -7,10 +7,12 @@ build = "build.rs" [dependencies] base64 = "0.13" +bs58 = "0.4" bincode = "1.3.1" -byteorder = "1.0.0" +byteorder = "1.0.0" curve25519-dalek = { package = "noah-curve25519-dalek", version = "4.0.0", default-features = false, features = ['serde'] } ed25519-dalek = { package = "noah-ed25519-dalek", git = "https://github.com/FindoraNetwork/ed25519-dalek", tag = "v4.0.0" } +digest = '0.10' hex = "0.4.3" lazy_static = { version = "1.2.0" } tracing = "0.1" @@ -24,7 +26,7 @@ serde-strz = "1.1.1" sha2 = "0.10" unicode-normalization = "0.1.13" time = "0.3" -tendermint = { git = "https://github.com/FindoraNetwork/tendermint-rs", tag = "v0.19.0a-fk" } +tendermint = { git = "https://github.com/FindoraNetwork/tendermint-rs", tag = "v0.19.0c" } indexmap = { version = "1.6.2", features = ["serde"] } config = { path = "../components/config" } fp-types = { path = "../components/contracts/primitives/types" } @@ -32,6 +34,7 @@ fp-utils = { path = "../components/contracts/primitives/utils" } ruc = "1.0" zei = { package="platform-lib-noah", git = "https://github.com/FindoraNetwork/platform-lib-noah", branch = "develop" } bulletproofs = { package = "bulletproofs", git = "https://github.com/FindoraNetwork/bp", rev = "57633a", features = ["yoloproofs"] } +itertools = "0.10" fbnc = { version = "0.2.9", default-features = false} once_cell = "1" num-bigint = "0.4.3" @@ -44,10 +47,11 @@ merkle_tree = { git = "https://github.com/FindoraNetwork/platform-lib-merkle", b sliding_set = { git = "https://github.com/FindoraNetwork/platform-lib-slidingset", branch = "develop" } [features] -default = [] +default = ["fin_storage"] diskcache = ["fbnc/diskcache"] debug_env = ["config/debug_env"] abci_mock = [] +fin_storage = ["storage", "fin_db"] [dev-dependencies] lazy_static = "1.4.0" @@ -58,11 +62,13 @@ features = ["f16", "serde"] [target.'cfg(not(target_arch = "wasm32"))'.dependencies] parking_lot = "0.12" -# sodiumoxide = "0.2.1" fs2 = "0.4" +storage = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.6", optional = true } +fin_db = { git = "https://github.com/FindoraNetwork/storage.git", tag = "v1.1.6", optional = true } +sparse_merkle_tree = { git = "https://github.com/FindoraNetwork/platform-lib-sparse-merkle", branch = "develop" } [target.'cfg(target_arch = "wasm32")'.dependencies] parking_lot = { version = "0.11.1", features = ["wasm-bindgen"] } [build-dependencies] -vergen = "=3.1.0" +vergen = "=3.1.0" \ No newline at end of file diff --git a/src/ledger/src/data_model/__trash__.rs b/src/ledger/src/data_model/__trash__.rs index ee27a584d..b73009afc 100644 --- a/src/ledger/src/data_model/__trash__.rs +++ b/src/ledger/src/data_model/__trash__.rs @@ -12,8 +12,7 @@ use { crate::data_model::AssetTypeCode, fixed::types::I20F12, serde::{Deserialize, Serialize}, - zei::noah_api::xfr::structs::AssetType, - zei::XfrPublicKey, + zei::{noah_api::xfr::structs::AssetType, XfrPublicKey}, }; #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)] diff --git a/src/ledger/src/data_model/effects.rs b/src/ledger/src/data_model/effects.rs index 09ccea520..e086a2034 100644 --- a/src/ledger/src/data_model/effects.rs +++ b/src/ledger/src/data_model/effects.rs @@ -1,10 +1,10 @@ -use zei::noah_api::parameters::bulletproofs::BulletproofParams; use { crate::{ data_model::{ - AssetType, AssetTypeCode, DefineAsset, IssueAsset, IssuerPublicKey, Memo, - NoReplayToken, Operation, Transaction, TransferAsset, TransferType, - TxOutput, TxnTempSID, TxoRef, TxoSID, UpdateMemo, + AbarConvNote, AbarToBarOps, AnonTransferOps, AssetType, AssetTypeCode, + BarToAbarOps, DefineAsset, IssueAsset, IssuerPublicKey, Memo, NoReplayToken, + Operation, Transaction, TransferAsset, TransferType, TxOutput, TxnTempSID, + TxoRef, TxoSID, UpdateMemo, }, staking::{ self, @@ -30,9 +30,16 @@ use { }, zei::{ noah_algebra::serialization::NoahFromToBytes, - noah_api::xfr::{ - structs::{XfrAmount, XfrAssetType}, - verify_xfr_body, + noah_api::{ + anon_xfr::{ + abar_to_abar::AXfrNote, + structs::{AnonAssetRecord, Nullifier}, + }, + parameters::bulletproofs::BulletproofParams, + xfr::{ + structs::{XfrAmount, XfrAssetType}, + verify_xfr_body, + }, }, XfrPublicKey, }, @@ -91,6 +98,12 @@ pub struct TxnEffect { pub fra_distributions: Vec, /// Staking operations pub update_stakers: Vec, + /// Newly created Anon Blind Asset Records + pub bar_conv_abars: Vec, + /// Body of Abar to Bar conversions + pub abar_conv_inputs: Vec, + /// New anon transfer bodies + pub axfr_bodies: Vec, /// replace staker operations pub replace_stakers: Vec, } @@ -197,6 +210,18 @@ impl TxnEffect { Operation::ConvertAccount(i) => { check_nonce!(i) } + Operation::BarToAbar(i) => { + check_nonce!(i); + te.add_bar_to_abar(i).c(d!())?; + } + Operation::AbarToBar(i) => { + check_nonce!(i); + te.add_abar_to_bar(i).c(d!())?; + } + Operation::TransferAnonAsset(i) => { + check_nonce!(i); + te.add_anon_transfer(i).c(d!())?; + } } } @@ -323,10 +348,10 @@ impl TxnEffect { // 1) The signatures on the body (a) all are valid and (b) // there is a signature for each input key // - Fully checked here - // 2) The UTXOs (a) exist on the ledger and (b) match the zei transaction. + // 2) The UTXOs (a) exist on the ledger and (b) match the noah transaction. // - Partially checked here -- anything which hasn't // been checked will appear in `input_txos` - // 3) The zei transaction is valid. + // 3) The noah transaction is valid. // - Checked here and in check_txn_effects // 4) Lien assignments match up // - Checked within a transaction here, recorded for @@ -348,14 +373,72 @@ impl TxnEffect { return Err(eg!()); } - // Transfer outputs must match outputs zei transaction + // Refuse any transfer with policies for now + let c1 = trn + .body + .policies + .inputs_tracing_policies + .iter() + .any(|x| !x.is_empty()); + let c2 = trn + .body + .policies + .outputs_tracing_policies + .iter() + .any(|x| !x.is_empty()); + let c3 = trn + .body + .policies + .inputs_sig_commitments + .iter() + .any(|x| !x.is_none()); + let c4 = trn + .body + .policies + .outputs_sig_commitments + .iter() + .any(|x| !x.is_none()); + let c5 = trn + .body + .transfer + .asset_tracing_memos + .iter() + .any(|x| !x.is_empty()); + let c6 = trn + .body + .transfer + .proofs + .asset_tracing_proof + .inputs_identity_proofs + .iter() + .any(|x| !x.is_empty()); + let c7 = trn + .body + .transfer + .proofs + .asset_tracing_proof + .outputs_identity_proofs + .iter() + .any(|x| !x.is_empty()); + let c8 = !trn + .body + .transfer + .proofs + .asset_tracing_proof + .asset_type_and_amount_proofs + .is_empty(); + if c1 || c2 || c3 || c4 || c5 || c6 || c7 || c8 { + return Err(eg!()); + } + + // Transfer outputs must match outputs noah transaction for (output, record) in trn .body .outputs .iter() .zip(trn.body.transfer.outputs.iter()) { - if output.record != *record { + if output.record != record.clone() { return Err(eg!()); } } @@ -455,7 +538,8 @@ impl TxnEffect { } Some(txo) => { // (2).(b) - if &txo.record != record || txo.lien != lien.cloned() { + if txo.record != record.clone() || txo.lien != lien.cloned() + { return Err(eg!()); } self.internally_spent_txos.push(txo.clone()); @@ -535,6 +619,75 @@ impl TxnEffect { Ok(()) } + + /// A bar to abar note is valid iff + /// 1. the signature is correct, + /// 2. the ZKP can be verified, + /// 3. the input txos are unspent. (checked in finish block) + /// # Arguments + /// * `bar_to_abar` - the BarToAbar Operation body + /// returns error if validation fails + fn add_bar_to_abar(&mut self, bar_to_abar: &BarToAbarOps) -> Result<()> { + // verify the note signature & Plonk proof + bar_to_abar.verify()?; + + // list input_txo to spend + self.input_txos.insert( + bar_to_abar.txo_sid, + TxOutput { + id: None, + record: bar_to_abar.input_record(), + lien: None, + }, + ); + // push new ABAR created + self.bar_conv_abars.push(bar_to_abar.output_record()); + Ok(()) + } + + /// An abar to bar note is valid iff + /// 1. the signature is correct, + /// 2. the ZKP can be verified, + /// 3. the input ABARs are unspent. (checked in finish block) + /// # Arguments + /// * abar_to_bar - The Operation for AbarToBar + /// returns an error if validation fails + fn add_abar_to_bar(&mut self, abar_to_bar: &AbarToBarOps) -> Result<()> { + // collect body in TxnEffect to verify ZKP later with merkle root + self.abar_conv_inputs.push(abar_to_bar.note.clone()); + // collect newly created BARs + self.txos.push(Some(TxOutput { + id: None, + record: abar_to_bar.note.get_output(), + lien: None, + })); + + Ok(()) + } + + /// An anon transfer note is valid iff + /// 1. no double spending in the txn, + /// 2. the signature is correct, + /// 3. ZKP can be verified, + /// 4. the input ABARs are unspent. (checked in finish block) + /// # Arguments + /// * anon_transfer - The Operation for Anon Transfer + /// returns an error if validation fails + fn add_anon_transfer(&mut self, anon_transfer: &AnonTransferOps) -> Result<()> { + // verify nullifiers not double spent within txn + for i in &anon_transfer.note.body.inputs { + if self + .axfr_bodies + .iter() + .flat_map(|ab| ab.body.inputs.iter()) + .any(|n| n == i) + { + return Err(eg!("Transaction has duplicate nullifiers")); + } + } + self.axfr_bodies.push(anon_transfer.note.clone()); + Ok(()) + } } /// Check tx in the context of a block, partially. @@ -550,8 +703,12 @@ pub struct BlockEffect { /// Internally-spent TXOs are None, UTXOs are Some(...) /// Should line up element-wise with `txns` pub txos: Vec>>, + /// New ABARs created + pub output_abars: Vec>, /// Which TXOs this consumes pub input_txos: HashMap, + /// Which new nullifiers are created + pub new_nullifiers: Vec, /// Which new asset types this defines pub new_asset_codes: HashMap, /// Which new TXO issuance sequence numbers are used, in sorted order @@ -614,6 +771,29 @@ impl BlockEffect { self.memo_updates.insert(code, memo); } + // collect ABARs generated from BAR to ABAR + let mut current_txn_abars: Vec = vec![]; + for abar in txn_effect.bar_conv_abars { + current_txn_abars.push(abar); + } + + // collect Nullifiers generated from ABAR to BAR + for inputs in txn_effect.abar_conv_inputs.iter() { + self.new_nullifiers.push(inputs.get_input()); + } + + // collect ABARs and Nullifiers from Anon Transfers + for axfr_note in txn_effect.axfr_bodies { + for n in axfr_note.body.inputs { + self.new_nullifiers.push(n); + } + for abar in axfr_note.body.outputs { + current_txn_abars.push(abar) + } + } + + self.output_abars.push(current_txn_abars); + Ok(temp_sid) } @@ -625,6 +805,21 @@ impl BlockEffect { } } + // Check that no nullifier is created twice in the same block + // for anon_transfer and abar to bar conversion + for axfr_note in txn_effect.axfr_bodies.iter() { + for nullifier in axfr_note.body.inputs.iter() { + if self.new_nullifiers.contains(nullifier) { + return Err(eg!()); + } + } + } + for inputs in txn_effect.abar_conv_inputs.iter() { + if self.new_nullifiers.contains(&inputs.get_input()) { + return Err(eg!()); + } + } + // Check that no AssetType is affected by both the block so far and // this transaction { diff --git a/src/ledger/src/data_model/mod.rs b/src/ledger/src/data_model/mod.rs index 22542b9fd..25f4d3cce 100644 --- a/src/ledger/src/data_model/mod.rs +++ b/src/ledger/src/data_model/mod.rs @@ -12,21 +12,24 @@ mod test; pub use effects::{BlockEffect, TxnEffect}; use { - crate::converter::ConvertAccount, - crate::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, + crate::{ + converter::ConvertAccount, + 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, + }, + Staking, }, - Staking, }, __trash__::{Policy, PolicyGlobals, TxnPolicyData}, bitmap::SparseMap, config::abci::CheckPointConfig, cryptohash::{sha256::Digest as BitDigest, HashValue}, + digest::{consts::U64, Digest}, fbnc::NumKey, globutils::wallet::public_key_to_base64, globutils::{HashOf, ProofOf, Serialized, SignatureOf}, @@ -52,7 +55,20 @@ use { traits::Scalar, }, noah_api::{ + anon_xfr::{ + abar_to_abar::AXfrNote, + abar_to_ar::{verify_abar_to_ar_note, AbarToArNote}, + abar_to_bar::{verify_abar_to_bar_note, AbarToBarNote}, + ar_to_abar::{verify_ar_to_abar_note, ArToAbarNote}, + bar_to_abar::{verify_bar_to_abar_note, BarToAbarNote}, + commit, + structs::{ + AnonAssetRecord, AxfrOwnerMemo, Nullifier, OpenAnonAssetRecord, + }, + AXfrAddressFoldingInstance, + }, keys::PublicKey as NoahXfrPublicKey, + parameters::{AddressFormat, VerifierParams}, xfr::{ gen_xfr_body, structs::{ @@ -479,7 +495,7 @@ pub struct XfrAddress { } impl XfrAddress { - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "fin_storage"))] pub(crate) fn to_base64(self) -> String { b64enc(&self.key.to_bytes()) } @@ -505,7 +521,7 @@ pub struct IssuerPublicKey { } impl IssuerPublicKey { - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "fin_storage"))] pub(crate) fn to_base64(self) -> String { b64enc(&self.key.noah_to_bytes().as_slice()) } @@ -578,7 +594,7 @@ impl SignatureRules { /// Keyset must store XfrPublicKeys in byte form. pub fn check_signature_set(&self, keyset: &HashSet>) -> Result<()> { let mut sum: u64 = 0; - let mut weight_map = HashMap::new(); + let mut weight_map: HashMap, u64> = HashMap::new(); // Convert to map for (key, weight) in self.weights.iter() { weight_map.insert(key.to_bytes(), *weight); @@ -586,7 +602,7 @@ impl SignatureRules { // Calculate weighted sum for key in keyset.iter() { sum = sum - .checked_add(*weight_map.get(&key[..]).unwrap_or(&0)) + .checked_add(*weight_map.get::<[u8]>(&key.as_slice()).unwrap_or(&0)) .c(d!())?; } @@ -795,6 +811,22 @@ impl NumKey for TxoSID { #[allow(missing_docs)] pub type TxoSIDList = Vec; +#[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + Eq, + Hash, + PartialEq, + Serialize, + Ord, + PartialOrd, +)] +#[allow(missing_docs)] +pub struct ATxoSID(pub u64); + #[allow(missing_docs)] #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct OutputPosition(pub usize); @@ -869,7 +901,7 @@ pub enum UtxoStatus { pub struct Utxo(pub TxOutput); impl Utxo { - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "fin_storage"))] #[inline(always)] pub(crate) fn get_nonconfidential_balance(&self) -> u64 { if let XfrAmount::NonConfidential(n) = self.0.record.amount { @@ -1014,10 +1046,10 @@ impl TransferAssetBody { keypair: &XfrKeyPair, input_idx: Option, ) -> IndexedSignature { - let public_key = keypair.get_pk_ref(); + let public_key = keypair.get_pk(); IndexedSignature { - signature: SignatureOf::new(keypair, &(self.clone(), input_idx)), - address: XfrAddress { key: *public_key }, + signature: SignatureOf::new(&keypair, &(self.clone(), input_idx)), + address: XfrAddress { key: public_key }, input_idx, } } @@ -1232,13 +1264,8 @@ impl TransferAsset { #[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() + pub fn get_owner_memos_ref(&self) -> Vec> { + self.body.transfer.owners_memos.to_vec() } #[inline(always)] @@ -1286,11 +1313,11 @@ impl IssueAsset { #[inline(always)] #[allow(missing_docs)] - pub fn get_owner_memos_ref(&self) -> Vec> { + pub fn get_owner_memos_ref(&self) -> Vec> { self.body .records .iter() - .map(|(_, memo)| memo.as_ref()) + .map(|(_, memo)| memo.clone()) .collect() } @@ -1346,7 +1373,7 @@ impl UpdateMemo { update_memo_body: UpdateMemoBody, signing_key: &XfrKeyPair, ) -> UpdateMemo { - let signature = SignatureOf::new(signing_key, &update_memo_body); + let signature = SignatureOf::new(&signing_key, &update_memo_body); UpdateMemo { body: update_memo_body, pubkey: *signing_key.get_pk_ref(), @@ -1355,6 +1382,281 @@ impl UpdateMemo { } } +/// A note which enumerates the transparent and confidential BAR to +/// Anon Asset record conversion. +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub enum BarAnonConvNote { + /// A transfer note with ZKP for a confidential asset record + BarNote(Box), + /// A transfer note with ZKP for a non-confidential asset record + ArNote(Box), +} + +/// Operation for converting a Blind Asset Record to an Anonymous record +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct BarToAbarOps { + /// the note which contains the inp/op and ZKP + pub note: BarAnonConvNote, + /// The TxoSID of the the input BAR + pub txo_sid: TxoSID, + nonce: NoReplayToken, +} + +impl BarToAbarOps { + /// Generates a new BarToAbarOps object + /// # Arguments + /// * bar_to_abar_note - The BarToAbarNote of the conversion + /// * txo_sid - the TxoSID of the converting BAR + /// * nonce + pub fn new( + note: BarAnonConvNote, + txo_sid: TxoSID, + nonce: NoReplayToken, + ) -> Result { + Ok(BarToAbarOps { + note, + txo_sid, + nonce, + }) + } + + /// verifies the signatures and proof of the note + pub fn verify(&self) -> Result<()> { + match &self.note { + BarAnonConvNote::BarNote(note) => { + // fetch the verifier Node Params for PlonkProof + let node_params = VerifierParams::get_bar_to_abar().c(d!())?; + // verify the Plonk proof and signature + verify_bar_to_abar_note(&node_params, ¬e, ¬e.body.input.public_key) + .c(d!()) + } + BarAnonConvNote::ArNote(note) => { + // fetch the verifier Node Params for PlonkProof + let node_params = VerifierParams::get_ar_to_abar().c(d!())?; + // verify the Plonk proof and signature + verify_ar_to_abar_note(&node_params, note).c(d!()) + } + } + } + + /// provides a copy of the input record in the note + pub fn input_record(&self) -> BlindAssetRecord { + match &self.note { + BarAnonConvNote::BarNote(n) => BlindAssetRecord::from_noah(&n.body.input), + BarAnonConvNote::ArNote(n) => BlindAssetRecord::from_noah(&n.body.input), + } + } + + /// provides a copy of the output record of the note. + pub fn output_record(&self) -> AnonAssetRecord { + match &self.note { + BarAnonConvNote::BarNote(n) => n.body.output.clone(), + BarAnonConvNote::ArNote(n) => n.body.output.clone(), + } + } + + /// provides a copy of the AxfrOwnerMemo in the note + pub fn axfr_memo(&self) -> AxfrOwnerMemo { + match &self.note { + BarAnonConvNote::BarNote(n) => n.body.memo.clone(), + BarAnonConvNote::ArNote(n) => n.body.memo.clone(), + } + } + + #[inline(always)] + /// Sets the nonce for the operation + pub fn set_nonce(&mut self, nonce: NoReplayToken) { + self.nonce = nonce; + } + + #[inline(always)] + /// Fetches the nonce of the operation + pub fn get_nonce(&self) -> NoReplayToken { + self.nonce + } +} + +/// AbarConvNote +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub enum AbarConvNote { + /// Conversion to a amount or type confidential BAR + AbarToBar(Box), + /// Conversion to a transparent BAR + AbarToAr(Box), +} + +impl AbarConvNote { + /// Verifies the ZKP based on the type of conversion + pub fn verify + Default>( + &self, + merkle_root: BN254Scalar, + hasher: D, + ) -> ruc::Result<()> { + match self { + AbarConvNote::AbarToBar(note) => { + let af = match note.folding_instance { + AXfrAddressFoldingInstance::Secp256k1(_) => AddressFormat::SECP256K1, + AXfrAddressFoldingInstance::Ed25519(_) => AddressFormat::ED25519, + }; + let abar_to_bar_verifier_params = + VerifierParams::get_abar_to_bar(af).c(d!())?; + // An axfr_abar_conv requires versioned merkle root hash for verification. + // verify zk proof with merkle root + verify_abar_to_bar_note( + &abar_to_bar_verifier_params, + ¬e, + &merkle_root, + hasher, + ) + .c(d!("Abar to Bar conversion proof verification failed")) + } + AbarConvNote::AbarToAr(note) => { + let af = match note.folding_instance { + AXfrAddressFoldingInstance::Secp256k1(_) => AddressFormat::SECP256K1, + AXfrAddressFoldingInstance::Ed25519(_) => AddressFormat::ED25519, + }; + let abar_to_ar_verifier_params = + VerifierParams::get_abar_to_ar(af).c(d!())?; + // An axfr_abar_conv requires versioned merkle root hash for verification. + // verify zk proof with merkle root + verify_abar_to_ar_note( + &abar_to_ar_verifier_params, + ¬e, + &merkle_root, + hasher, + ) + .c(d!("Abar to AR conversion proof verification failed")) + } + } + } + + /// input nullifier in the note body + pub fn get_input(&self) -> Nullifier { + match self { + AbarConvNote::AbarToBar(note) => note.body.input, + AbarConvNote::AbarToAr(note) => note.body.input, + } + } + + /// merkle root version of the proof + pub fn get_merkle_root_version(&self) -> u64 { + match self { + AbarConvNote::AbarToBar(note) => note.body.merkle_root_version, + AbarConvNote::AbarToAr(note) => note.body.merkle_root_version, + } + } + + /// public key of the note body + pub fn get_public_key(&self) -> XfrPublicKey { + match self { + AbarConvNote::AbarToBar(note) => { + XfrPublicKey::from_noah(¬e.body.output.public_key) + } + AbarConvNote::AbarToAr(note) => { + XfrPublicKey::from_noah(¬e.body.output.public_key) + } + } + } + + /// output BAR of the note body + pub fn get_output(&self) -> BlindAssetRecord { + match self { + AbarConvNote::AbarToBar(note) => { + BlindAssetRecord::from_noah(¬e.body.output) + } + AbarConvNote::AbarToAr(note) => { + BlindAssetRecord::from_noah(¬e.body.output) + } + } + } + + /// gets address of owner memo in the note body + pub fn get_owner_memos_ref(&self) -> Vec> { + match self { + AbarConvNote::AbarToBar(note) => { + vec![note + .body + .memo + .as_ref() + .map(|om| OwnerMemo::from_noah(om).unwrap())] + } + AbarConvNote::AbarToAr(note) => { + vec![note + .body + .memo + .as_ref() + .map(|om| OwnerMemo::from_noah(om).unwrap())] + } + } + } + + /// get serialized bytes for signature and prove (only ABAR body). + pub fn digest(&self) -> Vec { + match self { + AbarConvNote::AbarToBar(note) => { + Serialized::new(¬e.body).as_ref().to_vec() + } + AbarConvNote::AbarToAr(note) => { + Serialized::new(¬e.body).as_ref().to_vec() + } + } + } +} + +/// Operation for converting a Blind Asset Record to a Anonymous record +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct AbarToBarOps { + /// the note which contains the inp/op and ZKP + pub note: AbarConvNote, + nonce: NoReplayToken, +} + +impl AbarToBarOps { + /// Generates a new BarToAbarOps object + pub fn new(note: AbarConvNote, nonce: NoReplayToken) -> Result { + Ok(AbarToBarOps { note, nonce }) + } + + #[inline(always)] + /// Sets the nonce for the operation + pub fn set_nonce(&mut self, nonce: NoReplayToken) { + self.nonce = nonce; + } + + #[inline(always)] + /// Fetches the nonce of the operation + pub fn get_nonce(&self) -> NoReplayToken { + self.nonce + } +} + +/// A struct to hold the transfer ops +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct AnonTransferOps { + /// The note which holds the signatures, the ZKF and memo + pub note: AXfrNote, + nonce: NoReplayToken, +} +impl AnonTransferOps { + /// Generates the anon transfer note + pub fn new(note: AXfrNote, nonce: NoReplayToken) -> Result { + Ok(AnonTransferOps { note, nonce }) + } + + /// Sets the nonce for the operation + #[inline(always)] + #[allow(dead_code)] + fn set_nonce(&mut self, nonce: NoReplayToken) { + self.nonce = nonce; + } + + /// Fetches the nonce of the operation + #[inline(always)] + fn get_nonce(&self) -> NoReplayToken { + self.nonce + } +} + /// Operation list supported in findora network #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub enum Operation { @@ -1384,35 +1686,57 @@ pub enum Operation { MintFra(MintFraOps), /// Convert UTXOs to EVM Account balance ConvertAccount(ConvertAccount), + /// Anonymous conversion operation + BarToAbar(Box), + /// De-anonymize ABAR operation + AbarToBar(Box), + /// Anonymous transfer operation + TransferAnonAsset(Box), ///replace staker. ReplaceStaker(ReplaceStakerOps), } +impl Operation { + /// get serialized bytes for signature and prove. + pub fn digest(&self) -> Vec { + match self { + Operation::UpdateStaker(i) => Serialized::new(i).as_ref().to_vec(), + Operation::Delegation(i) => Serialized::new(i).as_ref().to_vec(), + Operation::UnDelegation(i) => Serialized::new(i).as_ref().to_vec(), + Operation::Claim(i) => Serialized::new(i).as_ref().to_vec(), + Operation::FraDistribution(i) => Serialized::new(i).as_ref().to_vec(), + Operation::UpdateValidator(i) => Serialized::new(i).as_ref().to_vec(), + Operation::Governance(i) => Serialized::new(i).as_ref().to_vec(), + Operation::UpdateMemo(i) => Serialized::new(i).as_ref().to_vec(), + Operation::ConvertAccount(i) => Serialized::new(i).as_ref().to_vec(), + Operation::BarToAbar(i) => Serialized::new(i).as_ref().to_vec(), + Operation::ReplaceStaker(i) => Serialized::new(i).as_ref().to_vec(), + Operation::TransferAsset(i) => Serialized::new(i).as_ref().to_vec(), + Operation::IssueAsset(i) => Serialized::new(i).as_ref().to_vec(), + Operation::DefineAsset(i) => Serialized::new(i).as_ref().to_vec(), + Operation::MintFra(i) => Serialized::new(i).as_ref().to_vec(), + Operation::AbarToBar(i) => i.note.digest(), + Operation::TransferAnonAsset(i) => { + Serialized::new(&i.note.body).as_ref().to_vec() + } + } + } +} + fn set_no_replay_token(op: &mut Operation, no_replay_token: NoReplayToken) { match op { - Operation::UpdateStaker(i) => { - i.set_nonce(no_replay_token); - } - Operation::Delegation(i) => { - i.set_nonce(no_replay_token); - } - Operation::UnDelegation(i) => { - i.set_nonce(no_replay_token); - } - Operation::Claim(i) => { - i.set_nonce(no_replay_token); - } - Operation::FraDistribution(i) => { - i.set_nonce(no_replay_token); - } - Operation::UpdateValidator(i) => { - i.set_nonce(no_replay_token); - } - Operation::Governance(i) => { - i.set_nonce(no_replay_token); - } + Operation::UpdateStaker(i) => i.set_nonce(no_replay_token), + Operation::Delegation(i) => i.set_nonce(no_replay_token), + Operation::UnDelegation(i) => i.set_nonce(no_replay_token), + Operation::Claim(i) => i.set_nonce(no_replay_token), + Operation::FraDistribution(i) => i.set_nonce(no_replay_token), + Operation::UpdateValidator(i) => i.set_nonce(no_replay_token), + Operation::Governance(i) => i.set_nonce(no_replay_token), Operation::UpdateMemo(i) => i.body.no_replay_token = no_replay_token, Operation::ConvertAccount(i) => i.set_nonce(no_replay_token), + Operation::BarToAbar(i) => i.set_nonce(no_replay_token), + Operation::AbarToBar(i) => i.set_nonce(no_replay_token), + Operation::TransferAnonAsset(i) => i.set_nonce(no_replay_token), _ => {} } } @@ -1440,6 +1764,19 @@ impl TransactionBody { result.no_replay_token = no_replay_token; result } + + /// get serialized bytes for signature and prove. + pub fn digest(&self) -> Vec { + let mut bytes = vec![]; + bytes.extend_from_slice(Serialized::new(&self.no_replay_token).as_ref()); + bytes.extend_from_slice(Serialized::new(&self.credentials).as_ref()); + bytes.extend_from_slice(Serialized::new(&self.policy_options).as_ref()); + bytes.extend_from_slice(Serialized::new(&self.memos).as_ref()); + for o in &self.operations { + bytes.extend_from_slice(&o.digest()); + } + bytes + } } #[allow(missing_docs)] @@ -1460,6 +1797,8 @@ pub struct FinalizedTransaction { pub txn: Transaction, pub tx_id: TxnSID, pub txo_ids: Vec, + #[serde(default)] + pub atxo_ids: Vec, pub merkle_id: u64, } @@ -1743,7 +2082,15 @@ 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: u64 = 10_000; // 0.01 FRA +/// Double the regular fee +pub const BAR_TO_ABAR_TX_FEE_MIN: u64 = 20_000; // 0.02 FRA (2*TX_FEE_MIN) + +/// Calculate the FEE with inputs and outputs number. +pub const FEE_CALCULATING_FUNC: fn(u32, u32) -> u32 = |x: u32, y: u32| { + let extra_outputs = y.saturating_sub(x); + 50_0000 + 10_0000 * x + 20_0000 * y + (10_000 * extra_outputs) +}; impl Transaction { #[inline(always)] @@ -1761,6 +2108,7 @@ impl Transaction { self.check_fee() && !self.is_coinbase_tx() } + #[allow(clippy::if_same_then_else)] /// A simple fee checker /// /// The check logic is as follows: @@ -1775,6 +2123,15 @@ impl Transaction { // // But it seems enough when we combine it with limiting // the payload size of submission-server's http-requests. + + let mut min_fee = TX_FEE_MIN; + // Charge double the min fee if the transaction is BarToAbar + for op in self.body.operations.iter() { + if let Operation::BarToAbar(_a) = op { + min_fee = BAR_TO_ABAR_TX_FEE_MIN; + } + } + self.is_coinbase_tx() || self.body.operations.iter().any(|ops| { if let Operation::TransferAsset(ref x) = ops { @@ -1785,12 +2142,13 @@ impl Transaction { == o.record.public_key { if let XfrAmount::NonConfidential(am) = o.record.amount { - if am > (TX_FEE_MIN - 1) { + if am > (min_fee - 1) { return true; } } } } + tracing::error!("Txn failed in check_fee {:?}", self); false }); } else if let Operation::DefineAsset(ref x) = ops { @@ -1801,9 +2159,16 @@ impl Transaction { if x.body.code.val == ASSET_TYPE_FRA { return true; } + } else if let Operation::TransferAnonAsset(_) = ops { + return true; + } else if let Operation::BarToAbar(_) = ops { + return true; + } else if let Operation::AbarToBar(_) = ops { + return true; } else if matches!(ops, Operation::UpdateValidator(_)) { return true; } + tracing::error!("Txn failed in check_fee {:?}", self); false }) } @@ -1900,7 +2265,7 @@ impl Transaction { #[inline(always)] #[allow(missing_docs)] - pub fn get_owner_memos_ref(&self) -> Vec> { + pub fn get_owner_memos_ref(&self) -> Vec> { let mut memos = Vec::new(); for op in self.body.operations.iter() { match op { @@ -1913,6 +2278,9 @@ impl Transaction { Operation::IssueAsset(issue_asset) => { memos.append(&mut issue_asset.get_owner_memos_ref()); } + Operation::AbarToBar(abar_to_bar) => { + memos.append(&mut abar_to_bar.note.get_owner_memos_ref()); + } _ => {} } } @@ -1949,7 +2317,7 @@ impl Transaction { 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) { + match sig.0.verify(&public_key, &serialized) { Err(_) => {} Ok(_) => { return Ok(()); @@ -1975,6 +2343,7 @@ impl Transaction { /// 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 + #[allow(missing_docs)] #[inline(always)] pub fn check_tx(&self) -> Result<()> { let select_check = |tx: &Transaction, pk: &XfrPublicKey| -> Result<()> { @@ -2027,6 +2396,9 @@ impl Transaction { } } } + Operation::BarToAbar(_) => {} + Operation::AbarToBar(_) => {} + Operation::TransferAnonAsset(_) => {} } } @@ -2069,6 +2441,23 @@ impl StateCommitmentData { } } +/// Commitment data for Anon merkle trees +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct AnonStateCommitmentData { + /// Root hash of the latest committed version of abar merkle tree + pub abar_root_hash: BN254Scalar, + /// Root hash of the nullifier set merkle tree + pub nullifier_root_hash: BitDigest, +} + +impl AnonStateCommitmentData { + #[inline(always)] + #[allow(missing_docs)] + pub fn compute_commitment(&self) -> HashOf> { + HashOf::new(&Some(self).cloned()) + } +} + /// Used in `Staking` logic to create consensus-tmp XfrPublicKey #[derive(Clone, Copy, Debug, Deserialize, Serialize, Eq, PartialEq, Default)] pub struct ConsensusRng(u32); @@ -2094,3 +2483,22 @@ impl RngCore for ConsensusRng { pub fn gen_random_keypair() -> XfrKeyPair { XfrKeyPair::generate(&mut ChaChaRng::from_entropy()) } + +#[inline(always)] +#[allow(missing_docs)] +pub fn get_abar_commitment(oabar: OpenAnonAssetRecord) -> BN254Scalar { + let c = commit( + oabar.pub_key_ref(), + oabar.get_blind(), + oabar.get_amount(), + oabar.get_asset_type().as_scalar(), + ) + .unwrap(); + c.0 +} + +#[derive(Serialize, Deserialize)] +#[allow(missing_docs)] +pub struct ABARData { + pub commitment: String, +} diff --git a/src/ledger/src/data_model/test.rs b/src/ledger/src/data_model/test.rs old mode 100644 new mode 100755 index 6476bba6c..01e157ea2 --- a/src/ledger/src/data_model/test.rs +++ b/src/ledger/src/data_model/test.rs @@ -10,7 +10,7 @@ use { ristretto, xfr::structs::{AssetTypeAndAmountProof, XfrProofs}, }, - XfrBody + XfrBody, }, }; @@ -27,7 +27,6 @@ macro_rules! msg_eq { }; } - const UTF8_ASSET_TYPES_WORK: bool = false; // This test may fail as it is a statistical test that sometimes fails (but very rarely) diff --git a/src/ledger/src/lib.rs b/src/ledger/src/lib.rs index 8d15bac66..10b83a333 100644 --- a/src/ledger/src/lib.rs +++ b/src/ledger/src/lib.rs @@ -10,7 +10,7 @@ pub mod data_model; pub mod converter; pub mod staking; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(not(target_arch = "wasm32"), feature = "fin_storage"))] pub mod store; use {ruc::*, std::sync::atomic::AtomicI64}; diff --git a/src/ledger/src/staking/mod.rs b/src/ledger/src/staking/mod.rs index 60633a796..7a42430b2 100644 --- a/src/ledger/src/staking/mod.rs +++ b/src/ledger/src/staking/mod.rs @@ -12,7 +12,7 @@ #![deny(missing_docs)] #![allow(clippy::upper_case_acronyms)] -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(not(target_arch = "wasm32"), feature = "fin_storage"))] use {num_bigint::BigUint, std::convert::TryFrom}; pub mod cosig; @@ -51,8 +51,7 @@ use { Arc, }, }, - zei::noah_api::keys::PublicKey as NoahXfrPublicKey, - zei::{XfrKeyPair, XfrPublicKey}, + zei::{noah_api::keys::PublicKey as NoahXfrPublicKey, XfrKeyPair, XfrPublicKey}, }; // height, reward rate @@ -1605,7 +1604,7 @@ impl Staking { &self.coinbase.distribution_plan } - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "fin_storage"))] /// set_proposer_rewards sets the rewards for the block proposer /// All rewards are allocated to the proposer only pub(crate) fn set_proposer_rewards( @@ -1647,7 +1646,7 @@ impl Staking { .map(|_| ()) } - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "fin_storage"))] fn get_proposer_rewards_rate(vote_percent: [u64; 2]) -> Result<[u128; 2]> { let p = [vote_percent[0] as u128, vote_percent[1] as u128]; // p[0] = Validator power which voted for this block @@ -2100,7 +2099,7 @@ impl Delegation { } #[inline(always)] - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "fin_storage"))] pub(crate) fn validator_entry_exists(&self, validator: &XfrPublicKey) -> bool { self.delegations.contains_key(validator) } @@ -2120,7 +2119,7 @@ impl Delegation { // > **NOTE:** // > use 'AssignAdd' instead of 'Assign' // > to keep compatible with the logic of governance penalty. - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), feature = "fin_storage"))] #[allow(clippy::too_many_arguments)] pub(crate) fn set_delegation_rewards( &mut self, @@ -2209,7 +2208,7 @@ impl Delegation { // Calculate the amount(in FRA units) that // should be paid to the owner of this delegation. -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(not(target_arch = "wasm32"), feature = "fin_storage"))] fn calculate_delegation_rewards( return_rate: [u128; 2], amount: Amount, diff --git a/src/ledger/src/staking/ops/delegation.rs b/src/ledger/src/staking/ops/delegation.rs index c0af11244..635706da2 100644 --- a/src/ledger/src/staking/ops/delegation.rs +++ b/src/ledger/src/staking/ops/delegation.rs @@ -23,7 +23,7 @@ use { tendermint::{signature::Ed25519Signature, PrivateKey, PublicKey, Signature}, zei::{ noah_api::xfr::structs::{XfrAmount, XfrAssetType}, - {XfrKeyPair, XfrPublicKey, XfrSignature}, + XfrKeyPair, XfrPublicKey, XfrSignature, }, }; diff --git a/src/ledger/src/staking/ops/mint_fra.rs b/src/ledger/src/staking/ops/mint_fra.rs index 33c86e2a3..46b07fb0c 100644 --- a/src/ledger/src/staking/ops/mint_fra.rs +++ b/src/ledger/src/staking/ops/mint_fra.rs @@ -48,7 +48,7 @@ impl MintFraOps { #[inline(always)] #[allow(missing_docs)] - pub fn get_owner_memos_ref(&self) -> Vec> { + pub fn get_owner_memos_ref(&self) -> Vec> { vec![None; self.entries.len()] } } diff --git a/src/ledger/src/store/api_cache.rs b/src/ledger/src/store/api_cache.rs index 2479cbb59..ad7077bf5 100644 --- a/src/ledger/src/store/api_cache.rs +++ b/src/ledger/src/store/api_cache.rs @@ -4,8 +4,9 @@ use { crate::{ data_model::{ - AssetTypeCode, AssetTypePrefix, DefineAsset, IssueAsset, IssuerPublicKey, - Operation, Transaction, TxOutput, TxnIDHash, TxnSID, TxoSID, XfrAddress, + ATxoSID, AssetTypeCode, AssetTypePrefix, DefineAsset, IssueAsset, + IssuerPublicKey, Operation, StateCommitmentData, Transaction, TxOutput, + TxnIDHash, TxnSID, TxoSID, XfrAddress, }, staking::{ ops::mint_fra::MintEntry, Amount, BlockHeight, DelegationRwdDetail, @@ -15,11 +16,11 @@ use { }, config::abci::global_cfg::CFG, fbnc::{new_mapx, new_mapxnk, Mapx, Mapxnk}, - globutils::wallet, + globutils::{wallet, HashOf}, ruc::*, serde::{Deserialize, Serialize}, std::collections::HashSet, - zei::{OwnerMemo, XfrPublicKey}, + zei::{noah_api::anon_xfr::structs::AxfrOwnerMemo, OwnerMemo, XfrPublicKey}, }; type Issuances = Vec<(TxOutput, Option)>; @@ -44,14 +45,20 @@ pub struct ApiCache { pub token_code_issuances: Mapx, /// used in confidential tx pub owner_memos: Mapxnk, + /// used in anonymous tx + pub abar_memos: Mapx, /// ownship of txo pub utxos_to_map_index: Mapxnk, /// txo(spent, unspent) to authenticated txn (sid, hash) pub txo_to_txnid: Mapxnk, + /// atxo to authenticated txn (sid, hash) + pub atxo_to_txnid: Mapx, /// txn sid to txn hash pub txn_sid_to_hash: Mapxnk, /// txn hash to txn sid pub txn_hash_to_sid: Mapx, + /// max (latest) atxo sid at block height + pub height_to_max_atxo: Mapxnk>, /// global rate history pub staking_global_rate_hist: Mapxnk, /// - self-delegation amount history @@ -66,6 +73,9 @@ pub struct ApiCache { Mapx>, /// there are no transactions lost before last_sid pub last_sid: Mapx, + /// State commitment history. + /// The BitDigest at index i is the state commitment of the ledger at block height i + 1. + pub state_commitment_version: Option>>, } impl ApiCache { @@ -88,15 +98,20 @@ impl ApiCache { "api_cache/{prefix}token_code_issuances", )), owner_memos: new_mapxnk!(format!("api_cache/{prefix}owner_memos",)), + abar_memos: new_mapx!(format!("api_cache/{prefix}abar_memos",)), utxos_to_map_index: new_mapxnk!(format!( "api_cache/{prefix}utxos_to_map_index", )), txo_to_txnid: new_mapxnk!(format!("api_cache/{prefix}txo_to_txnid",)), + atxo_to_txnid: new_mapx!(format!("api_cache/{prefix}atxo_to_txnid",)), txn_sid_to_hash: new_mapxnk!(format!("api_cache/{prefix}txn_sid_to_hash",)), txn_hash_to_sid: new_mapx!(format!("api_cache/{prefix}txn_hash_to_sid",)), staking_global_rate_hist: new_mapxnk!(format!( "api_cache/{prefix}staking_global_rate_hist", )), + height_to_max_atxo: new_mapxnk!(format!( + "api_cache/{prefix}height_to_max_atxo", + )), staking_self_delegation_hist: new_mapx!(format!( "api_cache/{prefix}staking_self_delegation_hist", )), @@ -107,6 +122,7 @@ impl ApiCache { "api_cache/{prefix}staking_delegation_rwd_hist", )), last_sid: new_mapx!(format!("api_cache/{prefix}last_sid",)), + state_commitment_version: None, } } @@ -259,7 +275,19 @@ where Operation::Governance(i) => staking_gen!(i), Operation::FraDistribution(i) => staking_gen!(i), Operation::MintFra(i) => staking_gen!(i), - + Operation::BarToAbar(i) => { + related_addresses.insert(XfrAddress { + key: i.input_record().public_key, + }); + } + Operation::AbarToBar(i) => { + related_addresses.insert(XfrAddress { + key: i.note.get_public_key(), + }); + } + Operation::TransferAnonAsset(_) => { + // Anon + } Operation::ConvertAccount(i) => { related_addresses.insert(XfrAddress { key: i.get_related_address(), @@ -468,38 +496,45 @@ pub fn update_api_cache(ledger: &mut LedgerState) -> Result<()> { check_lost_data(ledger)?; - ledger.api_cache.as_mut().unwrap().cache_hist_data(); + let mut api_cache = ledger.api_cache.take().unwrap(); + + api_cache.cache_hist_data(); let block = if let Some(b) = ledger.blocks.last() { b } else { + ledger.api_cache = Some(api_cache); return Ok(()); }; - let prefix = ledger.api_cache.as_mut().unwrap().prefix.clone(); + let prefix = api_cache.prefix.clone(); + + // Update state commitment versions + api_cache.state_commitment_version = ledger.status.state_commitment_versions.last(); // Update ownership status - for (txn_sid, txo_sids) in block.txns.iter().map(|v| (v.tx_id, v.txo_ids.as_slice())) + for (txn_sid, txo_sids, atxo_sids) in block + .txns + .iter() + .map(|v| (v.tx_id, v.txo_ids.as_slice(), v.atxo_ids.as_slice())) { let curr_txn = ledger.get_transaction_light(txn_sid).c(d!())?.txn; // get the transaction, ownership addresses, and memos associated with each transaction let (addresses, owner_memos) = { - let addresses: Vec = txo_sids - .iter() - .map(|sid| XfrAddress { - key: ((ledger - .get_utxo_light(*sid) - .or_else(|| ledger.get_spent_utxo_light(*sid)) - .unwrap() - .utxo) - .0) - .record - .public_key, - }) - .collect(); + let mut addresses: Vec = vec![]; + for sid in txo_sids.iter() { + let key = ledger + .get_utxo_light(*sid) + .or_else(|| ledger.get_spent_utxo_light(*sid)) + .c(d!())? + .utxo + .0 + .record + .public_key; + addresses.push(XfrAddress { key }); + } let owner_memos = curr_txn.get_owner_memos_ref(); - (addresses, owner_memos) }; @@ -509,10 +544,7 @@ pub fn update_api_cache(ledger: &mut LedgerState) -> Result<()> { let key = XfrAddress { key: i.get_claim_publickey(), }; - ledger - .api_cache - .as_mut() - .unwrap() + api_cache .claim_hist_txns .entry(key) .or_insert_with(|| { @@ -529,13 +561,8 @@ pub fn update_api_cache(ledger: &mut LedgerState) -> Result<()> { key: me.utxo.record.public_key, }; #[allow(unused_mut)] - let mut hist = ledger - .api_cache - .as_mut() - .unwrap() - .coinbase_oper_hist - .entry(key) - .or_insert_with(|| { + let mut hist = + api_cache.coinbase_oper_hist.entry(key).or_insert_with(|| { new_mapxnk!(format!( "api_cache/{}coinbase_oper_hist/{}", prefix, @@ -552,10 +579,7 @@ pub fn update_api_cache(ledger: &mut LedgerState) -> Result<()> { // Apply classify_op for each operation in curr_txn let related_addresses = get_related_addresses(&curr_txn, classify_op); for address in &related_addresses { - ledger - .api_cache - .as_mut() - .unwrap() + api_cache .related_transactions .entry(*address) .or_insert_with(|| { @@ -571,10 +595,7 @@ pub fn update_api_cache(ledger: &mut LedgerState) -> Result<()> { // Update transferred nonconfidential assets let transferred_assets = get_transferred_nonconfidential_assets(&curr_txn); for asset in &transferred_assets { - ledger - .api_cache - .as_mut() - .unwrap() + api_cache .related_transfers .entry(*asset) .or_insert_with(|| { @@ -591,17 +612,13 @@ pub fn update_api_cache(ledger: &mut LedgerState) -> Result<()> { for op in &curr_txn.body.operations { match op { Operation::DefineAsset(define_asset) => { - ledger.api_cache.as_mut().unwrap().add_created_asset( + api_cache.add_created_asset( &define_asset, ledger.status.td_commit_height, ); } Operation::IssueAsset(issue_asset) => { - ledger - .api_cache - .as_mut() - .unwrap() - .cache_issuance(&issue_asset); + api_cache.cache_issuance(&issue_asset); } _ => {} }; @@ -612,41 +629,41 @@ pub fn update_api_cache(ledger: &mut LedgerState) -> Result<()> { .iter() .zip(addresses.iter().zip(owner_memos.iter())) { - ledger - .api_cache - .as_mut() - .unwrap() - .utxos_to_map_index - .insert(*txo_sid, *address); + api_cache.utxos_to_map_index.insert(*txo_sid, *address); let hash = curr_txn.hash_tm().hex().to_uppercase(); - ledger - .api_cache - .as_mut() - .unwrap() + api_cache .txo_to_txnid .insert(*txo_sid, (txn_sid, hash.clone())); - ledger - .api_cache - .as_mut() - .unwrap() - .txn_sid_to_hash - .insert(txn_sid, hash.clone()); - ledger - .api_cache - .as_mut() - .unwrap() - .txn_hash_to_sid - .insert(hash.clone(), txn_sid); + api_cache.txn_sid_to_hash.insert(txn_sid, hash.clone()); + api_cache.txn_hash_to_sid.insert(hash.clone(), txn_sid); if let Some(owner_memo) = owner_memo { - ledger - .api_cache - .as_mut() - .unwrap() + api_cache .owner_memos .insert(*txo_sid, (*owner_memo).clone()); } } + + let abar_memos = curr_txn.body.operations.iter().flat_map(|o| match o { + Operation::BarToAbar(b) => { + vec![b.axfr_memo()] + } + Operation::TransferAnonAsset(b) => b.note.body.owner_memos.clone(), + _ => vec![], + }); + + for (a, id) in abar_memos.zip(atxo_sids) { + api_cache.abar_memos.insert(*id, a); + let hash = curr_txn.hash_tm().hex().to_uppercase(); + api_cache.atxo_to_txnid.insert(*id, (txn_sid, hash.clone())); + } } + // Update block height to max atxo mapping + let max_atxo = api_cache.abar_memos.len().checked_sub(1); + let block_height = ledger.status.td_commit_height; + api_cache.height_to_max_atxo.insert(block_height, max_atxo); + + ledger.api_cache = Some(api_cache); + Ok(()) } diff --git a/src/ledger/src/store/helpers.rs b/src/ledger/src/store/helpers.rs index 0ba1d196f..57aa65b9f 100644 --- a/src/ledger/src/store/helpers.rs +++ b/src/ledger/src/store/helpers.rs @@ -4,13 +4,13 @@ use { super::{ - IssuerKeyPair, IssuerPublicKey, LedgerState, TracingPolicies, TracingPolicy, - TransferType, XfrNotePolicies, + IssuerPublicKey, LedgerState, TracingPolicies, TracingPolicy, XfrNotePolicies, }, crate::data_model::{ Asset, AssetRules, AssetTypeCode, ConfidentialMemo, DefineAsset, - DefineAssetBody, IssueAsset, IssueAssetBody, Memo, Operation, Transaction, - TransferAsset, TransferAssetBody, TxOutput, TxnEffect, TxnSID, TxoRef, TxoSID, + DefineAssetBody, IssueAsset, IssueAssetBody, IssuerKeyPair, Memo, Operation, + Transaction, TransferAsset, TransferAssetBody, TransferType, TxOutput, + TxnEffect, TxnSID, TxoRef, TxoSID, }, globutils::SignatureOf, rand_core::{CryptoRng, RngCore}, diff --git a/src/ledger/src/store/mod.rs b/src/ledger/src/store/mod.rs index c9ccf6660..20420d741 100644 --- a/src/ledger/src/store/mod.rs +++ b/src/ledger/src/store/mod.rs @@ -12,12 +12,12 @@ pub use fbnc; use { crate::{ data_model::{ - AssetType, AssetTypeCode, AssetTypePrefix, AuthenticatedBlock, - AuthenticatedTransaction, AuthenticatedUtxo, AuthenticatedUtxoStatus, - BlockEffect, BlockSID, FinalizedBlock, FinalizedTransaction, IssuerKeyPair, - IssuerPublicKey, OutputPosition, StateCommitmentData, Transaction, - TransferType, TxnEffect, TxnSID, TxnTempSID, TxoSID, UnAuthenticatedUtxo, - Utxo, UtxoStatus, BLACK_HOLE_PUBKEY, + ATxoSID, AnonStateCommitmentData, AssetType, AssetTypeCode, AssetTypePrefix, + AuthenticatedBlock, AuthenticatedTransaction, AuthenticatedUtxo, + AuthenticatedUtxoStatus, BlockEffect, BlockSID, FinalizedBlock, + FinalizedTransaction, IssuerPublicKey, Operation, OutputPosition, + StateCommitmentData, Transaction, TxnEffect, TxnSID, TxnTempSID, TxoSID, + UnAuthenticatedUtxo, Utxo, UtxoStatus, BLACK_HOLE_PUBKEY, }, staking::{ Amount, Power, Staking, TendermintAddrRef, FF_PK_EXTRA_120_0000, FF_PK_LIST, @@ -29,7 +29,10 @@ use { bitmap::{BitMap, SparseMap}, config::abci::global_cfg::CFG, cryptohash::sha256::Digest as BitDigest, + digest::Digest, fbnc::{new_mapx, new_mapxnk, new_vecx, Mapx, Mapxnk, Vecx}, + fin_db::RocksDB, + globutils::wallet, globutils::{HashOf, ProofOf}, merkle_tree::AppendOnlyMerkle, parking_lot::RwLock, @@ -37,7 +40,9 @@ use { rand_core::SeedableRng, ruc::*, serde::{Deserialize, Serialize}, + sha2::Sha512, sliding_set::SlidingSet, + sparse_merkle_tree::{Key, SmtMap256}, std::{ collections::{BTreeMap, HashMap, HashSet}, env, @@ -47,16 +52,39 @@ use { ops::{Deref, DerefMut}, sync::Arc, }, + storage::{ + state::{ChainState, State}, + store::{ImmutablePrefixedStore, PrefixedStore}, + }, zei::{ - noah_api::xfr::{ - structs::{TracingPolicies, TracingPolicy}, - XfrNotePolicies, + noah_accumulators::merkle_tree::{ + ImmutablePersistentMerkleTree, PersistentMerkleTree, Proof, TreePath, + }, + noah_algebra::{bn254::BN254Scalar, prelude::*}, + noah_api::{ + anon_xfr::{ + abar_to_abar::verify_anon_xfr_note, + structs::{ + AnonAssetRecord, AxfrOwnerMemo, Commitment, MTLeafInfo, MTNode, + MTPath, Nullifier, + }, + AXfrAddressFoldingInstance, TREE_DEPTH as MERKLE_TREE_DEPTH, + }, + parameters::{AddressFormat, VerifierParams}, + xfr::{ + structs::{TracingPolicies, TracingPolicy}, + XfrNotePolicies, + }, }, + noah_crypto::anemoi_jive::{AnemoiJive, AnemoiJive254}, OwnerMemo, XfrPublicKey, }, }; const TRANSACTION_WINDOW_WIDTH: u64 = 128; +const VERSION_WINDOW: u64 = 100; +const GENESIS_ANON_HASH: &str = + "2501917d72f915a3afb91ae561a0e4230d5d4edbb9b62fb7e2ea41f18c3038b5"; type TmpSidMap = HashMap)>; @@ -85,6 +113,10 @@ pub struct LedgerState { txn_merkle: Arc>, // Bitmap tracing all the live TXOs utxo_map: Arc>, + // Merkle Tree with all the ABARs created till now + abar_state: Arc>>, + // Sparse Merkle Tree to hold nullifier Set + nullifier_set: Arc>>, } impl LedgerState { @@ -119,7 +151,7 @@ impl LedgerState { ) -> Result { let tx = txe.txn.clone(); self.status - .check_txn_effects(&txe) + .check_txn_effects(&txe, &self.abar_state) .c(d!()) .and_then(|_| block.add_txn_effect(txe).c(d!())) .map(|tmpid| { @@ -184,7 +216,12 @@ impl LedgerState { Ok(()) } - fn update_state(&mut self, mut block: BlockEffect, tsm: &TmpSidMap) -> Result<()> { + fn update_state( + &mut self, + mut block: BlockEffect, + tsm: &TmpSidMap, + next_txn_sid: usize, + ) -> Result<()> { let mut tx_block = Vec::new(); let height = block.staking_simulator.cur_height(); @@ -213,6 +250,7 @@ impl LedgerState { txn: txn.clone(), tx_id: txn_sid, txo_ids: txo_sids.clone(), + atxo_ids: vec![], merkle_id, }); @@ -224,10 +262,21 @@ impl LedgerState { } drop(txn_merkle); + tx_block = self + .update_anon_stores( + block.new_nullifiers.clone(), + block.output_abars.clone(), + next_txn_sid, + tx_block, + ) + .c(d!())?; + // Checkpoint let block_merkle_id = self.checkpoint(&block).c(d!())?; block.temp_sids.clear(); block.txns.clear(); + block.output_abars.clear(); + block.new_nullifiers.clear(); let block_idx = self.blocks.len(); tx_block.iter().enumerate().for_each(|(tx_idx, tx)| { @@ -263,14 +312,61 @@ impl LedgerState { } } + let backup_next_txn_sid = self.status.next_txn.0; let (tsm, base_sid, max_sid) = self.status.apply_block_effects(&mut block); self.update_utxo_map(base_sid, max_sid, &block.temp_sids, &tsm) .c(d!()) - .and_then(|_| self.update_state(block, &tsm).c(d!())) + .and_then(|_| self.update_state(block, &tsm, backup_next_txn_sid).c(d!())) .map(|_| tsm) } + /// Apply the changes from current block + /// to the merkle trees holding anonymous data + pub fn update_anon_stores( + &mut self, + new_nullifiers: Vec, + output_abars: Vec>, + backup_next_txn_sid: usize, + mut tx_block: Vec, + ) -> Result> { + for n in new_nullifiers.iter() { + let d: Key = Key::from_bytes(n.noah_to_bytes()).c(d!())?; + + // if the nullifier hash is present in our nullifier set, fail the block + if self.nullifier_set.read().get(&d).c(d!())?.is_some() { + return Err(eg!("Nullifier hash already present in set")); + } + self.nullifier_set + .write() + .set(&d, Some(n.noah_to_bytes())) + .c(d!())?; + self.status.spent_abars.insert(*n, ()); + } + + let mut txn_sid = TxnSID(backup_next_txn_sid); + for (txn_abars, txn) in output_abars.iter().zip(tx_block.iter_mut()) { + let mut op_position = OutputPosition(0); + let mut atxo_ids: Vec = vec![]; + for abar in txn_abars { + let uid = self.add_abar(&abar).c(d!())?; + self.status.ax_utxos.insert(uid, abar.clone()); + self.status.owned_ax_utxos.insert(abar.commitment, uid); + self.status + .ax_txo_to_txn_location + .insert(uid, (txn_sid, op_position)); + + atxo_ids.push(uid); + self.status.next_atxo = ATxoSID(uid.0 + 1); + op_position = OutputPosition(op_position.0 + 1); + } + txn.atxo_ids = atxo_ids; + txn_sid = TxnSID(txn_sid.0 + 1); + } + + Ok(tx_block) + } + #[inline(always)] #[allow(missing_docs)] pub fn get_staking_mut(&mut self) -> &mut Staking { @@ -311,6 +407,7 @@ impl LedgerState { pub fn tmp_ledger() -> LedgerState { fbnc::clear(); let tmp_dir = globutils::fresh_tmp_dir().to_string_lossy().into_owned(); + env::set_var("FINDORAD_KEEP_HIST", "1"); LedgerState::new(&tmp_dir, Some("test")).unwrap() } @@ -318,7 +415,8 @@ impl LedgerState { // 1. Compute the hash of transactions in the block and update txns_in_block_hash // 2. Append txns_in_block_hash to block_merkle #[inline(always)] - fn compute_and_append_txns_hash(&mut self, block: &BlockEffect) -> u64 { + #[allow(missing_docs)] + pub fn compute_and_append_txns_hash(&mut self, block: &BlockEffect) -> u64 { // 1. Compute the hash of transactions in the block and update txns_in_block_hash let txns_in_block_hash = block.compute_txns_in_block_hash(); self.status.txns_in_block_hash = Some(txns_in_block_hash.clone()); @@ -334,7 +432,8 @@ impl LedgerState { ret } - fn compute_and_save_state_commitment_data(&mut self, pulse_count: u64) { + #[allow(missing_docs)] + pub fn compute_and_save_state_commitment_data(&mut self, pulse_count: u64) { let staking_data = if self.get_tendermint_height() < CFG.checkpoint.remove_fake_staking_hash && self.get_staking().has_been_inited() @@ -365,9 +464,97 @@ impl LedgerState { .state_commitment_versions .push(state_commitment_data.compute_commitment()); self.status.state_commitment_data = Some(state_commitment_data); + + // Commit Anon tree changes here following Tendermint protocol + pnk!(self.commit_anon_changes().c(d!())); + pnk!(self.commit_nullifier_changes().c(d!())); + + let abar_root_hash = + self.get_abar_root_hash().expect("failed to read root hash"); + + let anon_state_commitment_data = AnonStateCommitmentData { + abar_root_hash, + nullifier_root_hash: self + .nullifier_set + .read() + .merkle_root() + .unwrap_or(sparse_merkle_tree::ZERO_DIGEST), + }; + + let anon_hash = anon_state_commitment_data.compute_commitment(); + // don't push anon_state_commitment until any anon transactions is committed. + // This is to make sure the app hash changes occur for all nodes at the same time + if anon_hash.hex() != GENESIS_ANON_HASH { + self.status.anon_state_commitment_versions.push(anon_hash); + } + self.status.anon_state_commitment_data = Some(anon_state_commitment_data); + self.status.incr_block_commit_count(); } + #[inline(always)] + /// Adds a new abar to session cache and updates merkle hashes of ancestors + pub fn add_abar(&mut self, abar: &AnonAssetRecord) -> Result { + let mut abar_state_val = self.abar_state.write(); + let store = PrefixedStore::new("abar_store", &mut abar_state_val); + let mut mt = PersistentMerkleTree::new(store).c(d!())?; + + let leaf = hash_abar(mt.entry_count(), abar); + mt.add_commitment_hash(leaf).map(ATxoSID).c(d!()) + } + + #[inline(always)] + /// writes the changes from session cache to the RocksDB store + pub fn commit_anon_changes(&mut self) -> Result { + let mut abar_state_val = self.abar_state.write(); + let store = PrefixedStore::new("abar_store", &mut abar_state_val); + let mut mt = PersistentMerkleTree::new(store).c(d!())?; + + mt.commit().c(d!()) + } + + #[inline(always)] + /// writes the changes from session cache to the RocksDB store + pub fn commit_nullifier_changes(&mut self) -> Result { + self.nullifier_set.write().commit() + } + + #[inline(always)] + /// Fetches the root hash of the committed merkle tree of abar commitments directly from committed + /// state and ignore session cache + pub fn get_abar_root_hash(&self) -> Result { + let abar_query_state = State::new(self.abar_state.read().chain_state(), false); + let store = ImmutablePrefixedStore::new("abar_store", &abar_query_state); + let mt = ImmutablePersistentMerkleTree::new(store).c(d!())?; + + mt.get_root_with_depth(MERKLE_TREE_DEPTH).c(d!( + "probably due to badly constructed tree or data corruption" + )) + } + + #[inline(always)] + /// Generates a MTLeafInfo from the latest committed version of tree from committed state and + /// ignore session cache + pub fn get_abar_proof(&self, id: ATxoSID) -> Result { + let abar_query_state = State::new(self.abar_state.read().chain_state(), false); + let store = ImmutablePrefixedStore::new("abar_store", &abar_query_state); + let mt = ImmutablePersistentMerkleTree::new(store).c(d!())?; + + let t = mt + .generate_proof_with_depth(id.0, MERKLE_TREE_DEPTH) + .c(d!())?; + Ok(build_mt_leaf_info_from_proof(t, id.0)) + } + + /// Check if the nullifier hash is present in nullifier set + #[inline(always)] + pub fn check_nullifier_hash(&self, hash: String) -> Result { + let n = wallet::nullifier_from_base58(hash.as_str())?; + let d: Key = Key::from_bytes(n.noah_to_bytes()).c(d!())?; + let is_null_present = self.nullifier_set.read().get(&d).c(d!())?.is_some(); + Ok(is_null_present) + } + // Initialize a logged Merkle tree for the ledger. // We might be creating a new tree or opening an existing one. #[inline(always)] @@ -389,6 +576,25 @@ impl LedgerState { .and_then(|f| BitMap::open(f).c(d!())) } + // Initialize a persistent merkle tree for ABAR store. + #[inline(always)] + fn init_abar_state(path: &str) -> Result> { + let fdb = RocksDB::open(path).c(d!("failed to open db"))?; + let cs = Arc::new(RwLock::new(ChainState::new( + fdb, + "abar_db".to_string(), + VERSION_WINDOW, + ))); + Ok(State::new(cs, false)) + } + + // Initialize persistent Sparse Merkle tree for the Nullifier set + #[inline(always)] + fn init_nullifier_smt(path: &str) -> Result> { + let rdb = RocksDB::open(path).c(d!("failed to open db"))?; + Ok(SmtMap256::new(rdb)) + } + /// Initialize a new Ledger structure. pub fn new(basedir: &str, prefix: Option<&str>) -> Result { let prefix = if let Some(p) = prefix { @@ -400,6 +606,8 @@ impl LedgerState { let block_merkle_path = format!("{}/{}block_merkle", basedir, &prefix); let txn_merkle_path = format!("{}/{}txn_merkle", basedir, &prefix); let utxo_map_path = format!("{}/{}utxo_map", basedir, &prefix); + let abar_store_path = format!("{}/{}abar_store", basedir, &prefix); + let nullifier_store_path = format!("{}/{}nullifier_store", basedir, &prefix); // These iterms will be set under ${BNC_DATA_DIR} fs::create_dir_all(&basedir).c(d!())?; @@ -411,6 +619,12 @@ impl LedgerState { let blocks_path = prefix.clone() + "blocks"; let tx_to_block_location_path = prefix.clone() + "tx_to_block_location"; + let mut abar_state = LedgerState::init_abar_state(&abar_store_path).c(d!())?; + + // Initializing Merkle tree to set Empty tree root hash, which is a hash of null children + let store = PrefixedStore::new("abar_store", &mut abar_state); + let _ = PersistentMerkleTree::new(store).c(d!())?; + let mut ledger = LedgerState { status: LedgerStatus::new(&basedir, &snapshot_file).c(d!())?, block_merkle: Arc::new(RwLock::new( @@ -426,6 +640,10 @@ impl LedgerState { )), block_ctx: Some(BlockEffect::default()), api_cache: alt!(*KEEP_HIST, Some(ApiCache::new(&prefix)), None), + abar_state: Arc::new(RwLock::new(abar_state)), + nullifier_set: Arc::new(RwLock::new( + LedgerState::init_nullifier_smt(&nullifier_store_path).c(d!())?, + )), }; ledger.status.refresh_data(); @@ -819,7 +1037,7 @@ impl LedgerState { .txn .get_owner_memos_ref() .get(au.utxo_location.0) - .and_then(|i| i.cloned()), + .and_then(|i| i.clone()), ), ) }) @@ -828,6 +1046,46 @@ impl LedgerState { Ok(res) } + /// Get all abars with sid which are associated with a diversified public key + #[allow(dead_code)] + pub fn get_owned_abar(&self, com: &Commitment) -> Option { + self.status.owned_ax_utxos.get(com) + } + + /// Get abar commitment with sid + pub fn get_abar(&self, sid: &ATxoSID) -> Option { + self.status.get_abar(sid).map(|v| v.commitment) + } + + /// Get the owner memo of a abar by ATxoSID + #[allow(dead_code)] + pub fn get_abar_memo(&self, ax_id: ATxoSID) -> Option { + if let Some(txn_location) = self.status.ax_txo_to_txn_location.get(&ax_id) { + if let Ok(authenticated_txn) = self.get_transaction(txn_location.0) { + let memo: Vec = authenticated_txn + .finalized_txn + .txn + .body + .operations + .iter() + .flat_map(|o| match o { + Operation::BarToAbar(body) => vec![body.axfr_memo()], + Operation::TransferAnonAsset(body) => { + body.note.body.owner_memos.clone() + } + _ => vec![], + }) + .collect::>(); + + if memo.is_empty() { + return None; + } + return memo.get(txn_location.1 .0).cloned(); + }; + }; + None + } + #[inline(always)] #[allow(missing_docs)] pub fn get_issuance_num(&self, code: &AssetTypeCode) -> Option { @@ -864,6 +1122,16 @@ impl LedgerState { (commitment, block_count) } + #[inline(always)] + #[allow(missing_docs)] + pub fn get_anon_state_commitment(&self) -> (Vec, u64) { + let block_count = self.status.block_commit_count; + let commitment = self.status.anon_state_commitment_versions.last(); + + let hash = commitment.map_or_else(Vec::new, |c| c.as_ref().to_vec()); + (hash, block_count) + } + /// Get utxo status and its proof data pub fn get_utxo_status(&self, addr: TxoSID) -> AuthenticatedUtxoStatus { let state_commitment_data = self.status.state_commitment_data.as_ref().unwrap(); @@ -980,38 +1248,78 @@ impl LedgerState { pub struct LedgerStatus { /// the file path of the snapshot pub snapshot_file: String, - // all currently-unspent TXOs + /// all currently-unspent TXOs + #[serde(default = "default_status_utxos")] utxos: Mapxnk, + /// all non-confidential balances + #[serde(default = "default_status_nonconfidential_balances")] nonconfidential_balances: Mapx, + /// all owned utxos + #[serde(default = "default_status_owned_utxos")] owned_utxos: Mapx>, + /// all existing ax_utxos + #[serde(default = "default_status_ax_utxos")] + ax_utxos: Mapx, + /// all owned abars + #[serde(default = "default_status_owned_ax_utxos")] + owned_ax_utxos: Mapx, /// all spent TXOs + #[serde(default = "default_status_spent_utxos")] pub spent_utxos: Mapxnk, - // Map a TXO to its output position in a transaction + /// all spent abars + #[serde(default = "default_status_spent_abars")] + pub spent_abars: Mapx, + /// Map a TXO to its output position in a transaction + #[serde(default = "default_status_txo_to_txn_location")] txo_to_txn_location: Mapxnk, - // State commitment history. - // The BitDigest at index i is the state commitment of the ledger at block height i + 1. + /// Map a Anonymous TXO to its output position in a transaction + #[serde(default = "default_status_ax_txo_to_txn_location")] + ax_txo_to_txn_location: Mapx, + /// State commitment history. + /// The BitDigest at index i is the state commitment of the ledger at block height i + 1. + #[serde(default = "default_status_state_commitment_versions")] state_commitment_versions: Vecx>>, - // Registered asset types + /// Anon state commitment versions + #[serde(default = "default_status_anon_state_commitment_versions")] + anon_state_commitment_versions: Vecx>>, + /// Registered asset types + #[serde(default = "default_status_asset_types")] asset_types: Mapx, - // Issuance number is always increasing + /// Issuance number is always increasing + #[serde(default = "default_status_issuance_num")] issuance_num: Mapx, - // Issuance amounts for assets with limits + /// Issuance amounts for assets with limits + #[serde(default = "default_status_issuance_amounts")] issuance_amounts: Mapx, - // Should be equal to the count of transactions + /// Should be equal to the count of transactions + #[serde(default = "default_status_next_txn")] next_txn: TxnSID, - // Should be equal to the count of TXOs + /// Should be equal to the count of TXOs + #[serde(default = "default_status_next_txo")] next_txo: TxoSID, - // Each block corresponds to such a summary structure + /// Should be equal to the count of ABARs + #[serde(default = "default_status_next_atxo")] + next_atxo: ATxoSID, + /// Each block corresponds to such a summary structure + #[serde(default = "default_status_state_commitment_data")] state_commitment_data: Option, - // number of non-empty blocks, equal to: - + /// Anon state commitment + #[serde(default = "default_status_anon_state_commitment_data")] + anon_state_commitment_data: Option, + /// number of non-empty blocks, equal to: - + #[serde(default = "default_status_block_commit_count")] block_commit_count: u64, - // Hash of the transactions in the most recent block + /// Hash of the transactions in the most recent block + #[serde(default = "default_status_txns_in_block_hash")] txns_in_block_hash: Option>>, - // Sliding window of operations for replay attack prevention + /// Sliding window of operations for replay attack prevention + #[serde(default = "default_status_sliding_set")] sliding_set: SlidingSet<[u8; 8]>, - // POS-related implementations + /// POS-related implementations + #[serde(default = "default_status_staking")] staking: Staking, - // tendermint commit height + /// tendermint commit height + #[serde(default = "default_status_td_commit_height")] td_commit_height: u64, } @@ -1025,6 +1333,18 @@ impl LedgerStatus { .unwrap_or_default() } + #[inline(always)] + #[allow(missing_docs)] + pub fn get_owned_abar(&self, com: &Commitment) -> Option { + self.owned_ax_utxos.get(com) + } + + #[inline(always)] + #[allow(missing_docs)] + pub fn get_abar(&self, uid: &ATxoSID) -> Option { + self.ax_utxos.get(uid) + } + #[inline(always)] #[allow(missing_docs)] fn get_utxo(&self, id: TxoSID) -> Option { @@ -1086,42 +1406,34 @@ impl LedgerStatus { } fn create(snapshot_file: &str) -> Result { - let utxos_path = SNAPSHOT_ENTRIES_DIR.to_owned() + "/utxo"; - let nonconfidential_balances_path = - SNAPSHOT_ENTRIES_DIR.to_owned() + "/nonconfidential_balances"; - let spent_utxos_path = SNAPSHOT_ENTRIES_DIR.to_owned() + "/spent_utxos"; - let txo_to_txn_location_path = - SNAPSHOT_ENTRIES_DIR.to_owned() + "/txo_to_txn_location"; - let issuance_amounts_path = - SNAPSHOT_ENTRIES_DIR.to_owned() + "/issuance_amounts"; - let state_commitment_versions_path = - SNAPSHOT_ENTRIES_DIR.to_owned() + "/state_commitment_versions"; - let asset_types_path = SNAPSHOT_ENTRIES_DIR.to_owned() + "/asset_types"; - let issuance_num_path = SNAPSHOT_ENTRIES_DIR.to_owned() + "/issuance_num"; - let owned_utxos_path = SNAPSHOT_ENTRIES_DIR.to_owned() + "/owned_utxos"; - - let ledger = LedgerStatus { + Ok(LedgerStatus { snapshot_file: snapshot_file.to_owned(), - sliding_set: SlidingSet::<[u8; 8]>::new(TRANSACTION_WINDOW_WIDTH as usize), - utxos: new_mapxnk!(utxos_path.as_str()), - nonconfidential_balances: new_mapx!(nonconfidential_balances_path.as_str()), - owned_utxos: new_mapx!(owned_utxos_path.as_str()), - spent_utxos: new_mapxnk!(spent_utxos_path.as_str()), - txo_to_txn_location: new_mapxnk!(txo_to_txn_location_path.as_str()), - issuance_amounts: new_mapx!(issuance_amounts_path.as_str()), - state_commitment_versions: new_vecx!(state_commitment_versions_path.as_str()), - asset_types: new_mapx!(asset_types_path.as_str()), - issuance_num: new_mapx!(issuance_num_path.as_str()), - next_txn: TxnSID(0), - next_txo: TxoSID(0), - txns_in_block_hash: None, - state_commitment_data: None, - block_commit_count: 0, - staking: Staking::new(), - td_commit_height: 0, - }; - - Ok(ledger) + sliding_set: default_status_sliding_set(), + utxos: default_status_utxos(), + nonconfidential_balances: default_status_nonconfidential_balances(), + owned_utxos: default_status_owned_utxos(), + ax_utxos: default_status_ax_utxos(), + owned_ax_utxos: default_status_owned_ax_utxos(), + spent_utxos: default_status_spent_utxos(), + spent_abars: default_status_spent_abars(), + txo_to_txn_location: default_status_txo_to_txn_location(), + ax_txo_to_txn_location: default_status_ax_txo_to_txn_location(), + issuance_amounts: default_status_issuance_amounts(), + state_commitment_versions: default_status_state_commitment_versions(), + anon_state_commitment_versions: + default_status_anon_state_commitment_versions(), + asset_types: default_status_asset_types(), + issuance_num: default_status_issuance_num(), + next_txn: default_status_next_txn(), + next_txo: default_status_next_txo(), + next_atxo: default_status_next_atxo(), + txns_in_block_hash: default_status_txns_in_block_hash(), + state_commitment_data: default_status_state_commitment_data(), + anon_state_commitment_data: default_status_anon_state_commitment_data(), + block_commit_count: default_status_block_commit_count(), + staking: default_status_staking(), + td_commit_height: default_status_td_commit_height(), + }) } #[inline(always)] @@ -1139,7 +1451,11 @@ impl LedgerStatus { // // ledger.check_txn_effects(txn_effect); // block.add_txn_effect(txn_effect); - fn check_txn_effects(&self, txn_effect: &TxnEffect) -> Result<()> { + fn check_txn_effects( + &self, + txn_effect: &TxnEffect, + abar_state: &Arc>>, + ) -> Result<()> { // The current transactions seq_id must be within the sliding window over seq_ids let (rand, seq_id) = ( txn_effect.txn.body.no_replay_token.get_rand(), @@ -1326,6 +1642,69 @@ impl LedgerStatus { } } + // current merkle tree version. + let abar_query_state = State::new(abar_state.read().chain_state(), false); + let store = ImmutablePrefixedStore::new("abar_store", &abar_query_state); + let abar_mt = ImmutablePersistentMerkleTree::new(store).c(d!())?; + + let mut hasher = Sha512::new(); + hasher.update(txn_effect.txn.body.digest()); + + // An axfr_body requires versioned merkle root hash for verification. + // here with LedgerStatus available. + for axfr_note in txn_effect.axfr_bodies.iter() { + for input in &axfr_note.body.inputs { + if self.spent_abars.get(&input).is_some() { + return Err(eg!("Input abar must be unspent")); + } + } + + let af = match axfr_note.folding_instance { + AXfrAddressFoldingInstance::Secp256k1(_) => AddressFormat::SECP256K1, + AXfrAddressFoldingInstance::Ed25519(_) => AddressFormat::ED25519, + }; + let verifier_params = VerifierParams::get_abar_to_abar( + axfr_note.body.inputs.len(), + axfr_note.body.outputs.len(), + af, + ) + .c(d!())?; + let abar_version = axfr_note.body.merkle_root_version; + if abar_mt.version() - abar_version > VERSION_WINDOW { + return Err(eg!("Proof is old, need rebuild!")); + } + let version_root = abar_mt + .get_root_with_depth_and_version(MERKLE_TREE_DEPTH, abar_version) + .c(d!())?; + + verify_anon_xfr_note( + &verifier_params, + axfr_note, + &version_root, + hasher.clone(), + ) + .c(d!("Anon Transfer proof verification failed"))?; + } + + // An axfr_abar_conv requires versioned merkle root hash for verification. + for abar_conv in &txn_effect.abar_conv_inputs { + if self.spent_abars.get(&abar_conv.get_input()).is_some() { + return Err(eg!("Input abar must be unspent")); + } + + // Get verifier params + let abar_version = abar_conv.get_merkle_root_version(); + if abar_mt.version() - abar_version > VERSION_WINDOW { + return Err(eg!("Proof is old, need rebuild!")); + } + let version_root = abar_mt + .get_root_with_depth_and_version(MERKLE_TREE_DEPTH, abar_version) + .c(d!())?; + + // verify zk proof with merkle root + abar_conv.verify(version_root, hasher.clone())?; + } + Ok(()) } @@ -1335,6 +1714,7 @@ impl LedgerStatus { // that is ever false, it's a bug). // // This drains every field of `block` except `txns` and `temp_sids`. + #[allow(unused_mut)] fn apply_block_effects(&mut self, block: &mut BlockEffect) -> (TmpSidMap, u64, u64) { let base_sid = self.next_txo.0; let handle_asset_type_code = |code: AssetTypeCode| { @@ -1480,3 +1860,127 @@ pub struct LoggedBlock { pub fn flush_data() { fbnc::flush_data(); } + +fn build_mt_leaf_info_from_proof(proof: Proof, uid: u64) -> MTLeafInfo { + return MTLeafInfo { + path: MTPath { + nodes: proof + .nodes + .iter() + .map(|e| MTNode { + left: e.left, + mid: e.mid, + right: e.right, + is_left_child: (e.path == TreePath::Left) as u8, + is_mid_child: (e.path == TreePath::Middle) as u8, + is_right_child: (e.path == TreePath::Right) as u8, + }) + .collect(), + }, + root: proof.root, + root_version: proof.root_version, + uid, + }; +} + +fn hash_abar(uid: u64, abar: &AnonAssetRecord) -> BN254Scalar { + AnemoiJive254::eval_variable_length_hash(&[BN254Scalar::from(uid), abar.commitment]) +} + +fn default_status_utxos() -> Mapxnk { + new_mapxnk!(SNAPSHOT_ENTRIES_DIR.to_owned() + "/utxo") +} + +fn default_status_owned_utxos() -> Mapx> { + new_mapx!(SNAPSHOT_ENTRIES_DIR.to_owned() + "/owned_utxos") +} + +fn default_status_nonconfidential_balances() -> Mapx { + new_mapx!(SNAPSHOT_ENTRIES_DIR.to_owned() + "/nonconfidential_balances") +} + +fn default_status_ax_utxos() -> Mapx { + new_mapx!(SNAPSHOT_ENTRIES_DIR.to_owned() + "/ax_utxos") +} + +fn default_status_owned_ax_utxos() -> Mapx { + new_mapx!(SNAPSHOT_ENTRIES_DIR.to_owned() + "/owned_ax_utxos") +} + +fn default_status_spent_utxos() -> Mapxnk { + new_mapxnk!(SNAPSHOT_ENTRIES_DIR.to_owned() + "/spent_utxos") +} + +fn default_status_spent_abars() -> Mapx { + new_mapx!(SNAPSHOT_ENTRIES_DIR.to_owned() + "/spent_abars") +} + +fn default_status_txo_to_txn_location() -> Mapxnk { + new_mapxnk!(SNAPSHOT_ENTRIES_DIR.to_owned() + "/txo_to_txn_location") +} + +fn default_status_ax_txo_to_txn_location() -> Mapx { + new_mapx!(SNAPSHOT_ENTRIES_DIR.to_owned() + "/atxo_to_txn_location") +} + +fn default_status_issuance_amounts() -> Mapx { + new_mapx!(SNAPSHOT_ENTRIES_DIR.to_owned() + "/issuance_amounts") +} + +fn default_status_state_commitment_versions() -> Vecx>> +{ + new_vecx!(SNAPSHOT_ENTRIES_DIR.to_owned() + "/state_commitment_versions") +} + +fn default_status_anon_state_commitment_versions( +) -> Vecx>> { + new_vecx!(SNAPSHOT_ENTRIES_DIR.to_owned() + "/anon_state_commitment_versions") +} + +fn default_status_asset_types() -> Mapx { + new_mapx!(SNAPSHOT_ENTRIES_DIR.to_owned() + "/asset_types") +} + +fn default_status_issuance_num() -> Mapx { + new_mapx!(SNAPSHOT_ENTRIES_DIR.to_owned() + "/issuance_num") +} + +fn default_status_next_txn() -> TxnSID { + TxnSID(0) +} + +fn default_status_next_txo() -> TxoSID { + TxoSID(0) +} + +fn default_status_next_atxo() -> ATxoSID { + ATxoSID(0) +} + +fn default_status_txns_in_block_hash() -> Option>> { + None +} + +fn default_status_state_commitment_data() -> Option { + None +} + +fn default_status_anon_state_commitment_data() -> Option { + None +} + +fn default_status_block_commit_count() -> u64 { + 0 +} + +fn default_status_staking() -> Staking { + Staking::new() +} + +fn default_status_td_commit_height() -> u64 { + 0 +} + +fn default_status_sliding_set() -> SlidingSet<[u8; 8]> { + SlidingSet::<[u8; 8]>::new(TRANSACTION_WINDOW_WIDTH as usize) +} diff --git a/src/ledger/src/store/test.rs b/src/ledger/src/store/test.rs old mode 100644 new mode 100755 index 064b322ac..fb1677abc --- a/src/ledger/src/store/test.rs +++ b/src/ledger/src/store/test.rs @@ -1,21 +1,30 @@ #![cfg(test)] #![allow(missing_docs)] - use { super::{helpers::*, *}, - 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, + crate::{ + data_model::{ + get_abar_commitment, AssetRules, AssetTypeCode, IssueAsset, IssueAssetBody, + IssuerKeyPair, Memo, Operation, Transaction, TransferAsset, + TransferAssetBody, TransferType, TxOutput, TxnEffect, TxoRef, TxoSID, + ASSET_TYPE_FRA, BLACK_HOLE_PUBKEY, TX_FEE_MIN, + }, + store::{helpers::create_definition_transaction, utils::fra_gen_initial_tx}, }, rand_core::SeedableRng, zei::{ - noah_algebra::ristretto::PedersenCommitmentRistretto, - noah_api::xfr::{ - asset_record::{ - build_blind_asset_record, open_blind_asset_record, AssetRecordType, + noah_algebra::{ + prelude::{One, Zero}, + ristretto::PedersenCommitmentRistretto, + }, + noah_api::{ + anon_xfr::structs::OpenAnonAssetRecordBuilder, + xfr::{ + asset_record::{ + build_blind_asset_record, open_blind_asset_record, AssetRecordType, + }, + structs::{AssetRecord, AssetRecordTemplate}, }, - structs::{AssetRecord, AssetRecordTemplate}, }, BlindAssetRecord, XfrKeyPair, }, @@ -29,6 +38,8 @@ fn abort_block(block: BlockEffect) -> HashMap { block.temp_sids.drain(..).zip(txns).collect(); block.txos.clear(); + block.output_abars.clear(); + block.new_nullifiers.clear(); block.input_txos.clear(); block.new_asset_codes.clear(); block.new_issuance_nums.clear(); @@ -109,12 +120,6 @@ fn test_asset_creation_valid() { } assert!(state.get_asset_type(&token_code).is_some()); - - assert_eq!( - *asset_body.asset, - state.get_asset_type(&token_code).unwrap().properties - ); - assert_eq!(0, state.get_asset_type(&token_code).unwrap().units); } @@ -144,6 +149,7 @@ fn test_asset_creation_invalid_public_key() { } #[test] +#[allow(clippy::redundant_clone)] fn test_asset_transfer() { let mut ledger = LedgerState::tmp_ledger(); @@ -182,12 +188,8 @@ fn test_asset_transfer() { key_pair.get_pk().into_noah(), ); let pc_gens = PedersenCommitmentRistretto::default(); - let (ba, _, _) = build_blind_asset_record( - &mut ledger.get_prng(), - &pc_gens, - &template, - vec![], - ); + let (ba, _, _) = + build_blind_asset_record(&mut ledger.get_prng(), &pc_gens, &template, vec![]); let asset_issuance_body = IssueAssetBody::new( &new_code, @@ -231,6 +233,8 @@ fn test_asset_transfer() { .unwrap() .remove(&temp_sid) .unwrap(); + ledger.api_cache.as_mut().unwrap().state_commitment_version = + ledger.status.state_commitment_versions.last(); let state_commitment = ledger.get_state_commitment().0; for txo_id in &txos { @@ -296,6 +300,8 @@ fn test_asset_transfer() { .unwrap() .remove(&temp_sid) .unwrap(); + ledger.api_cache.as_mut().unwrap().state_commitment_version = + ledger.status.state_commitment_versions.last(); // Ensure that previous txo is now spent let state_commitment = ledger.get_state_commitment().0; let utxo_status = ledger.get_utxo_status(TxoSID(0)); @@ -428,6 +434,8 @@ fn asset_issued() { let transaction = ledger.get_transaction(txn_sid).unwrap(); let txn_id = transaction.finalized_txn.tx_id; + ledger.api_cache.as_mut().unwrap().state_commitment_version = + ledger.status.state_commitment_versions.last(); let state_commitment_and_version = ledger.get_state_commitment(); println!("utxos = {:?}", ledger.status.utxos); @@ -786,7 +794,7 @@ fn test_check_fee_with_ledger() { let mut ledger = LedgerState::tmp_ledger(); let fra_owner_kp = XfrKeyPair::generate(&mut ChaChaRng::from_entropy()); - let tx = utils::fra_gen_initial_tx(&fra_owner_kp); + let tx = fra_gen_initial_tx(&fra_owner_kp); assert!(tx.check_fee()); let effect = TxnEffect::compute_effect(tx.clone()).unwrap(); @@ -815,3 +823,86 @@ fn test_check_fee_with_ledger() { let mut block = ledger.start_block().unwrap(); assert!(ledger.apply_transaction(&mut block, effect).is_err()); } + +#[test] +fn test_update_anon_stores() { + let mut prng = ChaChaRng::from_seed([0u8; 32]); + + let mut state = LedgerState::tmp_ledger(); + + let nullifiers = vec![ + Nullifier::zero() as Nullifier, + Nullifier::one() as Nullifier, + ]; + + let pub_key = XfrKeyPair::generate(&mut prng).get_pk().into_noah(); + let oabar = OpenAnonAssetRecordBuilder::new() + .amount(123) + .asset_type(zei::noah_api::xfr::structs::AssetType([39u8; 32])) + .pub_key(&pub_key) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(); + let oabar2 = OpenAnonAssetRecordBuilder::new() + .amount(123) + .asset_type(zei::noah_api::xfr::structs::AssetType([39u8; 32])) + .pub_key(&pub_key) + .finalize(&mut prng) + .unwrap() + .build() + .unwrap(); + let output_abars = vec![ + vec![AnonAssetRecord::from_oabar(&oabar)], + vec![AnonAssetRecord::from_oabar(&oabar2)], + ]; + let new_com = get_abar_commitment(oabar); + let new_com2 = get_abar_commitment(oabar2); + let tx_block = vec![ + FinalizedTransaction { + txn: Default::default(), + tx_id: Default::default(), + txo_ids: vec![], + atxo_ids: vec![], + merkle_id: 0, + }, + FinalizedTransaction { + txn: Default::default(), + tx_id: Default::default(), + txo_ids: vec![], + atxo_ids: vec![], + merkle_id: 0, + }, + ]; + + let str0 = bs58::encode(&BN254Scalar::zero().noah_to_bytes()).into_string(); + let d0: Key = Key::from_base58(&str0).unwrap(); + assert!(state.nullifier_set.read().get(&d0).unwrap().is_none()); + + let str1 = bs58::encode(&BN254Scalar::one().noah_to_bytes()).into_string(); + let d1: Key = Key::from_base58(&str1).unwrap(); + assert!(state.nullifier_set.read().get(&d1).unwrap().is_none()); + + let res = state.update_anon_stores(nullifiers, output_abars, 0, tx_block); + assert!(res.is_ok()); + + let res2 = state.commit_anon_changes(); + assert!(res2.is_ok()); + assert_eq!(res2.unwrap(), 1); + + assert!(state.nullifier_set.read().get(&d0).unwrap().is_some()); + assert!(state.nullifier_set.read().get(&d1).unwrap().is_some()); + + assert_eq!(state.status.next_atxo.0, 2); + assert_eq!( + state.status.ax_txo_to_txn_location.get(&ATxoSID(0)), + Some((TxnSID(0), OutputPosition(0))) + ); + assert_eq!( + state.status.ax_txo_to_txn_location.get(&ATxoSID(1)), + Some((TxnSID(1), OutputPosition(0))) + ); + + assert_eq!(state.status.owned_ax_utxos.get(&new_com), Some(ATxoSID(0))); + assert_eq!(state.status.owned_ax_utxos.get(&new_com2), Some(ATxoSID(1))); +} diff --git a/src/ledger/src/store/utils.rs b/src/ledger/src/store/utils.rs index d1496c472..c036b9397 100644 --- a/src/ledger/src/store/utils.rs +++ b/src/ledger/src/store/utils.rs @@ -26,6 +26,7 @@ use { /// Define and Issue FRA. /// Currently this should only be used for tests. +#[allow(unused)] pub fn fra_gen_initial_tx(fra_owner_kp: &XfrKeyPair) -> Transaction { /* * Define FRA diff --git a/tools/devnet/snapshot.sh b/tools/devnet/snapshot.sh index c03ee0007..32f5b48c4 100755 --- a/tools/devnet/snapshot.sh +++ b/tools/devnet/snapshot.sh @@ -41,6 +41,7 @@ $BIN/fn setup -S http://0.0.0.0 > /dev/null $BIN/fn setup -O $WALLET/mnenomic.key > /dev/null echo -e "host: http://0.0.0.0" echo -e "key : $WALLET/mnenomic.key" +sleep 3 #echo -e "$BIN/stt" $BIN/stt init -i $BLOCK_INTERVAL -s #./$stopnodes From 7b043ecbd18ad925d73cf084a8751437748e831d Mon Sep 17 00:00:00 2001 From: shaorongqiang <26101255+shaorongqiang@users.noreply.github.com> Date: Wed, 20 Sep 2023 17:28:14 +0800 Subject: [PATCH 4/7] fix rustc version (#1010) * fix rustc version * fix dockerfile * fix --------- Co-authored-by: shaorongqiang --- container/Dockerfile-binary-image-dev | 6 +++--- container/Dockerfile-binary-image-release | 6 +++--- rust-toolchain | 2 +- src/components/contracts/rpc/src/eth_pubsub.rs | 9 ++++----- src/components/finutils/src/bins/cfg_generator.rs | 2 +- src/ledger/src/store/mod.rs | 2 +- 6 files changed, 13 insertions(+), 14 deletions(-) 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/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/ledger/src/store/mod.rs b/src/ledger/src/store/mod.rs index 20420d741..498776a22 100644 --- a/src/ledger/src/store/mod.rs +++ b/src/ledger/src/store/mod.rs @@ -1026,7 +1026,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)| { ( From feb40e8010c79afc4271a22dfbdd7b6b42d63ab9 Mon Sep 17 00:00:00 2001 From: Harshad Patil Date: Tue, 17 Oct 2023 21:34:17 -0700 Subject: [PATCH 5/7] Fix failure for DefineAsset and IssueAsset operation sent in same txn (#1022) * Fix failure for DefineAsset and IssueAsset operation sent in same txn The DefineAsset Operation has the raw asset code whereas IssueAsset Operation has the derived asset code. Currently if both the operations are sent in the same txn for a new asset it fails because the Asset code don't match. This is fixed by comparing the derived asset code from newly defined assets in the txn. * lint * fix docker image build * fix lint * lint * lint * Remove fix for testing * trigger build * trigger github actions * Revert "Remove fix for testing" This reverts commit df1f070c45f5ff02b8c848c5782d9f244d4394e7. * fix typo in yaml of CLI * Update mod.rs --------- Co-authored-by: Weikeng Chen --- .../abciapp/src/abci/server/callback/mod.rs | 1 + .../abciapp/src/abci/staking/mod.rs | 1 + src/components/finutils/src/bins/fn.yml | 36 +++++++++---------- src/ledger/src/data_model/effects.rs | 2 +- src/ledger/src/staking/mod.rs | 8 ++--- src/ledger/src/store/mod.rs | 19 +++++++++- 6 files changed, 43 insertions(+), 24 deletions(-) diff --git a/src/components/abciapp/src/abci/server/callback/mod.rs b/src/components/abciapp/src/abci/server/callback/mod.rs index 34a6e63a0..8a1c9365e 100644 --- a/src/components/abciapp/src/abci/server/callback/mod.rs +++ b/src/components/abciapp/src/abci/server/callback/mod.rs @@ -507,6 +507,7 @@ pub fn deliver_tx( } /// putting block in the ledgerState +#[allow(noop_method_call)] pub fn end_block( s: &mut ABCISubmissionServer, req: &RequestEndBlock, diff --git a/src/components/abciapp/src/abci/staking/mod.rs b/src/components/abciapp/src/abci/staking/mod.rs index 4b0fd6422..7e6f892b6 100644 --- a/src/components/abciapp/src/abci/staking/mod.rs +++ b/src/components/abciapp/src/abci/staking/mod.rs @@ -234,6 +234,7 @@ pub fn get_validators( /// - pay delegation rewards /// - pay proposer rewards(traditional block rewards) /// - do governance operations +#[allow(noop_method_call)] pub fn system_ops( la: &mut LedgerState, header: &Header, diff --git a/src/components/finutils/src/bins/fn.yml b/src/components/finutils/src/bins/fn.yml index cbf96a6c3..02043a839 100644 --- a/src/components/finutils/src/bins/fn.yml +++ b/src/components/finutils/src/bins/fn.yml @@ -158,7 +158,7 @@ subcommands: - use-default-eth-address: help: use a private key of the eth address if `staker-priv-key` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - staker-priv-key - claim: about: Claim accumulated FRA rewards @@ -183,7 +183,7 @@ subcommands: - use-default-eth-address: help: use a private key of the eth address if `seckey` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - seckey - delegate: about: Delegating operations @@ -213,7 +213,7 @@ subcommands: - use-default-eth-address: help: use a private key of the eth address if `seckey` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - seckey - undelegate: about: Undelegating operations @@ -237,7 +237,7 @@ subcommands: - use-default-eth-address: help: use a private key of the eth address if `seckey` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - seckey - transfer: about: Transfer tokens from one address to another @@ -285,7 +285,7 @@ subcommands: - use-default-eth-address: help: use a private key of the eth address if `from-seckey` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - from-seckey - transfer-batch: about: Transfer tokens from one address to many others @@ -324,7 +324,7 @@ subcommands: - use-default-eth-address: help: use a private key of the eth address if `from-seckey` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - from-seckey - wallet: about: manipulates a findora wallet @@ -355,14 +355,14 @@ subcommands: - gen-eth-address: help: generate the keypair of an eth address long: gen-eth-address - conflicts-with: + conflicts_with: - show - seckey - asset - use-default-eth-address: help: use a private key of the eth address if `seckey` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - seckey - create - asset: @@ -466,7 +466,7 @@ subcommands: - use-default-eth-address: help: use a private key of the eth address if `seckey` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - seckey - account: about: Return user contract account information or the balance if secret key is provided @@ -492,7 +492,7 @@ subcommands: - use-default-eth-address: help: use a private key of the eth address if `sec-key` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - sec-key - contract-deposit: about: Transfer an asset from the UTXO chain to the EVM chain @@ -582,7 +582,7 @@ subcommands: - use-default-eth-address: help: use a private key of the eth address if `from-seckey` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - from-seckey - anon-balance: about: List Anon balance and spending status for a public key and a list of commitments @@ -611,7 +611,7 @@ subcommands: - use-default-eth-address: help: use a private key of the eth address if `from-seckey` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - from-seckey - owned-open-abars: about: Get Open Anon UTXOs for a keypair using commitment @@ -634,7 +634,7 @@ subcommands: - use-default-eth-address: help: use a private key of the eth address if `from-seckey` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - from-seckey - owned-utxos: about: List owned UTXOs for a public key @@ -674,7 +674,7 @@ subcommands: - use-default-eth-address: help: use a private key of the eth address if `from-seckey` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - from-seckey - convert-abar-to-bar: about: Convert an ABAR to BAR @@ -717,7 +717,7 @@ subcommands: - use-default-eth-address: help: use a private key of the eth address if `from-seckey` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - from-seckey - anon-transfer: about: Perform an anonymous transfer @@ -759,7 +759,7 @@ subcommands: - use-default-eth-address: help: use a private key of the eth address if `from-seckey` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - from-seckey - anon-transfer-batch: about: Anonymous Transfer of tokens from multiple inputs to multiple outputs @@ -801,7 +801,7 @@ subcommands: - use-default-eth-address: help: use a private key of the eth address if `from-seckey` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - from-seckey - anon-fetch-merkle-proof: about: Query Merkle tree leaf info @@ -834,7 +834,7 @@ subcommands: - use-default-eth-address: help: use a private key of the eth address if `from-seckey` is not provided long: use-default-eth-address - conflicts-with: + conflicts_with: - from-seckey - replace_staker: about: Replace the staker of the validator with target address diff --git a/src/ledger/src/data_model/effects.rs b/src/ledger/src/data_model/effects.rs index e086a2034..494edbef2 100644 --- a/src/ledger/src/data_model/effects.rs +++ b/src/ledger/src/data_model/effects.rs @@ -287,7 +287,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 { diff --git a/src/ledger/src/staking/mod.rs b/src/ledger/src/staking/mod.rs index 7a42430b2..de471b8d2 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/store/mod.rs b/src/ledger/src/store/mod.rs index 498776a22..28a2f42c8 100644 --- a/src/ledger/src/store/mod.rs +++ b/src/ledger/src/store/mod.rs @@ -1547,6 +1547,22 @@ impl LedgerStatus { // Asset issuance should match the currently registered key } + let get_effect_asset = + |derived_asset_code: &AssetTypeCode| -> Option { + for (code, asset) in &txn_effect.new_asset_codes { + let dc = AssetTypeCode::from_prefix_and_raw_asset_type_code( + AssetTypePrefix::UserDefined, + &code, + &CFG.checkpoint, + self.td_commit_height, + ); + if dc == *derived_asset_code { + return Some(asset.clone()); + } + } + None + }; + // New issuance numbers // (1) Must refer to a created asset type // - NOTE: if the asset type is created in this transaction, this @@ -1560,7 +1576,7 @@ impl LedgerStatus { let asset_type = self .asset_types .get(&code) - .or_else(|| txn_effect.new_asset_codes.get(&code).cloned()) + .or_else(|| get_effect_asset(&code)) .c(d!())?; let proper_key = asset_type.properties.issuer; if *iss_key != proper_key { @@ -1715,6 +1731,7 @@ impl LedgerStatus { // // This drains every field of `block` except `txns` and `temp_sids`. #[allow(unused_mut)] + #[allow(clippy::unwrap_or_default)] fn apply_block_effects(&mut self, block: &mut BlockEffect) -> (TmpSidMap, u64, u64) { let base_sid = self.next_txo.0; let handle_asset_type_code = |code: AssetTypeCode| { From 741e8ab62801dc6ad8a093c7837d75ba0698f6b4 Mon Sep 17 00:00:00 2001 From: Weikeng Chen Date: Tue, 31 Oct 2023 17:55:39 +0800 Subject: [PATCH 6/7] Trigger the CI for the v0.5.6 of Noah --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f9b4f261f..883a511ab 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ stack.yaml.lock **/__pycache__ .idea + node_modules package-lock.json From 2bc4e6d40d4e1e448f7bf00d75ae8d097bec62ef Mon Sep 17 00:00:00 2001 From: Weikeng Chen Date: Tue, 31 Oct 2023 18:17:33 +0800 Subject: [PATCH 7/7] Update mod.rs --- src/components/config/src/findora/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/config/src/findora/mod.rs b/src/components/config/src/findora/mod.rs index c40b5bc67..c23877ba4 100644 --- a/src/components/config/src/findora/mod.rs +++ b/src/components/config/src/findora/mod.rs @@ -3,6 +3,7 @@ pub mod init { ruc::*, std::{fs, str}, }; + const QA01_GENESIS_URL: &str = "https://dev-qa01.dev.findora.org:26657/genesis"; const QA02_GENESIS_URL: &str = "https://dev-qa02.dev.findora.org:26657/genesis";