From 25a55ddbc5801d257bdbce9a7870c4b55ea6fd10 Mon Sep 17 00:00:00 2001 From: driftluo Date: Wed, 8 May 2024 17:54:53 +0800 Subject: [PATCH] test: add more test --- examples/omnilock_examples.rs | 1 + examples/omnilock_multisig_example.rs | 2 + src/core/advanced_builders.rs | 3 +- src/tests/mod.rs | 59 +- src/tests/transaction/omnilock.rs | 1712 ++++++++++++++++++++++++- src/tests/tx_builder/mod.rs | 2 +- src/traits/default_impls.rs | 25 +- src/transaction/builder/mod.rs | 38 +- src/transaction/builder/simple.rs | 17 +- src/transaction/builder/sudt.rs | 18 +- src/transaction/handler/mod.rs | 2 + src/transaction/handler/omnilock.rs | 48 +- src/transaction/signer/mod.rs | 21 +- src/transaction/signer/omnilock.rs | 26 +- src/unlock/omni_lock.rs | 69 +- src/unlock/signer.rs | 9 +- 16 files changed, 1866 insertions(+), 186 deletions(-) diff --git a/examples/omnilock_examples.rs b/examples/omnilock_examples.rs index b8e4edf8..15cad958 100644 --- a/examples/omnilock_examples.rs +++ b/examples/omnilock_examples.rs @@ -51,6 +51,7 @@ fn main() -> Result<(), Box> { &SignContexts::new_omnilock( [secp256k1::SecretKey::from_slice(private_key.as_bytes())?].to_vec(), omni_cfg, + ckb_sdk::unlock::OmniUnlockMode::Normal, ), )?; diff --git a/examples/omnilock_multisig_example.rs b/examples/omnilock_multisig_example.rs index beae02e6..8085b582 100644 --- a/examples/omnilock_multisig_example.rs +++ b/examples/omnilock_multisig_example.rs @@ -62,6 +62,7 @@ fn main() -> Result<(), Box> { &SignContexts::new_omnilock( [secp256k1::SecretKey::from_slice(private_key.as_bytes())?].to_vec(), omni_cfg.clone(), + ckb_sdk::unlock::OmniUnlockMode::Normal, ), )?; let private_key = h256!("0x4fd809631a6aa6e3bb378dd65eae5d71df895a82c91a615a1e8264741515c79c"); @@ -70,6 +71,7 @@ fn main() -> Result<(), Box> { &SignContexts::new_omnilock( [secp256k1::SecretKey::from_slice(private_key.as_bytes())?].to_vec(), omni_cfg, + ckb_sdk::unlock::OmniUnlockMode::Normal, ), )?; diff --git a/src/core/advanced_builders.rs b/src/core/advanced_builders.rs index 0b2a4296..fb348241 100644 --- a/src/core/advanced_builders.rs +++ b/src/core/advanced_builders.rs @@ -232,7 +232,8 @@ impl TransactionBuilder { if witness_data.is_empty() { WitnessArgs::default() } else { - WitnessArgs::from_slice(witness_data.as_ref()).unwrap() + WitnessArgs::from_slice(witness_data.as_ref()) + .expect("WitnessArgs expected but failed to decode ") } } diff --git a/src/tests/mod.rs b/src/tests/mod.rs index b48421e1..093f049f 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -5,21 +5,39 @@ mod tx_builder; use std::{collections::HashMap, u64}; +use ckb_dao_utils::pack_dao_data; use ckb_hash::blake2b_256; use ckb_jsonrpc_types as json_types; use ckb_types::{ bytes::Bytes, - core::{BlockView, ScriptHashType}, + core::{BlockView, Capacity, EpochNumberWithFraction, HeaderBuilder, ScriptHashType}, h160, h256, - packed::{OutPoint, Script}, + packed::{CellInput, CellOutput, OutPoint, Script, ScriptOpt, WitnessArgs}, prelude::*, H160, H256, }; -use crate::constants::{DAO_TYPE_HASH, MULTISIG_TYPE_HASH, ONE_CKB, SIGHASH_TYPE_HASH}; +use crate::constants::{ + CHEQUE_CELL_SINCE, DAO_TYPE_HASH, MULTISIG_TYPE_HASH, ONE_CKB, SIGHASH_TYPE_HASH, +}; use crate::traits::SecpCkbRawKeySigner; -use crate::unlock::{MultisigConfig, OmniLockConfig, ScriptUnlocker, SecpMultisigUnlocker}; -use crate::ScriptId; +use crate::tx_builder::{ + acp::{AcpTransferBuilder, AcpTransferReceiver}, + cheque::{ChequeClaimBuilder, ChequeWithdrawBuilder}, + dao::{ + DaoDepositBuilder, DaoDepositReceiver, DaoPrepareBuilder, DaoWithdrawBuilder, + DaoWithdrawItem, DaoWithdrawReceiver, + }, + transfer::CapacityTransferBuilder, + udt::{UdtIssueBuilder, UdtTargetReceiver, UdtTransferBuilder, UdtType}, + unlock_tx, CapacityBalancer, TransferAction, TxBuilder, +}; +use crate::unlock::{ + AcpUnlocker, ChequeAction, ChequeUnlocker, MultisigConfig, OmniLockConfig, ScriptUnlocker, + SecpMultisigUnlocker, SecpSighashUnlocker, +}; +use crate::util::{calculate_dao_maximum_withdraw4, minimal_unlock_point}; +use crate::{ScriptId, Since, SinceType}; use crate::test_util::{random_out_point, Context}; @@ -161,7 +179,7 @@ fn init_context( fn test_transfer_from_sighash() { let sender = build_sighash_script(ACCOUNT1_ARG); let receiver = build_sighash_script(ACCOUNT2_ARG); - let ctx = init_context( + let (ctx, _) = init_context( Vec::new(), vec![ (sender.clone(), Some(100 * ONE_CKB)), @@ -218,7 +236,7 @@ fn test_transfer_from_sighash() { fn test_transfer_capacity_overflow() { let sender = build_sighash_script(ACCOUNT1_ARG); let receiver = build_sighash_script(ACCOUNT2_ARG); - let ctx = init_context(Vec::new(), vec![(sender.clone(), Some(100 * ONE_CKB))]); + let (ctx, _) = init_context(Vec::new(), vec![(sender.clone(), Some(100 * ONE_CKB))]); let large_amount: u64 = u64::MAX; let output = CellOutput::new_builder() @@ -251,7 +269,7 @@ fn test_transfer_from_multisig() { let sender = build_multisig_script(&cfg); let receiver = build_sighash_script(ACCOUNT2_ARG); - let ctx = init_context( + let (ctx, _) = init_context( Vec::new(), vec![ (sender.clone(), Some(100 * ONE_CKB)), @@ -315,7 +333,7 @@ fn test_transfer_from_acp() { .args(Bytes::from(ACCOUNT1_ARG.0.to_vec()).pack()) .build(); let receiver = build_sighash_script(ACCOUNT2_ARG); - let ctx = init_context( + let (ctx, _) = init_context( vec![(ACP_BIN, true)], vec![ (sender.clone(), Some(100 * ONE_CKB)), @@ -376,7 +394,7 @@ fn test_transfer_to_acp() { .hash_type(ScriptHashType::Data1.into()) .args(Bytes::from(ACCOUNT2_ARG.0.to_vec()).pack()) .build(); - let ctx = init_context( + let (ctx, _) = init_context( vec![(ACP_BIN, true)], vec![ (sender.clone(), Some(100 * ONE_CKB)), @@ -462,7 +480,7 @@ fn test_cheque_claim() { .hash_type(ScriptHashType::Data1.into()) .args(Bytes::from(vec![9u8; 32]).pack()) .build(); - let mut ctx = init_context( + let (mut ctx, _) = init_context( vec![(CHEQUE_BIN, true), (SUDT_BIN, false)], vec![ (receiver.clone(), Some(100 * ONE_CKB)), @@ -582,7 +600,7 @@ fn test_cheque_withdraw() { .hash_type(ScriptHashType::Data1.into()) .args(Bytes::from(vec![9u8; 32]).pack()) .build(); - let mut ctx = init_context( + let (mut ctx, _) = init_context( vec![(CHEQUE_BIN, true), (SUDT_BIN, false)], vec![ (sender.clone(), Some(100 * ONE_CKB)), @@ -667,7 +685,7 @@ fn test_cheque_withdraw() { #[test] fn test_dao_deposit() { let sender = build_sighash_script(ACCOUNT1_ARG); - let ctx = init_context( + let (ctx, _) = init_context( Vec::new(), vec![ (sender.clone(), Some(100 * ONE_CKB)), @@ -732,7 +750,7 @@ fn test_dao_deposit() { #[test] fn test_dao_prepare() { let sender = build_sighash_script(ACCOUNT1_ARG); - let mut ctx = init_context( + let (mut ctx, _) = init_context( Vec::new(), vec![ (sender.clone(), Some(100 * ONE_CKB)), @@ -821,7 +839,7 @@ fn test_dao_prepare() { #[test] fn test_dao_withdraw() { let sender = build_sighash_script(ACCOUNT1_ARG); - let mut ctx = init_context( + let (mut ctx, _) = init_context( Vec::new(), vec![ (sender.clone(), Some(100 * ONE_CKB)), @@ -961,7 +979,7 @@ fn test_udt_issue() { let sudt_data_hash = H256::from(blake2b_256(SUDT_BIN)); let owner = build_sighash_script(ACCOUNT1_ARG); let receiver = build_sighash_script(ACCOUNT2_ARG); - let ctx = init_context( + let (ctx, _) = init_context( vec![(SUDT_BIN, false)], vec![ (owner.clone(), Some(100 * ONE_CKB)), @@ -1055,7 +1073,7 @@ fn test_udt_transfer() { .hash_type(ScriptHashType::Data1.into()) .args(owner.calc_script_hash().as_bytes().pack()) .build(); - let mut ctx = init_context( + let (mut ctx, _) = init_context( vec![(ACP_BIN, true), (SUDT_BIN, false)], vec![ (sender.clone(), Some(100 * ONE_CKB)), @@ -1142,10 +1160,3 @@ fn test_udt_transfer() { ); ctx.verify(tx, FEE_RATE).unwrap(); } - -pub mod ckb_indexer_rpc; -pub mod ckb_rpc; -pub mod cycle; -pub mod omni_lock; -pub mod omni_lock_util; -pub mod transaction; diff --git a/src/tests/transaction/omnilock.rs b/src/tests/transaction/omnilock.rs index 2511644a..59af55a5 100644 --- a/src/tests/transaction/omnilock.rs +++ b/src/tests/transaction/omnilock.rs @@ -13,10 +13,10 @@ use crate::{ constants::ONE_CKB, tests::{ build_always_success_script, build_omnilock_script, build_sighash_script, init_context, - ACCOUNT0_ARG, ACCOUNT0_KEY, ACCOUNT1_ARG, ACCOUNT1_KEY, ACCOUNT2_ARG, ALWAYS_SUCCESS_BIN, - FEE_RATE, OMNILOCK_BIN, + random_out_point, ACCOUNT0_ARG, ACCOUNT0_KEY, ACCOUNT1_ARG, ACCOUNT1_KEY, ACCOUNT2_ARG, + ACCOUNT2_KEY, ACCOUNT3_ARG, ACCOUNT3_KEY, ALWAYS_SUCCESS_BIN, FEE_RATE, OMNILOCK_BIN, }, - traits::{Signer, SignerError}, + traits::{LiveCell, Signer, SignerError}, transaction::{ builder::{CkbTransactionBuilder, SimpleTransactionBuilder}, handler::{ @@ -30,11 +30,12 @@ use crate::{ signer::{SignContexts, TransactionSigner}, TransactionBuilderConfiguration, }, + types::xudt_rce_mol::SmtProofEntryVec, unlock::{ - omni_lock::{ExecDlConfig, Preimage}, - MultisigConfig, OmniLockConfig, + omni_lock::{AdminConfig, ExecDlConfig, Identity, Preimage}, + IdentityFlag, MultisigConfig, OmniLockAcpConfig, OmniLockConfig, OmniUnlockMode, }, - util::{blake160, keccak160}, + util::{blake160, btc_auth, eos_auth, keccak160}, NetworkInfo, }; @@ -48,12 +49,7 @@ fn test_omnilock_config(outpoints: Vec) -> TransactionBuilderConfigura OMNILOCK_BIN, )))); let dep_cells = { - let mut cells = Vec::with_capacity(outpoints.len() + 1); - cells.push(crate::transaction::handler::cell_dep!( - "0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37", - 0u32, - DepType::DepGroup - )); + let mut cells = Vec::with_capacity(outpoints.len()); for outpoint in outpoints { cells.push( ckb_types::packed::CellDep::new_builder() @@ -83,11 +79,13 @@ fn test_omnilock_ethereum() { let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap(); let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account0_key); let mut cfg = OmniLockConfig::new_ethereum(keccak160(Pubkey::from(pubkey).as_ref())); - let sign_context = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg.clone(), &sign_context); cfg.enable_cobuild(true); - let sign_context_2 = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context_2 = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg, &sign_context_2); } @@ -97,11 +95,13 @@ fn test_omnilock_pubkeyhash() { let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account0_key); let mut cfg = OmniLockConfig::new_pubkey_hash(blake160(&pubkey.serialize())); - let sign_context = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg.clone(), &sign_context); cfg.enable_cobuild(true); - let sign_context_2 = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context_2 = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg, &sign_context_2); } @@ -116,11 +116,19 @@ fn test_omnilock_multisign() { ]; let multi_cfg = MultisigConfig::new_with(lock_args, 0, 2).unwrap(); let mut cfg = OmniLockConfig::new_multisig(multi_cfg); - let sign_context = SignContexts::new_omnilock(vec![account0_key, account1_key], cfg.clone()); + let sign_context = SignContexts::new_omnilock( + vec![account0_key, account1_key], + cfg.clone(), + OmniUnlockMode::Normal, + ); omnilock_test(cfg.clone(), &sign_context); cfg.enable_cobuild(true); - let sign_context_2 = SignContexts::new_omnilock(vec![account0_key, account1_key], cfg.clone()); + let sign_context_2 = SignContexts::new_omnilock( + vec![account0_key, account1_key], + cfg.clone(), + OmniUnlockMode::Normal, + ); omnilock_test(cfg, &sign_context_2); } @@ -129,11 +137,13 @@ fn test_omnilock_ethereum_display() { let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap(); let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account0_key); let mut cfg = OmniLockConfig::new_ethereum_display(keccak160(Pubkey::from(pubkey).as_ref())); - let sign_context = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg.clone(), &sign_context); cfg.enable_cobuild(true); - let sign_context_2 = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context_2 = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg, &sign_context_2); } @@ -146,11 +156,13 @@ fn test_omnilock_btc() { &Pubkey::from(pubkey), crate::unlock::omni_lock::BTCSignVtype::P2PKHUncompressed, ); - let sign_context = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg.clone(), &sign_context); cfg.enable_cobuild(true); - let sign_context_2 = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context_2 = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg, &sign_context_2); // compressed @@ -158,11 +170,13 @@ fn test_omnilock_btc() { &Pubkey::from(pubkey), crate::unlock::omni_lock::BTCSignVtype::P2PKHCompressed, ); - let sign_context = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg.clone(), &sign_context); cfg.enable_cobuild(true); - let sign_context_2 = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context_2 = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg, &sign_context_2); // segwitp2sh @@ -170,11 +184,13 @@ fn test_omnilock_btc() { &Pubkey::from(pubkey), crate::unlock::omni_lock::BTCSignVtype::SegwitP2SH, ); - let sign_context = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg.clone(), &sign_context); cfg.enable_cobuild(true); - let sign_context_2 = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context_2 = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg, &sign_context_2); // segwitbech32 @@ -182,11 +198,13 @@ fn test_omnilock_btc() { &Pubkey::from(pubkey), crate::unlock::omni_lock::BTCSignVtype::SegwitBech32, ); - let sign_context = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg.clone(), &sign_context); cfg.enable_cobuild(true); - let sign_context_2 = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context_2 = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg, &sign_context_2); } @@ -200,11 +218,13 @@ fn test_omnilock_dog() { &Pubkey::from(pubkey), crate::unlock::omni_lock::BTCSignVtype::P2PKHUncompressed, ); - let sign_context = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg.clone(), &sign_context); cfg.enable_cobuild(true); - let sign_context_2 = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context_2 = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg, &sign_context_2); // compress @@ -212,11 +232,13 @@ fn test_omnilock_dog() { &Pubkey::from(pubkey), crate::unlock::omni_lock::BTCSignVtype::P2PKHCompressed, ); - let sign_context = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg.clone(), &sign_context); cfg.enable_cobuild(true); - let sign_context_2 = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context_2 = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg, &sign_context_2); // SegwitP2SH @@ -224,11 +246,13 @@ fn test_omnilock_dog() { &Pubkey::from(pubkey), crate::unlock::omni_lock::BTCSignVtype::SegwitP2SH, ); - let sign_context = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg.clone(), &sign_context); cfg.enable_cobuild(true); - let sign_context_2 = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context_2 = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg, &sign_context_2); // SegwitBech32 @@ -236,11 +260,13 @@ fn test_omnilock_dog() { &Pubkey::from(pubkey), crate::unlock::omni_lock::BTCSignVtype::SegwitBech32, ); - let sign_context = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg.clone(), &sign_context); cfg.enable_cobuild(true); - let sign_context_2 = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context_2 = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg, &sign_context_2); } @@ -254,11 +280,13 @@ fn test_omnilock_eos() { &Pubkey::from(pubkey), crate::unlock::omni_lock::BTCSignVtype::P2PKHUncompressed, ); - let sign_context = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg.clone(), &sign_context); cfg.enable_cobuild(true); - let sign_context_2 = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context_2 = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg, &sign_context_2); // compressed @@ -266,11 +294,13 @@ fn test_omnilock_eos() { &Pubkey::from(pubkey), crate::unlock::omni_lock::BTCSignVtype::P2PKHCompressed, ); - let sign_context = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg.clone(), &sign_context); cfg.enable_cobuild(true); - let sign_context_2 = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context_2 = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg, &sign_context_2); } @@ -279,11 +309,13 @@ fn test_omnilock_tron() { let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap(); let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account0_key); let mut cfg = OmniLockConfig::new_tron_from_pubkey(&Pubkey::from(pubkey)); - let sign_context = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg.clone(), &sign_context); cfg.enable_cobuild(true); - let sign_context_2 = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let sign_context_2 = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg, &sign_context_2); } @@ -293,11 +325,16 @@ fn test_omnilock_solana() { ed25519_dalek::SigningKey::from_bytes(&ACCOUNT0_KEY.as_bytes().try_into().unwrap()); let pubkey = account0_key.verifying_key(); let mut cfg = OmniLockConfig::new_solana_from_pubkey(&pubkey); - let sign_context = SignContexts::new_omnilock_solana(account0_key.clone(), cfg.clone()); + let sign_context = SignContexts::new_omnilock_solana( + vec![account0_key.clone()], + cfg.clone(), + OmniUnlockMode::Normal, + ); omnilock_test(cfg.clone(), &sign_context); cfg.enable_cobuild(true); - let sign_context_2 = SignContexts::new_omnilock_solana(account0_key, cfg.clone()); + let sign_context_2 = + SignContexts::new_omnilock_solana(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); omnilock_test(cfg, &sign_context_2); } @@ -356,7 +393,7 @@ fn omnilock_test(cfg: OmniLockConfig, sign_context: &SignContexts) { let script_groups = tx_with_groups.script_groups.clone(); assert_eq!(script_groups.len(), 1); assert_eq!(tx.header_deps().len(), 0); - assert_eq!(tx.cell_deps().len(), 2); + assert_eq!(tx.cell_deps().len(), 1); assert_eq!(tx.inputs().len(), 2); for out_point in tx.input_pts_iter() { assert_eq!(ctx.get_input(&out_point).unwrap().0.lock(), sender); @@ -386,7 +423,8 @@ fn test_omnilock_owner_lock_tranfer(cobuild: bool) { let mut cfg = OmniLockConfig::new_ownerlock(hash); cfg.enable_cobuild(cobuild); let sender0 = build_omnilock_script(&cfg); - let mut sign_context = SignContexts::new_omnilock(vec![account0_key], cfg.clone()); + let mut sign_context = + SignContexts::new_omnilock(vec![account0_key], cfg.clone(), OmniUnlockMode::Normal); let hashall_unlock = crate::transaction::signer::sighash::Secp256k1Blake160SighashAllSignerContext::new(vec![ account0_key, @@ -676,7 +714,8 @@ fn test_omnilock_dl_exec(config: ExecDlConfig, signer: T, c cfg.enable_cobuild(cobuild); let sender = build_omnilock_script(&cfg); - let sign_context = SignContexts::new_omnilock_exec_dl_custom(signer, cfg.clone()); + let sign_context = + SignContexts::new_omnilock_exec_dl_custom(signer, cfg.clone(), OmniUnlockMode::Normal); let (ctx, outpoints) = init_context( vec![(OMNILOCK_BIN, true), (bin, true)], @@ -723,7 +762,7 @@ fn test_omnilock_dl_exec(config: ExecDlConfig, signer: T, c assert_eq!(script_groups.len(), 1); assert_eq!(tx.header_deps().len(), 0); - assert_eq!(tx.cell_deps().len(), 3); + assert_eq!(tx.cell_deps().len(), 2); assert_eq!(tx.inputs().len(), 1); for out_point in tx.input_pts_iter() { assert_eq!(ctx.get_input(&out_point).unwrap().0.lock(), sender); @@ -736,3 +775,1580 @@ fn test_omnilock_dl_exec(config: ExecDlConfig, signer: T, c assert_eq!(tx.data().as_reader().serialized_size_in_block() as u64, fee); ctx.verify(tx, FEE_RATE).unwrap(); } + +#[test] +fn test_omnilock_pubkeyhash_rc_dep() { + let sender_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &sender_key); + let pubkey_hash = blake160(&pubkey.serialize()); + let mut cfg = OmniLockConfig::new_pubkey_hash(pubkey_hash); + + let account3_key = secp256k1::SecretKey::from_slice(ACCOUNT3_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account3_key); + let id = Identity::new_pubkey_hash(blake160(&pubkey.serialize())); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + false, + )); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Normal); + cfg.enable_cobuild(true); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg, OmniUnlockMode::Normal); +} + +#[test] +fn test_omnilock_ethereum_rc_dep() { + let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account0_key); + let mut cfg = OmniLockConfig::new_ethereum(keccak160(Pubkey::from(pubkey).as_ref())); + + let account3_key = secp256k1::SecretKey::from_slice(ACCOUNT3_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account3_key); + let id = Identity::new_ethereum(keccak160(Pubkey::from(pubkey).as_ref())); + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + false, + )); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Normal); + cfg.enable_cobuild(true); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg, OmniUnlockMode::Normal); +} + +#[test] +fn test_omnilock_ethereum_dispaly_rc_dep() { + let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account0_key); + let mut cfg = OmniLockConfig::new_ethereum_display(keccak160(Pubkey::from(pubkey).as_ref())); + + let account3_key = secp256k1::SecretKey::from_slice(ACCOUNT3_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account3_key); + let id = Identity::new_ethereum_display(keccak160(Pubkey::from(pubkey).as_ref())); + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + false, + )); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Normal); + cfg.enable_cobuild(true); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg, OmniUnlockMode::Normal); +} + +#[test] +fn test_omnilock_btc_rc_dep() { + let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap(); + let pubkey_0 = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account0_key); + // uncompressed + let mut cfg = OmniLockConfig::new_btc_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::P2PKHUncompressed, + ); + + let account3_key = secp256k1::SecretKey::from_slice(ACCOUNT3_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey_3 = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account3_key); + let id = Identity::new_btc(H160::from(btc_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::P2PKHUncompressed, + ))); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + false, + )); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Normal); + cfg.enable_cobuild(true); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg, OmniUnlockMode::Normal); + + // compressed + let mut cfg = OmniLockConfig::new_btc_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::P2PKHCompressed, + ); + let id = Identity::new_btc(H160::from(btc_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::P2PKHCompressed, + ))); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + false, + )); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Normal); + cfg.enable_cobuild(true); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg, OmniUnlockMode::Normal); + + // SegwitBech32 + let mut cfg = OmniLockConfig::new_btc_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::SegwitBech32, + ); + let id = Identity::new_btc(H160::from(btc_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::SegwitBech32, + ))); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + false, + )); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Normal); + cfg.enable_cobuild(true); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg, OmniUnlockMode::Normal); + + // SegwitP2SH + let mut cfg = OmniLockConfig::new_btc_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::SegwitP2SH, + ); + let id = Identity::new_btc(H160::from(btc_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::SegwitP2SH, + ))); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + false, + )); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Normal); + cfg.enable_cobuild(true); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg, OmniUnlockMode::Normal); +} + +#[test] +fn test_omnilock_dog_rc_dep() { + let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap(); + let pubkey_0 = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account0_key); + // uncompressed + let mut cfg = OmniLockConfig::new_dogcoin_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::P2PKHUncompressed, + ); + + let account3_key = secp256k1::SecretKey::from_slice(ACCOUNT3_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey_3 = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account3_key); + let id = Identity::new_dogcoin(H160::from(btc_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::P2PKHUncompressed, + ))); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + false, + )); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Normal); + cfg.enable_cobuild(true); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg, OmniUnlockMode::Normal); + + // compressed + let mut cfg = OmniLockConfig::new_dogcoin_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::P2PKHCompressed, + ); + let id = Identity::new_dogcoin(H160::from(btc_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::P2PKHCompressed, + ))); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + false, + )); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Normal); + cfg.enable_cobuild(true); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg, OmniUnlockMode::Normal); + + // SegwitBech32 + let mut cfg = OmniLockConfig::new_dogcoin_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::SegwitBech32, + ); + let id = Identity::new_dogcoin(H160::from(btc_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::SegwitBech32, + ))); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + false, + )); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Normal); + cfg.enable_cobuild(true); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg, OmniUnlockMode::Normal); + + // SegwitP2SH + let mut cfg = OmniLockConfig::new_dogcoin_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::SegwitP2SH, + ); + let id = Identity::new_dogcoin(H160::from(btc_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::SegwitP2SH, + ))); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + false, + )); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Normal); + cfg.enable_cobuild(true); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg, OmniUnlockMode::Normal); +} + +#[test] +fn test_omnilock_eos_rc_dep() { + let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap(); + let pubkey_0 = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account0_key); + // uncompressed + let mut cfg = OmniLockConfig::new_eos_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::P2PKHUncompressed, + ); + + let account3_key = secp256k1::SecretKey::from_slice(ACCOUNT3_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey_3 = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account3_key); + let id = Identity::new_eos(H160::from(eos_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::P2PKHUncompressed, + ))); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + false, + )); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Normal); + cfg.enable_cobuild(true); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg, OmniUnlockMode::Normal); + + // compressed + let mut cfg = OmniLockConfig::new_eos_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::P2PKHCompressed, + ); + let id = Identity::new_eos(H160::from(eos_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::P2PKHCompressed, + ))); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + false, + )); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Normal); + cfg.enable_cobuild(true); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg, OmniUnlockMode::Normal); +} + +#[test] +fn test_omnilock_tron_rc_dep() { + let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap(); + let pubkey_0 = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account0_key); + + let mut cfg = OmniLockConfig::new_tron_from_pubkey(&Pubkey::from(pubkey_0)); + + let account3_key = secp256k1::SecretKey::from_slice(ACCOUNT3_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey_3 = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account3_key); + let id = Identity::new_tron(keccak160(Pubkey::from(pubkey_3).as_bytes())); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + false, + )); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Normal); + cfg.enable_cobuild(true); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg, OmniUnlockMode::Normal); +} + +#[test] +fn test_omnilock_solana_rc_dep() { + let account0_key = + ed25519_dalek::SigningKey::from_bytes(ACCOUNT0_KEY.as_bytes().try_into().unwrap()); + let pubkey_0 = account0_key.verifying_key(); + + let mut cfg = OmniLockConfig::new_solana_from_pubkey(&pubkey_0); + + let account3_key = + ed25519_dalek::SigningKey::from_bytes(ACCOUNT3_KEY.as_bytes().try_into().unwrap()); + let pubkey_3 = account3_key.verifying_key(); + let id = Identity::new( + crate::unlock::IdentityFlag::Solana, + blake160(pubkey_3.as_bytes()), + ); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + false, + )); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Normal); + cfg.enable_cobuild(true); + test_omnilock_rc_dep(cfg.clone(), OmniUnlockMode::Admin); + test_omnilock_rc_dep(cfg, OmniUnlockMode::Normal); +} + +fn test_omnilock_rc_dep(mut cfg: OmniLockConfig, unlock_mode: OmniUnlockMode) { + let network_info = NetworkInfo::testnet(); + let receiver = build_sighash_script(ACCOUNT2_ARG); + + let (mut ctx, mut outpoints) = init_context(vec![(OMNILOCK_BIN, true)], vec![]); + let (rce_cells, rce_cells_len) = match unlock_mode { + OmniUnlockMode::Admin => { + let mut admin_config = cfg.get_admin_config().unwrap().clone(); + let rc_args = match unlock_mode { + OmniUnlockMode::Admin => ACCOUNT3_ARG, + OmniUnlockMode::Normal => ACCOUNT0_ARG, + }; + let (proof_vec, rc_type_id, rce_cells) = + crate::tests::tx_builder::omni_lock_util::generate_rc( + &mut ctx, + admin_config.get_auth().to_smt_key().into(), + false, + rc_args, + ); + admin_config.set_proofs(proof_vec); + admin_config.set_rc_type_id(H256::from_slice(rc_type_id.as_ref()).unwrap()); + cfg.set_admin_config(admin_config); + let rce_cells_len = rce_cells.len(); + (Some(rce_cells), rce_cells_len) + } + OmniUnlockMode::Normal => (None, 0), + }; + let sender = build_omnilock_script(&cfg); + for (lock, capacity_opt) in [ + (sender.clone(), Some(300 * ONE_CKB)), + (sender.clone(), Some(300 * ONE_CKB)), + ] { + ctx.add_simple_live_cell(random_out_point(), lock, capacity_opt); + } + + outpoints.extend(rce_cells.unwrap_or_default()); + + let configuration = test_omnilock_config(outpoints); + + let iterator = InputIterator::new_with_cell_collector( + vec![sender.clone()], + Box::new(ctx.to_live_cells_context()) as Box<_>, + ); + let mut builder = SimpleTransactionBuilder::new(configuration, iterator); + + let output = CellOutput::new_builder() + .capacity((110 * ONE_CKB).pack()) + .lock(receiver) + .build(); + + builder.add_output_and_data(output.clone(), ckb_types::packed::Bytes::default()); + builder.set_change_lock(sender.clone()); + + let unlock_key = match unlock_mode { + OmniUnlockMode::Admin => ACCOUNT3_KEY, + OmniUnlockMode::Normal => ACCOUNT0_KEY, + }; + + let sign_context = if cfg.id().flag() == IdentityFlag::Solana { + SignContexts::new_omnilock_solana( + vec![ed25519_dalek::SigningKey::from_bytes( + unlock_key.as_bytes().try_into().unwrap(), + )], + cfg.clone(), + unlock_mode, + ) + } else { + SignContexts::new_omnilock( + vec![secp256k1::SecretKey::from_slice(unlock_key.as_bytes()).unwrap()], + cfg.clone(), + unlock_mode, + ) + }; + + let context = + OmnilockScriptContext::new(cfg.clone(), network_info.url.clone()).unlock_mode(unlock_mode); + let mut contexts = HandlerContexts::default(); + contexts.add_context(Box::new(context) as Box<_>); + + let mut tx_with_groups = builder.build(&contexts).expect("build failed"); + + // let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone()); + // println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap()); + + TransactionSigner::new(&network_info) + // use unitest lock to verify + .insert_unlocker( + crate::ScriptId::new_data1(H256::from(blake2b_256(OMNILOCK_BIN))), + crate::transaction::signer::omnilock::OmnilockSigner {}, + ) + .sign_transaction(&mut tx_with_groups, &sign_context) + .unwrap(); + let tx = tx_with_groups.get_tx_view().clone(); + let script_groups = tx_with_groups.script_groups.clone(); + + // let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone()); + // println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap()); + + assert_eq!(script_groups.len(), 1); + assert_eq!(tx.header_deps().len(), 0); + assert_eq!(tx.cell_deps().len(), 1 + rce_cells_len); + assert_eq!(tx.inputs().len(), 1); + for out_point in tx.input_pts_iter() { + assert_eq!(ctx.get_input(&out_point).unwrap().0.lock(), sender); + } + assert_eq!(tx.outputs().len(), 2); + assert_eq!(tx.output(0).unwrap(), output); + assert_eq!(tx.output(1).unwrap().lock(), sender); + let change_capacity: u64 = tx.output(1).unwrap().capacity().unpack(); + let fee = (300 - 110) * ONE_CKB - change_capacity; + assert_eq!(tx.data().as_reader().serialized_size_in_block() as u64, fee); + + ctx.verify(tx, FEE_RATE).unwrap(); +} + +#[test] +fn test_omnilock_pubkeyhash_rc_input_and_dep() { + let sender_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &sender_key); + let pubkey_hash = blake160(&pubkey.serialize()); + let mut cfg = OmniLockConfig::new_pubkey_hash(pubkey_hash); + + let account3_key = secp256k1::SecretKey::from_slice(ACCOUNT3_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account3_key); + let id = Identity::new_pubkey_hash(blake160(&pubkey.serialize())); + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id.clone(), + None, + false, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg.clone()); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + true, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg); +} + +#[test] +fn test_omnilock_eth_rc_input_and_dep() { + let sender_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &sender_key); + let mut cfg = OmniLockConfig::new_ethereum(keccak160(Pubkey::from(pubkey).as_ref())); + + let account3_key = secp256k1::SecretKey::from_slice(ACCOUNT3_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account3_key); + let id = Identity::new_ethereum(keccak160(Pubkey::from(pubkey).as_ref())); + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id.clone(), + None, + false, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg.clone()); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + true, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg); +} + +#[test] +fn test_omnilock_eth_display_rc_input_and_dep() { + let sender_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &sender_key); + let mut cfg = OmniLockConfig::new_ethereum_display(keccak160(Pubkey::from(pubkey).as_ref())); + + let account3_key = secp256k1::SecretKey::from_slice(ACCOUNT3_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account3_key); + let id = Identity::new_ethereum_display(keccak160(Pubkey::from(pubkey).as_ref())); + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id.clone(), + None, + false, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg.clone()); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + true, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg); +} + +#[test] +fn test_omnilock_btc_rc_input_and_dep() { + let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap(); + let pubkey_0 = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account0_key); + // uncompressed + let mut cfg = OmniLockConfig::new_btc_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::P2PKHUncompressed, + ); + + let account3_key = secp256k1::SecretKey::from_slice(ACCOUNT3_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey_3 = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account3_key); + let id = Identity::new_btc(H160::from(btc_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::P2PKHUncompressed, + ))); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id.clone(), + None, + false, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg.clone()); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + true, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg); + + // P2PKHCompressed + let mut cfg = OmniLockConfig::new_btc_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::P2PKHCompressed, + ); + let id = Identity::new_btc(H160::from(btc_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::P2PKHCompressed, + ))); + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id.clone(), + None, + false, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg.clone()); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + true, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg); + + // SegwitBech32 + let mut cfg = OmniLockConfig::new_btc_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::SegwitBech32, + ); + let id = Identity::new_btc(H160::from(btc_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::SegwitBech32, + ))); + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id.clone(), + None, + false, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg.clone()); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + true, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg); + + // SegwitP2SH + let mut cfg = OmniLockConfig::new_btc_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::SegwitP2SH, + ); + let id = Identity::new_btc(H160::from(btc_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::SegwitP2SH, + ))); + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id.clone(), + None, + false, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg.clone()); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + true, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg); +} + +#[test] +fn test_omnilock_dog_rc_input_and_dep() { + let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap(); + let pubkey_0 = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account0_key); + // uncompressed + let mut cfg = OmniLockConfig::new_dogcoin_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::P2PKHUncompressed, + ); + + let account3_key = secp256k1::SecretKey::from_slice(ACCOUNT3_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey_3 = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account3_key); + let id = Identity::new_dogcoin(H160::from(btc_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::P2PKHUncompressed, + ))); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id.clone(), + None, + false, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg.clone()); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + true, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg); + + // P2PKHCompressed + let mut cfg = OmniLockConfig::new_dogcoin_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::P2PKHCompressed, + ); + let id = Identity::new_dogcoin(H160::from(btc_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::P2PKHCompressed, + ))); + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id.clone(), + None, + false, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg.clone()); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + true, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg); + + // SegwitBech32 + let mut cfg = OmniLockConfig::new_dogcoin_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::SegwitBech32, + ); + let id = Identity::new_dogcoin(H160::from(btc_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::SegwitBech32, + ))); + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id.clone(), + None, + false, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg.clone()); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + true, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg); + + // SegwitP2SH + let mut cfg = OmniLockConfig::new_dogcoin_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::SegwitP2SH, + ); + let id = Identity::new_dogcoin(H160::from(btc_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::SegwitP2SH, + ))); + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id.clone(), + None, + false, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg.clone()); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + true, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg); +} + +#[test] +fn test_omnilock_eos_rc_input_and_dep() { + let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap(); + let pubkey_0 = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account0_key); + // uncompressed + let mut cfg = OmniLockConfig::new_eos_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::P2PKHUncompressed, + ); + + let account3_key = secp256k1::SecretKey::from_slice(ACCOUNT3_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey_3 = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account3_key); + let id = Identity::new_eos(H160::from(eos_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::P2PKHUncompressed, + ))); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id.clone(), + None, + false, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg.clone()); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + true, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg); + + // P2PKHCompressed + let mut cfg = OmniLockConfig::new_eos_from_pubkey( + &Pubkey::from(pubkey_0), + crate::unlock::omni_lock::BTCSignVtype::P2PKHCompressed, + ); + let id = Identity::new_eos(H160::from(eos_auth( + &pubkey_3.into(), + crate::unlock::omni_lock::BTCSignVtype::P2PKHCompressed, + ))); + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id.clone(), + None, + false, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg.clone()); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + true, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg); +} + +#[test] +fn test_omnilock_tron_rc_input_and_dep() { + let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap(); + let pubkey_0 = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account0_key); + + let mut cfg = OmniLockConfig::new_tron_from_pubkey(&Pubkey::from(pubkey_0)); + + let account3_key = secp256k1::SecretKey::from_slice(ACCOUNT3_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey_3 = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account3_key); + let id = Identity::new_tron(keccak160(Pubkey::from(pubkey_3).as_bytes())); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id.clone(), + None, + false, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg.clone()); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + true, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg); +} + +#[test] +fn test_omnilock_solana_rc_input_and_dep() { + let account0_key = + ed25519_dalek::SigningKey::from_bytes(ACCOUNT0_KEY.as_bytes().try_into().unwrap()); + let pubkey_0 = account0_key.verifying_key(); + + let mut cfg = OmniLockConfig::new_solana_from_pubkey(&pubkey_0); + + let account3_key = + ed25519_dalek::SigningKey::from_bytes(ACCOUNT3_KEY.as_bytes().try_into().unwrap()); + let pubkey_3 = account3_key.verifying_key(); + let id = Identity::new( + crate::unlock::IdentityFlag::Solana, + blake160(pubkey_3.as_bytes()), + ); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id.clone(), + None, + false, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg.clone()); + + cfg.set_admin_config(AdminConfig::new( + H256::default(), + SmtProofEntryVec::default(), + id, + None, + true, + )); + test_omnilock_rc_input_and_dep(cfg.clone()); + cfg.enable_cobuild(true); + test_omnilock_rc_input_and_dep(cfg); +} + +fn test_omnilock_rc_input_and_dep(mut cfg: OmniLockConfig) { + let network_info = NetworkInfo::testnet(); + let unlock_mode = OmniUnlockMode::Admin; + + let receiver = build_sighash_script(ACCOUNT2_ARG); + + let (mut ctx, mut outpoints) = init_context( + vec![(OMNILOCK_BIN, true), (ALWAYS_SUCCESS_BIN, false)], + vec![], + ); + let mut admin_config = cfg.get_admin_config().unwrap().clone(); + let rc_input = admin_config.rce_in_input(); + + let (proof_vec, rc_type_id, rce_cells) = crate::tests::tx_builder::omni_lock_util::generate_rc( + &mut ctx, + admin_config.get_auth().to_smt_key().into(), + rc_input, + ACCOUNT3_ARG, + ); + admin_config.set_proofs(proof_vec); + admin_config.set_rc_type_id(H256::from_slice(rc_type_id.as_ref()).unwrap()); + cfg.set_admin_config(admin_config); + let sender = build_omnilock_script(&cfg); + for (lock, capacity_opt) in [(sender.clone(), Some(300 * ONE_CKB))] { + ctx.add_simple_live_cell(random_out_point(), lock, capacity_opt); + } + + let rc_inputs = if rc_input { + rce_cells + .clone() + .into_iter() + .map(|outpoint| { + let (output, output_data) = ctx.get_input(&outpoint).unwrap(); + LiveCell { + out_point: outpoint, + output, + output_data, + block_number: 0, + tx_index: 0, + } + }) + .collect() + } else { + // rc cell is dep cell + outpoints.extend(rce_cells.clone()); + Vec::new() + }; + let configuration = test_omnilock_config(outpoints); + + let iterator = InputIterator::new_with_cell_collector( + vec![sender.clone()], + Box::new(ctx.to_live_cells_context()) as Box<_>, + ); + let mut builder = SimpleTransactionBuilder::new(configuration, iterator); + + let output = CellOutput::new_builder() + .capacity((110 * ONE_CKB).pack()) + .lock(receiver) + .build(); + builder.add_output_and_data(output.clone(), ckb_types::packed::Bytes::default()); + builder.set_change_lock(sender.clone()); + + if !rc_inputs.is_empty() { + builder.set_rc_cells(rc_inputs) + } + + let account_key = secp256k1::SecretKey::from_slice(ACCOUNT3_KEY.as_bytes()).unwrap(); + let mut sign_context = if cfg.id().flag() == IdentityFlag::Solana { + SignContexts::new_omnilock_solana( + vec![ed25519_dalek::SigningKey::from_bytes( + ACCOUNT3_KEY.as_bytes().try_into().unwrap(), + )], + cfg.clone(), + unlock_mode, + ) + } else { + SignContexts::new_omnilock(vec![account_key], cfg.clone(), unlock_mode) + }; + let hashall_unlock = + crate::transaction::signer::sighash::Secp256k1Blake160SighashAllSignerContext::new(vec![ + account_key, + ]); + sign_context.add_context(Box::new(hashall_unlock)); + + let context = + OmnilockScriptContext::new(cfg.clone(), network_info.url.clone()).unlock_mode(unlock_mode); + let mut contexts = HandlerContexts::default(); + contexts.add_context(Box::new(context) as Box<_>); + + let mut tx_with_groups = builder.build(&contexts).expect("build failed"); + + // let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone()); + // println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap()); + + TransactionSigner::new(&network_info) + // use unitest lock to verify + .insert_unlocker( + crate::ScriptId::new_data1(H256::from(blake2b_256(OMNILOCK_BIN))), + crate::transaction::signer::omnilock::OmnilockSigner {}, + ) + .sign_transaction(&mut tx_with_groups, &sign_context) + .unwrap(); + let tx = tx_with_groups.get_tx_view().clone(); + let script_groups = tx_with_groups.script_groups.clone(); + + // let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone()); + // println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap()); + + if rc_input { + assert_eq!(script_groups.len(), 5); + assert_eq!(tx.header_deps().len(), 0); + assert_eq!(tx.cell_deps().len(), 3); // one is omnilock, one is sighash, one is always success + assert_eq!(tx.inputs().len(), 4); + for out_point in tx.input_pts_iter().skip(rce_cells.len()) { + assert_eq!(ctx.get_input(&out_point).unwrap().0.lock(), sender); + } + assert_eq!(tx.outputs().len(), 2); + assert_eq!(tx.output(0).unwrap(), output); + assert_eq!(tx.output(1).unwrap().lock(), sender); + let change_capacity: u64 = tx.output(1).unwrap().capacity().unpack(); + let fee = (300 - 110) * ONE_CKB - change_capacity; + assert_eq!(tx.data().as_reader().serialized_size_in_block() as u64, fee); + } else { + assert_eq!(script_groups.len(), 1); + assert_eq!(tx.header_deps().len(), 0); + assert_eq!(tx.cell_deps().len(), 5); + assert_eq!(tx.inputs().len(), 1); + for out_point in tx.input_pts_iter() { + assert_eq!(ctx.get_input(&out_point).unwrap().0.lock(), sender); + } + assert_eq!(tx.outputs().len(), 2); + assert_eq!(tx.output(0).unwrap(), output); + assert_eq!(tx.output(1).unwrap().lock(), sender); + let change_capacity: u64 = tx.output(1).unwrap().capacity().unpack(); + let fee = (300 - 110) * ONE_CKB - change_capacity; + assert_eq!(tx.data().as_reader().serialized_size_in_block() as u64, fee); + } + + ctx.verify(tx, FEE_RATE).unwrap(); +} + +#[test] +fn test_omnilock_multisign_rc_all() { + test_omnilock_multisign_rc_dep(false, OmniUnlockMode::Admin); + test_omnilock_multisign_rc_dep(false, OmniUnlockMode::Normal); + test_omnilock_multisign_rc_dep(true, OmniUnlockMode::Admin); + test_omnilock_multisign_rc_dep(true, OmniUnlockMode::Normal); +} + +fn test_omnilock_multisign_rc_dep(cobuild: bool, unlock_mode: OmniUnlockMode) { + let network_info = NetworkInfo::testnet(); + let lock_args = vec![ + ACCOUNT0_ARG.clone(), + ACCOUNT1_ARG.clone(), + ACCOUNT2_ARG.clone(), + ]; + let multi_cfg = MultisigConfig::new_with(lock_args, 0, 2).unwrap(); + let mut cfg = OmniLockConfig::new_multisig(multi_cfg); + + let lock_args = vec![ + ACCOUNT3_ARG.clone(), // the different key + ACCOUNT1_ARG.clone(), + ACCOUNT2_ARG.clone(), + ]; + let multi_cfg = MultisigConfig::new_with(lock_args, 0, 2).unwrap(); + let admin_id = Identity::new_multisig(multi_cfg.clone()); + + let (mut ctx, mut outpoints) = init_context(vec![(OMNILOCK_BIN, true)], vec![]); + let (proof_vec, rc_type_id, rce_cells) = crate::tests::tx_builder::omni_lock_util::generate_rc( + &mut ctx, + admin_id.to_smt_key().into(), + false, + ACCOUNT0_ARG, + ); + cfg.set_admin_config(AdminConfig::new( + H256::from_slice(rc_type_id.as_ref()).unwrap(), + proof_vec, + admin_id, + Some(multi_cfg), + false, + )); + cfg.enable_cobuild(cobuild); + + let sender = build_omnilock_script(&cfg); + let receiver = build_sighash_script(ACCOUNT2_ARG); + for (lock, capacity_opt) in [ + (sender.clone(), Some(100 * ONE_CKB)), + (sender.clone(), Some(200 * ONE_CKB)), + (sender.clone(), Some(300 * ONE_CKB)), + ] { + ctx.add_simple_live_cell(random_out_point(), lock, capacity_opt); + } + + outpoints.extend(rce_cells); + + let configuration = test_omnilock_config(outpoints); + + let iterator = InputIterator::new_with_cell_collector( + vec![sender.clone()], + Box::new(ctx.to_live_cells_context()) as Box<_>, + ); + let mut builder = SimpleTransactionBuilder::new(configuration, iterator); + let output = CellOutput::new_builder() + .capacity((120 * ONE_CKB).pack()) + .lock(receiver) + .build(); + builder.add_output_and_data(output.clone(), ckb_types::packed::Bytes::default()); + builder.set_change_lock(sender.clone()); + + let key0 = match unlock_mode { + OmniUnlockMode::Admin => ACCOUNT3_KEY, + OmniUnlockMode::Normal => ACCOUNT0_KEY, + }; + + let sign_context = SignContexts::new_omnilock( + vec![ + secp256k1::SecretKey::from_slice(key0.as_bytes()).unwrap(), + secp256k1::SecretKey::from_slice(ACCOUNT1_KEY.as_bytes()).unwrap(), + ], + cfg.clone(), + unlock_mode, + ); + + let context = + OmnilockScriptContext::new(cfg.clone(), network_info.url.clone()).unlock_mode(unlock_mode); + let mut contexts = HandlerContexts::default(); + contexts.add_context(Box::new(context) as Box<_>); + + let mut tx_with_groups = builder.build(&contexts).expect("build failed"); + + TransactionSigner::new(&network_info) + // use unitest lock to verify + .insert_unlocker( + crate::ScriptId::new_data1(H256::from(blake2b_256(OMNILOCK_BIN))), + crate::transaction::signer::omnilock::OmnilockSigner {}, + ) + .sign_transaction(&mut tx_with_groups, &sign_context) + .unwrap(); + let tx = tx_with_groups.get_tx_view().clone(); + let script_groups = tx_with_groups.script_groups.clone(); + + assert_eq!(script_groups.len(), 1); + assert_eq!(tx.header_deps().len(), 0); + assert_eq!(tx.cell_deps().len(), 4); + assert_eq!(tx.inputs().len(), 2); + for out_point in tx.input_pts_iter() { + assert_eq!(ctx.get_input(&out_point).unwrap().0.lock(), sender); + } + assert_eq!(tx.outputs().len(), 2); + assert_eq!(tx.output(0).unwrap(), output); + assert_eq!(tx.output(1).unwrap().lock(), sender); + let change_capacity: u64 = tx.output(1).unwrap().capacity().unpack(); + let fee = (300 - 120) * ONE_CKB - change_capacity; + assert_eq!(tx.data().as_reader().serialized_size_in_block() as u64, fee); + + ctx.verify(tx, FEE_RATE).unwrap(); +} + +#[test] +fn test_omnilock_owner_lock_rc_dep_all() { + test_omnilock_owner_lock_rc_dep(false); + test_omnilock_owner_lock_rc_dep(true); +} + +fn test_omnilock_owner_lock_rc_dep(cobuild: bool) { + let network_info = NetworkInfo::testnet(); + let unlock_mode = OmniUnlockMode::Admin; + let receiver = build_sighash_script(ACCOUNT2_ARG); + let sender1 = build_sighash_script(ACCOUNT1_ARG); + let hash = H160::from_slice(&sender1.calc_script_hash().as_slice()[0..20]).unwrap(); + let mut cfg = OmniLockConfig::new_ownerlock(hash); + + let owner_sender = build_sighash_script(ACCOUNT3_ARG); + let (mut ctx, mut outpoints) = init_context( + vec![(OMNILOCK_BIN, true)], + vec![(owner_sender.clone(), Some(61 * ONE_CKB))], + ); + + let owner_hash = H160::from_slice(&owner_sender.calc_script_hash().as_slice()[0..20]).unwrap(); + let owner_id = Identity::new_ownerlock(owner_hash); + let (proof_vec, rc_type_id, rce_cells) = crate::tests::tx_builder::omni_lock_util::generate_rc( + &mut ctx, + owner_id.to_smt_key().into(), + false, + ACCOUNT0_ARG, + ); + cfg.set_admin_config(AdminConfig::new( + H256::from_slice(rc_type_id.as_ref()).unwrap(), + proof_vec, + owner_id, + None, + false, + )); + cfg.enable_cobuild(cobuild); + let sender0 = build_omnilock_script(&cfg); + for (lock, capacity_opt) in [(sender0.clone(), Some(150 * ONE_CKB))] { + ctx.add_simple_live_cell(random_out_point(), lock, capacity_opt); + } + + outpoints.extend(rce_cells); + + let configuration = test_omnilock_config(outpoints); + + let iterator = InputIterator::new_with_cell_collector( + vec![sender0.clone(), owner_sender.clone()], + Box::new(ctx.to_live_cells_context()) as Box<_>, + ); + let mut builder = SimpleTransactionBuilder::new(configuration, iterator); + let output = CellOutput::new_builder() + .capacity((110 * ONE_CKB).pack()) + .lock(receiver) + .build(); + builder.add_output_and_data(output.clone(), ckb_types::packed::Bytes::default()); + builder.set_change_lock(sender0.clone()); + + let mut sign_context = SignContexts::new_omnilock( + vec![secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap()], + cfg.clone(), + unlock_mode, + ); + let hashall_unlock = + crate::transaction::signer::sighash::Secp256k1Blake160SighashAllSignerContext::new(vec![ + secp256k1::SecretKey::from_slice(ACCOUNT3_KEY.as_bytes()).unwrap(), + ]); + sign_context.add_context(Box::new(hashall_unlock)); + + let context = + OmnilockScriptContext::new(cfg.clone(), network_info.url.clone()).unlock_mode(unlock_mode); + let mut contexts = HandlerContexts::default(); + contexts.add_context(Box::new(context) as Box<_>); + + let mut tx_with_groups = builder.build(&contexts).expect("build failed"); + + TransactionSigner::new(&network_info) + // use unitest lock to verify + .insert_unlocker( + crate::ScriptId::new_data1(H256::from(blake2b_256(OMNILOCK_BIN))), + crate::transaction::signer::omnilock::OmnilockSigner {}, + ) + .sign_transaction(&mut tx_with_groups, &sign_context) + .unwrap(); + let tx = tx_with_groups.get_tx_view().clone(); + let script_groups = tx_with_groups.script_groups.clone(); + + assert_eq!(script_groups.len(), 2); + assert_eq!(tx.header_deps().len(), 0); + assert_eq!(tx.cell_deps().len(), 5); + assert_eq!(tx.inputs().len(), 2); + let mut senders = vec![sender0.clone(), owner_sender.clone()]; + for out_point in tx.input_pts_iter() { + let sender = ctx.get_input(&out_point).unwrap().0.lock(); + assert!(senders.contains(&sender)); + senders.retain(|x| x != &sender); + } + assert_eq!(tx.outputs().len(), 2); + assert_eq!(tx.output(0).unwrap(), output); + assert_eq!(tx.output(1).unwrap().lock(), sender0); + let change_capacity: u64 = tx.output(1).unwrap().capacity().unpack(); + let fee = (150 + 61 - 110) * ONE_CKB - change_capacity; + assert_eq!(tx.data().as_reader().serialized_size_in_block() as u64, fee); + ctx.verify(tx, FEE_RATE).unwrap(); +} + +#[test] +fn test_omnilock_transfer_acp() { + test_omnilock_transfer_from_acp(false); + test_omnilock_transfer_from_acp(true); + test_omnilock_transfer_to_acp(false); + test_omnilock_transfer_to_acp(true); +} + +fn test_omnilock_transfer_from_acp(cobuild: bool) { + // account0 sender with acp + // account2 receiver + let unlock_mode = OmniUnlockMode::Normal; + let network_info = NetworkInfo::testnet(); + + let sender_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &sender_key); + + let pubkey_hash = blake160(&pubkey.serialize()); + let mut cfg = OmniLockConfig::new_pubkey_hash(pubkey_hash); + + cfg.set_acp_config(OmniLockAcpConfig::new(0, 0)); + cfg.enable_cobuild(cobuild); + + let sender = build_omnilock_script(&cfg); + let receiver = build_sighash_script(ACCOUNT2_ARG); + + let (ctx, outpoints) = init_context( + vec![(OMNILOCK_BIN, true)], + vec![(sender.clone(), Some(300 * ONE_CKB))], + ); + + let configuration = test_omnilock_config(outpoints); + + let iterator = InputIterator::new_with_cell_collector( + vec![sender.clone()], + Box::new(ctx.to_live_cells_context()) as Box<_>, + ); + let mut builder = SimpleTransactionBuilder::new(configuration, iterator); + + let output = CellOutput::new_builder() + .capacity((110 * ONE_CKB).pack()) + .lock(receiver) + .build(); + + builder.add_output_and_data(output.clone(), ckb_types::packed::Bytes::default()); + builder.set_change_lock(sender.clone()); + + let sign_context = SignContexts::new_omnilock(vec![sender_key], cfg.clone(), unlock_mode); + + let context = + OmnilockScriptContext::new(cfg.clone(), network_info.url.clone()).unlock_mode(unlock_mode); + let mut contexts = HandlerContexts::default(); + contexts.add_context(Box::new(context) as Box<_>); + + let mut tx_with_groups = builder.build(&contexts).expect("build failed"); + + // let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone()); + // println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap()); + + TransactionSigner::new(&network_info) + // use unitest lock to verify + .insert_unlocker( + crate::ScriptId::new_data1(H256::from(blake2b_256(OMNILOCK_BIN))), + crate::transaction::signer::omnilock::OmnilockSigner {}, + ) + .sign_transaction(&mut tx_with_groups, &sign_context) + .unwrap(); + let tx = tx_with_groups.get_tx_view().clone(); + let script_groups = tx_with_groups.script_groups.clone(); + + // let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone()); + // println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap()); + + assert_eq!(script_groups.len(), 1); + assert_eq!(tx.header_deps().len(), 0); + assert_eq!(tx.cell_deps().len(), 1); + assert_eq!(tx.inputs().len(), 1); + for out_point in tx.input_pts_iter() { + assert_eq!(ctx.get_input(&out_point).unwrap().0.lock(), sender); + } + assert_eq!(tx.outputs().len(), 2); + assert_eq!(tx.output(0).unwrap(), output); + assert_eq!(tx.output(1).unwrap().lock(), sender); + let change_capacity: u64 = tx.output(1).unwrap().capacity().unpack(); + let fee = (300 - 110) * ONE_CKB - change_capacity; + assert_eq!(tx.data().as_reader().serialized_size_in_block() as u64, fee); + + ctx.verify(tx, FEE_RATE).unwrap(); +} + +fn test_omnilock_transfer_to_acp(cobuild: bool) { + // account0 sender + // account2 receiver with acp + let unlock_mode = OmniUnlockMode::Normal; + let network_info = NetworkInfo::testnet(); + + let sender = build_sighash_script(ACCOUNT0_ARG); + let receiver_key = secp256k1::SecretKey::from_slice(ACCOUNT2_KEY.as_bytes()) + .map_err(|err| format!("invalid sender secret key: {}", err)) + .unwrap(); + let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &receiver_key); + + let pubkey_hash = blake160(&pubkey.serialize()); + let mut cfg = OmniLockConfig::new_pubkey_hash(pubkey_hash); + cfg.set_acp_config(OmniLockAcpConfig::new(9, 5)); + cfg.enable_cobuild(cobuild); + let receiver = build_omnilock_script(&cfg); + + let (ctx, outpoints) = init_context( + vec![(OMNILOCK_BIN, true)], + vec![ + (sender.clone(), Some(100 * ONE_CKB)), + (receiver.clone(), Some(61 * ONE_CKB)), + ], + ); + + let configuration = test_omnilock_config(outpoints); + + let iterator = InputIterator::new_with_cell_collector( + vec![sender.clone(), receiver.clone()], + Box::new(ctx.to_live_cells_context()) as Box<_>, + ); + let mut builder = SimpleTransactionBuilder::new(configuration, iterator); + + let output = CellOutput::new_builder() + .capacity(((61 + 10) * ONE_CKB).pack()) + .lock(receiver) + .build(); + builder.add_output_and_data(output.clone(), ckb_types::packed::Bytes::default()); + builder.set_change_lock(sender.clone()); + + let mut sign_context = SignContexts::new_omnilock(vec![receiver_key], cfg.clone(), unlock_mode); + let hashall_unlock = + crate::transaction::signer::sighash::Secp256k1Blake160SighashAllSignerContext::new(vec![ + secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap(), + ]); + sign_context.add_context(Box::new(hashall_unlock)); + + let context = OmnilockScriptContext::new(cfg.clone(), network_info.url.clone()); + let mut contexts = HandlerContexts::default(); + contexts.add_context(Box::new(context) as Box<_>); + + let mut tx_with_groups = builder.build(&contexts).expect("build failed"); + + TransactionSigner::new(&network_info) + .insert_unlocker( + crate::ScriptId::new_data1(H256::from(blake2b_256(OMNILOCK_BIN))), + crate::transaction::signer::omnilock::OmnilockSigner {}, + ) + .sign_transaction(&mut tx_with_groups, &sign_context) + .unwrap(); + + let tx = tx_with_groups.get_tx_view().clone(); + let script_groups = tx_with_groups.script_groups.clone(); + + assert_eq!(script_groups.len(), 2); + assert_eq!(tx.header_deps().len(), 0); + assert_eq!(tx.cell_deps().len(), 2); + assert_eq!(tx.inputs().len(), 2); + assert_eq!(tx.outputs().len(), 2); + assert_eq!(tx.output(0).unwrap(), output); + assert_eq!(tx.output(1).unwrap().lock(), sender); + + let change_capacity: u64 = tx.output(1).unwrap().capacity().unpack(); + let fee = (161 - 71) * ONE_CKB - change_capacity; + assert_eq!(tx.data().as_reader().serialized_size_in_block() as u64, fee); + + ctx.verify(tx, FEE_RATE).unwrap(); +} diff --git a/src/tests/tx_builder/mod.rs b/src/tests/tx_builder/mod.rs index da602c82..4e09562f 100644 --- a/src/tests/tx_builder/mod.rs +++ b/src/tests/tx_builder/mod.rs @@ -3,6 +3,6 @@ mod cheque; mod cycle; mod dao; mod omni_lock; -mod omni_lock_util; +pub mod omni_lock_util; mod transfer; mod udt; diff --git a/src/traits/default_impls.rs b/src/traits/default_impls.rs index 013243c8..c4cf63c7 100644 --- a/src/traits/default_impls.rs +++ b/src/traits/default_impls.rs @@ -648,14 +648,6 @@ impl SecpCkbRawKeySigner { let hash160 = eos_auth(&pubkey.into(), vtype); self.keys.insert(hash160.into(), key); } - - pub fn new_with_owner_lock(keys: Vec, hash: H160) -> Self { - let mut signer = SecpCkbRawKeySigner::default(); - for key in keys { - signer.keys.insert(hash.clone(), key); - } - signer - } } impl Signer for SecpCkbRawKeySigner { @@ -703,18 +695,22 @@ impl Drop for SecpCkbRawKeySigner { /// A signer use ed25519 raw key #[derive(Clone)] pub struct Ed25519Signer { - key: ed25519_dalek::SigningKey, + keys: HashMap, } impl Ed25519Signer { - pub fn new(key: ed25519_dalek::SigningKey) -> Self { - Self { key } + pub fn new(keys: Vec) -> Self { + let mut res = HashMap::with_capacity(keys.len()); + for key in keys { + res.insert(blake160(key.verifying_key().as_bytes()), key); + } + Self { keys: res } } } impl Signer for Ed25519Signer { fn match_id(&self, id: &[u8]) -> bool { - id.len() == 20 && blake160(&self.key.verifying_key().as_bytes()[..]).as_bytes() == id + id.len() == 20 && self.keys.contains_key(&H160::from_slice(id).unwrap()) } fn sign( @@ -734,9 +730,10 @@ impl Signer for Ed25519Signer { ))); } - let sig = self.key.clone().sign(message); + let key = self.keys.get(&H160::from_slice(id).unwrap()).unwrap(); + let sig = key.clone().sign(message); - let verifying_key = self.key.verifying_key(); + let verifying_key = key.verifying_key(); // 64 + 32 let mut sig_plus_pubkey = sig.to_vec(); sig_plus_pubkey.extend(verifying_key.as_bytes()); diff --git a/src/transaction/builder/mod.rs b/src/transaction/builder/mod.rs index aa13b99f..38a815ca 100644 --- a/src/transaction/builder/mod.rs +++ b/src/transaction/builder/mod.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use super::{handler::HandlerContexts, input::TransactionInput}; use crate::{ core::TransactionBuilder, - traits::CellCollectorError, + traits::{CellCollectorError, LiveCell}, transaction::TransactionBuilderConfiguration, tx_builder::{BalanceTxCapacityError, TxBuilderError}, ScriptGroup, TransactionWithScriptGroups, @@ -143,6 +143,7 @@ fn inner_build< input_iter: I, configuration: &TransactionBuilderConfiguration, contexts: &HandlerContexts, + rc_cells: Vec, ) -> Result { let mut lock_groups: HashMap = HashMap::default(); let mut type_groups: HashMap = HashMap::default(); @@ -159,10 +160,43 @@ fn inner_build< } } + let rc_len = rc_cells.len(); + + for (input_index, input) in rc_cells.into_iter().enumerate() { + let input = TransactionInput::new(input, 0); + tx.input(input.cell_input()); + tx.witness(packed::Bytes::default()); + + inputs.insert( + input.live_cell.out_point.clone(), + ( + input.live_cell.output.clone(), + input.live_cell.output_data.clone(), + ), + ); + + let previous_output = input.previous_output(); + let lock_script = previous_output.lock(); + lock_groups + .entry(lock_script.calc_script_hash()) + .or_insert_with(|| ScriptGroup::from_lock_script(&lock_script)) + .input_indices + .push(input_index); + + if let Some(type_script) = previous_output.type_().to_opt() { + type_groups + .entry(type_script.calc_script_hash()) + .or_insert_with(|| ScriptGroup::from_type_script(&type_script)) + .input_indices + .push(input_index); + } + } + // setup change output and data change_builder.init(&mut tx); // collect inputs - for (input_index, input) in input_iter.enumerate() { + for (mut input_index, input) in input_iter.enumerate() { + input_index += rc_len; let input = input?; tx.input(input.cell_input()); tx.witness(packed::Bytes::default()); diff --git a/src/transaction/builder/simple.rs b/src/transaction/builder/simple.rs index 4e6756f2..3753067a 100644 --- a/src/transaction/builder/simple.rs +++ b/src/transaction/builder/simple.rs @@ -1,5 +1,6 @@ use crate::{ core::TransactionBuilder, + traits::LiveCell, transaction::{ handler::HandlerContexts, input::InputIterator, TransactionBuilderConfiguration, }, @@ -24,6 +25,7 @@ pub struct SimpleTransactionBuilder { input_iter: InputIterator, /// The inner transaction builder tx: TransactionBuilder, + rc_cells: Vec, } impl SimpleTransactionBuilder { @@ -37,9 +39,14 @@ impl SimpleTransactionBuilder { configuration, input_iter, tx: TransactionBuilder::default(), + rc_cells: Vec::new(), } } + pub fn set_rc_cells(&mut self, rc_cells: Vec) { + self.rc_cells = rc_cells + } + /// Update the change lock script. pub fn set_change_lock(&mut self, lock_script: Script) { self.change_lock = lock_script; @@ -71,6 +78,7 @@ impl CkbTransactionBuilder for SimpleTransactionBuilder { configuration, input_iter, tx, + rc_cells, } = self; let change_builder = DefaultChangeBuilder { @@ -79,6 +87,13 @@ impl CkbTransactionBuilder for SimpleTransactionBuilder { inputs: Vec::new(), }; - inner_build(tx, change_builder, input_iter, &configuration, contexts) + inner_build( + tx, + change_builder, + input_iter, + &configuration, + contexts, + rc_cells, + ) } } diff --git a/src/transaction/builder/sudt.rs b/src/transaction/builder/sudt.rs index 5b9097f5..f0e7d8e6 100644 --- a/src/transaction/builder/sudt.rs +++ b/src/transaction/builder/sudt.rs @@ -169,7 +169,14 @@ impl CkbTransactionBuilder for SudtTransactionBuilder { }; if owner_mode { - inner_build(tx, change_builder, input_iter, &configuration, contexts) + inner_build( + tx, + change_builder, + input_iter, + &configuration, + contexts, + Default::default(), + ) } else { let sudt_type_script = build_sudt_type_script( configuration.network_info(), @@ -198,7 +205,14 @@ impl CkbTransactionBuilder for SudtTransactionBuilder { .to_le_bytes() .pack(); tx.set_output_data(tx.outputs_data.len() - 1, change_output_data); - return inner_build(tx, change_builder, input_iter, &configuration, contexts); + return inner_build( + tx, + change_builder, + input_iter, + &configuration, + contexts, + Default::default(), + ); } } diff --git a/src/transaction/handler/mod.rs b/src/transaction/handler/mod.rs index 869c1c96..4e636342 100644 --- a/src/transaction/handler/mod.rs +++ b/src/transaction/handler/mod.rs @@ -77,6 +77,7 @@ impl HandlerContexts { } } +#[allow(unused_macros)] macro_rules! cell_dep { ($hash: literal, $idx: expr, $dep_type: expr) => {{ let out_point = ckb_types::packed::OutPoint::new_builder() @@ -90,4 +91,5 @@ macro_rules! cell_dep { }}; } +#[allow(unused_imports)] pub(crate) use cell_dep; diff --git a/src/transaction/handler/omnilock.rs b/src/transaction/handler/omnilock.rs index 1040f551..85162753 100644 --- a/src/transaction/handler/omnilock.rs +++ b/src/transaction/handler/omnilock.rs @@ -1,11 +1,10 @@ use ckb_types::{ - core::DepType, h256, packed::{CellDep, OutPoint, Script}, prelude::{Builder, Entity, Pack}, }; -use super::{cell_dep, HandlerContext, ScriptHandler}; +use super::{HandlerContext, ScriptHandler}; use crate::{ core::TransactionBuilder, tx_builder::TxBuilderError, @@ -20,8 +19,6 @@ use lazy_static::lazy_static; pub struct OmnilockScriptHandler { cell_deps: Vec, - sighash_dep: CellDep, - multisig_dep: CellDep, lock_script_id: ScriptId, } @@ -41,6 +38,11 @@ impl OmnilockScriptContext { rpc_url, } } + + pub fn unlock_mode(mut self, unlock_mode: OmniUnlockMode) -> Self { + self.unlock_mode = unlock_mode; + self + } } impl HandlerContext for OmnilockScriptContext {} @@ -53,8 +55,6 @@ impl OmnilockScriptHandler { pub fn new_with_network(network: &NetworkInfo) -> Result { let mut ret = Self { cell_deps: vec![], - sighash_dep: Default::default(), - multisig_dep: Default::default(), lock_script_id: ScriptId::default(), }; ret.init(network)?; @@ -65,6 +65,10 @@ impl OmnilockScriptHandler { self.cell_deps = cell_deps; } + pub fn insert_cell_dep(&mut self, cell_dep: CellDep) { + self.cell_deps.push(cell_dep) + } + pub fn set_lock_script_id(&mut self, lock_script_id: ScriptId) { self.lock_script_id = lock_script_id; } @@ -128,40 +132,8 @@ impl ScriptHandler for OmnilockScriptHandler { fn init(&mut self, network: &NetworkInfo) -> Result<(), TxBuilderError> { if network.network_type == NetworkType::Mainnet { - self.sighash_dep = cell_dep!( - "0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c", - 0u32, - DepType::DepGroup - ); - self.multisig_dep = cell_dep!( - "0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c", - 1u32, - DepType::DepGroup - ); - self.cell_deps.push(self.sighash_dep.clone()); - self.cell_deps.push(cell_dep!( - "0xc76edf469816aa22f416503c38d0b533d2a018e253e379f134c3985b3472c842", - 0u32, - DepType::Code - )); self.lock_script_id = MAINNET_OMNILOCK_SCRIPT_ID.clone(); } else if network.network_type == NetworkType::Testnet { - self.sighash_dep = cell_dep!( - "0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37", - 0u32, - DepType::DepGroup - ); - self.multisig_dep = cell_dep!( - "0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37", - 1u32, - DepType::DepGroup - ); - self.cell_deps.push(self.sighash_dep.clone()); - self.cell_deps.push(cell_dep!( - "0x3d4296df1bd2cc2bd3f483f61ab7ebeac462a2f336f2b944168fe6ba5d81c014", - 0u32, - DepType::Code - )); self.lock_script_id = get_testnet_omnilock_script_id().clone(); } else { return Err(TxBuilderError::UnsupportedNetworkType(network.network_type)); diff --git a/src/transaction/signer/mod.rs b/src/transaction/signer/mod.rs index 67903b26..3af341f8 100644 --- a/src/transaction/signer/mod.rs +++ b/src/transaction/signer/mod.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use crate::{ constants, traits::TransactionDependencyProvider, - unlock::{MultisigConfig, OmniLockConfig, UnlockError}, + unlock::{MultisigConfig, OmniLockConfig, OmniUnlockMode, UnlockError}, NetworkInfo, NetworkType, ScriptGroup, ScriptId, TransactionWithScriptGroups, }; @@ -72,19 +72,26 @@ impl SignContexts { Ok(Self::new_multisig(key, multisig_config)) } - pub fn new_omnilock(keys: Vec, omnilock_config: OmniLockConfig) -> Self { - let omnilock_context = omnilock::OmnilockSignerContext::new(keys, omnilock_config); + pub fn new_omnilock( + keys: Vec, + omnilock_config: OmniLockConfig, + unlock_mode: OmniUnlockMode, + ) -> Self { + let omnilock_context = + omnilock::OmnilockSignerContext::new(keys, omnilock_config).unlock_mode(unlock_mode); Self { contexts: vec![Box::new(omnilock_context)], } } pub fn new_omnilock_solana( - key: ed25519_dalek::SigningKey, + key: Vec, omnilock_config: OmniLockConfig, + unlock_mode: OmniUnlockMode, ) -> Self { let omnilock_context = - omnilock::OmnilockSignerContext::new_with_ed25519_key(key, omnilock_config); + omnilock::OmnilockSignerContext::new_with_ed25519_key(key, omnilock_config) + .unlock_mode(unlock_mode); Self { contexts: vec![Box::new(omnilock_context)], } @@ -93,9 +100,11 @@ impl SignContexts { pub fn new_omnilock_exec_dl_custom( signer: T, omnilock_config: OmniLockConfig, + unlock_mode: OmniUnlockMode, ) -> Self { let omnilock_context = - omnilock::OmnilockSignerContext::new_with_dl_exec_signer(signer, omnilock_config); + omnilock::OmnilockSignerContext::new_with_dl_exec_signer(signer, omnilock_config) + .unlock_mode(unlock_mode); Self { contexts: vec![Box::new(omnilock_context)], } diff --git a/src/transaction/signer/omnilock.rs b/src/transaction/signer/omnilock.rs index e00b3de6..93286f08 100644 --- a/src/transaction/signer/omnilock.rs +++ b/src/transaction/signer/omnilock.rs @@ -16,7 +16,7 @@ pub struct OmnilockSigner {} pub struct OmnilockSignerContext { keys: Vec, - ed25519_key: Option, + ed25519_key: Vec, custom_signer: Option>, cfg: OmniLockConfig, unlock_mode: OmniUnlockMode, @@ -26,17 +26,17 @@ impl OmnilockSignerContext { pub fn new(keys: Vec, cfg: OmniLockConfig) -> Self { Self { keys, - ed25519_key: None, + ed25519_key: Default::default(), custom_signer: None, cfg, unlock_mode: OmniUnlockMode::Normal, } } - pub fn new_with_ed25519_key(key: ed25519_dalek::SigningKey, cfg: OmniLockConfig) -> Self { + pub fn new_with_ed25519_key(key: Vec, cfg: OmniLockConfig) -> Self { Self { keys: Default::default(), - ed25519_key: Some(key), + ed25519_key: key, custom_signer: None, cfg, unlock_mode: OmniUnlockMode::Normal, @@ -46,13 +46,19 @@ impl OmnilockSignerContext { pub fn new_with_dl_exec_signer(signer: T, cfg: OmniLockConfig) -> Self { Self { keys: Default::default(), - ed25519_key: None, + ed25519_key: Default::default(), custom_signer: Some(Box::new(signer)), cfg, unlock_mode: OmniUnlockMode::Normal, } } + /// Default is Normal + pub fn unlock_mode(mut self, unlock_mode: OmniUnlockMode) -> Self { + self.unlock_mode = unlock_mode; + self + } + pub fn build_omnilock_unlocker(&self) -> OmniLockUnlocker { let signer: Box = match self.cfg.id().flag() { IdentityFlag::Ethereum | IdentityFlag::EthereumDisplaying | IdentityFlag::Tron => { @@ -70,13 +76,7 @@ impl OmnilockSignerContext { self.keys.clone(), self.cfg.btc_sign_vtype, )), - IdentityFlag::Solana => Box::new(Ed25519Signer::new( - self.ed25519_key.clone().expect("must have ed25519"), - )), - IdentityFlag::OwnerLock => Box::new(SecpCkbRawKeySigner::new_with_owner_lock( - self.keys.clone(), - self.cfg.id().auth_content().clone(), - )), + IdentityFlag::Solana => Box::new(Ed25519Signer::new(self.ed25519_key.clone())), IdentityFlag::Dl | IdentityFlag::Exec => { let signer = self .custom_signer @@ -84,7 +84,7 @@ impl OmnilockSignerContext { .expect("must have custom signer"); dyn_clone::clone_box(&**signer) } - IdentityFlag::Multisig | IdentityFlag::PubkeyHash => { + IdentityFlag::Multisig | IdentityFlag::PubkeyHash | IdentityFlag::OwnerLock => { Box::new(SecpCkbRawKeySigner::new_with_secret_keys(self.keys.clone())) } }; diff --git a/src/unlock/omni_lock.rs b/src/unlock/omni_lock.rs index 05ade729..1a08a234 100644 --- a/src/unlock/omni_lock.rs +++ b/src/unlock/omni_lock.rs @@ -119,6 +119,33 @@ impl Identity { Self::new(IdentityFlag::OwnerLock, script_hash) } + /// Create an ethereum display omnilock with according script hash. + /// # Arguments + /// * `auth_content` keccak160 hash of public key + pub fn new_ethereum_display(auth_content: H160) -> Self { + Self::new(IdentityFlag::EthereumDisplaying, auth_content) + } + + /// Create an bitcoin omnilock with according script hash. + pub fn new_btc(auth_content: H160) -> Self { + Self::new(IdentityFlag::Bitcoin, auth_content) + } + + /// Create an eos omnilock with according script hash. + pub fn new_eos(auth_content: H160) -> Self { + Self::new(IdentityFlag::Eos, auth_content) + } + + /// Create an tron omnilock with according script hash. + pub fn new_tron(auth_content: H160) -> Self { + Self::new(IdentityFlag::Tron, auth_content) + } + + /// Create an dogcoin omnilock with according script hash. + pub fn new_dogcoin(auth_content: H160) -> Self { + Self::new(IdentityFlag::Dogecoin, auth_content) + } + /// convert the identify to smt_key. pub fn to_smt_key(&self) -> [u8; 32] { let mut ret = [0u8; 32]; @@ -688,16 +715,21 @@ impl OmniLockConfig { } } - /// Enable cobuild's build transaction standards + /// Enable cobuild's build transaction standards, default is false pub fn enable_cobuild(&mut self, enable: bool) { self.enable_cobuild = enable } - /// Set cobuild message value + /// Set cobuild message value, default is Some(Message::default) pub fn cobuild_message(&mut self, message: Option) { self.cobuild_message = message.map(|i| i.as_bytes()); } + /// Set btc sign vtype, defult is P2PKHUncompressed + pub fn btc_sign_vtype(&mut self, vtype: BTCSignVtype) { + self.btc_sign_vtype = vtype; + } + /// Set the admin cofiguration, and set the OmniLockFlags::ADMIN flag. /// # Arguments /// * `admin_config` The new admin config. @@ -913,10 +945,7 @@ impl OmniLockConfig { if unlock_mode == OmniUnlockMode::Admin { if let Some(config) = self.admin_config.as_ref() { - let mut temp = [0u8; 21]; - temp[0] = config.auth.flag as u8; - temp[1..21].copy_from_slice(config.auth.auth_content.as_bytes()); - let auth = Auth::from_slice(&temp).unwrap(); + let auth = config.auth.to_auth(); let ident = IdentityType::new_builder() .identity(auth) .proofs(config.proofs.clone()) @@ -942,28 +971,8 @@ impl OmniLockConfig { &self, unlock_mode: OmniUnlockMode, ) -> Result { - match self.id.flag { - IdentityFlag::PubkeyHash - | IdentityFlag::Ethereum - | IdentityFlag::Multisig - | IdentityFlag::EthereumDisplaying - | IdentityFlag::Bitcoin - | IdentityFlag::Dogecoin - | IdentityFlag::Eos - | IdentityFlag::Tron - | IdentityFlag::Solana => { - let lock = self.placeholder_witness_lock(unlock_mode)?; - Ok(WitnessArgs::new_builder().lock(Some(lock).pack()).build()) - } - IdentityFlag::OwnerLock => { - let lock = self.placeholder_witness_lock(unlock_mode)?; - Ok(WitnessArgs::new_builder().lock(Some(lock).pack()).build()) - } - IdentityFlag::Dl | IdentityFlag::Exec => { - let lock = self.placeholder_witness_lock(unlock_mode)?; - Ok(WitnessArgs::new_builder().lock(Some(lock).pack()).build()) - } - } + let lock = self.placeholder_witness_lock(unlock_mode)?; + Ok(WitnessArgs::new_builder().lock(Some(lock).pack()).build()) } pub fn build_proofs(&self) -> SmtProofEntryVec { @@ -973,10 +982,6 @@ impl OmniLockConfig { Default::default() } } - - pub fn build_auth(&self) -> Auth { - self.id.to_auth() - } } #[derive( diff --git a/src/unlock/signer.rs b/src/unlock/signer.rs index d13eac0a..2ce535d9 100644 --- a/src/unlock/signer.rs +++ b/src/unlock/signer.rs @@ -841,10 +841,11 @@ impl ScriptSigner for OmniLockScriptSigner { generate_message(&tx_new, script_group, zero_lock)? }; let signature = match id.flag() { - IdentityFlag::PubkeyHash | IdentityFlag::OwnerLock => { + IdentityFlag::PubkeyHash => { self.signer .sign(id.auth_content().as_ref(), message.as_ref(), true, tx)? } + IdentityFlag::OwnerLock => Bytes::from(vec![0; 65]), IdentityFlag::Ethereum => { let message = convert_keccak256_hash(message.as_ref()); @@ -915,9 +916,9 @@ impl ScriptSigner for OmniLockScriptSigner { IdentityFlag::Solana => { // should we impl phantom signature mode? let msg = { - let mut preifx = b"CKB transaction: 0x".to_vec(); - preifx.extend(hex_encode(&message).as_bytes()); - preifx + let mut prefix = b"CKB transaction: 0x".to_vec(); + prefix.extend(hex_encode(&message).as_bytes()); + prefix }; self.signer .sign(id.auth_content().as_ref(), msg.as_slice(), true, tx)?