mod dao;
mod secp256k1_blake160_multisig_all;
mod secp256k1_blake160_sighash_all;
use ckb_crypto::secp::Privkey;
use ckb_traits::{CellDataProvider, HeaderProvider};
use ckb_types::{
bytes::Bytes,
core::{EpochExt, HeaderView, TransactionView},
packed::{self, Byte32, CellOutput, OutPoint, WitnessArgs},
prelude::*,
H256,
};
use lazy_static::lazy_static;
use std::collections::HashMap;
pub const MAX_CYCLES: u64 = std::u64::MAX;
pub const SIGNATURE_SIZE: usize = 65;
lazy_static! {
pub static ref SIGHASH_ALL_BIN: Bytes =
Bytes::from(&include_bytes!("../../specs/cells/secp256k1_blake160_sighash_all")[..]);
pub static ref SECP256K1_DATA_BIN: Bytes =
Bytes::from(&include_bytes!("../../specs/cells/secp256k1_data")[..]);
pub static ref DAO_BIN: Bytes = Bytes::from(&include_bytes!("../../specs/cells/dao")[..]);
pub static ref MULTISIG_ALL_BIN: Bytes =
Bytes::from(&include_bytes!("../../specs/cells/secp256k1_blake160_multisig_all")[..]);
}
#[derive(Default, Clone)]
pub struct DummyDataLoader {
pub cells: HashMap<OutPoint, (CellOutput, Bytes)>,
pub headers: HashMap<Byte32, HeaderView>,
pub epoches: HashMap<Byte32, EpochExt>,
}
impl DummyDataLoader {
fn new() -> Self {
Self::default()
}
}
impl CellDataProvider for DummyDataLoader {
fn get_cell_data(&self, out_point: &OutPoint) -> Option<Bytes> {
self.cells.get(out_point).map(|(_, data)| data.clone())
}
fn get_cell_data_hash(&self, out_point: &OutPoint) -> Option<Byte32> {
self.cells
.get(out_point)
.map(|(_, data)| CellOutput::calc_data_hash(data))
}
}
impl HeaderProvider for DummyDataLoader {
fn get_header(&self, block_hash: &Byte32) -> Option<HeaderView> {
self.headers.get(block_hash).cloned()
}
}
pub fn blake160(message: &[u8]) -> Bytes {
Bytes::from(ckb_hash::blake2b_256(message)[..20].to_vec())
}
pub fn sign_tx(tx: TransactionView, key: &Privkey) -> TransactionView {
let witnesses_len = tx.witnesses().len();
sign_tx_by_input_group(tx, key, 0, witnesses_len)
}
pub fn sign_tx_by_input_group(
tx: TransactionView,
key: &Privkey,
begin_index: usize,
len: usize,
) -> TransactionView {
let tx_hash = tx.hash();
let mut signed_witnesses: Vec<packed::Bytes> = tx
.inputs()
.into_iter()
.enumerate()
.map(|(i, _)| {
if i == begin_index {
let mut blake2b = ckb_hash::new_blake2b();
let mut message = [0u8; 32];
blake2b.update(&tx_hash.raw_data());
let witness = WitnessArgs::new_unchecked(tx.witnesses().get(i).unwrap().unpack());
let zero_lock: Bytes = {
let mut buf = Vec::new();
buf.resize(SIGNATURE_SIZE, 0);
buf.into()
};
let witness_for_digest = witness
.clone()
.as_builder()
.lock(Some(zero_lock).pack())
.build();
let witness_len = witness_for_digest.as_bytes().len() as u64;
blake2b.update(&witness_len.to_le_bytes());
blake2b.update(&witness_for_digest.as_bytes());
((i + 1)..(i + len)).for_each(|n| {
let witness = tx.witnesses().get(n).unwrap();
let witness_len = witness.raw_data().len() as u64;
blake2b.update(&witness_len.to_le_bytes());
blake2b.update(&witness.raw_data());
});
blake2b.finalize(&mut message);
let message = H256::from(message);
let sig = key.sign_recoverable(&message).expect("sign");
witness
.as_builder()
.lock(Some(Bytes::from(sig.serialize())).pack())
.build()
.as_bytes()
.pack()
} else {
tx.witnesses().get(i).unwrap_or_default()
}
})
.collect();
for i in signed_witnesses.len()..tx.witnesses().len() {
signed_witnesses.push(tx.witnesses().get(i).unwrap());
}
tx.as_advanced_builder()
.set_witnesses(signed_witnesses)
.build()
}