Skip to content

Commit

Permalink
Fix NetworkServer not dropped in unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
yangby-cryptape authored and eval-exec committed Oct 7, 2023
1 parent 5d33576 commit c574b80
Show file tree
Hide file tree
Showing 12 changed files with 392 additions and 313 deletions.
540 changes: 293 additions & 247 deletions Cargo.lock

Large diffs are not rendered by default.

41 changes: 21 additions & 20 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,24 @@ homepage = "https://github.com/nervosnetwork/ckb-light-client"
repository = "https://github.com/nervosnetwork/ckb-light-client"

[dependencies]
ckb-app-config = "0.110.2"
ckb-async-runtime = "0.110.2"
ckb-constant = "0.110.2"
ckb-types = "0.110.2"
ckb-network = "0.110.2"
ckb-jsonrpc-types = "0.110.2"
ckb-error = "0.110.2"
ckb-script = "0.110.2"
ckb-chain-spec = "0.110.2"
ckb-traits = "0.110.2"
ckb-resource = "0.110.2"
ckb-verification = "0.110.2"
ckb-systemtime = "0.110.2"
ckb-hash = "0.110.2"
ckb-app-config = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-async-runtime = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-stop-handler = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-constant = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-types = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-network = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-jsonrpc-types = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-error = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-script = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-chain-spec = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-traits = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-resource = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-verification = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-systemtime = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-hash = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-merkle-mountain-range = "0.5.1"
golomb-coded-set = "0.2.0"
rocksdb = { package = "ckb-rocksdb", version ="=0.19.0", features = ["snappy"], default-features = false }
rocksdb = { package = "ckb-rocksdb", version ="=0.20.0", features = ["snappy"], default-features = false }
numext-fixed-uint = { version = "0.1", features = ["support_rand", "support_heapsize", "support_serde"] }
anyhow = "1.0.56"
thiserror = "1.0.30"
Expand All @@ -45,11 +46,11 @@ jsonrpc-http-server = "18.0"
jsonrpc-server-utils = "18.0"

[dev-dependencies]
ckb-launcher = "0.110.2"
ckb-shared = "0.110.2"
ckb-chain = "0.110.2"
ckb-tx-pool = "0.110.2"
ckb-store = "0.110.2"
ckb-launcher = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-shared = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-chain = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-tx-pool = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
ckb-store = { git = "https://github.com/eval-exec/ckb.git", branch = "exec/stop-services-when-controller-dropped" }
tempfile = "3.0"
rand = "0.6"
serde_json = "1.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use ckb_types::{
prelude::*,
utilities::{
compact_to_difficulty,
merkle_mountain_range::{MMRProof, VerifiableHeader},
merkle_mountain_range::{HeaderDigest as _, MMRProof, VerifiableHeader},
},
U256,
};
Expand Down
6 changes: 3 additions & 3 deletions src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ pub struct BlockFilterRpcImpl {
pub struct TransactionRpcImpl {
pub(crate) pending_txs: Arc<RwLock<PendingTxs>>,
pub(crate) swc: StorageWithChainData,
pub(crate) consensus: Consensus,
pub(crate) consensus: Arc<Consensus>,
}

pub struct ChainRpcImpl {
Expand Down Expand Up @@ -1171,7 +1171,7 @@ impl TransactionRpc for TransactionRpcImpl {
fn send_transaction(&self, tx: Transaction) -> Result<H256> {
let tx: packed::Transaction = tx.into();
let tx = tx.into_view();
let cycles = verify_tx(tx.clone(), &self.swc, &self.consensus)
let cycles = verify_tx(tx.clone(), &self.swc, Arc::clone(&self.consensus))
.map_err(|e| Error::invalid_params(format!("invalid transaction: {:?}", e)))?;
self.pending_txs
.write()
Expand Down Expand Up @@ -1325,7 +1325,7 @@ impl Service {
let transaction_rpc_impl = TransactionRpcImpl {
pending_txs,
swc,
consensus,
consensus: Arc::new(consensus),
};
let net_rpc_impl = NetRpcImpl {
network_controller,
Expand Down
22 changes: 21 additions & 1 deletion src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use std::{
sync::Arc,
};

use ckb_traits::{CellDataProvider, HeaderProvider};
use ckb_traits::{
CellDataProvider, ExtensionProvider, HeaderFields, HeaderFieldsProvider, HeaderProvider,
};
use ckb_types::{
bytes::Bytes,
core::{
Expand Down Expand Up @@ -1136,6 +1138,18 @@ impl HeaderProvider for StorageWithChainData {
}
}

impl HeaderFieldsProvider for StorageWithChainData {
fn get_header_fields(&self, hash: &Byte32) -> Option<HeaderFields> {
self.get_header(hash).map(|header| HeaderFields {
hash: header.hash(),
number: header.number(),
epoch: header.epoch(),
timestamp: header.timestamp(),
parent_hash: header.parent_hash(),
})
}
}

impl CellDataProvider for StorageWithChainData {
fn get_cell_data(&self, out_point: &OutPoint) -> Option<Bytes> {
self.storage.get_cell_data(out_point)
Expand All @@ -1152,6 +1166,12 @@ impl CellProvider for StorageWithChainData {
}
}

impl ExtensionProvider for StorageWithChainData {
fn get_block_extension(&self, _hash: &Byte32) -> Option<packed::Bytes> {
todo!("New feature in CKB2023, introduced from \"RFC 0050: VM Syscalls 3\"")
}
}

pub struct Batch {
db: Arc<DB>,
wb: WriteBatch,
Expand Down
23 changes: 15 additions & 8 deletions src/subcmds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ use std::sync::{Arc, RwLock};
use ckb_async_runtime::new_global_runtime;
use ckb_chain_spec::ChainSpec;
use ckb_network::{
CKBProtocol, CKBProtocolHandler, DefaultExitHandler, ExitHandler, Flags, NetworkService,
NetworkState, SupportProtocols,
tokio, CKBProtocol, CKBProtocolHandler, Flags, NetworkService, NetworkState, SupportProtocols,
};
use ckb_resource::Resource;
use ckb_stop_handler::{broadcast_exit_signals, wait_all_ckb_services_exit};
use log::debug;

use crate::{
config::RunConfig,
Expand Down Expand Up @@ -97,8 +98,7 @@ impl RunConfig {
),
];

let (handle, _stop_handler) = new_global_runtime();
let exit_handler = DefaultExitHandler::default();
let (mut handle, mut handle_stop_rx, _stop_handler) = new_global_runtime();

let network_controller = NetworkService::new(
Arc::clone(&network_state),
Expand All @@ -109,7 +109,6 @@ impl RunConfig {
clap::crate_version!().to_owned(),
Flags::DISCOVERY,
),
exit_handler.clone(),
)
.start(&handle)
.map_err(|err| {
Expand All @@ -120,16 +119,24 @@ impl RunConfig {
let service = Service::new(&self.run_env.rpc.listen_address);
let rpc_server = service.start(network_controller, storage, peers, pending_txs, consensus);

let exit_handler_clone = exit_handler.clone();
ctrlc::set_handler(move || {
exit_handler_clone.notify_exit();
broadcast_exit_signals();
})
.map_err(|err| {
let errmsg = format!("failed to set Ctrl-C handler since {}", err);
Error::runtime(errmsg)
})?;
exit_handler.wait_for_exit();

wait_all_ckb_services_exit();

handle.drop_guard();
rpc_server.close();

tokio::task::block_in_place(|| {
debug!("Waiting all tokio tasks finished ...");
handle_stop_rx.blocking_recv();
});

Ok(())
}
}
2 changes: 1 addition & 1 deletion src/tests/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -935,7 +935,7 @@ fn rpc() {
let rpc = TransactionRpcImpl {
pending_txs: Arc::new(RwLock::new(PendingTxs::new(10))),
swc,
consensus: Consensus::default(),
consensus: Arc::new(Consensus::default()),
};
let fetched_txs: Vec<H256> = [h256!("0xbb11"), h256!("0xbb77"), h256!("0xbb88")]
.into_iter()
Expand Down
11 changes: 3 additions & 8 deletions src/tests/specs/dummy_pow.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,20 +90,15 @@ 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 = 14400
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

[params.hardfork]
rfc_0028 = 0
rfc_0029 = 0
rfc_0030 = 0
rfc_0031 = 0
rfc_0032 = 0
rfc_0036 = 0
rfc_0038 = 0
# TODO Enable CKB2023 later.
ckb2023 = 4294967296 # 2^32

[pow]
func = "Dummy"
3 changes: 1 addition & 2 deletions src/tests/utils/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use ckb_chain::chain::{ChainController, ChainService};
use ckb_chain_spec::{consensus::Consensus, ChainSpec};
use ckb_jsonrpc_types::JsonBytes;
use ckb_launcher::SharedBuilder;
use ckb_network::{DefaultExitHandler, Flags, NetworkController, NetworkService, NetworkState};
use ckb_network::{Flags, NetworkController, NetworkService, NetworkState};
use ckb_resource::Resource;
use ckb_shared::Shared;
use ckb_types::{core, prelude::*};
Expand Down Expand Up @@ -145,7 +145,6 @@ fn dummy_network(shared: &Shared) -> NetworkController {
"test".to_string(),
Flags::all(),
),
DefaultExitHandler::default(),
)
.start(shared.async_handle())
.expect("Start network service failed")
Expand Down
4 changes: 4 additions & 0 deletions src/tests/utils/network_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,4 +223,8 @@ impl CKBProtocolContext for MockProtocolContext {
fn protocol_id(&self) -> ProtocolId {
self.protocol.protocol_id()
}

fn ckb2023(&self) -> bool {
unimplemented!();
}
}
14 changes: 8 additions & 6 deletions src/tests/verify.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::sync::Arc;

use ckb_jsonrpc_types::{Block, Script, Transaction};
use ckb_types::packed;
use ckb_types::{packed, prelude::IntoTransactionView as _};

use crate::{
storage::{ScriptStatus, ScriptType, StorageWithChainData},
Expand All @@ -11,7 +13,7 @@ use crate::{
fn verify_valid_transaction() {
let chain = MockChain::new_with_default_pow("verify_valid_transaction");
let storage = chain.client_storage();
let consensus = chain.consensus();
let consensus = Arc::new(chain.consensus().clone());

// https://pudge.explorer.nervos.org/address/ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq0l2z2v9305wm7rs5gqrpsf507ey8wj3tggtl4sj
let script: packed::Script = serde_json::from_str::<Script>(r#"{"code_hash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8","hash_type": "type","args": "0xff5094c2c5f476fc38510018609a3fd921dd28ad"}"#).unwrap().into();
Expand All @@ -30,25 +32,25 @@ fn verify_valid_transaction() {
let transaction: packed::Transaction = serde_json::from_str::<Transaction>(r#"{"cell_deps":[{"dep_type":"dep_group","out_point":{"index":"0x0","tx_hash":"0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37"}}],"header_deps":[],"inputs":[{"previous_output":{"index":"0x7","tx_hash":"0x8f8c79eb6671709633fe6a46de93c0fedc9c1b8a6527a18d3983879542635c9f"},"since":"0x0"}],"outputs":[{"capacity":"0x470de4df820000","lock":{"args":"0xff5094c2c5f476fc38510018609a3fd921dd28ad","code_hash":"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8","hash_type":"type"},"type":null},{"capacity":"0xb61134e5a35e800","lock":{"args":"0x64257f00b6b63e987609fa9be2d0c86d351020fb","code_hash":"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8","hash_type":"type"},"type":null}],"outputs_data":["0x","0x"],"version":"0x0","witnesses":["0x5500000010000000550000005500000041000000af34b54bebf8c5971da6a880f2df5a186c3f8d0b5c9a1fe1a90c95b8a4fb89ef3bab1ccec13797dcb3fee80400f953227dd7741227e08032e3598e16ccdaa49c00"]}"#).unwrap().into();

let swc = StorageWithChainData::new(storage.to_owned(), chain.create_peers());
let result = verify_tx(transaction.into_view(), &swc, &consensus).unwrap();
let result = verify_tx(transaction.into_view(), &swc, consensus).unwrap();
assert_eq!(1682789, result);
}

#[test]
fn non_contextual_transaction_verifier() {
let chain = MockChain::new_with_default_pow("non_contextual_transaction_verifier");
let storage = chain.client_storage();
let consensus = chain.consensus();
let consensus = Arc::new(chain.consensus().clone());
let swc = StorageWithChainData::new(storage.to_owned(), chain.create_peers());

// duplicate cell deps base on a valid transaction
// https://pudge.explorer.nervos.org/transaction/0xf34f4eaac4a662927fb52d4cb608e603150b9e0678a0f5ed941e3cfd5b68fb30
let transaction: packed::Transaction = serde_json::from_str::<Transaction>(r#"{"cell_deps":[{"dep_type":"dep_group","out_point":{"index":"0x0","tx_hash":"0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37"}}, {"dep_type":"dep_group","out_point":{"index":"0x0","tx_hash":"0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37"}}],"header_deps":[],"inputs":[{"previous_output":{"index":"0x7","tx_hash":"0x8f8c79eb6671709633fe6a46de93c0fedc9c1b8a6527a18d3983879542635c9f"},"since":"0x0"}],"outputs":[{"capacity":"0x470de4df820000","lock":{"args":"0xff5094c2c5f476fc38510018609a3fd921dd28ad","code_hash":"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8","hash_type":"type"},"type":null},{"capacity":"0xb61134e5a35e800","lock":{"args":"0x64257f00b6b63e987609fa9be2d0c86d351020fb","code_hash":"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8","hash_type":"type"},"type":null}],"outputs_data":["0x","0x"],"version":"0x0","witnesses":["0x5500000010000000550000005500000041000000af34b54bebf8c5971da6a880f2df5a186c3f8d0b5c9a1fe1a90c95b8a4fb89ef3bab1ccec13797dcb3fee80400f953227dd7741227e08032e3598e16ccdaa49c00"]}"#).unwrap().into();
let error = verify_tx(transaction.into_view(), &swc, &consensus).unwrap_err();
let error = verify_tx(transaction.into_view(), &swc, Arc::clone(&consensus)).unwrap_err();
assert!(error.to_string().contains("DuplicateCellDeps"));

// insufficient cell capacity
let transaction: packed::Transaction = serde_json::from_str::<Transaction>(r#"{"cell_deps":[{"dep_type":"dep_group","out_point":{"index":"0x0","tx_hash":"0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37"}}],"header_deps":[],"inputs":[{"previous_output":{"index":"0x7","tx_hash":"0x8f8c79eb6671709633fe6a46de93c0fedc9c1b8a6527a18d3983879542635c9f"},"since":"0x0"}],"outputs":[{"capacity":"0x470de4df820000","lock":{"args":"0xff5094c2c5f476fc38510018609a3fd921dd28ad","code_hash":"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8","hash_type":"type"},"type":null},{"capacity":"0xb6113","lock":{"args":"0x64257f00b6b63e987609fa9be2d0c86d351020fb","code_hash":"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8","hash_type":"type"},"type":null}],"outputs_data":["0x","0x"],"version":"0x0","witnesses":["0x5500000010000000550000005500000041000000af34b54bebf8c5971da6a880f2df5a186c3f8d0b5c9a1fe1a90c95b8a4fb89ef3bab1ccec13797dcb3fee80400f953227dd7741227e08032e3598e16ccdaa49c00"]}"#).unwrap().into();
let error = verify_tx(transaction.into_view(), &swc, &consensus).unwrap_err();
let error = verify_tx(transaction.into_view(), &swc, consensus).unwrap_err();
assert!(error.to_string().contains("InsufficientCellCapacity"));
}
37 changes: 21 additions & 16 deletions src/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use ckb_types::{
Cycle, DepType, TransactionView,
},
packed::{OutPoint, OutPointVec},
prelude::Entity,
prelude::{Entity, IntoHeaderView},
};
use ckb_verification::{
CapacityVerifier, NonContextualTransactionVerifier, ScriptVerifier,
Expand All @@ -24,29 +24,34 @@ use crate::storage::StorageWithChainData;

/// Light client can only verify non-cellbase transaction,
/// can not reuse the `ContextualTransactionVerifier` in ckb_verification crate which is used to verify cellbase also.
pub struct ContextualTransactionVerifier<'a> {
pub(crate) time_relative: TimeRelativeTransactionVerifier<'a, StorageWithChainData>,
pub struct ContextualTransactionVerifier {
pub(crate) time_relative: TimeRelativeTransactionVerifier<StorageWithChainData>,
pub(crate) capacity: CapacityVerifier,
pub(crate) script: ScriptVerifier<StorageWithChainData>,
}

impl<'a> ContextualTransactionVerifier<'a> {
impl ContextualTransactionVerifier {
/// Creates a new ContextualTransactionVerifier
pub fn new(
rtx: &'a Arc<ResolvedTransaction>,
consensus: &'a Consensus,
swc: &'a StorageWithChainData,
tx_env: &'a TxVerifyEnv,
rtx: Arc<ResolvedTransaction>,
consensus: Arc<Consensus>,
swc: &StorageWithChainData,
tx_env: Arc<TxVerifyEnv>,
) -> Self {
ContextualTransactionVerifier {
time_relative: TimeRelativeTransactionVerifier::new(
Arc::clone(rtx),
consensus,
Arc::clone(&rtx),
Arc::clone(&consensus),
swc.clone(),
tx_env,
Arc::clone(&tx_env),
),
script: ScriptVerifier::new(Arc::clone(rtx), swc.clone()),
capacity: CapacityVerifier::new(Arc::clone(rtx), consensus.dao_type_hash()),
script: ScriptVerifier::new(
Arc::clone(&rtx),
swc.clone(),
Arc::clone(&consensus),
Arc::clone(&tx_env),
),
capacity: CapacityVerifier::new(Arc::clone(&rtx), consensus.dao_type_hash()),
}
}

Expand All @@ -60,14 +65,14 @@ impl<'a> ContextualTransactionVerifier<'a> {
pub fn verify_tx(
transaction: TransactionView,
swc: &StorageWithChainData,
consensus: &Consensus,
consensus: Arc<Consensus>,
) -> Result<Cycle, Error> {
NonContextualTransactionVerifier::new(&transaction, consensus).verify()?;
NonContextualTransactionVerifier::new(&transaction, &consensus).verify()?;

let rtx = resolve_tx(swc, transaction)?;
let (_, tip_header) = swc.storage().get_last_state();
let tx_env = TxVerifyEnv::new_submit(&tip_header.into_view());
ContextualTransactionVerifier::new(&Arc::new(rtx), consensus, swc, &tx_env)
ContextualTransactionVerifier::new(Arc::new(rtx), Arc::clone(&consensus), swc, Arc::new(tx_env))
.verify(consensus.max_block_cycles())
}

Expand Down

0 comments on commit c574b80

Please sign in to comment.