use crate::{
Node, User, GENESIS_DEP_GROUP_TRANSACTION_INDEX, GENESIS_SIGHASH_ALL_DEP_GROUP_CELL_INDEX,
SIGHASH_ALL_DATA_HASH, SIGHASH_ALL_TYPE_HASH,
};
use ckb_crypto::secp::Pubkey;
use ckb_hash::blake2b_256;
use ckb_types::core::cell::CellMeta;
use ckb_types::core::EpochNumberWithFraction;
use ckb_types::{
bytes::Bytes,
core::{DepType, ScriptHashType, TransactionView},
packed::{CellDep, OutPoint, Script, WitnessArgs},
prelude::*,
H160, H256,
};
impl User {
pub fn single_secp256k1_lock_script_via_type(&self) -> Script {
Script::new_builder()
.hash_type(ScriptHashType::Type.into())
.code_hash(SIGHASH_ALL_TYPE_HASH.pack())
.args(self.single_secp256k1_address().0.pack())
.build()
}
pub fn single_secp256k1_lock_script_via_data(&self) -> Script {
Script::new_builder()
.hash_type(ScriptHashType::Data.into())
.code_hash(SIGHASH_ALL_DATA_HASH.pack())
.args(self.single_secp256k1_address().0.pack())
.build()
}
pub fn single_secp256k1_lock_script_via_data1(&self) -> Script {
Script::new_builder()
.hash_type(ScriptHashType::Data1.into())
.code_hash(SIGHASH_ALL_DATA_HASH.pack())
.args(self.single_secp256k1_address().0.pack())
.build()
}
pub fn single_secp256k1_address(&self) -> H160 {
let pubkey = self.single_secp256k1_pubkey();
H160::from_slice(&blake2b_256(pubkey.serialize())[0..20]).unwrap()
}
pub fn single_secp256k1_out_point(&self) -> OutPoint {
OutPoint::new_builder()
.tx_hash(
self.genesis_block
.transaction(GENESIS_DEP_GROUP_TRANSACTION_INDEX)
.expect("index genesis dep-group transaction")
.hash(),
)
.index(GENESIS_SIGHASH_ALL_DEP_GROUP_CELL_INDEX.pack())
.build()
}
pub fn single_secp256k1_cell_dep(&self) -> CellDep {
CellDep::new_builder()
.out_point(self.single_secp256k1_out_point())
.dep_type(DepType::DepGroup.into())
.build()
}
pub fn single_secp256k1_pubkey(&self) -> Pubkey {
if let Some(ref privkey) = self.single_secp256k1_privkey {
privkey.pubkey().unwrap()
} else {
unreachable!("single_secp256k1 unset")
}
}
pub fn single_secp256k1_signed_witness(&self, tx: &TransactionView) -> WitnessArgs {
if let Some(ref privkey) = self.single_secp256k1_privkey {
let tx_hash = tx.hash();
let mut blake2b = ckb_hash::new_blake2b();
let mut message = [0u8; 32];
blake2b.update(&tx_hash.raw_data());
let witness_for_digest = WitnessArgs::new_builder()
.lock(Some(Bytes::from(vec![0u8; 65])).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());
blake2b.finalize(&mut message);
let message = H256::from(message);
let sig = privkey.sign_recoverable(&message).expect("sign");
WitnessArgs::new_builder()
.lock(Some(Bytes::from(sig.serialize())).pack())
.build()
} else {
unreachable!("single_secp256k1 unset")
}
}
pub fn get_spendable_single_secp256k1_cells(&self, node: &Node) -> Vec<CellMeta> {
let tip_number = node.get_tip_block_number();
let mut live_out_points = Vec::new();
live_out_points.extend(
node.indexer()
.get_live_cells_by_lock_script(&self.single_secp256k1_lock_script_via_type())
.expect("indexer get_live_cells_by_lock_script"),
);
live_out_points.extend(
node.indexer()
.get_live_cells_by_lock_script(&self.single_secp256k1_lock_script_via_data())
.expect("indexer get_live_cells_by_lock_script"),
);
live_out_points.extend(
node.indexer()
.get_live_cells_by_lock_script(&self.single_secp256k1_lock_script_via_data1())
.expect("indexer get_live_cells_by_lock_script"),
);
live_out_points
.into_iter()
.filter_map(|out_point| {
let cell_meta = node.get_cell_meta(out_point)?;
let txinfo = cell_meta
.transaction_info
.as_ref()
.expect("committed tx has transaction_info");
if txinfo.is_cellbase() {
let cellbase_maturity: EpochNumberWithFraction = {
EpochNumberWithFraction::from_full_value(
node.consensus().cellbase_maturity.into(),
)
};
if txinfo.block_number + cellbase_maturity.number() * 1800 > tip_number {
return None;
}
}
if cell_meta.data_bytes != 0 {
return None;
}
Some(cell_meta)
})
.collect::<Vec<_>>()
}
}