diff --git a/.gitignore b/.gitignore index 1eb08f84..acc79fb4 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ /tests/nodes/*/fiber/store /tests/nodes/*/config.yml +/tests/nodes/*/dev.toml /tests/deploy/udt-init/target tests/nodes/.ports /coverage-report diff --git a/Cargo.lock b/Cargo.lock index f05c203c..2c2795f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1518,9 +1518,11 @@ dependencies = [ "bech32 0.8.1", "bitcoin", "bitflags 2.6.0", + "ckb-chain-spec", "ckb-gen-types", "ckb-hash 0.115.0", "ckb-jsonrpc-types", + "ckb-resource", "ckb-rocksdb", "ckb-sdk", "ckb-testtool", diff --git a/Cargo.toml b/Cargo.toml index 2fb336e4..eacc5cbc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,8 @@ molecule = { version = "0.8.0", default-features = false } ckb-types = "0.118.0" ckb-gen-types = "0.118.0" ckb-jsonrpc-types = "0.118.0" +ckb-chain-spec = "0.118.0" +ckb-resource = "0.118.0" rocksdb = { package = "ckb-rocksdb", version = "=0.21.1", features = [ "snappy", ], default-features = false } diff --git a/config/testnet/config.yml b/config/testnet/config.yml index 5007308b..04834de9 100644 --- a/config/testnet/config.yml +++ b/config/testnet/config.yml @@ -1,10 +1,42 @@ fiber: listening_addr: "/ip4/127.0.0.1/tcp/8228" - network: "Testnet" bootnode_addrs: - "/ip4/54.179.226.154/tcp/8228/p2p/Qmes1EBD4yNo9Ywkfe6eRw9tG1nVNGLDmMud1xJMsoYFKy" - "/ip4/54.179.226.154/tcp/18228/p2p/QmdyQWjPtbK4NWWsvy8s69NGJaQULwgeQDT5ZpNDrTNaeV" announce_listening_addr: true + # chain spec, can be mainnet | testnet | "path to chain spec file" + chain: testnet + # lock script configurations related to fiber network + # https://github.com/nervosnetwork/fiber-scripts/blob/main/deployment/testnet/migrations/2024-09-14-084742.json + scripts: + - name: FundingLock + script: + code_hash: 0x6c67887fe201ee0c7853f1682c0b77c0e6214044c156c7558269390a8afa6d7c + hash_type: type + args: 0x + cell_deps: + - out_point: + tx_hash: 0x89af398edc7ed0054506b33349b031097d94378e11e77bf0690ee69d82623a43 + index: 0x0 + dep_type: code + - out_point: + tx_hash: 0xbfd6d68b328a02606f1f65ee0f79f8ed5f76dfe86998c7aaa9ee4720d53f4c49 # ckb_auth + index: 0x0 + dep_type: code + - name: CommitmentLock + script: + code_hash: 0x740dee83f87c6f309824d8fd3fbdd3c8380ee6fc9acc90b1a748438afcdf81d8 + hash_type: type + args: 0x + cell_deps: + - out_point: + tx_hash: 0x89af398edc7ed0054506b33349b031097d94378e11e77bf0690ee69d82623a43 + index: 0x1 + dep_type: code + - out_point: + tx_hash: 0xbfd6d68b328a02606f1f65ee0f79f8ed5f76dfe86998c7aaa9ee4720d53f4c49 #ckb_auth + index: 0x0 + dep_type: code rpc: listening_addr: "127.0.0.1:8227" diff --git a/src/ckb/contracts.rs b/src/ckb/contracts.rs index 32bd4103..0c61fbe3 100644 --- a/src/ckb/contracts.rs +++ b/src/ckb/contracts.rs @@ -1,456 +1,180 @@ use ckb_types::{ - core::{DepType, ScriptHashType}, - packed::{CellDep, CellDepVec, CellDepVecBuilder, OutPoint, Script}, + core::{BlockView, DepType, ScriptHashType}, + packed::{CellDep, CellDepVec, CellDepVecBuilder, CellOutput, OutPoint, Script}, prelude::{Builder, Entity, Pack, PackVec}, }; +use once_cell::sync::OnceCell; use regex::Regex; -use std::{collections::HashMap, env, str::FromStr, sync::Arc}; -use tracing::debug; +use serde::{Deserialize, Serialize}; +use std::{collections::HashMap, vec}; +use tracing::info; -use crate::fiber::{config::CkbNetwork, types::Hash256}; +use crate::fiber::config::FiberScript; -use ckb_types::bytes::Bytes; +use super::config::{UdtArgInfo, UdtCfgInfos}; -#[cfg(test)] -use ckb_testtool::context::Context; -#[cfg(test)] -use std::sync::{RwLock, RwLockWriteGuard}; - -use super::{ - config::{UdtArgInfo, UdtCfgInfos}, - CkbConfig, -}; - -#[cfg(test)] -#[derive(Clone)] -pub struct MockContext { - context: Arc>, - contracts_context: Arc, -} - -#[cfg(test)] -impl Default for MockContext { - fn default() -> Self { - Self::new() - } -} - -#[cfg(test)] -impl MockContext { - fn get_contract_binaries() -> Vec<(Contract, Bytes)> { - [ - ( - Contract::FundingLock, - Bytes::from_static(include_bytes!("../../tests/deploy/contracts/funding-lock")), - ), - ( - Contract::CommitmentLock, - Bytes::from_static(include_bytes!( - "../../tests/deploy/contracts/commitment-lock" - )), - ), - // mock secp256k1 lock script - ( - Contract::Secp256k1Lock, - Bytes::from_static(include_bytes!( - "../../tests/deploy/contracts/always_success" - )), - ), - ( - Contract::CkbAuth, - Bytes::from_static(include_bytes!("../../tests/deploy/contracts/auth")), - ), - ( - Contract::SimpleUDT, - Bytes::from_static(include_bytes!("../../tests/deploy/contracts/simple_udt")), - ), - ] - .into() - } - - pub fn new() -> Self { - let mut context = Context::new_with_deterministic_rng(); - - let (map, script_cell_deps) = Self::get_contract_binaries().into_iter().fold( - (HashMap::new(), HashMap::new()), - |(mut map, mut script_cell_deps), (contract, binary)| { - // Use a deterministic RNG to ensure that the outpoints are the same for all nodes. - // Otherwise, cell deps may differ for different nodes, which would make - // different nodes sign different messages (as transaction hashes differ). - let out_point = context.deploy_cell(binary); - let script = context - .build_script(&out_point, Default::default()) - .expect("valid script"); - map.insert(contract, script); - let cell_dep = CellDep::new_builder() - .out_point(out_point) - .dep_type(DepType::Code.into()) - .build(); - - script_cell_deps.insert(contract, CellDepVec::new_builder().push(cell_dep).build()); - (map, script_cell_deps) - }, - ); - debug!("Loaded contracts into the mock environement: {:?}", &map); - - let context = MockContext { - context: Arc::new(RwLock::new(context)), - contracts_context: Arc::new(ContractsInfo { - contract_default_scripts: map, - script_cell_deps, - udt_whitelist: UdtCfgInfos::default(), - }), - }; - debug!("Created mock context to test transactions."); - context - } - - pub fn write(&self) -> RwLockWriteGuard { - self.context.write().unwrap() - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy, Hash)] pub enum Contract { + CkbAuth, FundingLock, CommitmentLock, Secp256k1Lock, - CkbAuth, SimpleUDT, } #[derive(Clone, Debug)] -struct ContractsInfo { - contract_default_scripts: HashMap, - script_cell_deps: HashMap, - udt_whitelist: UdtCfgInfos, -} - -#[derive(Clone)] -pub enum ContractsContext { - #[cfg(test)] - Mock(MockContext), - #[allow(private_interfaces)] - Real(Arc), +pub struct ContractsInfo { + pub contract_default_scripts: HashMap, + pub script_cell_deps: HashMap>, + pub udt_whitelist: UdtCfgInfos, } -impl std::fmt::Debug for ContractsContext { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - #[cfg(test)] - Self::Mock(_mock) => write!(f, "Mock"), - Self::Real(_real) => write!(f, "Real"), - } - } -} - -enum EnvironmentVariableType { - CodeHash, - #[allow(dead_code)] - TypeHash, - TxIndex, - TxHash, -} - -fn get_hash_from_environment_variable( - contract: Contract, - env_type: EnvironmentVariableType, - dep_type: DepType, -) -> Hash256 { - let string = get_environment_variable(contract, env_type, dep_type); - if string.len() < 2 || &string[..2].to_lowercase() != "0x" { - panic!("hex string should start with 0x"); - }; - <[u8; 32]>::try_from(hex::decode(&string[2..]).expect("valid hex").as_slice()) - .expect("valid hash") - .into() +#[derive(Clone, Debug)] +pub struct ContractsContext { + pub contracts: ContractsInfo, } -const ENV_PREFIX: &str = "NEXT_PUBLIC"; -const DEFUALT_SECP256K1_TYPE_HASH: &str = - "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8"; - -fn get_environment_variable( - contract: Contract, - env_type: EnvironmentVariableType, - dep_type: DepType, -) -> String { - let contract_name = match contract { - Contract::FundingLock => "FUNDING_LOCK", - Contract::CommitmentLock => "COMMITMENT_LOCK", - Contract::SimpleUDT => "SIMPLE_UDT", - _ => panic!("Unsupported contract type {:?}", contract), - }; - let type_desc = match env_type { - EnvironmentVariableType::CodeHash => "CODE_HASH", - EnvironmentVariableType::TypeHash => "TYPE_HASH", - EnvironmentVariableType::TxIndex => "TX_INDEX", - EnvironmentVariableType::TxHash => "TX_HASH", - }; - let maybe_dep_group = if dep_type == DepType::Code { - "" - } else { - "_DEP_GROUP" - }; - let env = format!("{ENV_PREFIX}_{contract_name}{maybe_dep_group}_{type_desc}"); - std::env::var(&env).unwrap_or_else(|_| { - panic!( - "Environment variable {} for contract {:?}", - env.as_str(), - contract - ) - }) -} +impl ContractsContext { + pub fn new( + genesis_block: BlockView, + fiber_scripts: Vec, + udt_whitelist: UdtCfgInfos, + ) -> Self { + let mut contract_default_scripts: HashMap = HashMap::new(); + let mut script_cell_deps: HashMap> = HashMap::new(); + + let genesis_tx = genesis_block + .transaction(0) + .expect("genesis block transaction #0 should exist"); + + // setup secp256k1 + let secp256k1_binary_cell = genesis_tx + .output(1) + .expect("genesis block transaction #0 output #1 should exist"); + let secp256k1_binary_cell_type_script = secp256k1_binary_cell + .type_() + .to_opt() + .expect("secp256k1 binary type script should exist"); + contract_default_scripts.insert( + Contract::Secp256k1Lock, + Script::new_builder() + .code_hash(secp256k1_binary_cell_type_script.calc_script_hash()) + .hash_type(ScriptHashType::Type.into()) + .build(), + ); -#[cfg(test)] -impl From for ContractsContext { - fn from(mock: MockContext) -> Self { - Self::Mock(mock) - } -} + let secp256k1_dep_group_tx_hash = genesis_block + .transaction(1) + .expect("genesis block transaction #1 should exist") + .hash(); + let secp256k1_dep_group_out_point = OutPoint::new_builder() + .tx_hash(secp256k1_dep_group_tx_hash) + .index(0u32.pack()) + .build(); + script_cell_deps.insert( + Contract::Secp256k1Lock, + vec![CellDep::new_builder() + .out_point(secp256k1_dep_group_out_point) + .dep_type(DepType::DepGroup.into()) + .build()], + ); -impl ContractsContext { - pub fn new(network: CkbNetwork, udt_whitelist: UdtCfgInfos) -> Self { - match network { - #[cfg(test)] - CkbNetwork::Mocknet => { - tracing::warn!("Initializing mock context for testing."); - MockContext::new().into() + let genesis_hash = genesis_block.hash(); + match format!("{genesis_hash:#x}").as_str() { + "0x92b197aa1fba0f63633922c61c92375c9c074a93e85963554f5499fe1450d0e5" => { + info!("Creating ContractsContext for mainnet"); } - CkbNetwork::Dev => { - let mut map = HashMap::new(); - let mut script_cell_deps = HashMap::new(); - for (program_dep_type, group_dep_type, contracts) in [ - ( - DepType::Code, - DepType::DepGroup, - vec![Contract::FundingLock, Contract::CommitmentLock], - ), - (DepType::Code, DepType::Code, vec![Contract::SimpleUDT]), - ] { - for contract in contracts { - let program_code_hash = get_hash_from_environment_variable( - contract, - EnvironmentVariableType::CodeHash, - program_dep_type, - ); - let group_tx = get_hash_from_environment_variable( - contract, - EnvironmentVariableType::TxHash, - group_dep_type, - ); - let group_index: usize = get_environment_variable( - contract, - EnvironmentVariableType::TxIndex, - group_dep_type, - ) - .parse() - .expect("Valid index"); - let dep_group_out_point = OutPoint::new_builder() - .tx_hash(group_tx.into()) - .index(group_index.pack()) - .build(); - let script = Script::new_builder() - .code_hash(program_code_hash.into()) - .hash_type(ScriptHashType::Data1.into()) - .args(Bytes::new().pack()) - .build(); - let cell_dep = CellDep::new_builder() - .out_point(dep_group_out_point.clone()) - .dep_type(group_dep_type.into()) - .build(); - map.insert(contract, script); - script_cell_deps.insert( - contract, - CellDepVec::new_builder().push(cell_dep).build().pack(), - ); - } - } - let tx1_env_name = format!("{ENV_PREFIX}_CKB_GENESIS_TX_1"); - let tx1 = Hash256::from_str( - &env::var(&tx1_env_name) - .unwrap_or_else(|_| panic!("environment variable {tx1_env_name}")), - ) - .expect("valid hash"); - - let secp256k1_script = Script::new_builder() - .code_hash( - Hash256::from_str(DEFUALT_SECP256K1_TYPE_HASH) - .expect("valid hash") - .into(), - ) - .hash_type(ScriptHashType::Type.into()) - .args(Bytes::new().pack()) - .build(); - map.insert(Contract::Secp256k1Lock, secp256k1_script); - let cell_dep = CellDep::new_builder() + "0x10639e0895502b5688a6be8cf69460d76541bfa4821629d86d62ba0aae3f9606" => { + info!("Creating ContractsContext for testnet"); + } + _ => { + info!("Creating ContractsContext for dev"); + // index from 5 ~ 8 are the default contracts: CkbAuth, FundingLock, CommitmentLock, SimpleUDT + let ckb_auth_cell_dep = CellDep::new_builder() .out_point( OutPoint::new_builder() - .tx_hash(tx1.into()) - .index(0u32.pack()) + .tx_hash(genesis_tx.hash()) + .index(5u32.pack()) .build(), ) - .dep_type(DepType::DepGroup.into()) + .dep_type(DepType::Code.into()) .build(); - script_cell_deps.insert( - Contract::Secp256k1Lock, - CellDepVec::new_builder().push(cell_dep).build().pack(), - ); - - debug!("Loaded contracts into the real environement: {:?}", &map); - Self::Real(Arc::new(ContractsInfo { - contract_default_scripts: map, - script_cell_deps, - udt_whitelist, - })) - } - CkbNetwork::Testnet => { - let map = [ - ( - Contract::FundingLock, - "0x6c67887fe201ee0c7853f1682c0b77c0e6214044c156c7558269390a8afa6d7c", - ), - ( - Contract::CommitmentLock, - "0x740dee83f87c6f309824d8fd3fbdd3c8380ee6fc9acc90b1a748438afcdf81d8", - ), - (Contract::Secp256k1Lock, DEFUALT_SECP256K1_TYPE_HASH), - ] - .into_iter() - .map(|(contract, type_hash)| { - ( + script_cell_deps.insert(Contract::CkbAuth, vec![ckb_auth_cell_dep.clone()]); + + let contract_map = [ + (Contract::FundingLock, 6u32), + (Contract::CommitmentLock, 7u32), + (Contract::SimpleUDT, 8u32), + ]; + for (contract, index) in contract_map.into_iter() { + let cell_dep = CellDep::new_builder() + .out_point( + OutPoint::new_builder() + .tx_hash(genesis_tx.hash()) + .index(index.pack()) + .build(), + ) + .dep_type(DepType::Code.into()) + .build(); + let output_data = genesis_tx + .outputs_data() + .get(index as usize) + .unwrap() + .raw_data(); + let cell_deps = + if matches!(contract, Contract::FundingLock | Contract::CommitmentLock) { + vec![cell_dep, ckb_auth_cell_dep.clone()] + } else { + vec![cell_dep] + }; + script_cell_deps.insert(contract, cell_deps); + contract_default_scripts.insert( contract, Script::new_builder() - .code_hash(Hash256::from_str(type_hash).expect("valid hash").into()) - .hash_type(ScriptHashType::Type.into()) - .args(Bytes::new().pack()) + .code_hash(CellOutput::calc_data_hash(&output_data)) + .hash_type(ScriptHashType::Data1.into()) .build(), - ) - }) - .collect(); - let script_cell_info: HashMap<_, _> = [ - ( - Contract::Secp256k1Lock, - ( - "0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37", - 0u32, - DepType::DepGroup, - ), - ), - ( - Contract::CkbAuth, - ( - "0xbfd6d68b328a02606f1f65ee0f79f8ed5f76dfe86998c7aaa9ee4720d53f4c49", - 0, - DepType::Code, - ), - ), - ( - Contract::FundingLock, - ( - "0x89af398edc7ed0054506b33349b031097d94378e11e77bf0690ee69d82623a43", - 0, - DepType::Code, - ), - ), - ( - Contract::CommitmentLock, - ( - "0x89af398edc7ed0054506b33349b031097d94378e11e77bf0690ee69d82623a43", - 1, - DepType::Code, - ), - ), - ] - .into_iter() - .collect(); - let script_deps: HashMap<_, _> = [ - (Contract::FundingLock, vec![Contract::CkbAuth]), - (Contract::CommitmentLock, vec![Contract::CkbAuth]), - ] - .into_iter() - .collect(); + ); + } + } + } - let script_cell_deps = script_cell_info - .keys() - .map(|contract| { - let cell_deps = vec![contract] - .into_iter() - .chain(script_deps.get(contract).unwrap_or(&vec![])) - .map(|dep| { - let (tx, index, dep_type) = script_cell_info.get(dep).unwrap(); - CellDep::new_builder() - .out_point( - OutPoint::new_builder() - .tx_hash(Hash256::from_str(tx).unwrap().into()) - .index((*index).pack()) - .build(), - ) - .dep_type((*dep_type).into()) - .build() - }) - .collect(); - ( - *contract, - CellDepVec::new_builder().set(cell_deps).build().pack(), - ) - }) - .collect(); + // allow for overriding the default scripts and cell deps + for fiber_script in fiber_scripts { + let FiberScript { + name, + script, + cell_deps, + } = fiber_script; + contract_default_scripts.insert(name, script.into()); + script_cell_deps.insert(name, cell_deps.into_iter().map(CellDep::from).collect()); + } - Self::Real(Arc::new(ContractsInfo { - contract_default_scripts: map, - script_cell_deps, - udt_whitelist, - })) - } - _ => panic!("Unsupported network type {:?}", network), + Self { + contracts: ContractsInfo { + contract_default_scripts, + script_cell_deps, + udt_whitelist, + }, } } fn get_contracts_map(&self) -> &HashMap { - match self { - #[cfg(test)] - Self::Mock(mock) => &mock.contracts_context.contract_default_scripts, - Self::Real(real) => &real.contract_default_scripts, - } + &self.contracts.contract_default_scripts } pub(crate) fn get_cell_deps(&self, contracts: Vec) -> CellDepVec { - let (script_cell_deps, contracts) = match self { - #[cfg(test)] - Self::Mock(mock) => { - // ckb-testtool need to include CkbAuth - let mut contracts = contracts; - contracts.push(Contract::CkbAuth); - (&mock.contracts_context.script_cell_deps, contracts) + let mut builder: CellDepVecBuilder = CellDepVec::new_builder(); + for contract in contracts { + if let Some(cell_deps) = self.contracts.script_cell_deps.get(&contract) { + builder = builder.extend(cell_deps.clone()); } - Self::Real(real) => (&real.script_cell_deps, contracts), - }; - - let cell_deps_vec = contracts - .into_iter() - .map(|contract| { - script_cell_deps - .get(&contract) - .unwrap_or_else(|| { - panic!("Cell dep for contract {:?} does not exists", contract) - }) - .clone() - }) - .collect::>(); - let mut res: CellDepVecBuilder = CellDepVec::new_builder(); - for cell_dep in cell_deps_vec.into_iter().flatten() { - res = res.push(cell_dep); } - res.build() + builder.build() } pub fn get_udt_whitelist(&self) -> &UdtCfgInfos { - match self { - #[cfg(test)] - Self::Mock(mock) => &mock.contracts_context.udt_whitelist, - Self::Real(real) => &real.udt_whitelist, - } + &self.contracts.udt_whitelist } pub(crate) fn get_script(&self, contract: Contract, args: &[u8]) -> Script { @@ -480,37 +204,48 @@ impl ContractsContext { } } +pub static CONTRACTS_CONTEXT_INSTANCE: OnceCell = OnceCell::new(); + pub fn init_contracts_context( - network: Option, - ckb_config: Option<&CkbConfig>, -) -> &'static ContractsContext { - static INSTANCE: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); - let udt_whitelist = ckb_config - .map(|config| config.udt_whitelist.clone()) - .unwrap_or_default(); - INSTANCE.get_or_init(|| { - ContractsContext::new( - network.unwrap_or(DEFAULT_CONTRACT_NETWORK), - udt_whitelist.unwrap_or_default(), - ) - }) + genesis_block: BlockView, + fiber_scripts: Vec, + udt_whitelist: UdtCfgInfos, +) { + CONTRACTS_CONTEXT_INSTANCE + .set(ContractsContext::new( + genesis_block, + fiber_scripts, + udt_whitelist, + )) + .expect("init_contracts_context should only be called once"); } -#[cfg(test)] -const DEFAULT_CONTRACT_NETWORK: CkbNetwork = CkbNetwork::Mocknet; #[cfg(not(test))] -const DEFAULT_CONTRACT_NETWORK: CkbNetwork = CkbNetwork::Dev; +fn get_contracts_context() -> &'static ContractsContext { + CONTRACTS_CONTEXT_INSTANCE + .get() + .expect("init_contracts_context should be called first") +} + +#[cfg(test)] +fn get_contracts_context<'a>() -> ContractsContext { + super::tests::test_utils::MOCK_CONTEXT + .read() + .unwrap() + .contracts_context + .clone() +} pub fn get_script_by_contract(contract: Contract, args: &[u8]) -> Script { - init_contracts_context(None, None).get_script(contract, args) + get_contracts_context().get_script(contract, args) } pub fn get_cell_deps_by_contracts(contracts: Vec) -> CellDepVec { - init_contracts_context(None, None).get_cell_deps(contracts) + get_contracts_context().get_cell_deps(contracts) } -fn get_udt_info(script: &Script) -> Option<&UdtArgInfo> { - init_contracts_context(None, None).get_udt_info(script) +fn get_udt_info(script: &Script) -> Option { + get_contracts_context().get_udt_info(script).cloned() } pub fn check_udt_script(script: &Script) -> bool { @@ -528,9 +263,7 @@ pub fn get_udt_cell_deps(script: &Script) -> Option { } pub fn get_udt_whitelist() -> UdtCfgInfos { - init_contracts_context(None, None) - .get_udt_whitelist() - .clone() + get_contracts_context().get_udt_whitelist().clone() } pub fn is_udt_type_auto_accept(script: &Script, amount: u128) -> bool { diff --git a/src/ckb/tests/contracts.rs b/src/ckb/tests/contracts.rs deleted file mode 100644 index 1707e501..00000000 --- a/src/ckb/tests/contracts.rs +++ /dev/null @@ -1,33 +0,0 @@ -use ckb_types::{core::TransactionView, packed::CellOutput, prelude::Pack}; -use molecule::prelude::{Builder, Entity}; - -use crate::ckb::contracts::{get_script_by_contract, Contract, ContractsContext, MockContext}; - -// This test is to ensure that the same transaction is generated for different mock contexts. -// If different transactions are generated, then the mock context is not deterministic. -// We can't use the mock context to verify the validity of the transactions. -#[test] -fn test_same_tx_for_different_mock_context() { - let mock_ctx1 = MockContext::new(); - let mock_ctx2 = MockContext::new(); - let capacity = 100u64; - let output = CellOutput::new_builder() - .capacity(capacity.pack()) - .lock(get_script_by_contract( - Contract::FundingLock, - &b"whatever"[..], - )) - .build(); - assert_eq!( - TransactionView::new_advanced_builder() - .cell_deps(ContractsContext::from(mock_ctx1).get_cell_deps(vec![Contract::FundingLock])) - .output(output.clone()) - .output_data(Default::default()) - .build(), - TransactionView::new_advanced_builder() - .cell_deps(ContractsContext::from(mock_ctx2).get_cell_deps(vec![Contract::FundingLock])) - .output(output) - .output_data(Default::default()) - .build() - ); -} diff --git a/src/ckb/tests/mod.rs b/src/ckb/tests/mod.rs index 7096078c..1c0ebf32 100644 --- a/src/ckb/tests/mod.rs +++ b/src/ckb/tests/mod.rs @@ -1,5 +1,4 @@ mod actor; mod config; -mod contracts; pub mod test_utils; diff --git a/src/ckb/tests/test_utils.rs b/src/ckb/tests/test_utils.rs index f9eeb724..a3c24168 100644 --- a/src/ckb/tests/test_utils.rs +++ b/src/ckb/tests/test_utils.rs @@ -1,16 +1,21 @@ -use std::collections::HashMap; - use anyhow::anyhow; use ckb_jsonrpc_types::TxStatus; +use ckb_testtool::context::Context; use ckb_types::{ - core::TransactionView, - packed::{CellOutput, OutPoint}, + bytes::Bytes, + core::{DepType, TransactionView}, + packed::{CellDep, CellOutput, OutPoint, Script}, prelude::{Builder, Entity, Pack, PackVec, Unpack}, }; +use once_cell::sync::Lazy; +use std::{collections::HashMap, sync::RwLock}; -use crate::ckb::{TraceTxRequest, TraceTxResponse}; +use crate::ckb::{ + config::UdtCfgInfos, + contracts::{Contract, ContractsContext, ContractsInfo}, + TraceTxRequest, TraceTxResponse, +}; -use crate::ckb::contracts::MockContext; use crate::ckb::CkbChainMessage; use ckb_types::packed::Byte32; @@ -24,8 +29,93 @@ pub enum CellStatus { Consumed, } +pub static MOCK_CONTEXT: Lazy> = Lazy::new(|| RwLock::new(MockContext::new())); + +pub struct MockContext { + pub context: Context, + pub contracts_context: ContractsContext, +} + +impl MockContext { + pub fn new() -> Self { + let binaries = [ + ( + Contract::CkbAuth, + Bytes::from_static(include_bytes!("../../../tests/deploy/contracts/auth")), + ), + ( + Contract::FundingLock, + Bytes::from_static(include_bytes!( + "../../../tests/deploy/contracts/funding-lock" + )), + ), + ( + Contract::CommitmentLock, + Bytes::from_static(include_bytes!( + "../../../tests/deploy/contracts/commitment-lock" + )), + ), + // mock secp256k1 lock script + ( + Contract::Secp256k1Lock, + Bytes::from_static(include_bytes!( + "../../../tests/deploy/contracts/always_success" + )), + ), + ( + Contract::SimpleUDT, + Bytes::from_static(include_bytes!("../../../tests/deploy/contracts/simple_udt")), + ), + ]; + let mut context = Context::new_with_deterministic_rng(); + let mut contract_default_scripts: HashMap = HashMap::new(); + let mut script_cell_deps: HashMap> = HashMap::new(); + + for (contract, binary) in binaries.into_iter() { + let out_point = context.deploy_cell(binary); + let script = context + .build_script(&out_point, Default::default()) + .expect("valid script"); + contract_default_scripts.insert(contract, script); + let cell_dep = CellDep::new_builder() + .out_point(out_point) + .dep_type(DepType::Code.into()) + .build(); + + let cell_deps = if matches!(contract, Contract::FundingLock) + || matches!(contract, Contract::CommitmentLock) + { + // FundingLock and CommitmentLock depend on CkbAuth + vec![ + cell_dep, + script_cell_deps + .get(&Contract::CkbAuth) + .unwrap() + .clone() + .get(0) + .unwrap() + .clone(), + ] + } else { + vec![cell_dep] + }; + script_cell_deps.insert(contract, cell_deps); + } + + let contracts = ContractsInfo { + contract_default_scripts, + script_cell_deps, + udt_whitelist: UdtCfgInfos::default(), + }; + let contracts_context = ContractsContext { contracts }; + MockContext { + context, + contracts_context, + } + } +} + pub struct MockChainActorState { - ctx: MockContext, tx_status: HashMap< Byte32, ( @@ -45,7 +135,6 @@ impl Default for MockChainActorState { impl MockChainActorState { pub fn new() -> Self { Self { - ctx: MockContext::new(), tx_status: HashMap::new(), cell_status: HashMap::new(), } @@ -179,7 +268,6 @@ impl Actor for MockChainActor { } SendTx(tx, reply_port) => { const MAX_CYCLES: u64 = 100_000_000; - let mut context = state.ctx.write(); let mut f = || { // Mark the inputs as consumed for input in tx.input_pts_iter() { @@ -202,6 +290,7 @@ impl Actor for MockChainActor { } } } + let context = &mut MOCK_CONTEXT.write().unwrap().context; match context.verify_tx(&tx, MAX_CYCLES) { Ok(c) => { debug!("Verified transaction: {:?} with {} CPU cycles", tx, c); diff --git a/src/config.rs b/src/config.rs index b9cd9fce..a1340aea 100644 --- a/src/config.rs +++ b/src/config.rs @@ -106,6 +106,7 @@ pub struct Config { pub rpc: Option, // ckb actor config, None represents that we should not run ckb actor pub ckb: Option, + pub base_dir: PathBuf, } pub(crate) fn print_help_and_exit(code: i32) { @@ -197,6 +198,7 @@ impl Config { cch, rpc, ckb, + base_dir, } } } diff --git a/src/fiber/channel.rs b/src/fiber/channel.rs index 7c677c25..945cbdba 100644 --- a/src/fiber/channel.rs +++ b/src/fiber/channel.rs @@ -2503,7 +2503,7 @@ impl ChannelActorState { &node1_id, &node2_id, channel_outpoint, - Default::default(), + get_chain_hash(), &self.get_funding_lock_script_xonly_key(), capacity, self.funding_udt_type_script.clone(), diff --git a/src/fiber/config.rs b/src/fiber/config.rs index 9cecc958..f07b2cc8 100644 --- a/src/fiber/config.rs +++ b/src/fiber/config.rs @@ -1,14 +1,13 @@ -use crate::Result; -use ckb_sdk::NetworkType; -use clap::ValueEnum; +use crate::{ckb::contracts::Contract, Result}; +use ckb_jsonrpc_types::{CellDep, Script}; use clap_serde_derive::{ clap::{self}, ClapSerde, }; #[cfg(not(test))] use once_cell::sync::OnceCell; -use serde::{Deserialize, Deserializer, Serializer}; -use std::{fs, path::PathBuf}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::{fs, path::PathBuf, str::FromStr}; use tentacle::secio::{PublicKey, SecioKeyPair}; pub const CKB_SHANNONS: u64 = 100_000_000; // 1 CKB = 10 ^ 8 shannons @@ -98,9 +97,13 @@ pub struct FiberConfig { )] pub(crate) announced_node_name: Option, - /// name of the network to use (can be any of `mocknet`/`mainnet`/`testnet`/`staging`/`dev`) - #[arg(name = "FIBER_NETWORK", long = "fiber-network", env)] - pub network: Option, + /// chain spec file path, can be "mainnet", "testnet", or a file path to a custom chain spec + #[arg(name = "FIBER_CHAIN", long = "fiber-chain", env)] + pub chain: String, + + /// lock script configurations related to fiber network + #[arg(name = "FIBER_SCRIPTS", long = "fiber-scripts", env, value_parser, num_args = 0.., value_delimiter = ',')] + pub scripts: Vec, /// minimum ckb funding amount for auto accepting an open channel requests, aunit: shannons [default: 16200000000 shannons] #[arg( @@ -356,25 +359,17 @@ impl FiberConfig { } } -// Basically ckb_sdk::types::NetworkType. But we added a `Mocknet` variant. -// And we can't use `ckb_sdk::types::NetworkType` directly because it is not `ValueEnum`. -#[derive(Debug, Clone, Copy, ValueEnum, Deserialize, PartialEq, Eq)] -pub enum CkbNetwork { - Mocknet, - Mainnet, - Testnet, - Staging, - Dev, +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct FiberScript { + pub name: Contract, + pub script: Script, + pub cell_deps: Vec, } -impl From for Option { - fn from(network: CkbNetwork) -> Self { - match network { - CkbNetwork::Mocknet => None, - CkbNetwork::Mainnet => Some(NetworkType::Mainnet), - CkbNetwork::Testnet => Some(NetworkType::Testnet), - CkbNetwork::Staging => Some(NetworkType::Staging), - CkbNetwork::Dev => Some(NetworkType::Dev), - } +impl FromStr for FiberScript { + type Err = serde_json::Error; + + fn from_str(s: &str) -> std::result::Result { + serde_json::from_str(s) } } diff --git a/src/fiber/network.rs b/src/fiber/network.rs index e4315894..846fbf82 100644 --- a/src/fiber/network.rs +++ b/src/fiber/network.rs @@ -4,6 +4,7 @@ use ckb_types::core::{EpochNumberWithFraction, TransactionView}; use ckb_types::packed::{self, Byte32, CellOutput, OutPoint, Script, Transaction}; use ckb_types::prelude::{IntoTransactionView, Pack, Unpack}; use musig2::CompactSignature; +use once_cell::sync::OnceCell; use ractor::concurrency::Duration; use ractor::{ async_trait as rasync_trait, call, call_t, Actor, ActorCell, ActorProcessingErr, ActorRef, @@ -107,8 +108,16 @@ const NUM_PEER_CONNECTIONS: usize = 40; // The duration for which we will try to maintain the number of peers in connection. const MAINTAINING_CONNECTIONS_INTERVAL: Duration = Duration::from_secs(3600); +static CHAIN_HASH_INSTANCE: OnceCell = OnceCell::new(); + +pub fn init_chain_hash(chain_hash: Hash256) { + CHAIN_HASH_INSTANCE + .set(chain_hash) + .expect("init_chain_hash should only be called once"); +} + pub(crate) fn get_chain_hash() -> Hash256 { - Default::default() + CHAIN_HASH_INSTANCE.get().cloned().unwrap_or_default() } #[derive(Debug)] diff --git a/src/fiber/tests/channel.rs b/src/fiber/tests/channel.rs index 060a0273..cc6552f1 100644 --- a/src/fiber/tests/channel.rs +++ b/src/fiber/tests/channel.rs @@ -741,7 +741,6 @@ async fn test_open_channel_with_invalid_ckb_amount_range() { )) }; let open_channel_result = call!(node_a.network_actor, message).expect("node_a alive"); - eprintln!("{:?}", open_channel_result.as_ref().err().unwrap()); assert!(open_channel_result .err() .unwrap() diff --git a/src/fiber/tests/graph.rs b/src/fiber/tests/graph.rs index b0cc6534..34b5d96d 100644 --- a/src/fiber/tests/graph.rs +++ b/src/fiber/tests/graph.rs @@ -522,7 +522,6 @@ fn test_graph_build_route_three_nodes() { preimage: None, allow_self_payment: false, }); - eprintln!("return {:?}", route); assert!(route.is_ok()); let route = route.unwrap(); assert_eq!(route.len(), 3); @@ -632,7 +631,6 @@ fn test_graph_mark_failed_channel() { preimage: None, allow_self_payment: false, }); - eprintln!("return {:?}", route); assert!(route.is_err()); network.add_edge(0, 5, Some(500), Some(2)); @@ -653,7 +651,6 @@ fn test_graph_mark_failed_channel() { preimage: None, allow_self_payment: false, }); - eprintln!("return {:?}", route); assert!(route.is_ok()); } @@ -682,7 +679,6 @@ fn test_graph_mark_failed_node() { preimage: None, allow_self_payment: false, }); - eprintln!("return {:?}", route); assert!(route.is_ok()); // Test build route from node1 to node4 should be Ok @@ -700,7 +696,6 @@ fn test_graph_mark_failed_node() { preimage: None, allow_self_payment: false, }); - eprintln!("return {:?}", route); assert!(route.is_ok()); network.mark_node_failed(2); @@ -720,7 +715,6 @@ fn test_graph_mark_failed_node() { preimage: None, allow_self_payment: false, }); - eprintln!("return {:?}", route); assert!(route.is_err()); // Test build route from node1 to node4 @@ -738,7 +732,6 @@ fn test_graph_mark_failed_node() { preimage: None, allow_self_payment: false, }); - eprintln!("return {:?}", route); assert!(route.is_err()); } diff --git a/src/main.rs b/src/main.rs index 1d17c837..df455f43 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,12 @@ +use ckb_chain_spec::ChainSpec; +use ckb_resource::Resource; use fnn::actors::RootActor; use fnn::cch::CchMessage; use fnn::ckb::{ contracts::{get_script_by_contract, init_contracts_context, Contract}, CkbChainActor, }; -use fnn::fiber::{channel::ChannelSubscribers, graph::NetworkGraph}; +use fnn::fiber::{channel::ChannelSubscribers, graph::NetworkGraph, network::init_chain_hash}; use fnn::store::Store; use fnn::tasks::{ cancel_tasks_and_wait_for_completion, new_tokio_cancellation_token, new_tokio_task_tracker, @@ -13,6 +15,7 @@ use fnn::watchtower::{WatchtowerActor, WatchtowerMessage}; use fnn::{start_cch, start_network, start_rpc, Config}; use core::default::Default; +use std::path::Path; use std::sync::Arc; use std::time::Duration; @@ -71,7 +74,21 @@ pub async fn main() { Add ckb service to the services list in the config file and relevant configuration to the ckb section of the config file."); let node_public_key = fiber_config.public_key(); - let _ = init_contracts_context(fiber_config.network, Some(&ckb_config)); + let chain = fiber_config.chain.as_str(); + let chain_spec = ChainSpec::load_from(&match chain { + "mainnet" => Resource::bundled("specs/mainnet.toml".to_string()), + "testnet" => Resource::bundled("specs/testnet.toml".to_string()), + path => Resource::file_system(Path::new(&config.base_dir).join(path)), + }) + .expect("load chain spec"); + let genesis_block = chain_spec.build_genesis().expect("build genesis block"); + + init_chain_hash(genesis_block.hash().into()); + init_contracts_context( + genesis_block, + fiber_config.scripts.clone(), + ckb_config.udt_whitelist.clone().unwrap_or_default(), + ); let ckb_actor = Actor::spawn_linked( Some("ckb".to_string()), diff --git a/src/rpc/invoice.rs b/src/rpc/invoice.rs index 7c8ece82..755a66bd 100644 --- a/src/rpc/invoice.rs +++ b/src/rpc/invoice.rs @@ -1,4 +1,3 @@ -use crate::fiber::config::CkbNetwork; use crate::fiber::hash_algorithm::HashAlgorithm; use crate::fiber::serde_utils::{U128Hex, U64Hex}; use crate::fiber::types::{Hash256, Privkey}; @@ -107,11 +106,10 @@ impl InvoiceRpcServerImpl { ); // restrict currency to be the same as network - let currency = match config.network { - Some(CkbNetwork::Mainnet) => Some(Currency::Fibb), - Some(CkbNetwork::Testnet) => Some(Currency::Fibt), - Some(_) => Some(Currency::Fibd), - _ => None, + let currency = match config.chain.as_str() { + "mainnet" => Currency::Fibb, + "testnet" => Currency::Fibt, + _ => Currency::Fibd, }; (keypair, currency) @@ -119,10 +117,7 @@ impl InvoiceRpcServerImpl { Self { store, keypair: config.as_ref().map(|(kp, _)| kp.clone()), - currency: config - .as_ref() - .map(|(_, currency)| *currency) - .unwrap_or_default(), + currency: config.as_ref().map(|(_, currency)| *currency), } } } diff --git a/src/rpc/utils.rs b/src/rpc/utils.rs index 6db49d14..55e25e8f 100644 --- a/src/rpc/utils.rs +++ b/src/rpc/utils.rs @@ -26,12 +26,12 @@ macro_rules! handle_actor_call { Ok(result) => match result { Ok(res) => Ok(res), Err(e) => { - debug!("Error: {:?}", e); + error!("Error: {:?}", e); Err(e) } }, Err(e) => { - debug!("Error: {:?}", e); + error!("Error: {:?}", e); Err(e) } } diff --git a/tests/bruno/e2e/3-nodes-transfer/11-node3-gen-invoice.bru b/tests/bruno/e2e/3-nodes-transfer/11-node3-gen-invoice.bru index fe9f6de6..15d87811 100644 --- a/tests/bruno/e2e/3-nodes-transfer/11-node3-gen-invoice.bru +++ b/tests/bruno/e2e/3-nodes-transfer/11-node3-gen-invoice.bru @@ -23,7 +23,7 @@ body:json { "params": [ { "amount": "0x613ae6500", - "currency": "Fibb", + "currency": "Fibd", "description": "test invoice generated by node3", "expiry": "0xe10", "final_expiry_delta": "0x28", diff --git a/tests/bruno/e2e/3-nodes-transfer/16-node3-gen-invoice.bru b/tests/bruno/e2e/3-nodes-transfer/16-node3-gen-invoice.bru index 9da0999d..1986e446 100644 --- a/tests/bruno/e2e/3-nodes-transfer/16-node3-gen-invoice.bru +++ b/tests/bruno/e2e/3-nodes-transfer/16-node3-gen-invoice.bru @@ -23,7 +23,7 @@ body:json { "params": [ { "amount": "0x867ba4900", - "currency": "Fibb", + "currency": "Fibd", "description": "test invoice generated by node3", "expiry": "0xe10", "final_expiry_delta": "0x28", diff --git a/tests/bruno/e2e/invoice-ops/1-gen-invoice.bru b/tests/bruno/e2e/invoice-ops/1-gen-invoice.bru index 65665c0f..a4a63dac 100644 --- a/tests/bruno/e2e/invoice-ops/1-gen-invoice.bru +++ b/tests/bruno/e2e/invoice-ops/1-gen-invoice.bru @@ -36,7 +36,7 @@ body:json { "params": [ { "amount": "0x64", - "currency": "Fibb", + "currency": "Fibd", "description": "test invoice", "expiry": "0xe10", "final_expiry_delta": "0x28", diff --git a/tests/bruno/e2e/invoice-ops/2-gen-invoice-duplicate.bru b/tests/bruno/e2e/invoice-ops/2-gen-invoice-duplicate.bru index f43629a7..38f6e77a 100644 --- a/tests/bruno/e2e/invoice-ops/2-gen-invoice-duplicate.bru +++ b/tests/bruno/e2e/invoice-ops/2-gen-invoice-duplicate.bru @@ -27,7 +27,7 @@ body:json { "params": [ { "amount": "0x64", - "currency": "Fibb", + "currency": "Fibd", "description": "test invoice", "expiry": "0xe10", "final_expiry_delta": "0x28", diff --git a/tests/bruno/e2e/router-pay/11-node3-gen-invoice.bru b/tests/bruno/e2e/router-pay/11-node3-gen-invoice.bru index fe9f6de6..15d87811 100644 --- a/tests/bruno/e2e/router-pay/11-node3-gen-invoice.bru +++ b/tests/bruno/e2e/router-pay/11-node3-gen-invoice.bru @@ -23,7 +23,7 @@ body:json { "params": [ { "amount": "0x613ae6500", - "currency": "Fibb", + "currency": "Fibd", "description": "test invoice generated by node3", "expiry": "0xe10", "final_expiry_delta": "0x28", diff --git a/tests/bruno/e2e/router-pay/14-node3-gen-invoice-later.bru b/tests/bruno/e2e/router-pay/14-node3-gen-invoice-later.bru index 334e1a9c..f62cf864 100644 --- a/tests/bruno/e2e/router-pay/14-node3-gen-invoice-later.bru +++ b/tests/bruno/e2e/router-pay/14-node3-gen-invoice-later.bru @@ -23,7 +23,7 @@ body:json { "params": [ { "amount": "0x613", - "currency": "Fibb", + "currency": "Fibd", "description": "test invoice generated by node3", "expiry": "0xe10", "final_expiry_delta": "0x28", diff --git a/tests/bruno/e2e/router-pay/22-node3-gen-expiring-invoice.bru b/tests/bruno/e2e/router-pay/22-node3-gen-expiring-invoice.bru index 45351754..a321dfac 100644 --- a/tests/bruno/e2e/router-pay/22-node3-gen-expiring-invoice.bru +++ b/tests/bruno/e2e/router-pay/22-node3-gen-expiring-invoice.bru @@ -23,7 +23,7 @@ body:json { "params": [ { "amount": "0x613", - "currency": "Fibb", + "currency": "Fibd", "description": "test invoice generated by node3", "expiry": "0x2", "final_expiry_delta": "0x28", diff --git a/tests/bruno/e2e/udt-router-pay/11-node3-gen-invoice.bru b/tests/bruno/e2e/udt-router-pay/11-node3-gen-invoice.bru index 64db3dc8..65dff4e2 100644 --- a/tests/bruno/e2e/udt-router-pay/11-node3-gen-invoice.bru +++ b/tests/bruno/e2e/udt-router-pay/11-node3-gen-invoice.bru @@ -23,7 +23,7 @@ body:json { "params": [ { "amount": "0x5F5E100", - "currency": "Fibb", + "currency": "Fibd", "description": "test invoice generated by node3", "expiry": "0xe10", "final_expiry_delta": "0x28", diff --git a/tests/bruno/e2e/udt-router-pay/13-node3-gen-invoice-later.bru b/tests/bruno/e2e/udt-router-pay/13-node3-gen-invoice-later.bru index 554de4ec..99633888 100644 --- a/tests/bruno/e2e/udt-router-pay/13-node3-gen-invoice-later.bru +++ b/tests/bruno/e2e/udt-router-pay/13-node3-gen-invoice-later.bru @@ -23,7 +23,7 @@ body:json { "params": [ { "amount": "0x20", - "currency": "Fibb", + "currency": "Fibd", "description": "test invoice generated by node3", "expiry": "0xe10", "final_expiry_delta": "0x28", diff --git a/tests/bruno/e2e/udt/07-node2-gen-invoice.bru b/tests/bruno/e2e/udt/07-node2-gen-invoice.bru index 3c034164..3f68bea8 100644 --- a/tests/bruno/e2e/udt/07-node2-gen-invoice.bru +++ b/tests/bruno/e2e/udt/07-node2-gen-invoice.bru @@ -36,7 +36,7 @@ body:json { "params": [ { "amount": "0xc8", - "currency": "Fibb", + "currency": "Fibd", "description": "test invoice generated by node2", "expiry": "0xe10", "final_expiry_delta": "0x28", diff --git a/tests/deploy/create-dotenv-file.sh b/tests/deploy/create-dotenv-file.sh deleted file mode 100755 index d1ceeb23..00000000 --- a/tests/deploy/create-dotenv-file.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env bash - -set -xeuo pipefail - -script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" -cd "$script_dir" || exit 1 - -case "${1:-}" in ---testnet) - shift - cat env.example - ;; ---mainnet) - shift - echo 'NEXT_PUBLIC_CKB="LINA"' - echo 'NEXT_PUBLIC_CKB_RPC_URL=" https://mainnet.ckb.dev/"' - ;; -*) - echo 'NEXT_PUBLIC_CKB="DEV"' - echo 'NEXT_PUBLIC_CKB_RPC_URL="http://127.0.0.1:8114/"' - GENESIS_TXS="$(ckb-cli rpc get_block_by_number --number 0 | sed -n 's/^ hash: //p')" - echo 'NEXT_PUBLIC_CKB_GENESIS_TX_0="'"$(echo "$GENESIS_TXS" | head -n 1)"'"' - echo 'NEXT_PUBLIC_CKB_GENESIS_TX_1="'"$(echo "$GENESIS_TXS" | tail -n 1)"'"' - ;; -esac - -create_dotenv_for_contract() { - local CONTRACT_NAME="$1" - local CONTRACT_INFO_FILE="$(ls "migrations/$CONTRACT_NAME"/*.json | grep -v deployment | head -n 1)" - # Replace dash with underscore because envirornment variable names cannot contain dashes. - # Also use uppercase because environment variable names are usually uppercase. - CONTRACT_NAME="$(echo "$CONTRACT_NAME" | tr '-' '_' | tr '[:lower:]' '[:upper:]')" - - sed -n \ - -e 's/,$//' \ - -e 's/^ *"data_hash": "/NEXT_PUBLIC_'"$CONTRACT_NAME"'_CODE_HASH="/p' \ - "$CONTRACT_INFO_FILE" | head -1 - - sed -n \ - -e 's/,$//' \ - -e 's/^ *"type_id": "/NEXT_PUBLIC_'"$CONTRACT_NAME"'_TYPE_HASH="/p' \ - "$CONTRACT_INFO_FILE" | head -1 - - sed -n \ - -e 's/,$//' \ - -e 's/^ *"tx_hash": /NEXT_PUBLIC_'"$CONTRACT_NAME"'_TX_HASH=/p' \ - "$CONTRACT_INFO_FILE" | head -1 - - sed -n \ - -e 's/,$//' \ - -e 's/^ *"index": /NEXT_PUBLIC_'"$CONTRACT_NAME"'_TX_INDEX=/p' \ - "$CONTRACT_INFO_FILE" | head -1 - - if ! grep -Eq '"dep_group_recipes": *\[ *\]$' "$CONTRACT_INFO_FILE"; then - sed -n \ - -e 's/,$//' \ - -e 's/^ *"data_hash": "/NEXT_PUBLIC_'"$CONTRACT_NAME"'_DEP_GROUP_CODE_HASH="/p' \ - "$CONTRACT_INFO_FILE" | tail -1 - - sed -n \ - -e 's/,$//' \ - -e 's/^ *"tx_hash": "/NEXT_PUBLIC_'"$CONTRACT_NAME"'_DEP_GROUP_TX_HASH="/p' \ - "$CONTRACT_INFO_FILE" | tail -1 - - sed -n \ - -e 's/,$//' \ - -e 's/^ *"index": /NEXT_PUBLIC_'"$CONTRACT_NAME"'_DEP_GROUP_TX_INDEX=/p' \ - "$CONTRACT_INFO_FILE" | tail -1 - - fi -} - -create_dotenv_for_contract funding-lock -create_dotenv_for_contract commitment-lock -create_dotenv_for_contract simple-udt -create_dotenv_for_contract xudt diff --git a/tests/deploy/deploy.sh b/tests/deploy/deploy.sh index 752447ad..a4fabb8f 100755 --- a/tests/deploy/deploy.sh +++ b/tests/deploy/deploy.sh @@ -25,40 +25,7 @@ if ! (echo | ckb-cli account import --local-only --privkey-path "$miner_key_file : fi -function deploy() { - local DEPLOY_NAME="$1" - local MIGRATION_DIR="migrations/$DEPLOY_NAME" - local CONFIG_FILE="$MIGRATION_DIR/deployment.toml" - local INFO_FILE="$MIGRATION_DIR/deployment.json" - local TEMPLATE_FILE="migrations/templates/$DEPLOY_NAME.toml" - - rm -rf "$MIGRATION_DIR" && mkdir -p "$MIGRATION_DIR" - GENESIS_TX0="$(ckb -C "$data_dir" list-hashes | sed -n 's/tx_hash = "\(.*\)"/\1/p' | head -1)" - sed "s/0x8f8c79eb6671709633fe6a46de93c0fedc9c1b8a6527a18d3983879542635c9f/$GENESIS_TX0/" "$TEMPLATE_FILE" >"$CONFIG_FILE" - - ckb-cli deploy gen-txs --from-address $(cat "$nodes_dir/deployer/ckb/wallet") \ - --fee-rate 100000 --deployment-config "$CONFIG_FILE" --info-file "$INFO_FILE" --migration-dir "$MIGRATION_DIR" - - ckb-cli deploy sign-txs --add-signatures --info-file "$INFO_FILE" --privkey-path "$miner_key_file" --output-format json | sed -n 's/: \("[^"]*"\)/: [\1]/p' - - if ckb-cli deploy apply-txs --info-file "$INFO_FILE" --migration-dir "$MIGRATION_DIR" | grep -q "already exists in transaction_pool"; then - : - fi -} - -generate_blocks() { - ./generate-blocks.sh 8 - sleep 1 -} - -# try twice in case the indexer has not updated yet -deploy_and_generate_blocks() { - deploy "$1" || deploy "$1" - generate_blocks -} - run_udt_init() { - export $(xargs <".env") export NODES_DIR="$nodes_dir" ( cd "$udt_init_dir" || exit 1 @@ -66,10 +33,4 @@ run_udt_init() { ) } -deploy_and_generate_blocks funding-lock -deploy_and_generate_blocks commitment-lock -deploy_and_generate_blocks simple-udt -deploy_and_generate_blocks xudt - -./create-dotenv-file.sh >.env run_udt_init diff --git a/tests/deploy/init-dev-chain.sh b/tests/deploy/init-dev-chain.sh index d478233b..250ebc52 100755 --- a/tests/deploy/init-dev-chain.sh +++ b/tests/deploy/init-dev-chain.sh @@ -33,6 +33,9 @@ done # Initialize the data directory if it does not exist. if ! [[ -d "$data_dir" ]]; then ckb init -C "$data_dir" -c dev --force --ba-arg 0xc8328aabcd9b9e8e64fbc566c4385c3bdeb219d7 + cp "$nodes_dir/deployer/dev.toml" "$data_dir/specs/dev.toml" + sed -i.bak 's|\.\./\.\./deploy/contracts|\.\./\.\./\.\./deploy/contracts|g' "$data_dir/specs/dev.toml" + # Enable the IntegrationTest module (required to generate blocks). if ! grep -E '^modules.*IntegrationTest' "$data_dir/ckb.toml"; then # -i.bak is required to sed work on both Linux and macOS. @@ -61,13 +64,13 @@ if ! [[ -d "$data_dir" ]]; then ckb-cli wallet transfer --to-address $(cat "$nodes_dir/1/ckb/wallet") --capacity 5000000000 --fee-rate 2000 --privkey-path "$nodes_dir/deployer/ckb/key" sleep 1 - "$script_dir/generate-blocks.sh" 6 + "$script_dir/generate-blocks.sh" 4 sleep 1 # Transfer some money to the node 2. ckb-cli wallet transfer --to-address $(cat "$nodes_dir/2/ckb/wallet") --capacity 5000000000 --fee-rate 2000 --privkey-path "$nodes_dir/deployer/ckb/key" sleep 1 - "$script_dir/generate-blocks.sh" 6 + "$script_dir/generate-blocks.sh" 4 sleep 1 # Transfer some money to the node 3. @@ -75,7 +78,7 @@ if ! [[ -d "$data_dir" ]]; then sleep 1 # Generate a few blocks so that above transaction is confirmed. echo "begin to generate blocks for wallet updating..." - "$script_dir/generate-blocks.sh" 6 + "$script_dir/generate-blocks.sh" 4 # Also deploy the contracts. echo "deploy.sh..." diff --git a/tests/deploy/udt-init/Cargo.lock b/tests/deploy/udt-init/Cargo.lock index 637d0c64..55147317 100644 --- a/tests/deploy/udt-init/Cargo.lock +++ b/tests/deploy/udt-init/Cargo.lock @@ -178,9 +178,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "ckb-chain-spec" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e955d55380bbd2ca883b4426fb1483e61f06fe65c8b377d5d4bceeb03ecf07bb" +checksum = "38fa470ac81179a066b3dd3e0d56e8fb9988aaddf5c2ae921cbc2ee6c60bbc56" dependencies = [ "cacache", "ckb-constant", @@ -201,38 +201,38 @@ dependencies = [ [[package]] name = "ckb-channel" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853f561e90ff59d858dc87c1ac385fae948984859c874fd8d3bd1bbab335889d" +checksum = "081350579a7d6cee3c7d3b82b3667860517e785269f8cd72b27ae472775d9c04" dependencies = [ "crossbeam-channel", ] [[package]] name = "ckb-constant" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baf91b16a3b8360c85211dfdff3d2adc0a1f3ae571ea6b1637d55d6b227e312" +checksum = "fce0d46bfe7d555b60e7e1b589643bcd2d6a40e4cc0a04c5e9412dbb30c1f206" [[package]] name = "ckb-crypto" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e2094270f5632808cbff1c37a37ffb9b3e79f7a99e78927fb228d8c343793eb" +checksum = "d2b268e177104ec7089656562adac06dd8209298873cb806fff76c1d3df16566" dependencies = [ "ckb-fixed-hash", "faster-hex", "lazy_static", - "rand 0.7.3", + "rand 0.8.5", "secp256k1", "thiserror", ] [[package]] name = "ckb-dao-utils" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eb3606c602a424098317bfde4b7d6427d4fe5dfe1a6d4ebc831ce0308508085" +checksum = "1df36dfa384153423e777f3f40beeb5fbb42d5ba223d411d7850bf72e190428e" dependencies = [ "byteorder", "ckb-error", @@ -241,9 +241,9 @@ dependencies = [ [[package]] name = "ckb-error" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01041f8a1d7eeaf85caca3547bb78d929d6a4d62774509d7eb438b6bc310ba30" +checksum = "e6726194aed3b38485270e64d3823b3fb5e9d7ce6ea2ea117106f97619272de5" dependencies = [ "anyhow", "ckb-occupied-capacity", @@ -253,9 +253,9 @@ dependencies = [ [[package]] name = "ckb-fixed-hash" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a7491f18717b84827923935cc5adb1bcdf9c924e377b478d089f4694e7c779b" +checksum = "e497f03441f4622bc6d1d44db95ff47c37bec03ef2c8132ca19ac8005c70995f" dependencies = [ "ckb-fixed-hash-core", "ckb-fixed-hash-macros", @@ -263,9 +263,9 @@ dependencies = [ [[package]] name = "ckb-fixed-hash-core" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9509f63fedb9b6e42cfd0db47d3dc5acb6b029da546d5d4451d08afc44c70cf8" +checksum = "bb5f80c82b9b0498272f085b86824cfe0b76a2c04ee653a91f9ff362fd9b6f6c" dependencies = [ "ckb_schemars", "faster-hex", @@ -275,9 +275,9 @@ dependencies = [ [[package]] name = "ckb-fixed-hash-macros" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd89533a5da746f50798752a46f5f084f110c849335be94baf506790ebee931" +checksum = "00ede2291016d17450e9d117fac6fb515629779e31ea452d5146a117cd12bf0f" dependencies = [ "ckb-fixed-hash-core", "proc-macro2", @@ -287,9 +287,9 @@ dependencies = [ [[package]] name = "ckb-gen-types" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0f2d0f4224507a027d25d64824dd0dc8d367c8b5bead30289eaffe1381a7fb" +checksum = "e0a7891f62f4ae4f018bfde91a46178c78491a1dfee740a20b994003a23f10af" dependencies = [ "cfg-if 1.0.0", "ckb-error", @@ -302,9 +302,9 @@ dependencies = [ [[package]] name = "ckb-hash" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5754bc49cf76a7e8829fe6a7cf1eea1284cbca9777b521f072c76d6ae28d303" +checksum = "d96b7aec74956ae5e79d0fc68e5903dc2b133c2c64644514485bbc9feb5367eb" dependencies = [ "blake2b-ref", "blake2b-rs", @@ -312,9 +312,9 @@ dependencies = [ [[package]] name = "ckb-jsonrpc-types" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef7e123043ca3701cf05ba4c3699b34f3b179609109a4c8c3afa68922f722be7" +checksum = "44e622a66404770b52da9dfbc9b994f2b711ea2368ef23cc9b1c96ca38491ecf" dependencies = [ "ckb-types", "ckb_schemars", @@ -325,9 +325,9 @@ dependencies = [ [[package]] name = "ckb-logger" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ebecd56c9acb453bdcb5c39e66b6b7f980bdf72b35515750bc295fa635287d" +checksum = "c76af0252cd14e57fafac7c67282eedb9c7bbf40a529ed4eb1bb85067b767e7a" dependencies = [ "log", ] @@ -343,9 +343,9 @@ dependencies = [ [[package]] name = "ckb-mock-tx-types" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1ddfee88ad65ff6fd828695a78ec49be60888c58e631feb66d130008ce130d0" +checksum = "fd785084e7c3903cb49f0d2abb12c56880827cae14723cd4fed1bf3fa26a74db" dependencies = [ "ckb-jsonrpc-types", "ckb-traits", @@ -355,9 +355,9 @@ dependencies = [ [[package]] name = "ckb-occupied-capacity" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4aa07af7cec38d15cfe4c1ce150514fba5a4e78996bbbd098982106bee7d8d" +checksum = "5e01910f17fcdb1850df67a5b340bbb98d18948eacb476fc85d9a7699294d7ab" dependencies = [ "ckb-occupied-capacity-core", "ckb-occupied-capacity-macros", @@ -365,18 +365,18 @@ dependencies = [ [[package]] name = "ckb-occupied-capacity-core" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a63ed90996ba24ab26d5ac8ae22fd002a293f4a4e4526042e1adf84b1889e176" +checksum = "21ead5905cedba4acf082f88723c8f42a508bd28fd9c00e1dbf170049ef778b4" dependencies = [ "serde", ] [[package]] name = "ckb-occupied-capacity-macros" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a6aae3f1f8d194cd5bd4328c9c7281f0d7acc73976b2771576cdc06a9ed608f" +checksum = "893198354933ba8fa0a1d99c013c819a295f6ae30b1af89fc14e0b62d7afa024" dependencies = [ "ckb-occupied-capacity-core", "quote", @@ -385,9 +385,9 @@ dependencies = [ [[package]] name = "ckb-pow" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb981de6e56107cd3e1660a9105bb07891277b21604946f70bf5097dd03690f7" +checksum = "069c3db99adb9d350d186de8e02a43e77dff7be2a8b9b7cf61ba80a280e2dd00" dependencies = [ "byteorder", "ckb-hash", @@ -399,9 +399,9 @@ dependencies = [ [[package]] name = "ckb-rational" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570e816c80fffdfafb58c7c895df8c08c64ba56ce79d824e5ff976dd1a7381" +checksum = "7be813511d1c17a6bab8a7dcfbee6e086aa2bae3bb77cfd4a570abfb67af2c16" dependencies = [ "numext-fixed-uint", "serde", @@ -409,9 +409,9 @@ dependencies = [ [[package]] name = "ckb-resource" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d482493fabf4ce3670277d7dbaa5811872379535031431dc6b19699722c7b846" +checksum = "d1e74f9bc4039a4cf6d579dc8b444b3d76780e51aab94daccdd5e6e58d01cc32" dependencies = [ "ckb-system-scripts", "ckb-types", @@ -424,9 +424,9 @@ dependencies = [ [[package]] name = "ckb-script" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2d6528e95a0f93d4a39e569b1ffffd60cbb0a9ae8f1c96dd465e2576ad510a9" +checksum = "f6b92a1f4f059f4680b08817dfb739a40356dcf4798b3cb8ae1f1d67218eb0fb" dependencies = [ "byteorder", "ckb-chain-spec", @@ -438,12 +438,14 @@ dependencies = [ "ckb-vm", "faster-hex", "serde", + "tokio", ] [[package]] name = "ckb-sdk" -version = "3.2.0" -source = "git+https://github.com/chenyukang/ckb-sdk-rust.git?branch=pcn-udt#e205f61b0df4ae73c4688d6505079cdce6445527" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75d816b57b37c49a99c715f07e120928d8139993523efec0b9e2faa94db7edce" dependencies = [ "anyhow", "bech32", @@ -496,18 +498,18 @@ dependencies = [ [[package]] name = "ckb-traits" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c528f704f3088ec2dd467d374920b64b2bbb9ed9c4e8e12931c069a99150d8bc" +checksum = "b6500281355bbf7a235fb386b2883e8ffb8cb5bab8447bd86dd229148ec52704" dependencies = [ "ckb-types", ] [[package]] name = "ckb-types" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b05cc1c6aab0c40b323b233617b67860f9d679fac431a34d1f1b0853d700e9d" +checksum = "88f4ef54b7665440d1984489c580e8d540888496d7b9ff8d57262ac583ff97a4" dependencies = [ "bit-vec", "bytes", @@ -531,9 +533,9 @@ dependencies = [ [[package]] name = "ckb-vm" -version = "0.24.9" +version = "0.24.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2c3d68dc7f891e5555c7ebc054722b28ab005e51c5076f54c20d36002dc8e83" +checksum = "ddff96029d3298cb630e95f29d4b9a93384e938a0b75758684aa8794b53bdd1a" dependencies = [ "byteorder", "bytes", @@ -549,9 +551,9 @@ dependencies = [ [[package]] name = "ckb-vm-definitions" -version = "0.24.9" +version = "0.24.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2fdf9c8ee14409b2208d23b9ad88828242d7881153ddc04872b66d2e018a52f" +checksum = "c280bf1d589d23ab0358f58601c2187fc6be86a131644583ef72ea96a0a13ddd" dependencies = [ "paste", ] @@ -1006,6 +1008,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "hex" version = "0.4.3" @@ -1287,9 +1295,9 @@ dependencies = [ [[package]] name = "molecule" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd9767ab5e5f2ea40f71ff4c8bdb633c50509052e093c2fdd0e390a749dfa3" +checksum = "6efe1c7efcd0bdf4ca590e104bcb13087d9968956ae4ae98e92fb8c1da0f3730" dependencies = [ "bytes", "cfg-if 1.0.0", @@ -1313,6 +1321,16 @@ dependencies = [ "tempfile", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "numext-constructor" version = "0.1.6" @@ -1793,18 +1811,18 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.24.3" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ "secp256k1-sys", ] [[package]] name = "secp256k1-sys" -version = "0.6.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" dependencies = [ "cc", ] @@ -2113,6 +2131,7 @@ dependencies = [ "bytes", "libc", "mio", + "num_cpus", "pin-project-lite", "socket2", "tokio-macros", @@ -2214,7 +2233,10 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" name = "udt-init" version = "0.1.0" dependencies = [ + "ckb-chain-spec", + "ckb-gen-types", "ckb-jsonrpc-types", + "ckb-resource", "ckb-sdk", "ckb-types", "hex", diff --git a/tests/deploy/udt-init/Cargo.toml b/tests/deploy/udt-init/Cargo.toml index 0b5b2146..1ee2b7d5 100644 --- a/tests/deploy/udt-init/Cargo.toml +++ b/tests/deploy/udt-init/Cargo.toml @@ -6,9 +6,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ckb-sdk = { version = "3.2.0", git = "https://github.com/chenyukang/ckb-sdk-rust.git", branch = "pcn-udt"} -ckb-types = "0.116.1" -ckb-jsonrpc-types = "0.116.1" +ckb-sdk = { version = "3.4" } +ckb-types = "0.118" +ckb-jsonrpc-types = "0.118" serde = { version = "1.0", features = ["derive"] } serde_derive = "1.0" serde_json = "1.0" @@ -16,3 +16,6 @@ thiserror = "1.0.30" hex = "0.4.3" serde_yaml = "0.9.34" rand = "0.8.5" +ckb-chain-spec = "0.118.0" +ckb-resource = "0.118.0" +ckb-gen-types = "0.118.0" diff --git a/tests/deploy/udt-init/src/main.rs b/tests/deploy/udt-init/src/main.rs index 30299f35..a585d730 100644 --- a/tests/deploy/udt-init/src/main.rs +++ b/tests/deploy/udt-init/src/main.rs @@ -1,3 +1,5 @@ +use ckb_chain_spec::ChainSpec; +use ckb_resource::Resource; use ckb_sdk::{ transaction::{ builder::{sudt::SudtTransactionBuilder, CkbTransactionBuilder}, @@ -8,72 +10,74 @@ use ckb_sdk::{ }, Address, CkbRpcClient, NetworkInfo, ScriptId, }; +use ckb_types::{ + core::BlockView, + packed::CellOutput, + prelude::{Entity, Unpack}, +}; use ckb_types::{ core::{DepType, ScriptHashType}, - h256, packed::{OutPoint, Script}, - prelude::{Entity, Pack}, + prelude::Pack, H256, }; use ckb_types::{packed::CellDep, prelude::Builder}; use rand::Rng; use serde::{Deserialize, Serialize}; -use std::collections::HashSet; -use std::net::TcpListener; +use std::{collections::HashSet, path::Path}; +use std::{fs, net::TcpListener}; use std::{error::Error as StdErr, str::FromStr}; -const SIMPLE_CODE_HASH: H256 = - h256!("0xe1e354d6d643ad42724d40967e334984534e0367405c5ae42a9d7d63d77df419"); -const XUDT_CODE_HASH: H256 = - h256!("0x50bd8d6680b8b9cf98b73f3c08faf8b2a21914311954118ad6609be6e78a1b95"); - const UDT_KINDS: [&str; 2] = ["SIMPLE_UDT", "XUDT"]; -fn get_code_hash(udt_kind: &str) -> H256 { - match udt_kind { - "SIMPLE_UDT" => SIMPLE_CODE_HASH.clone(), - "XUDT" => XUDT_CODE_HASH.clone(), - _ => panic!("unsupported udt kind"), - } -} - -fn get_env_hex(name: &str) -> H256 { - let value = std::env::var(name).expect("env var"); - // strip prefix 0x - let value = value.trim_start_matches("0x"); - H256::from_str(value).expect("parse hex") +fn get_udt_info(udt_kind: &str) -> (H256, H256, usize) { + let genesis_block = build_gensis_block(); + let genesis_tx = genesis_block + .transaction(0) + .expect("genesis block transaction #0 should exist"); + + let index = if udt_kind == "SIMPLE_UDT" { 8 } else { 9 }; + let output_data = genesis_tx.outputs_data().get(index).unwrap().raw_data(); + ( + CellOutput::calc_data_hash(&output_data).unpack(), + genesis_tx.hash().unpack(), + index, + ) } fn gen_dev_udt_handler(udt_kind: &str) -> SudtHandler { - let udt_tx = get_env_hex(format!("NEXT_PUBLIC_{}_TX_HASH", udt_kind).as_str()); - let code_hash = get_code_hash(udt_kind); - let (out_point, script_id) = ( - OutPoint::new_builder() - .tx_hash(udt_tx.pack()) - .index(0u32.pack()) - .build(), - ScriptId::new_data1(code_hash), - ); - - let cell_dep = CellDep::new_builder() - .out_point(out_point) + let (data_hash, genesis_tx, index) = get_udt_info(udt_kind); + let script_id = ScriptId::new_data1(data_hash); + + let udt_cell_dep = CellDep::new_builder() + .out_point( + OutPoint::new_builder() + .tx_hash(genesis_tx.pack()) + .index(index.pack()) + .build(), + ) .dep_type(DepType::Code.into()) .build(); - ckb_sdk::transaction::handler::sudt::SudtHandler::new_with_customize(vec![cell_dep], script_id) + ckb_sdk::transaction::handler::sudt::SudtHandler::new_with_customize( + vec![udt_cell_dep], + script_id, + ) } fn gen_dev_sighash_handler() -> Secp256k1Blake160SighashAllScriptHandler { - let sighash_tx = get_env_hex("NEXT_PUBLIC_CKB_GENESIS_TX_1"); - - let out_point = OutPoint::new_builder() - .tx_hash(sighash_tx.pack()) + let genesis_block = build_gensis_block(); + let secp256k1_dep_group_tx_hash = genesis_block + .transaction(1) + .expect("genesis block transaction #1 should exist") + .hash(); + let secp256k1_dep_group_out_point = OutPoint::new_builder() + .tx_hash(secp256k1_dep_group_tx_hash) .index(0u32.pack()) .build(); - let cell_dep = CellDep::new_builder() - .out_point(out_point) + .out_point(secp256k1_dep_group_out_point) .dep_type(DepType::DepGroup.into()) .build(); @@ -155,7 +159,7 @@ fn generate_blocks(num: u64) -> Result<(), Box> { fn generate_udt_type_script(udt_kind: &str, address: &str) -> ckb_types::packed::Script { let address = Address::from_str(address).expect("parse address"); let sudt_owner_lock_script: Script = (&address).into(); - let code_hash = get_code_hash(udt_kind); + let (code_hash, _, _) = get_udt_info(udt_kind); Script::new_builder() .code_hash(code_hash.pack()) .hash_type(ScriptHashType::Data1.into()) @@ -225,24 +229,26 @@ fn generate_ports(num_ports: usize) -> Vec { } fn genrate_nodes_config() { - let nodes_dir = std::env::var("NODES_DIR").expect("env var"); - let yaml_file_path = format!("{}/deployer/config.yml", nodes_dir); + let node_dir_env = std::env::var("NODES_DIR").expect("env var"); + let nodes_dir = Path::new(&node_dir_env); + let yaml_file_path = nodes_dir.join("deployer/config.yml"); let content = std::fs::read_to_string(yaml_file_path).expect("read failed"); let data: serde_yaml::Value = serde_yaml::from_str(&content).expect("Unable to parse YAML"); let mut udt_infos = vec![]; for udt in UDT_KINDS { + let (code_hash, genesis_tx, index) = get_udt_info(udt); let udt_info = UdtInfo { name: udt.to_string(), auto_accept_amount: Some(1000), script: UdtScript { - code_hash: get_code_hash(udt), + code_hash: code_hash, hash_type: "Data1".to_string(), args: "0x.*".to_string(), }, cell_deps: vec![UdtCellDep { dep_type: "code".to_string(), - tx_hash: get_env_hex(format!("NEXT_PUBLIC_{}_TX_HASH", udt).as_str()), - index: 0, + tx_hash: genesis_tx, + index: index as u32, }], }; udt_infos.push(udt_info); @@ -257,6 +263,7 @@ fn genrate_nodes_config() { let on_github_action = std::env::var("ON_GITHUB_ACTION").is_ok(); let gen_ports = generate_ports(6); let mut ports_iter = gen_ports.iter(); + let dev_config = nodes_dir.join("deployer/dev.toml"); for (i, config_dir) in config_dirs.iter().enumerate() { let use_gen_port = on_github_action && i != 0; let default_fiber_port = (8343 + i) as u16; @@ -290,20 +297,17 @@ fn genrate_nodes_config() { } let new_yaml = header.to_string() + &serde_yaml::to_string(&data).unwrap(); - let config_path = format!("{}/{}/config.yml", nodes_dir, config_dir); - + let config_path = nodes_dir.join(config_dir).join("config.yml"); std::fs::write(config_path, new_yaml).expect("write failed"); + let node_dev_config = nodes_dir.join(config_dir).join("dev.toml"); + fs::copy(dev_config.clone(), node_dev_config).expect("copy dev.toml failed"); } if on_github_action { - let bruno_dir = format!("{}/../bruno/environments/", nodes_dir); + let bruno_dir = nodes_dir.join("../bruno/environments/"); for config in std::fs::read_dir(bruno_dir).expect("read dir") { let config = config.expect("read config"); for (default_port, port) in ports_map.iter() { - eprintln!( - "update bruno config: {:?} {} -> {}", - config, default_port, port - ); let content = std::fs::read_to_string(config.path()).expect("read config"); let new_content = content.replace(&default_port.to_string(), &port.to_string()); std::fs::write(config.path(), new_content).expect("write config"); @@ -319,21 +323,20 @@ fn genrate_nodes_config() { .collect::>() .join("\n"); - let port_file_path = format!("{}/.ports", nodes_dir); + let port_file_path = nodes_dir.join(".ports"); + std::fs::write(port_file_path, content).expect("write ports list"); } fn init_udt_accounts() -> Result<(), Box> { let udt_owner = get_nodes_info("deployer"); for udt in UDT_KINDS { - eprintln!("begin init udt: {} ...", udt); init_or_send_udt(udt, &udt_owner.0, &udt_owner, None, 1000000000000, true) .expect("init udt"); generate_blocks(8).expect("ok"); std::thread::sleep(std::time::Duration::from_millis(1000)); for i in 0..3 { let wallet = get_nodes_info(&(i + 1).to_string()); - eprintln!("begin send udt: {} to node {} ...", udt, i); init_or_send_udt( udt, &udt_owner.0, @@ -351,8 +354,18 @@ fn init_udt_accounts() -> Result<(), Box> { Ok(()) } +fn build_gensis_block() -> BlockView { + let node_dir_env = std::env::var("NODES_DIR").expect("env var"); + let nodes_dir = Path::new(&node_dir_env); + let dev_toml = nodes_dir.join("deployer/dev.toml"); + let chain_spec = + ChainSpec::load_from(&Resource::file_system(dev_toml)).expect("load chain spec"); + let genesis_block = chain_spec.build_genesis().expect("build genesis block"); + genesis_block +} + fn main() -> Result<(), Box> { - init_udt_accounts()?; genrate_nodes_config(); + init_udt_accounts()?; Ok(()) } diff --git a/tests/nodes/deployer/config.yml b/tests/nodes/deployer/config.yml index 11c7bd9f..963ceef6 100644 --- a/tests/nodes/deployer/config.yml +++ b/tests/nodes/deployer/config.yml @@ -2,8 +2,7 @@ ## Instead the initialize program `udt-init` will use it as a config template to generate `config.yml` for nodes fiber: - listening_port: 8346 - #announce_node_interval_seconds: 36000 + chain: dev.toml auto_announce_node: true rpc: diff --git a/tests/nodes/deployer/dev.toml b/tests/nodes/deployer/dev.toml new file mode 100644 index 00000000..ee7f1dcc --- /dev/null +++ b/tests/nodes/deployer/dev.toml @@ -0,0 +1,122 @@ +name = "ckb_dev" + +[genesis] +version = 0 +parent_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +timestamp = 0 +compact_target = 0x20010000 +uncles_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +nonce = "0x0" + +[genesis.genesis_cell] +message = "ckb_dev" + +[genesis.genesis_cell.lock] +code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +args = "0x" +hash_type = "data" + +# An array list paths to system cell files, which is absolute or relative to +# the directory containing this config file. +[[genesis.system_cells]] +file = { bundled = "specs/cells/secp256k1_blake160_sighash_all" } +create_type_id = true +capacity = 100_000_0000_0000 +[[genesis.system_cells]] +file = { bundled = "specs/cells/dao" } +create_type_id = true +capacity = 16_000_0000_0000 +[[genesis.system_cells]] +file = { bundled = "specs/cells/secp256k1_data" } +create_type_id = false +capacity = 1_048_617_0000_0000 +[[genesis.system_cells]] +file = { bundled = "specs/cells/secp256k1_blake160_multisig_all" } +create_type_id = true +capacity = 100_000_0000_0000 +[[genesis.system_cells]] +file = { file = "../../deploy/contracts/auth" } +create_type_id = false +capacity = 200_000_0000_0000 +[[genesis.system_cells]] +file = { file = "../../deploy/contracts/funding-lock" } +create_type_id = false +capacity = 200_000_0000_0000 +[[genesis.system_cells]] +file = { file = "../../deploy/contracts/commitment-lock" } +create_type_id = false +capacity = 200_000_0000_0000 +[[genesis.system_cells]] +file = { file = "../../deploy/contracts/simple_udt" } +create_type_id = false +capacity = 200_000_0000_0000 +[[genesis.system_cells]] +file = { file = "../../deploy/contracts/xudt_rce" } +create_type_id = false +capacity = 200_000_0000_0000 + +[genesis.system_cells_lock] +code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +args = "0x" +hash_type = "data" + +# Dep group cells +[[genesis.dep_groups]] +name = "secp256k1_blake160_sighash_all" +files = [ + { bundled = "specs/cells/secp256k1_data" }, + { bundled = "specs/cells/secp256k1_blake160_sighash_all" }, +] +[[genesis.dep_groups]] +name = "secp256k1_blake160_multisig_all" +files = [ + { bundled = "specs/cells/secp256k1_data" }, + { bundled = "specs/cells/secp256k1_blake160_multisig_all" }, +] + +# For first 11 block +[genesis.bootstrap_lock] +code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +args = "0x" +hash_type = "type" + +# Burn +[[genesis.issued_cells]] +capacity = 8_400_000_000_00000000 +lock.code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +lock.args = "0x62e907b15cbf27d5425399ebf6f0fb50ebb88f18" +lock.hash_type = "data" + +# issue for random generated private key: d00c06bfd800d27397002dca6fb0993d5ba6399b4238b2f29ee9deb97593d2bc +[[genesis.issued_cells]] +capacity = 20_000_000_000_00000000 +lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" +lock.args = "0xc8328aabcd9b9e8e64fbc566c4385c3bdeb219d7" +lock.hash_type = "type" + +# issue for random generated private key: 63d86723e08f0f813a36ce6aa123bb2289d90680ae1e99d4de8cdb334553f24d +[[genesis.issued_cells]] +capacity = 5_198_735_037_00000000 +lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" +lock.args = "0x470dcdc5e44064909650113a274b3b36aecb6dc7" +lock.hash_type = "type" + +[params] +initial_primary_epoch_reward = 1_917_808_21917808 +secondary_epoch_reward = 613_698_63013698 +max_block_cycles = 10_000_000_000 +cellbase_maturity = 0 +primary_epoch_reward_halving_interval = 8760 +epoch_duration_target = 80 +genesis_epoch_length = 10 +# For development and testing purposes only. +# Keep difficulty be permanent if the pow is Dummy. (default: false) +permanent_difficulty_in_dummy = true +starting_block_limiting_dao_withdrawing_lock = 0 + +[params.hardfork] +ckb2023 = 0 + + +[pow] +func = "Dummy" diff --git a/tests/nodes/start.sh b/tests/nodes/start.sh index 410b50fb..ac473cc7 100755 --- a/tests/nodes/start.sh +++ b/tests/nodes/start.sh @@ -19,30 +19,13 @@ export TESTING_CONTRACTS_DIR="$deploy_dir/contracts" # This script is nilpotent, so it is safe to run multiple times. "$deploy_dir/init-dev-chain.sh" -# Load the environment variables from the .env file generated by create-dotenv-file.sh. -# These are environment variables that specify the contract hashes and other information. -if [[ ! -f "$deploy_dir/.env" ]]; then +if [ -n "$should_clean_fiber_state" ]; then + echo "starting to clean fiber store ...." + rm -rf "$nodes_dir"/*/fiber/store +elif [ -n "$should_remove_old_state" ]; then + echo "starting to reset ...." + rm -rf "$nodes_dir"/*/fiber/store "$deploy_dir/init-dev-chain.sh" -f - if [[ ! -f "$deploy_dir/.env" ]]; then - echo "The .env file does not exist. This should no happen" >&2 - echo "In case of issue pesisting, run $deploy_dir/init-dev-chain.sh -f to reintialize the devchain" - exit 1 - fi -else - if [ -n "$should_clean_fiber_state" ]; then - echo "starting to clean fiber store ...." - rm -rf "$nodes_dir"/*/fiber/store - elif [ -n "$should_remove_old_state" ]; then - echo "starting to reset ...." - rm -rf "$nodes_dir"/*/fiber/store - "$deploy_dir/init-dev-chain.sh" -f - fi -fi -export $(xargs <"$deploy_dir/.env") - -if [[ -f "$deploy_dir/.env.local" ]]; then - # Local environment variables, may used to override the default ones. - export $(xargs <"$deploy_dir/.env.local") fi echo "Initializing finished, begin to start services ...."