Skip to content

Commit 1c8bf7f

Browse files
author
Liu Chuankai
committed
test: 💍 Tests with index opentx input to end a transaction
1 parent 75b0bf8 commit 1c8bf7f

File tree

7 files changed

+264
-53
lines changed

7 files changed

+264
-53
lines changed

src/tests/omni_lock.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ fn test_omnilock_simple_hash(cfg: OmniLockConfig) {
118118

119119
let mut cell_collector = ctx.to_live_cells_context();
120120
let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap();
121-
let unlockers = build_omnilock_unlockers(account0_key, cfg.clone(), unlock_mode);
121+
let unlockers = build_omnilock_unlockers(account0_key, cfg, unlock_mode);
122122
let mut tx = builder
123123
.build_balanced(&mut cell_collector, &ctx, &ctx, &ctx, &balancer, &unlockers)
124124
.unwrap();

src/tests/opentx.rs

Lines changed: 187 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,29 @@ use std::collections::HashMap;
33

44
use crate::{
55
constants::{ONE_CKB, SIGHASH_TYPE_HASH},
6-
test_util::random_out_point,
76
tests::{
87
build_sighash_script, init_context,
98
omni_lock::{build_omnilock_script, build_omnilock_unlockers, OMNILOCK_BIN},
10-
omni_lock_util::generate_rc,
11-
ACCOUNT0_ARG, ACCOUNT0_KEY, ACCOUNT1_ARG, ACCOUNT1_KEY, ACCOUNT2_ARG, ACCOUNT2_KEY,
12-
ACCOUNT3_ARG, ACCOUNT3_KEY, ALWAYS_SUCCESS_BIN, FEE_RATE, SUDT_BIN,
9+
ACCOUNT0_ARG, ACCOUNT0_KEY, ACCOUNT1_ARG, ACCOUNT2_ARG, ACCOUNT2_KEY, ACCOUNT3_ARG,
10+
ACCOUNT3_KEY, FEE_RATE,
1311
},
14-
traits::{CellCollector, CellDepResolver, CellQueryOptions, SecpCkbRawKeySigner},
12+
traits::{CellCollector, CellQueryOptions, SecpCkbRawKeySigner},
1513
tx_builder::{
16-
acp::{AcpTransferBuilder, AcpTransferReceiver},
17-
balance_tx_capacity, fill_placeholder_witnesses,
18-
omni_lock::OmniLockTransferBuilder,
19-
transfer::{CapacityTransferBuilder, CapacityTransferBuilderWithTransaction},
20-
udt::{UdtTargetReceiver, UdtTransferBuilder},
21-
CapacityProvider, TransferAction,
14+
omni_lock::OmniLockTransferBuilder, transfer::CapacityTransferBuilderWithTransaction,
2215
},
23-
types::xudt_rce_mol::SmtProofEntryVec,
2416
unlock::{
25-
omni_lock::{AdminConfig, Identity},
26-
opentx::OpentxWitness,
27-
IdentityFlag, InfoCellData, MultisigConfig, OmniLockAcpConfig, OmniLockConfig,
28-
OmniLockScriptSigner, OmniLockUnlocker, OmniUnlockMode, ScriptUnlocker,
17+
opentx::OpentxWitness, MultisigConfig, OmniLockConfig, OmniUnlockMode, ScriptUnlocker,
2918
SecpSighashUnlocker,
3019
},
3120
util::{blake160, keccak160},
32-
ScriptId, Since,
21+
ScriptId,
3322
};
3423

3524
use ckb_crypto::secp::{Pubkey, SECP256K1};
36-
use ckb_hash::blake2b_256;
3725
use ckb_types::{
3826
bytes::Bytes,
39-
core::{FeeRate, ScriptHashType},
40-
packed::{Byte32, CellInput, CellOutput, Script, WitnessArgs},
27+
packed::{CellOutput, WitnessArgs},
4128
prelude::*,
42-
H160, H256,
4329
};
4430
use rand::Rng;
4531

@@ -83,17 +69,16 @@ fn test_omnilock_simple_hash(mut cfg: OmniLockConfig) {
8369

8470
let output = CellOutput::new_builder()
8571
.capacity((199 * ONE_CKB).pack())
86-
.lock(receiver.clone())
72+
.lock(sender.clone())
8773
.build();
8874
let builder = OmniLockTransferBuilder::new_open(
89-
(1 * ONE_CKB).into(),
75+
ONE_CKB.into(),
9076
vec![(output.clone(), Bytes::default())],
9177
cfg.clone(),
9278
None,
9379
);
9480
let placeholder_witness = cfg.placeholder_witness(unlock_mode).unwrap();
95-
let balancer =
96-
CapacityBalancer::new_simple(sender.clone(), placeholder_witness.clone(), ZERO_FEE_RATE);
81+
let balancer = CapacityBalancer::new_simple(sender.clone(), placeholder_witness, ZERO_FEE_RATE);
9782

9883
let mut cell_collector = ctx.to_live_cells_context();
9984
let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap();
@@ -139,8 +124,7 @@ fn test_omnilock_simple_hash(mut cfg: OmniLockConfig) {
139124
let placeholder_witness = WitnessArgs::new_builder()
140125
.lock(Some(Bytes::from(vec![0u8; 65])).pack())
141126
.build();
142-
let balancer =
143-
CapacityBalancer::new_simple(receiver.clone(), placeholder_witness.clone(), 1000);
127+
let balancer = CapacityBalancer::new_simple(receiver.clone(), placeholder_witness, 1000);
144128
// // Build the transaction
145129
let query = CellQueryOptions::new_lock(receiver.clone());
146130
let (inputs, total_capacity) = cell_collector.collect_live_cells(&query, false).unwrap();
@@ -173,13 +157,8 @@ fn test_omnilock_simple_hash(mut cfg: OmniLockConfig) {
173157
let output1 = tx.output(1).unwrap();
174158
assert_eq!(output1.lock(), receiver);
175159
let receiver_capacity: u64 = output1.capacity().unpack();
176-
assert!(receiver_capacity - 100 * ONE_CKB < ONE_CKB );
177-
let witnesses = tx
178-
.witnesses()
179-
.into_iter()
180-
.map(|w| w.raw_data())
181-
.collect::<Vec<_>>();
182-
assert_eq!(witnesses.len(), 2);
160+
assert!(receiver_capacity - 100 * ONE_CKB < ONE_CKB);
161+
assert_eq!(tx.witnesses().len(), 2);
183162
ctx.verify(tx, FEE_RATE).unwrap();
184163
}
185164

@@ -213,17 +192,16 @@ fn test_omnilock_transfer_from_multisig() {
213192

214193
let output = CellOutput::new_builder()
215194
.capacity((199 * ONE_CKB).pack())
216-
.lock(receiver.clone())
195+
.lock(sender.clone())
217196
.build();
218197
let builder = OmniLockTransferBuilder::new_open(
219-
(1 * ONE_CKB).into(),
198+
ONE_CKB.into(),
220199
vec![(output.clone(), Bytes::default())],
221200
cfg.clone(),
222201
None,
223202
);
224203
let placeholder_witness = cfg.placeholder_witness(unlock_mode).unwrap();
225-
let balancer =
226-
CapacityBalancer::new_simple(sender.clone(), placeholder_witness.clone(), ZERO_FEE_RATE);
204+
let balancer = CapacityBalancer::new_simple(sender.clone(), placeholder_witness, ZERO_FEE_RATE);
227205

228206
let mut cell_collector = ctx.to_live_cells_context();
229207
let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap();
@@ -306,7 +284,7 @@ fn test_omnilock_transfer_from_multisig() {
306284
let output1 = tx.output(1).unwrap();
307285
assert_eq!(output1.lock(), receiver);
308286
let receiver_capacity: u64 = output1.capacity().unpack();
309-
assert!(receiver_capacity - 400 * ONE_CKB < ONE_CKB );
287+
assert!(receiver_capacity - 400 * ONE_CKB < ONE_CKB);
310288
let witnesses = tx
311289
.witnesses()
312290
.into_iter()
@@ -316,3 +294,173 @@ fn test_omnilock_transfer_from_multisig() {
316294
assert_eq!(witnesses[1].len(), placeholder_witness.as_slice().len());
317295
ctx.verify(tx, FEE_RATE).unwrap();
318296
}
297+
298+
#[test]
299+
fn test_omnilock_transfer_from_sighash_absolute_from_start() {
300+
test_omnilock_transfer_from_sighash_absolute(true);
301+
}
302+
#[test]
303+
fn test_omnilock_transfer_from_sighash_absolute_self() {
304+
test_omnilock_transfer_from_sighash_absolute(false);
305+
}
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);
318+
}
319+
320+
#[test]
321+
fn test_omnilock_transfer_from_ethereum_absolute_from_start() {
322+
test_omnilock_transfer_from_ethereum_absolute(true);
323+
}
324+
#[test]
325+
fn test_omnilock_transfer_from_ethereum_absolute_from_self() {
326+
test_omnilock_transfer_from_ethereum_absolute(false);
327+
}
328+
fn test_omnilock_transfer_from_ethereum_absolute(from_start: bool) {
329+
let cfgs: Vec<OmniLockConfig> = [ACCOUNT0_KEY, ACCOUNT2_KEY]
330+
.iter()
331+
.map(|key| {
332+
let priv_key = secp256k1::SecretKey::from_slice(key.as_bytes()).unwrap();
333+
let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &priv_key);
334+
OmniLockConfig::new_ethereum(keccak160(Pubkey::from(pubkey).as_ref()))
335+
})
336+
.collect();
337+
test_omnilock_simple_hash_absolute(cfgs[0].clone(), cfgs[1].clone(), from_start);
338+
}
339+
340+
/// account0(200) => account0(exchange 199) + open pay 1,
341+
/// account2(100) => account2(101 - transaction fee)
342+
fn test_omnilock_simple_hash_absolute(
343+
mut sender_cfg: OmniLockConfig,
344+
mut receiver_cfg: OmniLockConfig,
345+
from_start: bool,
346+
) {
347+
sender_cfg.set_opentx_mode();
348+
receiver_cfg.set_opentx_mode();
349+
let unlock_mode = OmniUnlockMode::Normal;
350+
let sender = build_omnilock_script(&sender_cfg);
351+
let receiver = build_omnilock_script(&receiver_cfg);
352+
353+
let ctx = init_context(
354+
vec![(OMNILOCK_BIN, true)],
355+
vec![
356+
(sender.clone(), Some(200 * ONE_CKB)),
357+
(receiver.clone(), Some(100 * ONE_CKB)),
358+
(receiver.clone(), Some(200 * ONE_CKB)),
359+
],
360+
);
361+
362+
let output = CellOutput::new_builder()
363+
.capacity((199 * ONE_CKB).pack())
364+
.lock(sender.clone())
365+
.build();
366+
let builder = OmniLockTransferBuilder::new_open(
367+
(ONE_CKB).into(),
368+
vec![(output.clone(), Bytes::default())],
369+
sender_cfg.clone(),
370+
None,
371+
);
372+
let placeholder_witness = sender_cfg.placeholder_witness(unlock_mode).unwrap();
373+
let balancer = CapacityBalancer::new_simple(sender.clone(), placeholder_witness, ZERO_FEE_RATE);
374+
375+
let mut cell_collector = ctx.to_live_cells_context();
376+
let account0_key = secp256k1::SecretKey::from_slice(ACCOUNT0_KEY.as_bytes()).unwrap();
377+
let unlockers = build_omnilock_unlockers(account0_key, sender_cfg.clone(), unlock_mode);
378+
let mut tx = builder
379+
.build_balanced(&mut cell_collector, &ctx, &ctx, &ctx, &balancer, &unlockers)
380+
.unwrap();
381+
let mut rng = rand::thread_rng();
382+
let salt: u32 = rng.gen();
383+
let wit = OpentxWitness::new_sig_all_absolute(&tx, Some(salt)).unwrap();
384+
sender_cfg.set_opentx_input(wit);
385+
tx = OmniLockTransferBuilder::update_opentx_witness(
386+
tx,
387+
&sender_cfg,
388+
OmniUnlockMode::Normal,
389+
&ctx,
390+
&sender,
391+
)
392+
.unwrap();
393+
// config updated, so unlockers must rebuilt.
394+
let unlockers = build_omnilock_unlockers(account0_key, sender_cfg.clone(), unlock_mode);
395+
let (new_tx, new_locked_groups) = unlock_tx(tx.clone(), &ctx, &unlockers).unwrap();
396+
assert!(new_locked_groups.is_empty());
397+
tx = new_tx;
398+
399+
// use the opentx
400+
let opentx_input_len = tx.inputs().len();
401+
let opentx_output_len = tx.outputs().len();
402+
receiver_cfg.set_opentx_reserve_bytes_by_commands(20);
403+
// Build ScriptUnlocker
404+
let account2_key = secp256k1::SecretKey::from_slice(ACCOUNT2_KEY.as_bytes()).unwrap();
405+
let unlockers = build_omnilock_unlockers(account2_key, receiver_cfg.clone(), unlock_mode);
406+
407+
// Build CapacityBalancer
408+
let placeholder_witness = receiver_cfg.placeholder_witness(unlock_mode).unwrap();
409+
// why + 100? After update openwitness input list, will need tens of bytes more, if not +100, after update, should calculate adjust the fee again.
410+
// If adjust the transaction fee later, the exchange may mot be enough to maintain the minimal capacity.
411+
let balancer = CapacityBalancer::new_simple(receiver.clone(), placeholder_witness, FEE_RATE);
412+
413+
let builder = CapacityTransferBuilderWithTransaction::new(
414+
vec![/*(output.clone(), Bytes::default())*/],
415+
tx,
416+
);
417+
let mut tx = builder
418+
.build_balanced(&mut cell_collector, &ctx, &ctx, &ctx, &balancer, &unlockers)
419+
.unwrap();
420+
assert_eq!(opentx_input_len + 1, tx.inputs().len());
421+
assert_eq!(opentx_output_len + 1, tx.outputs().len());
422+
423+
let mut rng = rand::thread_rng();
424+
let salt: u32 = rng.gen();
425+
let mut wit = if from_start {
426+
OpentxWitness::new_sig_all_absolute(&tx, Some(salt))
427+
} else {
428+
OpentxWitness::new_sig_to_end_absolute(&tx, Some(salt), opentx_input_len, opentx_output_len)
429+
}
430+
.unwrap(); //OpentxWitness::new_sig_all_absolute(&tx, Some(salt)).unwrap();
431+
wit.add_tx_hash_input();
432+
receiver_cfg.set_opentx_input(wit);
433+
434+
tx = OmniLockTransferBuilder::update_opentx_witness(
435+
tx,
436+
&receiver_cfg,
437+
OmniUnlockMode::Normal,
438+
&ctx,
439+
&receiver,
440+
)
441+
.unwrap();
442+
443+
// config updated, so unlockers must rebuilt.
444+
let unlockers = build_omnilock_unlockers(account2_key, receiver_cfg.clone(), unlock_mode);
445+
let (new_tx, new_locked_groups) = unlock_tx(tx.clone(), &ctx, &unlockers).unwrap();
446+
447+
assert_eq!(1, new_locked_groups.len());
448+
tx = new_tx;
449+
450+
println!(
451+
"> tx: {}",
452+
serde_json::to_string_pretty(&json_types::TransactionView::from(tx.clone())).unwrap()
453+
);
454+
455+
assert_eq!(tx.header_deps().len(), 0);
456+
assert_eq!(tx.cell_deps().len(), 1);
457+
assert_eq!(tx.inputs().len(), 2);
458+
assert_eq!(tx.outputs().len(), 2);
459+
assert_eq!(tx.output(0).unwrap(), output);
460+
let output1 = tx.output(1).unwrap();
461+
assert_eq!(output1.lock(), receiver);
462+
let receiver_capacity: u64 = output1.capacity().unpack();
463+
assert!(receiver_capacity - 100 * ONE_CKB < ONE_CKB);
464+
assert_eq!(tx.witnesses().len(), 2);
465+
ctx.verify(tx, FEE_RATE).unwrap();
466+
}

src/tx_builder/omni_lock.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::{HashSet, HashMap};
1+
use std::collections::{HashMap, HashSet};
22

33
use ckb_types::{
44
bytes::Bytes,
@@ -8,7 +8,9 @@ use ckb_types::{
88
H256,
99
};
1010

11-
use super::{TxBuilder, TxBuilderError, CapacityBalancer, fill_placeholder_witnesses, balance_tx_capacity};
11+
use super::{
12+
balance_tx_capacity, fill_placeholder_witnesses, CapacityBalancer, TxBuilder, TxBuilderError,
13+
};
1214
use crate::{
1315
traits::{CellCollector, CellDepResolver, HeaderDepResolver, TransactionDependencyProvider},
1416
unlock::{omni_lock::ConfigError, OmniLockConfig, OmniUnlockMode, ScriptUnlocker},

src/tx_builder/transfer.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,21 @@ impl TxBuilder for CapacityTransferBuilder {
5858
}
5959
}
6060

61-
6261
/// It's like CapacityTransferBuilder, except with a predefined transaction, it can be used when an open transaction is avaiable.
6362
pub struct CapacityTransferBuilderWithTransaction {
6463
pub outputs: Vec<(CellOutput, Bytes)>,
6564
pub transaction: TransactionView,
6665
}
6766

6867
impl CapacityTransferBuilderWithTransaction {
69-
pub fn new(outputs: Vec<(CellOutput, Bytes)>, transaction: TransactionView) -> CapacityTransferBuilderWithTransaction {
70-
CapacityTransferBuilderWithTransaction { outputs, transaction }
68+
pub fn new(
69+
outputs: Vec<(CellOutput, Bytes)>,
70+
transaction: TransactionView,
71+
) -> CapacityTransferBuilderWithTransaction {
72+
CapacityTransferBuilderWithTransaction {
73+
outputs,
74+
transaction,
75+
}
7176
}
7277
}
7378

@@ -96,11 +101,12 @@ impl TxBuilder for CapacityTransferBuilderWithTransaction {
96101
}
97102
}
98103
}
99-
Ok(self.transaction.as_advanced_builder()
104+
Ok(self
105+
.transaction
106+
.as_advanced_builder()
100107
.cell_deps(cell_deps)
101108
.outputs(outputs)
102109
.outputs_data(outputs_data)
103110
.build())
104111
}
105112
}
106-

0 commit comments

Comments
 (0)