use ckb_chain_spec::consensus::{Consensus, ConsensusBuilder};
use ckb_chain_spec::{
ChainSpec, OUTPUT_INDEX_SECP256K1_BLAKE160_SIGHASH_ALL, OUTPUT_INDEX_SECP256K1_DATA,
build_genesis_type_id_script,
};
use ckb_dao_utils::genesis_dao_data;
use ckb_resource::Resource;
use ckb_types::{
H256, U256,
bytes::Bytes,
core::{
BlockBuilder, BlockNumber, Capacity, EpochNumberWithFraction, ScriptHashType,
TransactionBuilder, TransactionView,
},
packed::{CellInput, CellOutput, OutPoint, Script},
prelude::*,
utilities::difficulty_to_compact,
};
use std::fs::File;
use std::io::Read;
use std::path::Path;
fn load_cell_from_path(path: &str) -> (CellOutput, Bytes, Script) {
let mut file = File::open(Path::new(env!("CARGO_MANIFEST_DIR")).join(path)).unwrap();
let mut buffer = Vec::new();
file.read_to_end(&mut buffer).unwrap();
let data: Bytes = buffer.into();
let cell = CellOutput::new_builder()
.capacity(Capacity::bytes(data.len()).unwrap())
.build();
let script = Script::new_builder()
.hash_type(ScriptHashType::Data)
.code_hash(CellOutput::calc_data_hash(&data))
.build();
(cell, data, script)
}
static SUCCESS_CELL: std::sync::LazyLock<(CellOutput, Bytes, Script)> =
std::sync::LazyLock::new(|| load_cell_from_path("../../script/testdata/always_success"));
static LOAD_INPUT_DATA_HASH: std::sync::LazyLock<(CellOutput, Bytes, Script)> =
std::sync::LazyLock::new(|| load_cell_from_path("vendor/load_input_data_hash"));
#[doc(hidden)]
pub fn load_input_data_hash_cell() -> &'static (CellOutput, Bytes, Script) {
&LOAD_INPUT_DATA_HASH
}
static LOAD_INPUT_ONE_BYTE: std::sync::LazyLock<(CellOutput, Bytes, Script)> =
std::sync::LazyLock::new(|| load_cell_from_path("vendor/load_input_one_byte"));
#[doc(hidden)]
pub fn load_input_one_byte_cell() -> &'static (CellOutput, Bytes, Script) {
&LOAD_INPUT_ONE_BYTE
}
#[doc(hidden)]
pub fn always_success_cell() -> &'static (CellOutput, Bytes, Script) {
&SUCCESS_CELL
}
static IS_EVEN_LIB: std::sync::LazyLock<(CellOutput, Bytes, Script)> =
std::sync::LazyLock::new(|| load_cell_from_path("../../script/testdata/is_even.lib"));
#[doc(hidden)]
pub fn is_even_lib() -> &'static (CellOutput, Bytes, Script) {
&IS_EVEN_LIB
}
static LOAD_IS_EVEN: std::sync::LazyLock<(CellOutput, Bytes, Script)> =
std::sync::LazyLock::new(|| load_cell_from_path("vendor/load_is_even_with_snapshot"));
#[doc(hidden)]
pub fn load_is_even() -> &'static (CellOutput, Bytes, Script) {
&LOAD_IS_EVEN
}
const GENESIS_TIMESTAMP: u64 = 1_557_310_743;
#[doc(hidden)]
pub fn always_success_consensus() -> Consensus {
let (always_success_cell, always_success_cell_data, always_success_script) =
always_success_cell();
let always_success_tx = TransactionBuilder::default()
.input(CellInput::new(OutPoint::null(), 0))
.output(always_success_cell.clone())
.output_data(always_success_cell_data)
.witness(always_success_script.clone().into_witness())
.build();
let dao = genesis_dao_data(vec![&always_success_tx]).unwrap();
let genesis = BlockBuilder::default()
.timestamp(GENESIS_TIMESTAMP)
.compact_target(difficulty_to_compact(U256::from(1000u64)))
.dao(dao)
.transaction(always_success_tx)
.build();
ConsensusBuilder::default()
.genesis_block(genesis)
.cellbase_maturity(EpochNumberWithFraction::new(0, 0, 1))
.build()
}
#[doc(hidden)]
pub fn always_success_cellbase(
block_number: BlockNumber,
reward: Capacity,
consensus: &Consensus,
) -> TransactionView {
let (_, _, always_success_script) = always_success_cell();
let input = CellInput::new_cellbase_input(block_number);
let witness = always_success_script.to_owned().into_witness();
let data = Bytes::new();
let builder = TransactionBuilder::default().input(input).witness(witness);
if block_number <= consensus.finalization_delay_length() {
builder.build()
} else {
let output = CellOutput::new_builder()
.capacity(reward)
.lock(always_success_script.to_owned())
.build();
builder.output(output).output_data(data).build()
}
}
#[doc(hidden)]
fn load_spec_by_name(name: &str) -> ChainSpec {
let base_name = &name[4..];
let res = Resource::bundled(format!("specs/{base_name}.toml"));
ChainSpec::load_from(&res).expect("load spec by name")
}
#[doc(hidden)]
pub fn ckb_testnet_consensus() -> Consensus {
let name = "ckb_testnet";
let spec = load_spec_by_name(name);
spec.build_consensus().unwrap()
}
#[doc(hidden)]
pub fn type_lock_script_code_hash() -> H256 {
build_genesis_type_id_script(OUTPUT_INDEX_SECP256K1_BLAKE160_SIGHASH_ALL)
.calc_script_hash()
.into()
}
#[doc(hidden)]
pub fn secp256k1_blake160_sighash_cell(consensus: Consensus) -> (CellOutput, Bytes) {
let genesis_block = consensus.genesis_block();
let tx = genesis_block.transactions()[0].clone();
let (cell_output, data) = tx
.output_with_data(OUTPUT_INDEX_SECP256K1_BLAKE160_SIGHASH_ALL as usize)
.unwrap();
(cell_output, data)
}
#[doc(hidden)]
pub fn secp256k1_data_cell(consensus: Consensus) -> (CellOutput, Bytes) {
let genesis_block = consensus.genesis_block();
let tx = genesis_block.transactions()[0].clone();
let (cell_output, data) = tx
.output_with_data(OUTPUT_INDEX_SECP256K1_DATA as usize)
.unwrap();
(cell_output, data)
}