Skip to content

Commit 8710343

Browse files
author
Liu Chuankai
committed
test: 💍 Add test about open transaction buy udt
1 parent df492dd commit 8710343

File tree

6 files changed

+262
-112
lines changed

6 files changed

+262
-112
lines changed

src/tests/mod.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,11 +1029,7 @@ fn test_udt_transfer() {
10291029
ctx.add_live_cell(receiver_input, receiver_output.clone(), receiver_data, None);
10301030

10311031
let udt_receiver = UdtTargetReceiver::new(TransferAction::Update, receiver_acp_lock, 300);
1032-
let builder = UdtTransferBuilder {
1033-
type_script,
1034-
sender: sender.clone(),
1035-
receivers: vec![udt_receiver],
1036-
};
1032+
let builder = UdtTransferBuilder::new(type_script, sender.clone(), vec![udt_receiver]);
10371033
let placeholder_witness = WitnessArgs::new_builder()
10381034
.lock(Some(Bytes::from(vec![0u8; 65])).pack())
10391035
.build();

src/tests/omni_lock.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,11 +1171,7 @@ fn test_omnilock_udt_transfer() {
11711171
ctx.add_live_cell(receiver_input, receiver_output.clone(), receiver_data, None);
11721172

11731173
let udt_receiver = UdtTargetReceiver::new(TransferAction::Update, receiver_acp_lock, 300);
1174-
let builder = UdtTransferBuilder {
1175-
type_script,
1176-
sender: sender.clone(),
1177-
receivers: vec![udt_receiver],
1178-
};
1174+
let builder = UdtTransferBuilder::new(type_script, sender.clone(), vec![udt_receiver]);
11791175
let placeholder_witness = WitnessArgs::new_builder()
11801176
.lock(Some(Bytes::from(vec![0u8; 65])).pack())
11811177
.build();

src/tests/opentx.rs

Lines changed: 181 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
1+
use ckb_hash::blake2b_256;
12
use ckb_jsonrpc_types as json_types;
23
use std::collections::HashMap;
34

45
use crate::{
56
constants::{ONE_CKB, SIGHASH_TYPE_HASH},
7+
test_util::random_out_point,
68
tests::{
79
build_sighash_script, init_context,
810
omni_lock::{build_omnilock_script, build_omnilock_unlockers, OMNILOCK_BIN},
911
ACCOUNT0_ARG, ACCOUNT0_KEY, ACCOUNT1_ARG, ACCOUNT1_KEY, ACCOUNT2_ARG, ACCOUNT2_KEY,
10-
ACCOUNT3_ARG, ACCOUNT3_KEY, FEE_RATE,
12+
ACCOUNT3_ARG, ACCOUNT3_KEY, FEE_RATE, SUDT_BIN,
1113
},
1214
traits::{CellCollector, CellQueryOptions, SecpCkbRawKeySigner},
1315
tx_builder::{
14-
omni_lock::OmniLockTransferBuilder, transfer::CapacityTransferBuilderWithTransaction,
16+
omni_lock::OmniLockTransferBuilder, transfer::CapacityTransferBuilder,
17+
udt::UdtTransferBuilder,
1518
},
1619
unlock::{
1720
opentx::OpentxWitness, MultisigConfig, OmniLockConfig, OmniUnlockMode, ScriptUnlocker,
@@ -24,35 +27,40 @@ use crate::{
2427
use ckb_crypto::secp::{Pubkey, SECP256K1};
2528
use ckb_types::{
2629
bytes::Bytes,
27-
packed::{CellOutput, WitnessArgs},
30+
core::{Capacity, ScriptHashType},
31+
packed::{CellInput, CellOutput, Script, WitnessArgs},
2832
prelude::*,
33+
H160, H256,
2934
};
3035
use rand::Rng;
3136

3237
use crate::tx_builder::{unlock_tx, CapacityBalancer, TxBuilder};
3338
const ZERO_FEE_RATE: u64 = 0;
3439

35-
#[test]
36-
fn test_omnilock_transfer_from_sighash() {
37-
let sender_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes())
40+
fn build_simple_config(key: H256) -> OmniLockConfig {
41+
let priv_key = secp256k1::SecretKey::from_slice(key.as_bytes())
3842
.map_err(|err| format!("invalid sender secret key: {}", err))
3943
.unwrap();
40-
let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &sender_key);
41-
let cfg = OmniLockConfig::new_pubkey_hash(blake160(&pubkey.serialize()));
42-
test_omnilock_simple_hash(cfg);
44+
let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &priv_key);
45+
OmniLockConfig::new_pubkey_hash(blake160(&pubkey.serialize()))
46+
}
47+
#[test]
48+
fn test_opentx_pay_from_sighash() {
49+
let cfg = build_simple_config(ACCOUNT0_KEY);
50+
test_opentx_pay_simple_hash(cfg);
4351
}
4452

4553
#[test]
46-
fn test_omnilock_transfer_from_ethereum() {
54+
fn test_opentx_pay_from_ethereum() {
4755
let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap();
4856
let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &account0_key);
4957
let cfg = OmniLockConfig::new_ethereum(keccak160(Pubkey::from(pubkey).as_ref()));
50-
test_omnilock_simple_hash(cfg);
58+
test_opentx_pay_simple_hash(cfg);
5159
}
5260

5361
/// account0(200) => account0(exchange 199) + open pay 1,
5462
/// account2(100) => account2(101 - transaction fee)
55-
fn test_omnilock_simple_hash(mut cfg: OmniLockConfig) {
63+
fn test_opentx_pay_simple_hash(mut cfg: OmniLockConfig) {
5664
cfg.set_opentx_mode();
5765
let unlock_mode = OmniUnlockMode::Normal;
5866
let sender = build_omnilock_script(&cfg);
@@ -135,7 +143,7 @@ fn test_omnilock_simple_hash(mut cfg: OmniLockConfig) {
135143
// .lock(receiver.clone())
136144
// .capacity((100 * ONE_CKB).pack())
137145
// .build();
138-
let builder = CapacityTransferBuilderWithTransaction::new(
146+
let builder = CapacityTransferBuilder::new_with_transaction(
139147
vec![/*(output.clone(), Bytes::default())*/],
140148
tx,
141149
);
@@ -165,7 +173,7 @@ fn test_omnilock_simple_hash(mut cfg: OmniLockConfig) {
165173
/// multisig(200) => multisig(exchange 199) + open pay 1, locked by account0, account1, account2
166174
/// account3(400) => account2(401 - transaction fee)
167175
#[test]
168-
fn test_omnilock_transfer_from_multisig() {
176+
fn test_opentx_pay_from_multisig() {
169177
let unlock_mode = OmniUnlockMode::Normal;
170178
let lock_args = vec![
171179
ACCOUNT0_ARG.clone(),
@@ -263,7 +271,7 @@ fn test_omnilock_transfer_from_multisig() {
263271
// .lock(receiver.clone())
264272
// .capacity((100 * ONE_CKB).pack())
265273
// .build();
266-
let builder = CapacityTransferBuilderWithTransaction::new(
274+
let builder = CapacityTransferBuilder::new_with_transaction(
267275
vec![/*(output.clone(), Bytes::default())*/],
268276
tx,
269277
);
@@ -296,36 +304,28 @@ fn test_omnilock_transfer_from_multisig() {
296304
}
297305

298306
#[test]
299-
fn test_omnilock_transfer_from_sighash_absolute_from_start() {
300-
test_omnilock_transfer_from_sighash_absolute(true);
307+
fn test_opentx_pay_receive_sighash_absolute_from_start() {
308+
test_opentx_pay_receive_sighash_absolute(true);
301309
}
302310
#[test]
303-
fn test_omnilock_transfer_from_sighash_absolute_self() {
304-
test_omnilock_transfer_from_sighash_absolute(false);
311+
fn test_opentx_pay_receive_sighash_absolute_self() {
312+
test_opentx_pay_receive_sighash_absolute(false);
305313
}
306-
fn test_omnilock_transfer_from_sighash_absolute(from_start: bool) {
307-
let cfgs: Vec<OmniLockConfig> = [ACCOUNT0_KEY, ACCOUNT2_KEY]
308-
.iter()
309-
.map(|key| {
310-
let priv_key = secp256k1::SecretKey::from_slice(key.as_bytes())
311-
.map_err(|err| format!("invalid sender secret key: {}", err))
312-
.unwrap();
313-
let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &priv_key);
314-
OmniLockConfig::new_pubkey_hash(blake160(&pubkey.serialize()))
315-
})
316-
.collect();
317-
test_omnilock_simple_hash_absolute(cfgs[0].clone(), cfgs[1].clone(), from_start);
314+
fn test_opentx_pay_receive_sighash_absolute(from_start: bool) {
315+
let sender_cfg = build_simple_config(ACCOUNT0_KEY);
316+
let receiver_cfg = build_simple_config(ACCOUNT2_KEY);
317+
test_opentx_pay_receive_simple_hash_absolute(sender_cfg, receiver_cfg, from_start);
318318
}
319319

320320
#[test]
321-
fn test_omnilock_transfer_from_ethereum_absolute_from_start() {
322-
test_omnilock_transfer_from_ethereum_absolute(true);
321+
fn test_opentx_pay_receive_ethereum_absolute_from_start() {
322+
test_opentx_pay_receive_ethereum_absolute(true);
323323
}
324324
#[test]
325-
fn test_omnilock_transfer_from_ethereum_absolute_from_self() {
326-
test_omnilock_transfer_from_ethereum_absolute(false);
325+
fn test_opentx_pay_receive_ethereum_absolute_from_self() {
326+
test_opentx_pay_receive_ethereum_absolute(false);
327327
}
328-
fn test_omnilock_transfer_from_ethereum_absolute(from_start: bool) {
328+
fn test_opentx_pay_receive_ethereum_absolute(from_start: bool) {
329329
let cfgs: Vec<OmniLockConfig> = [ACCOUNT0_KEY, ACCOUNT2_KEY]
330330
.iter()
331331
.map(|key| {
@@ -334,12 +334,12 @@ fn test_omnilock_transfer_from_ethereum_absolute(from_start: bool) {
334334
OmniLockConfig::new_ethereum(keccak160(Pubkey::from(pubkey).as_ref()))
335335
})
336336
.collect();
337-
test_omnilock_simple_hash_absolute(cfgs[0].clone(), cfgs[1].clone(), from_start);
337+
test_opentx_pay_receive_simple_hash_absolute(cfgs[0].clone(), cfgs[1].clone(), from_start);
338338
}
339339

340340
/// account0(200) => account0(exchange 199) + open pay 1,
341341
/// account2(100) => account2(101 - transaction fee)
342-
fn test_omnilock_simple_hash_absolute(
342+
fn test_opentx_pay_receive_simple_hash_absolute(
343343
mut sender_cfg: OmniLockConfig,
344344
mut receiver_cfg: OmniLockConfig,
345345
from_start: bool,
@@ -410,7 +410,7 @@ fn test_omnilock_simple_hash_absolute(
410410
// If adjust the transaction fee later, the exchange may mot be enough to maintain the minimal capacity.
411411
let balancer = CapacityBalancer::new_simple(receiver.clone(), placeholder_witness, FEE_RATE);
412412

413-
let builder = CapacityTransferBuilderWithTransaction::new(
413+
let builder = CapacityTransferBuilder::new_with_transaction(
414414
vec![/*(output.clone(), Bytes::default())*/],
415415
tx,
416416
);
@@ -464,18 +464,18 @@ fn test_omnilock_simple_hash_absolute(
464464
ctx.verify(tx, FEE_RATE).unwrap();
465465
}
466466
#[test]
467-
fn test_omnilock_transfer_from_multisig_absolute_from_start() {
468-
test_omnilock_transfer_from_multisig_absolute(true);
467+
fn test_opentx_pay_receive_multisig_absolute_from_start() {
468+
test_opentx_pay_receive_multisig_absolute(true);
469469
}
470470

471471
#[test]
472-
fn test_omnilock_transfer_from_multisig_absolute_from_self() {
473-
test_omnilock_transfer_from_multisig_absolute(false);
472+
fn test_opentx_pay_receive_multisig_absolute_from_self() {
473+
test_opentx_pay_receive_multisig_absolute(false);
474474
}
475475

476476
/// multisig(200) => multisig(exchange 199) + open pay 1, locked by account0, account1, account2
477477
/// account3(400) => account2(401 - transaction fee)
478-
fn test_omnilock_transfer_from_multisig_absolute(from_start: bool) {
478+
fn test_opentx_pay_receive_multisig_absolute(from_start: bool) {
479479
let unlock_mode = OmniUnlockMode::Normal;
480480
let lock_args = vec![
481481
ACCOUNT0_ARG.clone(),
@@ -564,7 +564,7 @@ fn test_omnilock_transfer_from_multisig_absolute(from_start: bool) {
564564
let placeholder_witness = receiver_cfg.placeholder_witness(unlock_mode).unwrap();
565565
let balancer = CapacityBalancer::new_simple(receiver.clone(), placeholder_witness, FEE_RATE);
566566

567-
let builder = CapacityTransferBuilderWithTransaction::new(vec![], tx);
567+
let builder = CapacityTransferBuilder::new_with_transaction(vec![], tx);
568568
let mut tx = builder
569569
.build_balanced(&mut cell_collector, &ctx, &ctx, &ctx, &balancer, &unlockers)
570570
.unwrap();
@@ -613,3 +613,139 @@ fn test_omnilock_transfer_from_multisig_absolute(from_start: bool) {
613613
assert_eq!(tx.witnesses().len(), 2);
614614
ctx.verify(tx, FEE_RATE).unwrap();
615615
}
616+
617+
#[test]
618+
fn test_opentx_udt_open_buy() {
619+
// ACCOUNT1(alice) will spend 50.01 CKB with fee to buy 1,000,000 SUDT
620+
// ACCOUNT2(bob) collect the 50 CKB with the transfer 1,000,000 SUDT
621+
let unlock_mode = OmniUnlockMode::Normal;
622+
let mut alice_cfg = build_simple_config(ACCOUNT1_KEY);
623+
alice_cfg.set_opentx_mode();
624+
let alice = build_omnilock_script(&alice_cfg);
625+
let bob = build_sighash_script(ACCOUNT2_ARG);
626+
627+
let mut ctx = init_context(
628+
vec![(OMNILOCK_BIN, true), (SUDT_BIN, false)],
629+
vec![
630+
(alice.clone(), Some(300 * ONE_CKB)),
631+
(bob.clone(), Some(400 * ONE_CKB)),
632+
],
633+
);
634+
let sudt_data_hash = H256::from(blake2b_256(SUDT_BIN));
635+
let owner = build_sighash_script(H160::default());
636+
let type_script = Script::new_builder()
637+
.code_hash(sudt_data_hash.pack())
638+
.hash_type(ScriptHashType::Data1.into())
639+
.args(owner.calc_script_hash().as_bytes().pack())
640+
.build();
641+
let sudt_input = CellInput::new(random_out_point(), 0);
642+
let sudt_output = CellOutput::new_builder()
643+
.capacity(ONE_CKB.pack())
644+
.lock(bob.clone())
645+
.type_(Some(type_script.clone()).pack())
646+
.build();
647+
let sudt_capacity = sudt_output
648+
.occupied_capacity(Capacity::bytes(16).unwrap())
649+
.unwrap()
650+
.as_u64();
651+
println!("sudt_capacity: {}", sudt_capacity);
652+
let sudt_output = sudt_output
653+
.as_builder()
654+
.capacity(sudt_capacity.pack())
655+
.build();
656+
let sudt_data = Bytes::from(1_000_000u128.to_le_bytes().to_vec());
657+
ctx.add_live_cell(sudt_input, sudt_output, sudt_data.clone(), None);
658+
659+
let fee = 100_0000u64;
660+
// build opentx alice's input
661+
let builder = OmniLockTransferBuilder::new_open(
662+
(50 * ONE_CKB + sudt_capacity + fee).into(),
663+
vec![],
664+
alice_cfg.clone(),
665+
None,
666+
);
667+
let placeholder_witness = alice_cfg.placeholder_witness(unlock_mode).unwrap();
668+
let balancer = CapacityBalancer::new_simple(alice.clone(), placeholder_witness, ZERO_FEE_RATE);
669+
670+
let mut cell_collector = ctx.to_live_cells_context();
671+
let alice_key = secp256k1::SecretKey::from_slice(ACCOUNT1_KEY.as_bytes()).unwrap();
672+
let unlockers = build_omnilock_unlockers(alice_key, alice_cfg.clone(), unlock_mode);
673+
let mut tx = builder
674+
.build_balanced(&mut cell_collector, &ctx, &ctx, &ctx, &balancer, &unlockers)
675+
.unwrap();
676+
// add sudt output
677+
let sudt_output = CellOutput::new_builder()
678+
.capacity((sudt_capacity).pack())
679+
.lock(alice.clone())
680+
.type_(Some(type_script.clone()).pack())
681+
.build();
682+
tx = tx
683+
.as_advanced_builder()
684+
.output(sudt_output.clone())
685+
.output_data(sudt_data.pack())
686+
.build();
687+
// update opentx input list
688+
let mut rng = rand::thread_rng();
689+
let salt: u32 = rng.gen();
690+
let wit = OpentxWitness::new_sig_all_relative(&tx, Some(salt)).unwrap();
691+
alice_cfg.set_opentx_input(wit);
692+
tx = OmniLockTransferBuilder::update_opentx_witness(
693+
tx,
694+
&alice_cfg,
695+
OmniUnlockMode::Normal,
696+
&ctx,
697+
&alice,
698+
)
699+
.unwrap();
700+
// config updated, so unlockers must rebuilt.
701+
let unlockers = build_omnilock_unlockers(alice_key, alice_cfg.clone(), unlock_mode);
702+
let (new_tx, new_locked_groups) = unlock_tx(tx.clone(), &ctx, &unlockers).unwrap();
703+
assert!(new_locked_groups.is_empty());
704+
tx = new_tx;
705+
println!(
706+
"> tx: {}",
707+
serde_json::to_string_pretty(&json_types::TransactionView::from(tx.clone())).unwrap()
708+
);
709+
// use opentx
710+
let builder = UdtTransferBuilder::new_with_transaction(type_script, bob.clone(), vec![], tx);
711+
let placeholder_witness = WitnessArgs::new_builder()
712+
.lock(Some(Bytes::from(vec![0u8; 65])).pack())
713+
.build();
714+
let balancer = CapacityBalancer::new_simple(bob, placeholder_witness, FEE_RATE);
715+
716+
let bob_key = secp256k1::SecretKey::from_slice(ACCOUNT2_KEY.as_bytes()).unwrap();
717+
let signer = SecpCkbRawKeySigner::new_with_secret_keys(vec![bob_key]);
718+
let script_unlocker = SecpSighashUnlocker::from(Box::new(signer) as Box<_>);
719+
let mut unlockers: HashMap<ScriptId, Box<dyn ScriptUnlocker>> = HashMap::default();
720+
unlockers.insert(
721+
ScriptId::new_type(SIGHASH_TYPE_HASH.clone()),
722+
Box::new(script_unlocker),
723+
);
724+
725+
let mut cell_collector = ctx.to_live_cells_context();
726+
let (tx, locked_groups) = builder
727+
.build_unlocked(&mut cell_collector, &ctx, &ctx, &ctx, &balancer, &unlockers)
728+
.unwrap();
729+
println!(
730+
"> tx: {}",
731+
serde_json::to_string_pretty(&json_types::TransactionView::from(tx.clone())).unwrap()
732+
);
733+
assert_eq!(locked_groups.len(), 1);
734+
assert_eq!(tx.header_deps().len(), 0);
735+
assert_eq!(tx.cell_deps().len(), 3);
736+
assert_eq!(tx.inputs().len(), 3);
737+
let outputs = tx.outputs().into_iter().collect::<Vec<_>>();
738+
assert_eq!(outputs.len(), 4);
739+
assert_eq!(outputs[1], sudt_output);
740+
let expected_outputs_data = vec![
741+
Bytes::from(1_000_000u128.to_le_bytes().to_vec()),
742+
Bytes::from(0u128.to_le_bytes().to_vec()),
743+
];
744+
let outputs_data = tx
745+
.outputs_data()
746+
.into_iter()
747+
.map(|d| d.raw_data())
748+
.collect::<Vec<_>>();
749+
assert_eq!(outputs_data[1..3], expected_outputs_data);
750+
ctx.verify(tx, FEE_RATE).unwrap();
751+
}

src/tx_builder/omni_lock.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ impl OmniLockTransferBuilder {
4040
/// Create an OmniLockTransferBuilder with open out in the output list.
4141
/// After the transaction built, the open out should be removed.
4242
pub fn new_open(
43-
open_capacity: HumanCapacity,
43+
open_out_capacity: HumanCapacity,
4444
mut outputs: Vec<(CellOutput, Bytes)>,
4545
cfg: OmniLockConfig,
4646
rce_cells: Option<Vec<OutPoint>>,
4747
) -> OmniLockTransferBuilder {
48-
let tmp_out = OmniLockTransferBuilder::build_tmp_open_out(open_capacity);
48+
let tmp_out = OmniLockTransferBuilder::build_tmp_open_out(open_out_capacity);
4949
outputs.push((tmp_out, Bytes::default()));
5050
OmniLockTransferBuilder {
5151
outputs,

0 commit comments

Comments
 (0)