Skip to content

Commit

Permalink
test: support dl test
Browse files Browse the repository at this point in the history
  • Loading branch information
driftluo committed Dec 13, 2024
1 parent 934eff5 commit 3ed8d5e
Show file tree
Hide file tree
Showing 24 changed files with 250 additions and 107 deletions.
12 changes: 7 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ license = "MIT"
description = "Rust SDK for CKB"
homepage = "https://github.com/nervosnetwork/ckb-sdk-rust"
repository = "https://github.com/nervosnetwork/ckb-sdk-rust"
exclude = ["/test-data"]

[dependencies]
serde = { version = "1.0", features = ["derive"] }
Expand Down Expand Up @@ -62,16 +63,17 @@ sparse-merkle-tree = "0.6.1"
lazy_static = "1.3.0"

[features]
default = ["default-tls", "test", "rand"]
default = ["default-tls"]
default-tls = ["reqwest/default-tls"]
native-tls-vendored = ["reqwest/native-tls-vendored"]
rustls-tls = ["reqwest/rustls-tls"]
test = []

[dev-dependencies]
clap = { version = "=4.4.18", features = [
"derive",
] } # TODO clap v4.5 requires rustc v1.74.0+
clap = { version = "4.4.18", features = ["derive"] }
httpmock = "0.6"
async-global-executor = "2.3.1"
hex = "0.4"


[target.'cfg(unix)'.dev-dependencies]
openssl = "0.10"
2 changes: 0 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ pub mod types;
pub mod unlock;
pub mod util;

#[cfg(feature = "test")]
pub mod test_util;

#[cfg(feature = "test")]
#[cfg(test)]
mod tests;

Expand Down
43 changes: 29 additions & 14 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,18 @@ const ACCOUNT3_KEY: H256 =
const ACCOUNT3_ARG: H160 = h160!("0xdabe88a65760c662ee3f07dee162409f7b20b694");

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

fn build_sighash_script(args: H160) -> Script {
Script::new_builder()
Expand All @@ -76,13 +81,23 @@ fn build_always_success_script() -> Script {
.build()
}

// fn build_always_success_script_dl() -> Script {
// let data_hash = H256::from(blake2b_256(ALWAYS_SUCCESS_BIN_DL));
// Script::new_builder()
// .code_hash(data_hash.pack())
// .hash_type(ScriptHashType::Data1.into())
// .build()
// }
#[cfg(not(unix))]
fn build_always_success_dl_script() -> Script {
let data_hash = H256::from(blake2b_256(ALWAYS_SUCCESS_DL_BIN));
Script::new_builder()
.code_hash(data_hash.pack())
.hash_type(ScriptHashType::Data1.into())
.build()
}

#[cfg(unix)]
fn build_rsa_script_dl() -> Script {
let data_hash = H256::from(blake2b_256(RSA_DL_BIN));
Script::new_builder()
.code_hash(data_hash.pack())
.hash_type(ScriptHashType::Data1.into())
.build()
}

fn build_dao_script() -> Script {
Script::new_builder()
Expand Down
206 changes: 187 additions & 19 deletions src/tests/transaction/omnilock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,24 +456,163 @@ fn test_omnilock_owner_lock_tranfer(cobuild: bool) {
ctx.verify(tx, FEE_RATE).unwrap();
}

#[cfg(unix)]
mod rsa_dl_test {
use super::test_omnilock_dl_exec;
use crate::{
tests::build_rsa_script_dl,
traits::{Signer, SignerError},
unlock::omni_lock::{ExecDlConfig, Preimage},
util::blake160,
};

use ckb_types::core::TransactionView;
use openssl::{
hash::MessageDigest,
pkey::{PKey, Private, Public},
rsa::Rsa,
sign::Signer as RSASigner,
};

#[derive(Clone)]
struct RSASinger {
key: PKey<Private>,
}

impl Signer for RSASinger {
fn match_id(&self, id: &[u8]) -> bool {
let rsa_script = build_rsa_script_dl();
let public_key_pem: Vec<u8> = self.key.public_key_to_pem().unwrap();
let rsa_pubkey = PKey::public_key_from_pem(&public_key_pem).unwrap();
let signning_pubkey = rsa_signning_prepare_pubkey(&rsa_pubkey);

let preimage = Preimage::new_with_dl(rsa_script, blake160(&signning_pubkey));
id.len() == 20 && id == preimage.auth().as_bytes()
}

fn sign(
&self,
id: &[u8],
message: &[u8],
_recoverable: bool,
_tx: &TransactionView,
) -> Result<bytes::Bytes, SignerError> {
if !self.match_id(id) {
return Err(SignerError::IdNotFound);
}
Ok(bytes::Bytes::from(rsa_sign(message, &self.key)))
}
}

fn rsa_signning_prepare_pubkey(pubkey: &PKey<Public>) -> Vec<u8> {
let mut sig = vec![
1, // algorithm id
1, // key size, 1024
0, // padding, PKCS# 1.5
6, // hash type SHA256
];

let pubkey2 = pubkey.rsa().unwrap();
let mut e = pubkey2.e().to_vec();
let mut n = pubkey2.n().to_vec();
e.reverse();
n.reverse();

while e.len() < 4 {
e.push(0);
}
while n.len() < 128 {
n.push(0);
}
sig.append(&mut e); // 4 bytes E
sig.append(&mut n); // N

sig
}

pub fn rsa_sign(msg: &[u8], key: &PKey<Private>) -> Vec<u8> {
let pem: Vec<u8> = key.public_key_to_pem().unwrap();
let pubkey = PKey::public_key_from_pem(&pem).unwrap();

let mut sig = rsa_signning_prepare_pubkey(&pubkey);

let mut signer = RSASigner::new(MessageDigest::sha256(), key).unwrap();
signer.update(msg).unwrap();
sig.extend(signer.sign_to_vec().unwrap()); // sig

sig
}

#[test]
fn test_omnilock_dl() {
let rsa_script = build_rsa_script_dl();
let bits = 1024;
let rsa = Rsa::generate(bits).unwrap();
let rsa_private_key = PKey::from_rsa(rsa).unwrap();
let public_key_pem: Vec<u8> = rsa_private_key.public_key_to_pem().unwrap();
let rsa_pubkey = PKey::public_key_from_pem(&public_key_pem).unwrap();
let signning_pubkey = rsa_signning_prepare_pubkey(&rsa_pubkey);

let preimage = Preimage::new_with_dl(rsa_script, blake160(&signning_pubkey));
let config = ExecDlConfig::new(preimage, 264);
let signer = RSASinger {
key: rsa_private_key,
};
test_omnilock_dl_exec(config.clone(), signer.clone(), false);
test_omnilock_dl_exec(config, signer.clone(), true);
}
}

#[derive(Clone)]
struct DummySinger {}

impl Signer for DummySinger {
fn match_id(&self, id: &[u8]) -> bool {
let always_success_script = build_always_success_script();
let preimage =
Preimage::new_with_exec(always_success_script, 0, [0; 8], blake160(&[0u8; 20]));
id.len() == 20 && id == preimage.auth().as_bytes()
let (preimage, preimage_dl) = if cfg!(unix) {
let always_success_script = build_always_success_script();

(
Preimage::new_with_exec(
always_success_script.clone(),
0,
[0; 8],
blake160(&[0u8; 20]),
),
Preimage::new_with_exec(always_success_script, 0, [0; 8], blake160(&[0u8; 20])),
)
} else {
#[cfg(not(unix))]
{
use crate::tests::build_always_success_dl_script;
let always_success_script_dl = build_always_success_dl_script();
let always_success_script = build_always_success_script();
(
Preimage::new_with_exec(
always_success_script.clone(),
0,
[0; 8],
blake160(&[0u8; 20]),
),
Preimage::new_with_dl(always_success_script_dl, H160::from([0u8; 20])),
)
}
#[cfg(unix)]
unreachable!()
};

id.len() == 20 && (id == preimage.auth().as_bytes() || id == preimage_dl.auth().as_bytes())
}

fn sign(
&self,
_id: &[u8],
id: &[u8],
_message: &[u8],
_recoverable: bool,
_tx: &TransactionView,
) -> Result<bytes::Bytes, SignerError> {
if !self.match_id(id) {
return Err(SignerError::IdNotFound);
}
Ok(bytes::Bytes::from(vec![0; 65]))
}
}
Expand All @@ -484,34 +623,63 @@ fn test_omnilock_exec() {
let preimage = Preimage::new_with_exec(always_success_script, 0, [0; 8], blake160(&[0u8; 20]));
let config = ExecDlConfig::new(preimage, 65);

test_omnilock_dl_exec(config.clone(), false);
test_omnilock_dl_exec(config, true)
test_omnilock_dl_exec(config.clone(), DummySinger {}, false);
test_omnilock_dl_exec(config, DummySinger {}, true)
}

#[ignore]
#[cfg(not(unix))]
#[test]
fn test_omnilock_dl() {
// let always_success_script = build_always_success_script_dl();
// let preimage = Preimage::new_with_dl(always_success_script, blake160(&[0u8; 20]));
// test_omnilock_dl_exec(preimage)
use crate::tests::build_always_success_dl_script;
let always_success_script = build_always_success_dl_script();
let preimage = Preimage::new_with_dl(always_success_script, H160::from([0u8; 20]));
let config = ExecDlConfig::new(preimage, 65);

test_omnilock_dl_exec(config.clone(), DummySinger {}, false);
test_omnilock_dl_exec(config, DummySinger {}, true)
}

fn test_omnilock_dl_exec(config: ExecDlConfig, cobuild: bool) {
#[cfg(unix)]
fn dl_exec_cfg(config: ExecDlConfig) -> (OmniLockConfig, &'static [u8]) {
use crate::tests::RSA_DL_BIN;
if config.preimage().len() == 32 + 1 + 1 + 8 + 20 {
(
OmniLockConfig::new_with_exec_preimage(config),
ALWAYS_SUCCESS_BIN,
)
} else {
(OmniLockConfig::new_with_dl_preimage(config), RSA_DL_BIN)
}
}

#[cfg(not(unix))]
fn dl_exec_cfg(config: ExecDlConfig) -> (OmniLockConfig, &'static [u8]) {
use crate::tests::ALWAYS_SUCCESS_DL_BIN;
if config.preimage().len() == 32 + 1 + 1 + 8 + 20 {
(
OmniLockConfig::new_with_exec_preimage(config),
ALWAYS_SUCCESS_BIN,
)
} else {
(
OmniLockConfig::new_with_dl_preimage(config),
ALWAYS_SUCCESS_DL_BIN,
)
}
}

fn test_omnilock_dl_exec<T: Signer + 'static>(config: ExecDlConfig, signer: T, cobuild: bool) {
let network_info = NetworkInfo::testnet();
let receiver = build_sighash_script(ACCOUNT2_ARG);

let mut cfg = if config.preimage().len() == 32 + 1 + 1 + 8 + 20 {
OmniLockConfig::new_with_exec_preimage(config)
} else {
OmniLockConfig::new_with_dl_preimage(config)
};
let (mut cfg, bin) = dl_exec_cfg(config);

cfg.enable_cobuild(cobuild);
let sender = build_omnilock_script(&cfg);
let sign_context = SignContexts::new_omnilock_exec_dl_custom(DummySinger {}, cfg.clone());
let sign_context = SignContexts::new_omnilock_exec_dl_custom(signer, cfg.clone());

let (ctx, outpoints) = init_context(
vec![(OMNILOCK_BIN, true), (ALWAYS_SUCCESS_BIN, true)],
vec![(OMNILOCK_BIN, true), (bin, true)],
vec![(sender.clone(), Some(300 * ONE_CKB))],
);

Expand Down
2 changes: 1 addition & 1 deletion src/tests/tx_builder/cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::{
ScriptGroup, ScriptId,
};

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

pub struct CycleUnlocker {
loops: u64,
Expand Down
Loading

0 comments on commit 3ed8d5e

Please sign in to comment.