Skip to content

Commit

Permalink
feat: support exec
Browse files Browse the repository at this point in the history
  • Loading branch information
driftluo committed Dec 13, 2024
1 parent d4cb217 commit 934eff5
Show file tree
Hide file tree
Showing 14 changed files with 373 additions and 315 deletions.
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ faster-hex = "0.9.0"
ripemd = "0.1.3"
sha2 = "0.10.6"
ed25519-dalek = "2.1.1"
openssl = "0.10"

ckb-types = "0.119.0"
ckb-dao-utils = "0.119.0"
Expand Down
2 changes: 1 addition & 1 deletion examples/omnilock_examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn main() -> Result<(), Box<dyn StdErr>> {
let mut contexts = HandlerContexts::default();
contexts.add_context(Box::new(context) as Box<_>);

let mut tx_with_groups = builder.build(&mut contexts)?;
let mut tx_with_groups = builder.build(&contexts)?;

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());
Expand Down
2 changes: 1 addition & 1 deletion examples/omnilock_multisig_example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ fn main() -> Result<(), Box<dyn StdErr>> {
let mut contexts = HandlerContexts::default();
contexts.add_context(Box::new(context) as Box<_>);

let mut tx_with_groups = builder.build(&mut contexts)?;
let mut tx_with_groups = builder.build(&contexts)?;

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());
Expand Down
17 changes: 17 additions & 0 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ 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");

fn build_sighash_script(args: H160) -> Script {
Script::new_builder()
Expand All @@ -67,6 +68,22 @@ fn build_multisig_script(cfg: &MultisigConfig) -> Script {
.build()
}

fn build_always_success_script() -> Script {
let data_hash = H256::from(blake2b_256(ALWAYS_SUCCESS_BIN));
Script::new_builder()
.code_hash(data_hash.pack())
.hash_type(ScriptHashType::Data1.into())
.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()
// }

fn build_dao_script() -> Script {
Script::new_builder()
.code_hash(DAO_TYPE_HASH.pack())
Expand Down
163 changes: 144 additions & 19 deletions src/tests/transaction/omnilock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::convert::TryInto;
use ckb_crypto::secp::{Pubkey, SECP256K1};
use ckb_hash::blake2b_256;
use ckb_types::{
core::DepType,
core::{DepType, TransactionView},
packed::{CellOutput, OutPoint},
prelude::*,
H160, H256,
Expand All @@ -12,9 +12,11 @@ use ckb_types::{
use crate::{
constants::ONE_CKB,
tests::{
build_omnilock_script, build_sighash_script, init_context, ACCOUNT0_ARG, ACCOUNT0_KEY,
ACCOUNT1_ARG, ACCOUNT1_KEY, ACCOUNT2_ARG, FEE_RATE, OMNILOCK_BIN,
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,
},
traits::{Signer, SignerError},
transaction::{
builder::{CkbTransactionBuilder, SimpleTransactionBuilder},
handler::{
Expand All @@ -28,12 +30,15 @@ use crate::{
signer::{SignContexts, TransactionSigner},
TransactionBuilderConfiguration,
},
unlock::{MultisigConfig, OmniLockConfig},
unlock::{
omni_lock::{ExecDlConfig, Preimage},
MultisigConfig, OmniLockConfig,
},
util::{blake160, keccak160},
NetworkInfo,
};

fn test_omnilock_config(omnilock_outpoint: OutPoint) -> TransactionBuilderConfiguration {
fn test_omnilock_config(outpoints: Vec<OutPoint>) -> TransactionBuilderConfiguration {
let network_info = NetworkInfo::testnet();
let mut configuration =
TransactionBuilderConfiguration::new_with_empty_handlers(network_info.clone());
Expand All @@ -42,17 +47,24 @@ fn test_omnilock_config(omnilock_outpoint: OutPoint) -> TransactionBuilderConfig
omni_lock_handler.set_lock_script_id(crate::ScriptId::new_data1(H256::from(blake2b_256(
OMNILOCK_BIN,
))));
omni_lock_handler.set_cell_deps(vec![
crate::transaction::handler::cell_dep!(
let dep_cells = {
let mut cells = Vec::with_capacity(outpoints.len() + 1);
cells.push(crate::transaction::handler::cell_dep!(
"0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37",
0u32,
DepType::DepGroup
),
ckb_types::packed::CellDep::new_builder()
.out_point(omnilock_outpoint)
.dep_type(DepType::Code.into())
.build(),
]);
));
for outpoint in outpoints {
cells.push(
ckb_types::packed::CellDep::new_builder()
.out_point(outpoint)
.dep_type(DepType::Code.into())
.build(),
)
}
cells
};
omni_lock_handler.set_cell_deps(dep_cells);

configuration.register_script_handler(Box::new(
Secp256k1Blake160SighashAllScriptHandler::new_with_network(&network_info).unwrap(),
Expand Down Expand Up @@ -295,7 +307,7 @@ fn omnilock_test(cfg: OmniLockConfig, sign_context: &SignContexts) {
let sender = build_omnilock_script(&cfg);
let receiver = build_sighash_script(ACCOUNT2_ARG);

let (ctx, mut outpoints) = init_context(
let (ctx, outpoints) = init_context(
vec![(OMNILOCK_BIN, true)],
vec![
(sender.clone(), Some(100 * ONE_CKB)),
Expand All @@ -304,7 +316,7 @@ fn omnilock_test(cfg: OmniLockConfig, sign_context: &SignContexts) {
],
);

let configuration = test_omnilock_config(outpoints.pop().unwrap());
let configuration = test_omnilock_config(outpoints);

let iterator = InputIterator::new_with_cell_collector(
vec![sender.clone()],
Expand Down Expand Up @@ -374,22 +386,22 @@ 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.clone()], cfg.clone());
let mut sign_context = SignContexts::new_omnilock(vec![account0_key], cfg.clone());
let hashall_unlock =
crate::transaction::signer::sighash::Secp256k1Blake160SighashAllSignerContext::new(vec![
account0_key.clone(),
account0_key,
]);
sign_context.add_context(Box::new(hashall_unlock));

let (ctx, mut outpoints) = init_context(
let (ctx, outpoints) = init_context(
vec![(OMNILOCK_BIN, true)],
vec![
(sender0.clone(), Some(150 * ONE_CKB)),
(sender1.clone(), Some(61 * ONE_CKB)),
],
);

let configuration = test_omnilock_config(outpoints.pop().unwrap());
let configuration = test_omnilock_config(outpoints);
let iterator = InputIterator::new_with_cell_collector(
vec![sender0.clone(), sender1.clone()],
Box::new(ctx.to_live_cells_context()) as Box<_>,
Expand Down Expand Up @@ -443,3 +455,116 @@ fn test_omnilock_owner_lock_tranfer(cobuild: bool) {
assert_eq!(tx.data().as_reader().serialized_size_in_block() as u64, fee);
ctx.verify(tx, FEE_RATE).unwrap();
}

#[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()
}

fn sign(
&self,
_id: &[u8],
_message: &[u8],
_recoverable: bool,
_tx: &TransactionView,
) -> Result<bytes::Bytes, SignerError> {
Ok(bytes::Bytes::from(vec![0; 65]))
}
}

#[test]
fn test_omnilock_exec() {
let always_success_script = build_always_success_script();
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)
}

#[ignore]
#[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)
}

fn test_omnilock_dl_exec(config: ExecDlConfig, 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)
};

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

let (ctx, outpoints) = init_context(
vec![(OMNILOCK_BIN, true), (ALWAYS_SUCCESS_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((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 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");

// 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(), 3);
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 - 120) * ONE_CKB - change_capacity;
assert_eq!(tx.data().as_reader().serialized_size_in_block() as u64, fee);
ctx.verify(tx, FEE_RATE).unwrap();
}
54 changes: 2 additions & 52 deletions src/traits/default_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,13 @@ use ckb_types::{
prelude::*,
H160,
};
use openssl::pkey::{PKey, Private};

use super::{
offchain_impls::CollectResult, OffchainCellCollector, OffchainCellDepResolver,
OffchainTransactionDependencyProvider,
};
use crate::util::{
get_max_mature_number, iso9796_2_batch_sign, serialize_signature, zeroize_privkey,
};
use crate::types::ScriptId;
use crate::util::{get_max_mature_number, serialize_signature, zeroize_privkey};
use crate::SECP256K1;
use crate::{
constants::{
Expand All @@ -53,7 +51,6 @@ use crate::{
},
util::blake160,
};
use crate::{types::ScriptId, util::rsa_sign};
use ckb_resource::{
CODE_HASH_DAO, CODE_HASH_SECP256K1_BLAKE160_MULTISIG_ALL,
CODE_HASH_SECP256K1_BLAKE160_SIGHASH_ALL,
Expand Down Expand Up @@ -703,53 +700,6 @@ impl Drop for SecpCkbRawKeySigner {
}
}

pub struct RsaSigner {
key: PKey<Private>,
use_rsa: bool,
use_iso9796_2: bool,
}

impl RsaSigner {
pub fn new(key: PKey<Private>, use_rsa: bool, use_iso9796_2: bool) -> Self {
Self {
key,
use_rsa,
use_iso9796_2,
}
}
}

impl Signer for RsaSigner {
fn match_id(&self, id: &[u8]) -> bool {
id.len() == 20 && id == blake160(&self.key.public_key_to_pem().unwrap()).as_bytes()
}

fn sign(
&self,
id: &[u8],
message: &[u8],
_recoverable: bool,
_tx: &TransactionView,
) -> Result<Bytes, SignerError> {
if !self.match_id(id) {
return Err(SignerError::IdNotFound);
}
if message.len() != 32 {
return Err(SignerError::InvalidMessage(format!(
"expected length: 32, got: {}",
message.len()
)));
}
if self.use_rsa {
Ok(rsa_sign(message, &self.key).into())
} else if self.use_iso9796_2 {
Ok(iso9796_2_batch_sign(message, &self.key).into())
} else {
Ok(Default::default())
}
}
}

/// A signer use ed25519 raw key
#[derive(Clone)]
pub struct Ed25519Signer {
Expand Down
2 changes: 1 addition & 1 deletion src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub enum SignerError {
/// * secp256k1 eth signer
/// * RSA signer
/// * Hardware wallet signer
pub trait Signer {
pub trait Signer: DynClone {
/// typecial id are blake160(pubkey) and keccak256(pubkey)[12..20]
fn match_id(&self, id: &[u8]) -> bool;

Expand Down
Loading

0 comments on commit 934eff5

Please sign in to comment.