Skip to content

Commit 0b09023

Browse files
committed
test: support dl test
1 parent 5a591e7 commit 0b09023

File tree

24 files changed

+251
-108
lines changed

24 files changed

+251
-108
lines changed

Cargo.toml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ license = "MIT"
1010
description = "Rust SDK for CKB"
1111
homepage = "https://github.com/nervosnetwork/ckb-sdk-rust"
1212
repository = "https://github.com/nervosnetwork/ckb-sdk-rust"
13+
exclude = ["/test-data"]
1314

1415
[dependencies]
1516
serde = { version = "1.0", features = ["derive"] }
@@ -52,24 +53,25 @@ sha3 = "0.10.1"
5253
enum-repr-derive = "0.2.0"
5354

5455
# for feature test
55-
rand = { version = "0.7.3", optional = true }
56+
rand = { version = "0.7.3" }
5657
ckb-mock-tx-types = { version = "0.116.1" }
5758
ckb-chain-spec = "0.116.1"
5859

5960
sparse-merkle-tree = "0.6.1"
6061
lazy_static = "1.3.0"
6162

6263
[features]
63-
default = ["default-tls", "test", "rand"]
64+
default = ["default-tls"]
6465
default-tls = ["reqwest/default-tls"]
6566
native-tls-vendored = ["reqwest/native-tls-vendored"]
6667
rustls-tls = ["reqwest/rustls-tls"]
6768
test = []
6869

6970
[dev-dependencies]
70-
clap = { version = "=4.4.18", features = [
71-
"derive",
72-
] } # TODO clap v4.5 requires rustc v1.74.0+
71+
clap = { version = "4.4.18", features = ["derive"] }
7372
httpmock = "0.6"
7473
async-global-executor = "2.3.1"
75-
hex = "0.4"
74+
75+
76+
[target.'cfg(unix)'.dev-dependencies]
77+
openssl = "0.10"

src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@ pub mod types;
99
pub mod unlock;
1010
pub mod util;
1111

12-
#[cfg(feature = "test")]
1312
pub mod test_util;
1413

15-
#[cfg(feature = "test")]
1614
#[cfg(test)]
1715
mod tests;
1816

src/tests/mod.rs

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,18 @@ const ACCOUNT3_KEY: H256 =
4444
const ACCOUNT3_ARG: H160 = h160!("0xdabe88a65760c662ee3f07dee162409f7b20b694");
4545

4646
const FEE_RATE: u64 = 1000;
47-
const GENESIS_JSON: &str = include_str!("../test-data/genesis_block.json");
48-
const SUDT_BIN: &[u8] = include_bytes!("../test-data/simple_udt");
49-
const ACP_BIN: &[u8] = include_bytes!("../test-data/anyone_can_pay");
50-
const CHEQUE_BIN: &[u8] = include_bytes!("../test-data/ckb-cheque-script");
51-
const ALWAYS_SUCCESS_BIN: &[u8] = include_bytes!("../test-data/always_success");
52-
const OMNILOCK_BIN: &[u8] = include_bytes!("../test-data/omni_lock");
53-
// const ALWAYS_SUCCESS_BIN_DL: &[u8] = include_bytes!("../test-data/always_success_dl");
47+
const GENESIS_JSON: &str = include_str!("../../test-data/genesis_block.json");
48+
const SUDT_BIN: &[u8] = include_bytes!("../../test-data/simple_udt");
49+
const ACP_BIN: &[u8] = include_bytes!("../../test-data/anyone_can_pay");
50+
const CHEQUE_BIN: &[u8] = include_bytes!("../../test-data/ckb-cheque-script");
51+
const ALWAYS_SUCCESS_BIN: &[u8] = include_bytes!("../../test-data/always_success");
52+
// https://github.com/XuJiandong/ckb-production-scripts/commit/f692e01ead9378093b57b47023f3408e4c35349f
53+
#[cfg(not(unix))]
54+
const ALWAYS_SUCCESS_DL_BIN: &[u8] = include_bytes!("../../test-data/always_success_dl");
55+
const OMNILOCK_BIN: &[u8] = include_bytes!("../../test-data/omni_lock");
56+
// https://github.com/nervosnetwork/ckb-production-scripts/blob/410b16c499a8888781d9ab03160eeef93182d8e6/c/validate_signature_rsa.c
57+
#[cfg(unix)]
58+
const RSA_DL_BIN: &[u8] = include_bytes!("../../test-data/validate_signature_rsa");
5459

5560
fn build_sighash_script(args: H160) -> Script {
5661
Script::new_builder()
@@ -76,13 +81,23 @@ fn build_always_success_script() -> Script {
7681
.build()
7782
}
7883

79-
// fn build_always_success_script_dl() -> Script {
80-
// let data_hash = H256::from(blake2b_256(ALWAYS_SUCCESS_BIN_DL));
81-
// Script::new_builder()
82-
// .code_hash(data_hash.pack())
83-
// .hash_type(ScriptHashType::Data1.into())
84-
// .build()
85-
// }
84+
#[cfg(not(unix))]
85+
fn build_always_success_dl_script() -> Script {
86+
let data_hash = H256::from(blake2b_256(ALWAYS_SUCCESS_DL_BIN));
87+
Script::new_builder()
88+
.code_hash(data_hash.pack())
89+
.hash_type(ScriptHashType::Data1.into())
90+
.build()
91+
}
92+
93+
#[cfg(unix)]
94+
fn build_rsa_script_dl() -> Script {
95+
let data_hash = H256::from(blake2b_256(RSA_DL_BIN));
96+
Script::new_builder()
97+
.code_hash(data_hash.pack())
98+
.hash_type(ScriptHashType::Data1.into())
99+
.build()
100+
}
86101

87102
fn build_dao_script() -> Script {
88103
Script::new_builder()

src/tests/transaction/omnilock.rs

Lines changed: 187 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -456,24 +456,163 @@ fn test_omnilock_owner_lock_tranfer(cobuild: bool) {
456456
ctx.verify(tx, FEE_RATE).unwrap();
457457
}
458458

459+
#[cfg(unix)]
460+
mod rsa_dl_test {
461+
use super::test_omnilock_dl_exec;
462+
use crate::{
463+
tests::build_rsa_script_dl,
464+
traits::{Signer, SignerError},
465+
unlock::omni_lock::{ExecDlConfig, Preimage},
466+
util::blake160,
467+
};
468+
469+
use ckb_types::core::TransactionView;
470+
use openssl::{
471+
hash::MessageDigest,
472+
pkey::{PKey, Private, Public},
473+
rsa::Rsa,
474+
sign::Signer as RSASigner,
475+
};
476+
477+
#[derive(Clone)]
478+
struct RSASinger {
479+
key: PKey<Private>,
480+
}
481+
482+
impl Signer for RSASinger {
483+
fn match_id(&self, id: &[u8]) -> bool {
484+
let rsa_script = build_rsa_script_dl();
485+
let public_key_pem: Vec<u8> = self.key.public_key_to_pem().unwrap();
486+
let rsa_pubkey = PKey::public_key_from_pem(&public_key_pem).unwrap();
487+
let signning_pubkey = rsa_signning_prepare_pubkey(&rsa_pubkey);
488+
489+
let preimage = Preimage::new_with_dl(rsa_script, blake160(&signning_pubkey));
490+
id.len() == 20 && id == preimage.auth().as_bytes()
491+
}
492+
493+
fn sign(
494+
&self,
495+
id: &[u8],
496+
message: &[u8],
497+
_recoverable: bool,
498+
_tx: &TransactionView,
499+
) -> Result<bytes::Bytes, SignerError> {
500+
if !self.match_id(id) {
501+
return Err(SignerError::IdNotFound);
502+
}
503+
Ok(bytes::Bytes::from(rsa_sign(message, &self.key)))
504+
}
505+
}
506+
507+
fn rsa_signning_prepare_pubkey(pubkey: &PKey<Public>) -> Vec<u8> {
508+
let mut sig = vec![
509+
1, // algorithm id
510+
1, // key size, 1024
511+
0, // padding, PKCS# 1.5
512+
6, // hash type SHA256
513+
];
514+
515+
let pubkey2 = pubkey.rsa().unwrap();
516+
let mut e = pubkey2.e().to_vec();
517+
let mut n = pubkey2.n().to_vec();
518+
e.reverse();
519+
n.reverse();
520+
521+
while e.len() < 4 {
522+
e.push(0);
523+
}
524+
while n.len() < 128 {
525+
n.push(0);
526+
}
527+
sig.append(&mut e); // 4 bytes E
528+
sig.append(&mut n); // N
529+
530+
sig
531+
}
532+
533+
pub fn rsa_sign(msg: &[u8], key: &PKey<Private>) -> Vec<u8> {
534+
let pem: Vec<u8> = key.public_key_to_pem().unwrap();
535+
let pubkey = PKey::public_key_from_pem(&pem).unwrap();
536+
537+
let mut sig = rsa_signning_prepare_pubkey(&pubkey);
538+
539+
let mut signer = RSASigner::new(MessageDigest::sha256(), key).unwrap();
540+
signer.update(msg).unwrap();
541+
sig.extend(signer.sign_to_vec().unwrap()); // sig
542+
543+
sig
544+
}
545+
546+
#[test]
547+
fn test_omnilock_dl() {
548+
let rsa_script = build_rsa_script_dl();
549+
let bits = 1024;
550+
let rsa = Rsa::generate(bits).unwrap();
551+
let rsa_private_key = PKey::from_rsa(rsa).unwrap();
552+
let public_key_pem: Vec<u8> = rsa_private_key.public_key_to_pem().unwrap();
553+
let rsa_pubkey = PKey::public_key_from_pem(&public_key_pem).unwrap();
554+
let signning_pubkey = rsa_signning_prepare_pubkey(&rsa_pubkey);
555+
556+
let preimage = Preimage::new_with_dl(rsa_script, blake160(&signning_pubkey));
557+
let config = ExecDlConfig::new(preimage, 264);
558+
let signer = RSASinger {
559+
key: rsa_private_key,
560+
};
561+
test_omnilock_dl_exec(config.clone(), signer.clone(), false);
562+
test_omnilock_dl_exec(config, signer.clone(), true);
563+
}
564+
}
565+
459566
#[derive(Clone)]
460567
struct DummySinger {}
461568

462569
impl Signer for DummySinger {
463570
fn match_id(&self, id: &[u8]) -> bool {
464-
let always_success_script = build_always_success_script();
465-
let preimage =
466-
Preimage::new_with_exec(always_success_script, 0, [0; 8], blake160(&[0u8; 20]));
467-
id.len() == 20 && id == preimage.auth().as_bytes()
571+
let (preimage, preimage_dl) = if cfg!(unix) {
572+
let always_success_script = build_always_success_script();
573+
574+
(
575+
Preimage::new_with_exec(
576+
always_success_script.clone(),
577+
0,
578+
[0; 8],
579+
blake160(&[0u8; 20]),
580+
),
581+
Preimage::new_with_exec(always_success_script, 0, [0; 8], blake160(&[0u8; 20])),
582+
)
583+
} else {
584+
#[cfg(not(unix))]
585+
{
586+
use crate::tests::build_always_success_dl_script;
587+
let always_success_script_dl = build_always_success_dl_script();
588+
let always_success_script = build_always_success_script();
589+
(
590+
Preimage::new_with_exec(
591+
always_success_script.clone(),
592+
0,
593+
[0; 8],
594+
blake160(&[0u8; 20]),
595+
),
596+
Preimage::new_with_dl(always_success_script_dl, H160::from([0u8; 20])),
597+
)
598+
}
599+
#[cfg(unix)]
600+
unreachable!()
601+
};
602+
603+
id.len() == 20 && (id == preimage.auth().as_bytes() || id == preimage_dl.auth().as_bytes())
468604
}
469605

470606
fn sign(
471607
&self,
472-
_id: &[u8],
608+
id: &[u8],
473609
_message: &[u8],
474610
_recoverable: bool,
475611
_tx: &TransactionView,
476612
) -> Result<bytes::Bytes, SignerError> {
613+
if !self.match_id(id) {
614+
return Err(SignerError::IdNotFound);
615+
}
477616
Ok(bytes::Bytes::from(vec![0; 65]))
478617
}
479618
}
@@ -484,34 +623,63 @@ fn test_omnilock_exec() {
484623
let preimage = Preimage::new_with_exec(always_success_script, 0, [0; 8], blake160(&[0u8; 20]));
485624
let config = ExecDlConfig::new(preimage, 65);
486625

487-
test_omnilock_dl_exec(config.clone(), false);
488-
test_omnilock_dl_exec(config, true)
626+
test_omnilock_dl_exec(config.clone(), DummySinger {}, false);
627+
test_omnilock_dl_exec(config, DummySinger {}, true)
489628
}
490629

491-
#[ignore]
630+
#[cfg(not(unix))]
492631
#[test]
493632
fn test_omnilock_dl() {
494-
// let always_success_script = build_always_success_script_dl();
495-
// let preimage = Preimage::new_with_dl(always_success_script, blake160(&[0u8; 20]));
496-
// test_omnilock_dl_exec(preimage)
633+
use crate::tests::build_always_success_dl_script;
634+
let always_success_script = build_always_success_dl_script();
635+
let preimage = Preimage::new_with_dl(always_success_script, H160::from([0u8; 20]));
636+
let config = ExecDlConfig::new(preimage, 65);
637+
638+
test_omnilock_dl_exec(config.clone(), DummySinger {}, false);
639+
test_omnilock_dl_exec(config, DummySinger {}, true)
497640
}
498641

499-
fn test_omnilock_dl_exec(config: ExecDlConfig, cobuild: bool) {
642+
#[cfg(unix)]
643+
fn dl_exec_cfg(config: ExecDlConfig) -> (OmniLockConfig, &'static [u8]) {
644+
use crate::tests::RSA_DL_BIN;
645+
if config.preimage().len() == 32 + 1 + 1 + 8 + 20 {
646+
(
647+
OmniLockConfig::new_with_exec_preimage(config),
648+
ALWAYS_SUCCESS_BIN,
649+
)
650+
} else {
651+
(OmniLockConfig::new_with_dl_preimage(config), RSA_DL_BIN)
652+
}
653+
}
654+
655+
#[cfg(not(unix))]
656+
fn dl_exec_cfg(config: ExecDlConfig) -> (OmniLockConfig, &'static [u8]) {
657+
use crate::tests::ALWAYS_SUCCESS_DL_BIN;
658+
if config.preimage().len() == 32 + 1 + 1 + 8 + 20 {
659+
(
660+
OmniLockConfig::new_with_exec_preimage(config),
661+
ALWAYS_SUCCESS_BIN,
662+
)
663+
} else {
664+
(
665+
OmniLockConfig::new_with_dl_preimage(config),
666+
ALWAYS_SUCCESS_DL_BIN,
667+
)
668+
}
669+
}
670+
671+
fn test_omnilock_dl_exec<T: Signer + 'static>(config: ExecDlConfig, signer: T, cobuild: bool) {
500672
let network_info = NetworkInfo::testnet();
501673
let receiver = build_sighash_script(ACCOUNT2_ARG);
502674

503-
let mut cfg = if config.preimage().len() == 32 + 1 + 1 + 8 + 20 {
504-
OmniLockConfig::new_with_exec_preimage(config)
505-
} else {
506-
OmniLockConfig::new_with_dl_preimage(config)
507-
};
675+
let (mut cfg, bin) = dl_exec_cfg(config);
508676

509677
cfg.enable_cobuild(cobuild);
510678
let sender = build_omnilock_script(&cfg);
511-
let sign_context = SignContexts::new_omnilock_exec_dl_custom(DummySinger {}, cfg.clone());
679+
let sign_context = SignContexts::new_omnilock_exec_dl_custom(signer, cfg.clone());
512680

513681
let (ctx, outpoints) = init_context(
514-
vec![(OMNILOCK_BIN, true), (ALWAYS_SUCCESS_BIN, true)],
682+
vec![(OMNILOCK_BIN, true), (bin, true)],
515683
vec![(sender.clone(), Some(300 * ONE_CKB))],
516684
);
517685

src/tests/tx_builder/cycle.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::{
2222
ScriptGroup, ScriptId,
2323
};
2424

25-
const CYCLE_BIN: &[u8] = include_bytes!("../../test-data/cycle");
25+
const CYCLE_BIN: &[u8] = include_bytes!("../../../test-data/cycle");
2626

2727
pub struct CycleUnlocker {
2828
loops: u64,

0 commit comments

Comments
 (0)