From 65c7bc5c25b3c2567946a101a750d316c2ff0104 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 20 Jun 2023 18:29:56 +0800 Subject: [PATCH 01/47] test: make sure `2_in_2_out_rtx` will suspend on first run --- script/src/verify/tests/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/src/verify/tests/utils.rs b/script/src/verify/tests/utils.rs index a92ed6cd11..d206de1f37 100644 --- a/script/src/verify/tests/utils.rs +++ b/script/src/verify/tests/utils.rs @@ -35,7 +35,7 @@ use tempfile::TempDir; use crate::verify::*; pub(crate) const ALWAYS_SUCCESS_SCRIPT_CYCLE: u64 = 537; -pub(crate) const CYCLE_BOUND: Cycle = 200_000; +pub(crate) const CYCLE_BOUND: Cycle = 250_000; pub(crate) const V2_CYCLE_BOUND: Cycle = 300_000; fn sha3_256>(s: T) -> [u8; 32] { From 3955cff41670152f6e0b9fc0f21f6ba78ec2f16f Mon Sep 17 00:00:00 2001 From: ian Date: Sun, 25 Jun 2023 21:43:05 +0800 Subject: [PATCH 02/47] chore: add `make docker-publish-rc` Push the latest version as the image tag only. Skip the `latest` image tag. This will be used to push the rc version, which should not become the latest image in Docker. --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index e264edde70..7d7adb98fb 100644 --- a/Makefile +++ b/Makefile @@ -168,6 +168,10 @@ docker-publish: docker tag nervos/ckb:$$(git describe) nervos/ckb:latest docker push nervos/ckb:latest +.PHONY: docker-publish-rc +docker-publish-rc: + docker push nervos/ckb:$$(git describe) + ##@ Code Quality .PHONY: fmt fmt: setup-ckb-test ## Check Rust source code format to keep to the same style. From 82b12d132250837c3b9f71ecd9a9c2caab3b89ec Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Thu, 29 Jun 2023 08:56:23 +0800 Subject: [PATCH 03/47] Fix bats tests failed for rc version like `ckb 0.111.0-rc6` --- util/app-config/src/tests/cli.bats | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/app-config/src/tests/cli.bats b/util/app-config/src/tests/cli.bats index 08368f7de6..6212a0025b 100644 --- a/util/app-config/src/tests/cli.bats +++ b/util/app-config/src/tests/cli.bats @@ -31,7 +31,7 @@ _full_help() { function short_version { #@test run _short assert_success - assert_output --regexp "^ckb [0-9.]+[-]?[a-z]*$" + assert_output --regexp "^ckb [0-9.]+[-]?[a-z0-9]*$" } #@test "ckb --version" { From 00ff6817daaa6c8bf28cc40862b3593ecbc4bbe0 Mon Sep 17 00:00:00 2001 From: driftluo Date: Tue, 4 Jul 2023 14:01:41 +0800 Subject: [PATCH 04/47] chore: add comment to header sync with empty --- sync/src/synchronizer/block_fetcher.rs | 12 ++++++++++-- sync/src/synchronizer/headers_process.rs | 5 +++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/sync/src/synchronizer/block_fetcher.rs b/sync/src/synchronizer/block_fetcher.rs index ec0688f238..14d882933e 100644 --- a/sync/src/synchronizer/block_fetcher.rs +++ b/sync/src/synchronizer/block_fetcher.rs @@ -97,8 +97,16 @@ impl<'a> BlockFetcher<'a> { } } - // This peer has nothing interesting. - let best_known = self.peer_best_known_header()?; + let best_known = match self.peer_best_known_header() { + Some(t) => t, + None => { + debug!( + "peer {} doesn't have best known header, ignore it", + self.peer + ); + return None; + } + }; if !best_known.is_better_than(self.active_chain.total_difficulty()) { // Advancing this peer's last_common_header is unnecessary for block-sync mechanism. // However, RPC `get_peers`, returns peers information which includes diff --git a/sync/src/synchronizer/headers_process.rs b/sync/src/synchronizer/headers_process.rs index ec0b732335..5a875f79ba 100644 --- a/sync/src/synchronizer/headers_process.rs +++ b/sync/src/synchronizer/headers_process.rs @@ -108,6 +108,11 @@ impl<'a> HeadersProcess<'a> { } if headers.is_empty() { + // Empty means that the other peer's tip may be consistent with our own best known, + // but empty cannot 100% confirm this, so it does not set the other peer's best header + // to the shared best known. + // This action means that if the newly connected node has not been sync with headers, + // it cannot be used as a synchronization node. debug!("HeadersProcess is_empty (synchronized)"); if let Some(mut state) = self.synchronizer.peers().state.get_mut(&self.peer) { self.synchronizer From 4bf0df1b41c71c030e572eacf6d1711b8d0f10c3 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Wed, 5 Jul 2023 17:40:27 +0800 Subject: [PATCH 05/47] Fix `hermit-abi` yanked --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ad60946eca..cad033854e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2466,9 +2466,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -2719,7 +2719,7 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi 0.3.2", "io-lifetimes", "rustix 0.37.7", "windows-sys 0.48.0", From 37e8cf3046a45ef6a89ca990c5652c883b030753 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Wed, 5 Jul 2023 11:25:23 +0800 Subject: [PATCH 06/47] Fix relayer::request_proposal_txs dedup proposals Signed-off-by: Eval EXEC --- Cargo.lock | 16 +++++++++++++--- Cargo.toml | 1 + sync/Cargo.toml | 1 + sync/src/relayer/mod.rs | 9 +++++---- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cad033854e..6004ceb3d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1188,7 +1188,7 @@ dependencies = [ "ckb-util", "ckb-verification", "ckb-verification-traits", - "itertools", + "itertools 0.10.5", "jsonrpc-core", "jsonrpc-derive", "jsonrpc-http-server", @@ -1342,6 +1342,7 @@ dependencies = [ "faux", "futures", "governor", + "itertools 0.11.0", "keyed_priority_queue", "lru", "once_cell", @@ -1700,7 +1701,7 @@ dependencies = [ "ciborium", "clap 3.2.23", "criterion-plot", - "itertools", + "itertools 0.10.5", "lazy_static", "num-traits", "oorandom", @@ -1721,7 +1722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", - "itertools", + "itertools 0.10.5", ] [[package]] @@ -2740,6 +2741,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index 6127ae0c8c..b280ac8d31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -93,6 +93,7 @@ members = [ [workspace.dependencies] tempfile = "3" +itertools = "0.11.0" [profile.release] overflow-checks = true diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 0bdb2ecf62..fa998193e7 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -39,6 +39,7 @@ bitflags = "1.0" dashmap = "4.0" keyed_priority_queue = "0.3" sled = "0.34.7" +itertools.workspace = true [dev-dependencies] ckb-test-chain-utils = { path = "../util/test-chain-utils", version = "= 0.111.0-rc8" } diff --git a/sync/src/relayer/mod.rs b/sync/src/relayer/mod.rs index 92a03a77ea..38a31a19af 100644 --- a/sync/src/relayer/mod.rs +++ b/sync/src/relayer/mod.rs @@ -39,6 +39,7 @@ use ckb_types::{ prelude::*, }; use ckb_util::Mutex; +use itertools::Itertools; use std::collections::{HashMap, HashSet}; use std::sync::Arc; use std::time::{Duration, Instant}; @@ -238,11 +239,11 @@ impl Relayer { nc: &dyn CKBProtocolContext, peer: PeerIndex, block_hash_and_number: BlockNumberAndHash, - mut proposals: Vec, + proposals: Vec, ) { - proposals.dedup(); let tx_pool = self.shared.shared().tx_pool_controller(); - let fresh_proposals = match tx_pool.fresh_proposals_filter(proposals) { + let fresh_proposals: Vec = match tx_pool.fresh_proposals_filter(proposals) + { Err(err) => { debug_target!( crate::LOG_TARGET_RELAY, @@ -251,7 +252,7 @@ impl Relayer { ); return; } - Ok(fresh_proposals) => fresh_proposals, + Ok(fresh_proposals) => fresh_proposals.into_iter().unique().collect(), }; let to_ask_proposals: Vec = self From ee0b414490eea6751e08fb82bf29296efb856ba5 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Wed, 5 Jul 2023 17:47:05 +0800 Subject: [PATCH 07/47] deps: let `ckb-rpc` use `workspace.itertools` --- Cargo.lock | 2 +- rpc/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6004ceb3d8..66155fd786 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1188,7 +1188,7 @@ dependencies = [ "ckb-util", "ckb-verification", "ckb-verification-traits", - "itertools 0.10.5", + "itertools 0.11.0", "jsonrpc-core", "jsonrpc-derive", "jsonrpc-http-server", diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index a9bf1b717e..c9a856d56a 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -43,7 +43,7 @@ ckb-tx-pool = { path = "../tx-pool", version = "= 0.111.0-rc8" } ckb-memory-tracker = { path = "../util/memory-tracker", version = "= 0.111.0-rc8" } ckb-pow = { path = "../pow", version = "= 0.111.0-rc8" } ckb-indexer = { path = "../util/indexer", version = "= 0.111.0-rc8" } -itertools = "0.10.5" +itertools.workspace = true tokio = "1" [dev-dependencies] From 316e09e6b487c525631be0098a4dd7628a9e13d2 Mon Sep 17 00:00:00 2001 From: mohanson Date: Thu, 6 Jul 2023 14:40:50 +0800 Subject: [PATCH 08/47] feat(script): add peak_memory syscall --- script/src/syscalls/mod.rs | 3 ++ script/src/syscalls/peak_memory.rs | 30 ++++++++++++++++ script/src/syscalls/spawn.rs | 3 ++ script/src/verify.rs | 10 ++++-- .../tests/ckb_latest/features_since_v2023.rs | 32 ++++++++++++++++++ script/testdata/Makefile | 4 ++- script/testdata/spawn_peak_memory | Bin 0 -> 4240 bytes script/testdata/spawn_peak_memory.c | 28 +++++++++++++++ 8 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 script/src/syscalls/peak_memory.rs create mode 100755 script/testdata/spawn_peak_memory create mode 100644 script/testdata/spawn_peak_memory.c diff --git a/script/src/syscalls/mod.rs b/script/src/syscalls/mod.rs index 5b5f84fc52..258c30b3ec 100644 --- a/script/src/syscalls/mod.rs +++ b/script/src/syscalls/mod.rs @@ -11,6 +11,7 @@ mod load_script; mod load_script_hash; mod load_tx; mod load_witness; +mod peak_memory; mod set_content; pub(crate) mod spawn; mod utils; @@ -35,6 +36,7 @@ pub use self::load_script::LoadScript; pub use self::load_script_hash::LoadScriptHash; pub use self::load_tx::LoadTx; pub use self::load_witness::LoadWitness; +pub use self::peak_memory::PeakMemory; pub use self::set_content::SetContent; pub use self::spawn::Spawn; pub use self::vm_version::VMVersion; @@ -77,6 +79,7 @@ pub const SPAWN: u64 = 2101; pub const GET_MEMORY_LIMIT: u64 = 2102; pub const SET_CONTENT: u64 = 2103; pub const LOAD_EXTENSION: u64 = 2104; +pub const PEAK_MEMORY: u64 = 2105; pub const DEBUG_PRINT_SYSCALL_NUMBER: u64 = 2177; #[cfg(test)] pub const DEBUG_PAUSE: u64 = 2178; diff --git a/script/src/syscalls/peak_memory.rs b/script/src/syscalls/peak_memory.rs new file mode 100644 index 0000000000..e86e9d034f --- /dev/null +++ b/script/src/syscalls/peak_memory.rs @@ -0,0 +1,30 @@ +use crate::syscalls::PEAK_MEMORY; +use ckb_vm::{ + registers::{A0, A7}, + Error as VMError, Register, SupportMachine, Syscalls, +}; + +#[derive(Debug, Default)] +pub struct PeakMemory { + value: u64, +} + +impl PeakMemory { + pub fn new(value: u64) -> Self { + Self { value } + } +} + +impl Syscalls for PeakMemory { + fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> { + Ok(()) + } + + fn ecall(&mut self, machine: &mut Mac) -> Result { + if machine.registers()[A7].to_u64() != PEAK_MEMORY { + return Ok(false); + } + machine.set_register(A0, Mac::REG::from_u64(self.value)); + Ok(true) + } +} diff --git a/script/src/syscalls/spawn.rs b/script/src/syscalls/spawn.rs index 78f2c9715d..3ff98bcec2 100644 --- a/script/src/syscalls/spawn.rs +++ b/script/src/syscalls/spawn.rs @@ -287,6 +287,9 @@ pub fn build_child_machine< *callee_peak_memory, Arc::clone(context), ))); + let machine_builder = machine_builder.syscall(Box::new( + syscalls_generator.build_peak_memory(*callee_peak_memory), + )); let mut machine_child = Machine::new(machine_builder.build()); set_vm_max_cycles(&mut machine_child, cycles_limit); Ok(machine_child) diff --git a/script/src/verify.rs b/script/src/verify.rs index ee1e524e32..0e62f8497c 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -6,8 +6,8 @@ use crate::{ syscalls::{ spawn::{build_child_machine, update_caller_machine}, CurrentCycles, Debugger, Exec, GetMemoryLimit, LoadCell, LoadCellData, LoadExtension, - LoadHeader, LoadInput, LoadScript, LoadScriptHash, LoadTx, LoadWitness, SetContent, Spawn, - VMVersion, + LoadHeader, LoadInput, LoadScript, LoadScriptHash, LoadTx, LoadWitness, PeakMemory, + SetContent, Spawn, VMVersion, }, type_id::TypeIdSystemScript, types::{ @@ -257,6 +257,11 @@ impl PeakMemory { + PeakMemory::new(peak_memory) + } + /// Generate same syscalls. The result does not contain spawn syscalls. pub fn generate_same_syscalls( &self, @@ -323,6 +328,7 @@ impl 1); } + +#[test] +fn check_spawn_peak_memory() { + let script_version = SCRIPT_VERSION; + + let (spawn_caller_cell, spawn_caller_data_hash) = + load_cell_from_path("testdata/spawn_peak_memory"); + + let spawn_caller_script = Script::new_builder() + .hash_type(script_version.data_hash_type().into()) + .code_hash(spawn_caller_data_hash) + .build(); + let output = CellOutputBuilder::default() + .capacity(capacity_bytes!(100).pack()) + .lock(spawn_caller_script) + .build(); + let input = CellInput::new(OutPoint::null(), 0); + + let transaction = TransactionBuilder::default().input(input).build(); + let dummy_cell = create_dummy_cell(output); + + let rtx = ResolvedTransaction { + transaction, + resolved_cell_deps: vec![spawn_caller_cell], + resolved_inputs: vec![dummy_cell], + resolved_dep_groups: vec![], + }; + let verifier = TransactionScriptsVerifierWithEnv::new(); + let result = verifier.verify_without_limit(script_version, &rtx); + assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +} diff --git a/script/testdata/Makefile b/script/testdata/Makefile index 0584b38224..f78b9a4fe2 100644 --- a/script/testdata/Makefile +++ b/script/testdata/Makefile @@ -68,7 +68,8 @@ ALL_BINS := jalr_zero \ spawn_caller_strcat_wrap \ spawn_caller_strcat \ spawn_caller_strcat_data_hash \ - spawn_recursive + spawn_recursive \ + spawn_peak_memory ALL_LIBS := is_even.lib \ add1.lib sub1.lib mul2.lib div2.lib @@ -154,3 +155,4 @@ spawn_caller_strcat_data_hash: spawn_caller_strcat_data_hash.c spawn_peak_memory_2m_to_32m: spawn_peak_memory_2m_to_32m.c spawn_peak_memory_4m_to_32m: spawn_peak_memory_4m_to_32m.c spawn_recursive: spawn_recursive.c +spawn_peak_memory: spawn_peak_memory.c diff --git a/script/testdata/spawn_peak_memory b/script/testdata/spawn_peak_memory new file mode 100755 index 0000000000000000000000000000000000000000..417eaca59965076e7f47f8639ee4e36979cce6c9 GIT binary patch literal 4240 zcmeHLeN0nV6hH6vwS|ZRD;qdbkqT_Yb$m^6D52t`%xpr2x?r+Nc~oFpg|_0yV(bT{ z7R8U$v@C83(##pR7&BwaT+}hbG+9ixKZr|AHawFRlXl*>76jj?3YD@! zCh${=?plvaS?1_cGRMs)54L~cxTOTyEf>hTT+BzuDjUD;zZIH($FH1#3%bG)58~yK zE2B5Y3rCwCnI3-=WXIVM!?*ECNy$;3sEWC4Oj`T^!yEK=tDLu68B`C>#C=C=P|4-m z%Fpdq-zor)ZQx6l(>AGUVg8IhW#e%UixY9hRPs+UmiCIZUiBDQ(^2ItzXq6+vGJcL ze!HoSPwjWyu}vz1XU9m-w(oe-bA=CQJB;eosZUOXI;+?kEhFYWiwuvG`Gc?$al31g zg(Hhk9qFy*Yqs=zT)GOCa&v`ZG(DK>9xf8vhCx-izDUJwuCQ%Ru5xm#IJ<9XboC5h z(~GO-+NM%AR}dy)2`7-vHAgT9t2Whi*0A+*T!)RtnJ%HRhxHtsg6^T41D+hWKpxt^+(Nol_@UZ}1Z>{wrsFeZmD*~WK^~(`a{Tw2yUxtY4XAx2T z3?ix@5K(d7lasL?uM_&(JYG37Te5v^l>v`81H>FH_F-%KUtVi>;_}ml-l4{xM;`~? zZG3xNcEc9h@~9;!Ti?2}vp@au*3gd8og?oBtNVrMXg2f2l@rb_)0K|ZZdleFni0x4 zaB|mzt5*pvi&#g1OA+h`Wk>S{5{8oUW-eAKY6dNv4tE}Aj|{%QX;0@KcCQ{+#F62K z_NwW1LbHogU*$mmz>yK1{gt;BWNX|odD@oY9%FqnWI5Kgt`rhn%#bVN?|Tml-THtd z`buNyuJ{;cZWPJm-)i|01w>4Ow2+)0<-6xLQzWii*P%-M+mRDrEt4}CAms~ZS zpii*-et9hJ5!s>3PW;uBFnn}}EMN;c*11+*=xNs-EfvZ}xaHl~>ZVfEU3cSTmz3G^ zl7bf=LT=q%P@|>p`Z2{_BE~k7C{ifi~yi9*O@IQi@q8( z7Q-P6XiWQS^cFp640XG9oAgElXzKUXTXyM9CjDX1>_&suMV?uNYO@(M!hWOCu#a>? zMySzSET;PE0~Q1Mka=by?_lz7CU+zvBeNDkQJ&xze7N8T^E`=1i^Nm^)9)maRyvOj z5EWrBMVrLaH1u9Z?`!0)7%q{v8XK3O()fJo9OO&)LFpPe*9FZ_@l|Yz4T~?8;!CA? z%A*}nn_>YrgpZ$|zj7(Q6z@#oLgT1Ui +#include + +#include "ckb_syscalls.h" + +int main(int argc, char *argv[]) { + int peak_memory = ckb_peak_memory(); + if (peak_memory != (argc + 1) * 8) { + return 1; + } + if (peak_memory < 56) { + int spawn_argc = argc + 1; + const char *spawn_argv[] = {"", "", "", "", "", "", "", ""}; + int8_t spawn_exit_code = 255; + spawn_args_t spgs = { + .memory_limit = 8, + .exit_code = &spawn_exit_code, + .content = NULL, + .content_length = NULL, + }; + uint64_t success = ckb_spawn(0, 3, 0, spawn_argc, spawn_argv, &spgs); + if (success != 0) { + return success; + } + } else { + return 0; + } +} From 7fb2f2f1d7e2f06b1254cea28ac5a29ade207ca7 Mon Sep 17 00:00:00 2001 From: mohanson Date: Thu, 6 Jul 2023 17:55:25 +0800 Subject: [PATCH 09/47] Rename peak_memory to current_memory --- .../syscalls/{peak_memory.rs => current_memory.rs} | 10 +++++----- script/src/syscalls/mod.rs | 6 +++--- script/src/syscalls/spawn.rs | 2 +- script/src/verify.rs | 12 ++++++------ .../verify/tests/ckb_latest/features_since_v2023.rs | 6 +++--- script/testdata/Makefile | 4 ++-- .../{spawn_peak_memory => spawn_current_memory} | Bin .../{spawn_peak_memory.c => spawn_current_memory.c} | 2 +- 8 files changed, 21 insertions(+), 21 deletions(-) rename script/src/syscalls/{peak_memory.rs => current_memory.rs} (71%) rename script/testdata/{spawn_peak_memory => spawn_current_memory} (100%) rename script/testdata/{spawn_peak_memory.c => spawn_current_memory.c} (93%) diff --git a/script/src/syscalls/peak_memory.rs b/script/src/syscalls/current_memory.rs similarity index 71% rename from script/src/syscalls/peak_memory.rs rename to script/src/syscalls/current_memory.rs index e86e9d034f..401d778191 100644 --- a/script/src/syscalls/peak_memory.rs +++ b/script/src/syscalls/current_memory.rs @@ -1,27 +1,27 @@ -use crate::syscalls::PEAK_MEMORY; +use crate::syscalls::CURRENT_MEMORY; use ckb_vm::{ registers::{A0, A7}, Error as VMError, Register, SupportMachine, Syscalls, }; #[derive(Debug, Default)] -pub struct PeakMemory { +pub struct CurrentMemory { value: u64, } -impl PeakMemory { +impl CurrentMemory { pub fn new(value: u64) -> Self { Self { value } } } -impl Syscalls for PeakMemory { +impl Syscalls for CurrentMemory { fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> { Ok(()) } fn ecall(&mut self, machine: &mut Mac) -> Result { - if machine.registers()[A7].to_u64() != PEAK_MEMORY { + if machine.registers()[A7].to_u64() != CURRENT_MEMORY { return Ok(false); } machine.set_register(A0, Mac::REG::from_u64(self.value)); diff --git a/script/src/syscalls/mod.rs b/script/src/syscalls/mod.rs index 258c30b3ec..17012469a5 100644 --- a/script/src/syscalls/mod.rs +++ b/script/src/syscalls/mod.rs @@ -1,4 +1,5 @@ mod current_cycles; +mod current_memory; mod debugger; mod exec; mod get_memory_limit; @@ -11,7 +12,6 @@ mod load_script; mod load_script_hash; mod load_tx; mod load_witness; -mod peak_memory; mod set_content; pub(crate) mod spawn; mod utils; @@ -24,6 +24,7 @@ mod pause; mod tests; pub use self::current_cycles::CurrentCycles; +pub use self::current_memory::CurrentMemory; pub use self::debugger::Debugger; pub use self::exec::Exec; pub use self::get_memory_limit::GetMemoryLimit; @@ -36,7 +37,6 @@ pub use self::load_script::LoadScript; pub use self::load_script_hash::LoadScriptHash; pub use self::load_tx::LoadTx; pub use self::load_witness::LoadWitness; -pub use self::peak_memory::PeakMemory; pub use self::set_content::SetContent; pub use self::spawn::Spawn; pub use self::vm_version::VMVersion; @@ -79,7 +79,7 @@ pub const SPAWN: u64 = 2101; pub const GET_MEMORY_LIMIT: u64 = 2102; pub const SET_CONTENT: u64 = 2103; pub const LOAD_EXTENSION: u64 = 2104; -pub const PEAK_MEMORY: u64 = 2105; +pub const CURRENT_MEMORY: u64 = 2105; pub const DEBUG_PRINT_SYSCALL_NUMBER: u64 = 2177; #[cfg(test)] pub const DEBUG_PAUSE: u64 = 2178; diff --git a/script/src/syscalls/spawn.rs b/script/src/syscalls/spawn.rs index 3ff98bcec2..15d48b6908 100644 --- a/script/src/syscalls/spawn.rs +++ b/script/src/syscalls/spawn.rs @@ -288,7 +288,7 @@ pub fn build_child_machine< Arc::clone(context), ))); let machine_builder = machine_builder.syscall(Box::new( - syscalls_generator.build_peak_memory(*callee_peak_memory), + syscalls_generator.build_current_memory(*callee_peak_memory), )); let mut machine_child = Machine::new(machine_builder.build()); set_vm_max_cycles(&mut machine_child, cycles_limit); diff --git a/script/src/verify.rs b/script/src/verify.rs index 0e62f8497c..0d1356aeda 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -5,8 +5,8 @@ use crate::{ error::{ScriptError, TransactionScriptError}, syscalls::{ spawn::{build_child_machine, update_caller_machine}, - CurrentCycles, Debugger, Exec, GetMemoryLimit, LoadCell, LoadCellData, LoadExtension, - LoadHeader, LoadInput, LoadScript, LoadScriptHash, LoadTx, LoadWitness, PeakMemory, + CurrentCycles, CurrentMemory, Debugger, Exec, GetMemoryLimit, LoadCell, LoadCellData, + LoadExtension, LoadHeader, LoadInput, LoadScript, LoadScriptHash, LoadTx, LoadWitness, SetContent, Spawn, VMVersion, }, type_id::TypeIdSystemScript, @@ -257,9 +257,9 @@ impl PeakMemory { - PeakMemory::new(peak_memory) + /// Build syscall: current_memory + pub fn build_current_memory(&self, current_memory: u64) -> CurrentMemory { + CurrentMemory::new(current_memory) } /// Generate same syscalls. The result does not contain spawn syscalls. @@ -328,7 +328,7 @@ impl Date: Mon, 3 Jul 2023 15:40:45 +0800 Subject: [PATCH 10/47] Fix bats test `ckb_run` should wait ckb process exit --- util/app-config/src/tests/ckb_run_replay.bats | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/util/app-config/src/tests/ckb_run_replay.bats b/util/app-config/src/tests/ckb_run_replay.bats index be7eba5a3b..6ca4dd5405 100644 --- a/util/app-config/src/tests/ckb_run_replay.bats +++ b/util/app-config/src/tests/ckb_run_replay.bats @@ -3,12 +3,18 @@ bats_load_library 'bats-assert' bats_load_library 'bats-support' _ckb_run() { - ckb run -C ${CKB_DIRNAME} 1>${TMP_DIR}/ckb_run.log 2>&1 & - echo $! >${TMP_DIR}/ckb_run.pid + ckb run -C ${CKB_DIRNAME} &> ${TMP_DIR}/ckb_run.log & + PID=$! sleep 5 - kill "$(<"${TMP_DIR}/ckb_run.pid")" + kill ${PID} + + while kill -0 ${PID}; do + echo "waiting for ckb to exit" + sleep 1 + done tail -n 50 ${TMP_DIR}/ckb_run.log } + _ckb_replay() { # from 1 to 2500 enough to trigger profile action CKB_LOG=err ckb replay -C ${CKB_DIRNAME} --tmp-target ${TMP_DIR} --profile 1 2500 From 5323d3cd8b1d80359233d925d8ca75608e2b730c Mon Sep 17 00:00:00 2001 From: mohanson Date: Wed, 5 Jul 2023 16:47:34 +0800 Subject: [PATCH 11/47] refactor(scripts): current_cycles returns the sum of cycles of all living machine --- script/src/syscalls/current_cycles.rs | 14 ++++-- script/src/syscalls/spawn.rs | 5 +++ .../syscalls/tests/vm_latest/syscalls_2.rs | 2 +- script/src/types.rs | 4 ++ script/src/verify.rs | 10 +++-- .../tests/ckb_latest/features_since_v2023.rs | 34 +++++++++++++++ script/testdata/Makefile | 6 ++- script/testdata/spawn_callee_current_cycles | Bin 0 -> 4744 bytes script/testdata/spawn_callee_current_cycles.c | 15 +++++++ script/testdata/spawn_caller_current_cycles | Bin 0 -> 7008 bytes script/testdata/spawn_caller_current_cycles.c | 41 ++++++++++++++++++ 11 files changed, 122 insertions(+), 9 deletions(-) create mode 100755 script/testdata/spawn_callee_current_cycles create mode 100644 script/testdata/spawn_callee_current_cycles.c create mode 100755 script/testdata/spawn_caller_current_cycles create mode 100644 script/testdata/spawn_caller_current_cycles.c diff --git a/script/src/syscalls/current_cycles.rs b/script/src/syscalls/current_cycles.rs index 15528ce111..dc87cd281c 100644 --- a/script/src/syscalls/current_cycles.rs +++ b/script/src/syscalls/current_cycles.rs @@ -5,11 +5,13 @@ use ckb_vm::{ }; #[derive(Debug, Default)] -pub struct CurrentCycles {} +pub struct CurrentCycles { + base: u64, +} impl CurrentCycles { - pub fn new() -> Self { - Self {} + pub fn new(base: u64) -> Self { + Self { base } } } @@ -22,7 +24,11 @@ impl Syscalls for CurrentCycles { if machine.registers()[A7].to_u64() != CURRENT_CYCLES { return Ok(false); } - machine.set_register(A0, Mac::REG::from_u64(machine.cycles())); + let cycles = self + .base + .checked_add(machine.cycles()) + .ok_or(VMError::CyclesOverflow)?; + machine.set_register(A0, Mac::REG::from_u64(cycles)); Ok(true) } } diff --git a/script/src/syscalls/spawn.rs b/script/src/syscalls/spawn.rs index 15d48b6908..7c96b2b682 100644 --- a/script/src/syscalls/spawn.rs +++ b/script/src/syscalls/spawn.rs @@ -155,6 +155,7 @@ where caller_exit_code_addr: exit_code_addr.to_u64(), caller_content_addr: content_addr.to_u64(), caller_content_length_addr: content_length_addr.to_u64(), + cycles_base: machine.cycles(), }; let mut machine_child = build_child_machine( &self.script_group, @@ -258,6 +259,7 @@ pub fn build_child_machine< callee_memory_limit, content, content_length, + cycles_base, .. } = spawn_data; @@ -275,6 +277,9 @@ pub fn build_child_machine< let machine_builder = machine_syscalls .into_iter() .fold(machine_builder, |builder, syscall| builder.syscall(syscall)); + let machine_builder = machine_builder.syscall(Box::new( + syscalls_generator.build_current_cycles(*cycles_base), + )); let machine_builder = machine_builder.syscall(Box::new( syscalls_generator.build_get_memory_limit(*callee_memory_limit), )); diff --git a/script/src/syscalls/tests/vm_latest/syscalls_2.rs b/script/src/syscalls/tests/vm_latest/syscalls_2.rs index 85c44d7fd3..b0ad504a91 100644 --- a/script/src/syscalls/tests/vm_latest/syscalls_2.rs +++ b/script/src/syscalls/tests/vm_latest/syscalls_2.rs @@ -53,7 +53,7 @@ fn test_current_cycles() { machine.set_cycles(cycles); - let result = CurrentCycles::new().ecall(&mut machine); + let result = CurrentCycles::new(0).ecall(&mut machine); assert!(result.unwrap()); assert_eq!(machine.registers()[A0], cycles); diff --git a/script/src/types.rs b/script/src/types.rs index 1fdab303c1..19434b7a9c 100644 --- a/script/src/types.rs +++ b/script/src/types.rs @@ -133,6 +133,7 @@ pub enum ResumePoint { caller_exit_code_addr: u64, caller_content_addr: u64, caller_content_length_addr: u64, + cycles_base: u64, }, } @@ -146,6 +147,7 @@ pub struct SpawnData { pub(crate) caller_exit_code_addr: u64, pub(crate) caller_content_addr: u64, pub(crate) caller_content_length_addr: u64, + pub(crate) cycles_base: u64, } impl TryFrom<&SpawnData> for ResumePoint { @@ -160,6 +162,7 @@ impl TryFrom<&SpawnData> for ResumePoint { caller_exit_code_addr, caller_content_addr, caller_content_length_addr, + cycles_base, } = value; Ok(ResumePoint::Spawn { callee_peak_memory: *callee_peak_memory, @@ -172,6 +175,7 @@ impl TryFrom<&SpawnData> for ResumePoint { caller_exit_code_addr: *caller_exit_code_addr, caller_content_addr: *caller_content_addr, caller_content_length_addr: *caller_content_length_addr, + cycles_base: *cycles_base, }) } } diff --git a/script/src/verify.rs b/script/src/verify.rs index 0d1356aeda..af1182af12 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -137,8 +137,8 @@ impl { /// Build syscall: current_cycles - pub fn build_current_cycles(&self) -> CurrentCycles { - CurrentCycles::new() + pub fn build_current_cycles(&self, base: u64) -> CurrentCycles { + CurrentCycles::new(base) } /// Build syscall: vm_version @@ -299,7 +299,6 @@ impl= ScriptVersion::V1 { syscalls.append(&mut vec![ Box::new(self.build_vm_version()), - Box::new(self.build_current_cycles()), Box::new(self.build_exec( Arc::clone(&script_group_input_indices), Arc::clone(&script_group_output_indices), @@ -323,6 +322,9 @@ impl>, ) -> Vec)>> { let mut syscalls = self.generate_same_syscalls(script_version, script_group); + if script_version >= ScriptVersion::V1 { + syscalls.push(Box::new(self.build_current_cycles(0))); + } if script_version >= ScriptVersion::V2 { syscalls.append(&mut vec![ Box::new(self.build_get_memory_limit(8)), @@ -1044,6 +1046,7 @@ impl { let spawn_data = SpawnData { callee_peak_memory: *callee_peak_memory, @@ -1053,6 +1056,7 @@ impl= ScriptVersion::V2); } + +#[test] +fn check_spawn_current_cycles() { + let script_version = SCRIPT_VERSION; + + let (spawn_caller_cell, spawn_caller_data_hash) = + load_cell_from_path("testdata/spawn_caller_current_cycles"); + let (spawn_callee_cell, _spawn_callee_data_hash) = + load_cell_from_path("testdata/spawn_callee_current_cycles"); + + let spawn_caller_script = Script::new_builder() + .hash_type(script_version.data_hash_type().into()) + .code_hash(spawn_caller_data_hash) + .build(); + let output = CellOutputBuilder::default() + .capacity(capacity_bytes!(100).pack()) + .lock(spawn_caller_script) + .build(); + let input = CellInput::new(OutPoint::null(), 0); + + let transaction = TransactionBuilder::default().input(input).build(); + let dummy_cell = create_dummy_cell(output); + + let rtx = ResolvedTransaction { + transaction, + resolved_cell_deps: vec![spawn_caller_cell, spawn_callee_cell], + resolved_inputs: vec![dummy_cell], + resolved_dep_groups: vec![], + }; + let verifier = TransactionScriptsVerifierWithEnv::new(); + let result = verifier.verify_without_limit(script_version, &rtx); + assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +} diff --git a/script/testdata/Makefile b/script/testdata/Makefile index 79df20d70a..e57b995194 100644 --- a/script/testdata/Makefile +++ b/script/testdata/Makefile @@ -69,7 +69,9 @@ ALL_BINS := jalr_zero \ spawn_caller_strcat \ spawn_caller_strcat_data_hash \ spawn_recursive \ - spawn_current_memory + spawn_current_memory \ + spawn_caller_current_cycles \ + spawn_callee_current_cycles ALL_LIBS := is_even.lib \ add1.lib sub1.lib mul2.lib div2.lib @@ -138,12 +140,14 @@ get_memory_limit: get_memory_limit.c set_content: set_content.c spawn_big_content_length: spawn_big_content_length.c spawn_big_memory_size: spawn_big_memory_size.c +spawn_callee_current_cycles: spawn_callee_current_cycles.c spawn_callee_exec_callee: spawn_callee_exec_callee.c spawn_callee_exec_caller: spawn_callee_exec_caller.c spawn_callee_get_memory_limit: spawn_callee_get_memory_limit.c spawn_callee_out_of_cycles: spawn_callee_out_of_cycles.c spawn_callee_set_content: spawn_callee_out_of_cycles.c spawn_callee_strcat: spawn_callee_strcat.c +spawn_caller_current_cycles: spawn_caller_current_cycles.c spawn_caller_exec: spawn_caller_exec.c spawn_caller_get_memory_limit: spawn_caller_get_memory_limit.c spawn_caller_out_of_cycles: spawn_caller_out_of_cycles.c diff --git a/script/testdata/spawn_callee_current_cycles b/script/testdata/spawn_callee_current_cycles new file mode 100755 index 0000000000000000000000000000000000000000..b726e5699fe594cf5ed4a793efc4c3e0ca1d810d GIT binary patch literal 4744 zcmeHLe{56L9{--(+j~2ybhFEwW}B21H`s%^(JAnN*>1KSsDl{s1(FBr?&>zR3T*)~ zS?rH>T{l2UNedyy{Rl+R5OtX~yu7#9w~UdzkoaDL)0pU3E1hwnGwU44=H5BG_kip3 z{pBCVWZ&eR&-s48pYQp8?>V>k_S`p2Pn#KpfC>XsKs2*tGf0khl{g?i18f8t?v=0% zBkX6f?do!gm;pO8bef5ve39?x9)LBx=%fhQqE1*GZfhm~+B`9iqD!*BFCmRH=6Fm+ zqgkTK)rh-XT zPaS$h|A-tJk=GrNbHnrTe>vXr*9a#ww@~j+H`#sa@Hgr4dxW|NNQ{~}HRLjp+ zJv1bahAMG(V+#JkF{ZVE%&EzDZoM5f<`j+khCS0<;zWwf?D>}o&phOa;LJ(f{1)xe z@6$bXOask*0y9E>^aEk#;Vo#yEU(*`v&QT(k?U}ml4=PXkA?!gQ_ZtZ zZlXA$4<-%5u_UN>Z!)M^*6De&pw7>(WWAC2#Hx8y!%!n;y9k>w2}|h2?Ehho)m1h0 zG%(F_tJl4?x-=jh7-T|+XCM~;+x5^PZhmXWrLZ!tOd9#PedMQ{F|WIi8#Huq5e6U} zZgigmEgywmE(%)QdgT~#>t!+G)+@t^TQ7qVw_b!1w_d=A8{UWMX;mofhik_|VL4jp znQO;(M?>Kf5OcJ7lkVal!|qsK;hUA=_<=#Z-YAEgC>k$L;5Fe5jPUJ<(r*#keoz{l zF1D)`r|MOzf0pY6=Mp$+ewd@tf zRY>SmEtA*k6|XUsr+hfGUqNC?O#IHx*?fNLju0PHoC!o`q)GL$ z>iEfInq0YB;g+ip&)gp`;HP}U4??UusEC=@Me}7-x8v9AZ{bRQ+&U0{DxE$b4e=VL zAXeON{7=Y#YreQ$IrjDd$w6|FEb?vF`stkA)nwLgb3B_**`oh!y&b&}koBYKkJ@x? zfA{zI|K-55ld?;m^!8hA3E8HO6+NTHv$g5xC-#i*P1KJHSy@bJ=fzI{_PO1@RYAya zP0tHESn#ubiB&6wwq=Yj%4!7fVOdMX_1yS_74zrnxP~!T)sdbf%R=w2o67#YZ zuY<272&d}iHVCZ&R{H@9)-Qb}S>=BXcYthd5T@Vslmt^uM21Dzg$%4AMTx+g3^3ANcZ)A5a`0*3Rj7(WwvZyER+YngMJ$TB}QX}jbXA5I}O*0zp zCs(p%@ABnx^X5O?0DaRH&|*#d$>*A&Sx{YrGh7~=9M(6^Xpl+y9eGCa8ts;uhwTHt zbCz;s`uB0|g^{v*EW&Bog?Wlk<>VPBRLcQ%k!Mk9E0@^Jx(%txC#E2Vy08;KLuEA) zs@%i&?8U;~70GT~5cCTo5~>!2`2`_<%|a2sefKyL-!~sg*eW5d%v~V*%L+vtm5};> z?EUm!O3jDeisFBWd6fM=&f6}aOTyL{I zW~q%ZLqqmptCjYd%5mGiZ0e>+H;M&^T%)I<1}B2o{n}!O|qc-99t^zxI}Vr2qf` literal 0 HcmV?d00001 diff --git a/script/testdata/spawn_callee_current_cycles.c b/script/testdata/spawn_callee_current_cycles.c new file mode 100644 index 0000000000..b84fb5353f --- /dev/null +++ b/script/testdata/spawn_callee_current_cycles.c @@ -0,0 +1,15 @@ +#include +#include +#include + +#include "ckb_syscalls.h" + +int main(int argc, char *argv[]) { + int caller_cycles = atoi(argv[0]); + // Callee's current cycles must >= caller's current cycles. + int callee_cycles = ckb_current_cycles(); + if (callee_cycles < caller_cycles) { + return 1; + } + return 0; +} diff --git a/script/testdata/spawn_caller_current_cycles b/script/testdata/spawn_caller_current_cycles new file mode 100755 index 0000000000000000000000000000000000000000..efa2fcec4dc2521451a7944a9c92c52bcb89966a GIT binary patch literal 7008 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 literal 0 HcmV?d00001 diff --git a/script/testdata/spawn_caller_current_cycles.c b/script/testdata/spawn_caller_current_cycles.c new file mode 100644 index 0000000000..f508cd3966 --- /dev/null +++ b/script/testdata/spawn_caller_current_cycles.c @@ -0,0 +1,41 @@ +#include +#include +#include + +#include "ckb_syscalls.h" + +int fib(int n) { + if (n < 2) { + return n; + } + return fib(n - 1) + fib(n - 2); +} + +int main() { + // Use invalid calculations to make the current cycles a larger value. + if (fib(20) != 6765) { + return 1; + } + + int cycles = ckb_current_cycles(); + char buffer[8]; + itoa(cycles, buffer, 10); + const char *argv[] = { &buffer[0] }; + int8_t spawn_exit_code = 255; + uint8_t spawn_content[80] = {}; + uint64_t spawn_content_length = 80; + spawn_args_t spgs = { + .memory_limit = 8, + .exit_code = &spawn_exit_code, + .content = &spawn_content[0], + .content_length = &spawn_content_length, + }; + int success = ckb_spawn(1, 3, 0, 1, argv, &spgs); + if (success != 0) { + return 1; + } + if (spawn_exit_code != 0) { + return 1; + } + return 0; +} From 3fd9de51b3c6e7a072d641e42ceb215b1cb67f39 Mon Sep 17 00:00:00 2001 From: mohanson Date: Thu, 6 Jul 2023 10:20:40 +0800 Subject: [PATCH 12/47] User more strict checking in spawn_callee_current_cycles --- script/testdata/spawn_callee_current_cycles | Bin 4744 -> 4760 bytes script/testdata/spawn_callee_current_cycles.c | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/script/testdata/spawn_callee_current_cycles b/script/testdata/spawn_callee_current_cycles index b726e5699fe594cf5ed4a793efc4c3e0ca1d810d..1c2dd40aa077b6b63675e0cae5d1acad0e851907 100755 GIT binary patch delta 456 zcmeBBouN8GLNJVxkpTo8z$631jES1^On3PvZ)6jjm|($a$qo^>oVZY2&<4t}5r^op znRrr1+KPE=;}@IUiHDn}E4997UMBRhZQ^Y_b!hz4Z5)`yB<99yA|s{L1!Z;(L&M<7ro* z{L$jca~M?_izgpq)OIcrW@jm3d!zQmxbwL~a_@5n;YdpdVHTE>Mi-fcRu)B;rs6ylqL4ZOH}-Q3 delta 440 zcmbQC+Mzl@LePzokpTo8z$61h$3#tern7vL53-3(Ot9e8WQT}rPFyH1r~~Ebh(q+~ zOgyP0ZOOc~@rzCF#KTR~m0I63Fa&fYItsEq0kU`|3ouGaEJ|QhHCAP1bYyI5m<%+a z^SEQGFsp0myI_aOPk)2=}IqeYX~Fsd>ZO}@ma?OZI( z&Qi?wM(v4l=W~bT-scR$k(Lg^EG)&1E;0$NEQ%~m(;vT4`R|%?G<|YAdkIK2NF_*B zayL*lP~~I?rpJs)n^l;-nOIANSz1aqm$05;G&FZJ@kIgIj{23W-CjaEu=hR?>sL_~gC}7SB52MM2K%N0qgTdsD0_Kxf2nbC6 zAz*+oX0oB6Ip+j9i2eza3kA(5X9x;R-XUngxM1=}L3_rtlMRLJ8D%FI3aJAChGA;r diff --git a/script/testdata/spawn_callee_current_cycles.c b/script/testdata/spawn_callee_current_cycles.c index b84fb5353f..c2005c9da4 100644 --- a/script/testdata/spawn_callee_current_cycles.c +++ b/script/testdata/spawn_callee_current_cycles.c @@ -6,9 +6,9 @@ int main(int argc, char *argv[]) { int caller_cycles = atoi(argv[0]); - // Callee's current cycles must >= caller's current cycles. + // Callee's current cycles must > caller's current cycles. int callee_cycles = ckb_current_cycles(); - if (callee_cycles < caller_cycles) { + if (callee_cycles < caller_cycles + 100000) { return 1; } return 0; From 8bea079b1439a673ff7ec5d6ea547ce4fa053a29 Mon Sep 17 00:00:00 2001 From: mohanson Date: Tue, 11 Jul 2023 15:16:48 +0800 Subject: [PATCH 13/47] chore(script): test case spawn_peak_memory_512k_to_32m --- .../tests/ckb_latest/features_since_v2023.rs | 32 ++++++++++++++++ script/testdata/Makefile | 6 ++- script/testdata/spawn_peak_memory_512k_to_32m | Bin 0 -> 7008 bytes .../testdata/spawn_peak_memory_512k_to_32m.c | 36 ++++++++++++++++++ 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100755 script/testdata/spawn_peak_memory_512k_to_32m create mode 100644 script/testdata/spawn_peak_memory_512k_to_32m.c diff --git a/script/src/verify/tests/ckb_latest/features_since_v2023.rs b/script/src/verify/tests/ckb_latest/features_since_v2023.rs index 05990ee14d..82d7e96964 100644 --- a/script/src/verify/tests/ckb_latest/features_since_v2023.rs +++ b/script/src/verify/tests/ckb_latest/features_since_v2023.rs @@ -22,6 +22,7 @@ use crate::verify::{tests::utils::*, *}; // check_spawn_big_content_length: fails when content_length > 256K. // check_peak_memory_4m_to_32m: spawn should success when peak memory <= 32M // check_peak_memory_2m_to_32m: spawn should success when peak memory <= 32M +// check_peak_memory_512k_to_32m: spawn should success when peak memory <= 32M // check_spawn_snapshot: A spawn B, then B gets suspended to snapshot and resume again. // check_spawn_state: Like check_spawn_snapshot but invoking verifier.resume_from_state instead. // check_spawn_current_memory: Use current_memory() to terminate infinite recursion. @@ -572,6 +573,37 @@ fn check_peak_memory_2m_to_32m() { assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); } +#[test] +fn check_peak_memory_512k_to_32m() { + let script_version = SCRIPT_VERSION; + + let (spawn_caller_cell, spawn_caller_data_hash) = + load_cell_from_path("testdata/spawn_peak_memory_512k_to_32m"); + + let spawn_caller_script = Script::new_builder() + .hash_type(script_version.data_hash_type().into()) + .code_hash(spawn_caller_data_hash) + .build(); + let output = CellOutputBuilder::default() + .capacity(capacity_bytes!(100).pack()) + .lock(spawn_caller_script) + .build(); + let input = CellInput::new(OutPoint::null(), 0); + + let transaction = TransactionBuilder::default().input(input).build(); + let dummy_cell = create_dummy_cell(output); + + let rtx = ResolvedTransaction { + transaction, + resolved_cell_deps: vec![spawn_caller_cell], + resolved_inputs: vec![dummy_cell], + resolved_dep_groups: vec![], + }; + let verifier = TransactionScriptsVerifierWithEnv::new(); + let result = verifier.verify_without_limit(script_version, &rtx); + assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +} + #[test] fn check_spawn_snapshot() { let script_version = SCRIPT_VERSION; diff --git a/script/testdata/Makefile b/script/testdata/Makefile index e57b995194..1550a931de 100644 --- a/script/testdata/Makefile +++ b/script/testdata/Makefile @@ -71,7 +71,10 @@ ALL_BINS := jalr_zero \ spawn_recursive \ spawn_current_memory \ spawn_caller_current_cycles \ - spawn_callee_current_cycles + spawn_callee_current_cycles \ + spawn_peak_memory_512k_to_32m \ + spawn_peak_memory_2m_to_32m \ + spawn_peak_memory_4m_to_32m ALL_LIBS := is_even.lib \ add1.lib sub1.lib mul2.lib div2.lib @@ -156,6 +159,7 @@ spawn_caller_set_content: spawn_caller_set_content.c spawn_caller_strcat_wrap: spawn_caller_strcat_wrap.c spawn_caller_strcat: spawn_caller_strcat.c spawn_caller_strcat_data_hash: spawn_caller_strcat_data_hash.c +spawn_peak_memory_512k_to_32m: spawn_peak_memory_512k_to_32m.c spawn_peak_memory_2m_to_32m: spawn_peak_memory_2m_to_32m.c spawn_peak_memory_4m_to_32m: spawn_peak_memory_4m_to_32m.c spawn_recursive: spawn_recursive.c diff --git a/script/testdata/spawn_peak_memory_512k_to_32m b/script/testdata/spawn_peak_memory_512k_to_32m new file mode 100755 index 0000000000000000000000000000000000000000..118c5ab1d3667660fd139ae7df1657e77c51cb44 GIT binary patch literal 7008 zcmeHMeN0nX7C-m3?}LF6n4&NXu9XU?JJSJS{1``;f^F5ELHEN^C)u&(Q7NNUfvRXi zZ2NdE_%X)RfD?BTh3Jk>V%#Ncjb@i+31YG_aX(ylGs!H_j_qWL#aP4-Dtj;QJwKY6 zzvi#a_9XZH?z!i8?m6$g+xOCY4;tSyQ3!z|6x;`*waH@@vcZxgb%?D3mV*jk(;yWi z>{jEkv)M8+0X8J)N+g2xOSTs+0B%k)DhL^pPFM`-$~t7oelj+*67Q0X3eS+~Hs%jA zp~bCHaJ{GMb;sUy93Sv>=8I7Per`j2Q#X4LM05E=KgRMY?^svFGwccd%9?Vc9CKW= z{OoQO|M=H{jCU-i+5)S`MaJP(E!QP3GSLN5&}NDD{0K50H6oK}%Hi^I{B4_sCY(?@ zjHjal>x5vw2P1!@jV*nCoL~Ep!KR^&_Ss)}T%DN!ez&_`Bf2LvUi2vC6Spx6!V8^z}ihclP}#ST;oAj|^pe1CS{?elRvWV93lL7KYptOz3!&%3Qts9FQ^xCrAoX81+)fUvUhL#)FrkIRs`$mBLMAspkaE(WT`-|s_Rh4Q)l&LaJ`$$RoB7lSfC{=ut&6%W`J!|W z!AtIqYO#-R7@++7CZRw0`w{j}FGA9uL=v*#Ww?+7*wJp3$x zGMTabNMQ(9n604rZ*HfFX5RZC&0xRSrr~m$RYM$@1d;1uBOna1aOQA)Qp4S(PO&WT zh}CG=OBCN8e#M_P{-bynT03}G!-9%G63#eZb>37Ob5dukbA4%W>@d-Y;JC)1cf5Hbx zxl_K*so=HSQ}Ina^OWP&DNxFR0bS$sX1$U&syx+7kv!KZoSsic{$n4fAbH6`FBF_(>pPeeScN(L^ww7T*J9&&A!Q3gL&+IVJHXstJ=AK)0=@@ z)%{1ok(!4%lgF$2f-gENjsvZ`E%RW$DX3>dV!jPHT-|)`g zb<92L2O(3Wa%}0ivSRtsFr)Wf^t#tv-8V>SW+9cx>ewTTO_`i4@3Azysu#zCt4 z*n_9Rg9B3+PwHG8@M@0g@zSW$s~TWHSi?fgQXT$1>RfZsRrY!X&Bo^h2Zo;NMI){n zS>wn^dcSP=*|_S8JGSnjH>6r|XkOQF;Z$|(gRu`IABAd$`IHoD@!^Yy#dYy5!h&|l zZH-Oy>(wBtdqNB5^WIcS2&lEZXP>I2Y$Pj~Q#O6h!qkpBEBANprw)vMT)Dk#JGH}# z;|N9VaMBWA#<%*^x=U)Xekl~Clw9pN1gbaMVd9v(s69$`sxV7fc4!`-C%)vk)@_>b>HKRS(#P+YR4 zwCwGr%a*UO*6_8qZFTngkGJn|?A*1xp|Q!iXYan|{RapSw2CYwqA1U?E#qZTKNES} zFeB(&L?Tqq2=y&O?AnWV|M$Qj5*AB|A4q z!pkx$_WyO1cM)J#>5VVSUUS?T`-;Z98%ar4AX$NA1(Fp=R^a8&dPlpk zZi&tIwymtRxVU8bB5lbM{StjKNG5aj#%Cjj^*DHAeG|VI@BQGeI)iT9yR@u+$?oE< z4sx-Q3r{Ww9F9FZN=T>1DnX3|yaY`c0Q61vCTFA5S_68gt=S3s#$B~mrxo-z`_^rZ zR)-Dr^*igGTdj?a*8QO0h83kR@tP#4X=(yJzsupU?Ie?s4E0v0v$4KrkJCmrNxrv` zZ!q~b&+PeQjLc{RCE1}EWF2qhz9e{Cea1r>-^@y1`ptL`oX8^O!!M~IA3Mkz!0Wh2 zD0qupl4s`)l1k1#UX(;#hmEsvQ~WvEpOeoolw%BK4kf;VZ(&3F3;sE>e~#>^@V?7` zB{sa6zq08#Q5*y zaT2jOfv5PtnJ_M8C;1T52e{$byAx>7&Z{;g7!-eHnCMFG${4{3Ie+_$gSemQ|6g9z B{SN>D literal 0 HcmV?d00001 diff --git a/script/testdata/spawn_peak_memory_512k_to_32m.c b/script/testdata/spawn_peak_memory_512k_to_32m.c new file mode 100644 index 0000000000..21680926ce --- /dev/null +++ b/script/testdata/spawn_peak_memory_512k_to_32m.c @@ -0,0 +1,36 @@ +#include +#include +#include + +#include "ckb_syscalls.h" + +int main(int argc, char *argv[]) { + int8_t spawn_exit_code = 255; + spawn_args_t spgs = { + .memory_limit = 1, + .exit_code = &spawn_exit_code, + .content = NULL, + .content_length = NULL, + }; + int8_t can_i_spawn = 0; + if (argc == 0) { + can_i_spawn = 1; + } + uint64_t depth = (uint64_t)atoi(argv[0]); + if (depth < 56) { + can_i_spawn = 1; + } + if (can_i_spawn) { + char buffer[20]; + itoa(depth + 1, buffer, 10); + const char *argv[] = {buffer}; + uint64_t success = ckb_spawn(0, 3, 0, 1, argv, &spgs); + if (success != 0) { + return success; + } + if (spawn_exit_code != 0) { + return 1; + } + } + return 0; +} From 9cf92da60a7db567298e2f329354b354cc13cfc0 Mon Sep 17 00:00:00 2001 From: mohanson Date: Tue, 11 Jul 2023 17:48:25 +0800 Subject: [PATCH 14/47] Update ckb to v0.24.2 --- Cargo.lock | 8 ++++---- script/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 66155fd786..6e02264f93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1523,9 +1523,9 @@ dependencies = [ [[package]] name = "ckb-vm" -version = "0.24.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77a1ce8d1ed8b18041d194ffe0d647c3a707af9347f49b5f543317c73943634" +checksum = "cb89eb30f9e82e63c637a0824e25b12d99de9be9c36675ba6f79479094a8b42c" dependencies = [ "byteorder", "bytes 1.4.0", @@ -1541,9 +1541,9 @@ dependencies = [ [[package]] name = "ckb-vm-definitions" -version = "0.24.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "328c7a6b5664483d5c02fae7b0ada0c407660e7064b2f1505ee6f5d07a4dbf2b" +checksum = "9d51f3b5550ebe2a37a6921127273afc00257b11f39517664dd0b35455d7e396" [[package]] name = "clang-sys" diff --git a/script/Cargo.toml b/script/Cargo.toml index b16fb6ed8d..f583b88923 100644 --- a/script/Cargo.toml +++ b/script/Cargo.toml @@ -22,7 +22,7 @@ ckb-traits = { path = "../traits", version = "= 0.111.0-rc8" } byteorder = "1.3.1" ckb-types = { path = "../util/types", version = "= 0.111.0-rc8" } ckb-hash = { path = "../util/hash", version = "= 0.111.0-rc8" } -ckb-vm = { version = "=0.24.0", default-features = false } +ckb-vm = { version = "=0.24.2", default-features = false } faster-hex = "0.6" ckb-logger = { path = "../util/logger", version = "= 0.111.0-rc8", optional = true } serde = { version = "1.0", features = ["derive"] } From 2dc251624a7da1b79a4ce0ac9d0e36ca267c263e Mon Sep 17 00:00:00 2001 From: mohanson Date: Mon, 17 Jul 2023 10:52:27 +0800 Subject: [PATCH 15/47] deps(script): update ckb-vm to v0.24.3 --- Cargo.lock | 8 ++++---- script/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6e02264f93..cdf443d006 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1523,9 +1523,9 @@ dependencies = [ [[package]] name = "ckb-vm" -version = "0.24.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb89eb30f9e82e63c637a0824e25b12d99de9be9c36675ba6f79479094a8b42c" +checksum = "1f5747a877a71ff164fa0f17daf6e9abca036c2381b8576679fb3ac07ae77bbc" dependencies = [ "byteorder", "bytes 1.4.0", @@ -1541,9 +1541,9 @@ dependencies = [ [[package]] name = "ckb-vm-definitions" -version = "0.24.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d51f3b5550ebe2a37a6921127273afc00257b11f39517664dd0b35455d7e396" +checksum = "83869c9d322de1ddbfde5b54b7376f9a1ac32273c50e21cdd5e8a1bd1a1cf632" [[package]] name = "clang-sys" diff --git a/script/Cargo.toml b/script/Cargo.toml index f583b88923..708bd6fc58 100644 --- a/script/Cargo.toml +++ b/script/Cargo.toml @@ -22,7 +22,7 @@ ckb-traits = { path = "../traits", version = "= 0.111.0-rc8" } byteorder = "1.3.1" ckb-types = { path = "../util/types", version = "= 0.111.0-rc8" } ckb-hash = { path = "../util/hash", version = "= 0.111.0-rc8" } -ckb-vm = { version = "=0.24.2", default-features = false } +ckb-vm = { version = "=0.24.3", default-features = false } faster-hex = "0.6" ckb-logger = { path = "../util/logger", version = "= 0.111.0-rc8", optional = true } serde = { version = "1.0", features = ["derive"] } From 920baf76ca1cbb9f9c04a74ae377de977db4f16e Mon Sep 17 00:00:00 2001 From: mohanson Date: Mon, 17 Jul 2023 11:41:09 +0800 Subject: [PATCH 16/47] test(script): add check_spawn_times_bug test case --- .../tests/ckb_latest/features_since_v2023.rs | 97 ++++++++++++++++++ script/testdata/spawn_times | Bin 0 -> 15288 bytes script/testdata/spawn_times.md | 81 +++++++++++++++ 3 files changed, 178 insertions(+) create mode 100755 script/testdata/spawn_times create mode 100644 script/testdata/spawn_times.md diff --git a/script/src/verify/tests/ckb_latest/features_since_v2023.rs b/script/src/verify/tests/ckb_latest/features_since_v2023.rs index 82d7e96964..09ed1b2ce4 100644 --- a/script/src/verify/tests/ckb_latest/features_since_v2023.rs +++ b/script/src/verify/tests/ckb_latest/features_since_v2023.rs @@ -27,6 +27,8 @@ use crate::verify::{tests::utils::*, *}; // check_spawn_state: Like check_spawn_snapshot but invoking verifier.resume_from_state instead. // check_spawn_current_memory: Use current_memory() to terminate infinite recursion. // check_spawn_current_cycles: callee's current_cycles should inherit caller's current_cycles. +// check_spawn_times_bug_1: BUG: execution results may be inconsistent +// check_spawn_times_bug_2: BUG: execution results may be inconsistent #[test] fn check_vm_version() { @@ -777,3 +779,98 @@ fn check_spawn_current_cycles() { let result = verifier.verify_without_limit(script_version, &rtx); assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); } + +#[test] +fn check_spawn_times_bug_1() { + let script_version = SCRIPT_VERSION; + + let (spawn_caller_cell, spawn_caller_data_hash) = load_cell_from_path("testdata/spawn_times"); + + let spawn_caller_script = Script::new_builder() + .hash_type(script_version.data_hash_type().into()) + .code_hash(spawn_caller_data_hash) + .build(); + let output = CellOutputBuilder::default() + .capacity(capacity_bytes!(100).pack()) + .lock(spawn_caller_script) + .build(); + let input = CellInput::new(OutPoint::null(), 0); + + let transaction = TransactionBuilder::default().input(input).build(); + let dummy_cell = create_dummy_cell(output); + + let rtx = ResolvedTransaction { + transaction, + resolved_cell_deps: vec![spawn_caller_cell], + resolved_inputs: vec![dummy_cell], + resolved_dep_groups: vec![], + }; + let verifier = TransactionScriptsVerifierWithEnv::new(); + let result = verifier.verify_without_limit(script_version, &rtx); + assert_eq!(result.is_ok(), script_version >= ScriptVersion::V2); +} + +#[test] +fn check_spawn_times_bug_2() { + let script_version = SCRIPT_VERSION; + if script_version <= ScriptVersion::V1 { + return; + } + let (spawn_caller_cell, spawn_caller_data_hash) = load_cell_from_path("testdata/spawn_times"); + + let spawn_caller_script = Script::new_builder() + .hash_type(script_version.data_hash_type().into()) + .code_hash(spawn_caller_data_hash) + .build(); + let output = CellOutputBuilder::default() + .capacity(capacity_bytes!(100).pack()) + .lock(spawn_caller_script) + .build(); + let input = CellInput::new(OutPoint::null(), 0); + + let transaction = TransactionBuilder::default().input(input).build(); + let dummy_cell = create_dummy_cell(output); + + let rtx = ResolvedTransaction { + transaction, + resolved_cell_deps: vec![spawn_caller_cell], + resolved_inputs: vec![dummy_cell], + resolved_dep_groups: vec![], + }; + let verifier = TransactionScriptsVerifierWithEnv::new(); + let result = verifier.verify_without_pause(script_version, &rtx, Cycle::MAX); + let cycles_once = result.unwrap(); + + let (cycles, _) = verifier + .verify_map(script_version, &rtx, |verifier| { + let max_cycles = Cycle::MAX; + let cycles; + let mut times = 0usize; + times += 1; + let mut init_state = match verifier.resumable_verify(max_cycles).unwrap() { + VerifyResult::Suspended(state) => Some(state), + VerifyResult::Completed(cycle) => { + cycles = cycle; + return Ok((cycles, times)); + } + }; + + loop { + times += 1; + let state = init_state.take().unwrap(); + match verifier.resume_from_state(state, max_cycles).unwrap() { + VerifyResult::Suspended(state) => { + init_state = Some(state); + } + VerifyResult::Completed(cycle) => { + cycles = cycle; + break; + } + } + } + + Ok::<(u64, usize), Error>((cycles, times)) + }) + .unwrap(); + assert_eq!(cycles, cycles_once); +} diff --git a/script/testdata/spawn_times b/script/testdata/spawn_times new file mode 100755 index 0000000000000000000000000000000000000000..c7dcd39e58e0206107a29fda1098222a07eacb1c GIT binary patch literal 15288 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 literal 0 HcmV?d00001 diff --git a/script/testdata/spawn_times.md b/script/testdata/spawn_times.md new file mode 100644 index 0000000000..351817947d --- /dev/null +++ b/script/testdata/spawn_times.md @@ -0,0 +1,81 @@ +This binary comes from: . Since I couldn't build a binary in C that would cause the same bug, I just added the binary to the project. + +```rs +#![no_std] +#![cfg_attr(not(test), no_main)] + +#[cfg(test)] +extern crate alloc; + +#[cfg(not(test))] +use ckb_std::default_alloc; +#[cfg(not(test))] +ckb_std::entry!(program_entry); +#[cfg(not(test))] +default_alloc!(); + +use core::result::Result; + +use alloc::{vec}; +use core::ffi::{CStr}; + +use ckb_std::{debug, syscalls}; +use ckb_std::ckb_constants::Source; +use ckb_std::env::argv; +use ckb_std::syscalls::{current_cycles, get_memory_limit, set_content, spawn}; + + +/// +/// test case : +/// invoke int ckb_spawn( uint64_t memory_limit, +/// size_t index, +/// size_t source, +/// size_t bounds, +/// int argc, char* argv[], +/// int8_t* exit_code, +/// uint8_t* content, +/// uint64_t* content_length); +/// +/// for { +/// spawn(xxx) +/// } +/// case1 : for { +/// spawn(xxx) +/// } +/// +/// result: +/// return ERROR : ExceededMaximumCycles +/// +pub fn program_entry() -> i8 { + // let argvs = argv(); + // debug!("argvs length:{:?}:{:?}",argvs.len(),argvs); + + if get_memory_limit() != 8 { + return 0; + } + let mut exit_code: i8 = 0; + let mut content: [u8; 10] = [1; 10]; + + let content_length: u64 = content.len() as u64; + let mut spawn_args = syscalls::SpawnArgs { + memory_limit: 8, + exit_code: &mut exit_code as *mut i8, + content: content.as_mut_ptr(), + content_length: &content_length as *const u64 as *mut u64, + }; + // let cstr1 = CStr::from_bytes_with_nul(b"arg0\0").unwrap(); + //argv is empty + let cstrs = vec![]; + + spawn_args.memory_limit = 1; + for i in 0..10000 { + debug!("current idx:{:?}",i); + let result = spawn(0, Source::CellDep, 0, cstrs.as_slice(), &spawn_args); + assert_eq!(exit_code, 0); + // debug!("result:{:?}",result); + let cycles = current_cycles(); + debug!("cycle:{:?}",cycles); + } + return 0; +} +``` From a632415301def4fc711a314c3de5840f345e0f83 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 20 Jun 2023 17:02:17 +0800 Subject: [PATCH 17/47] feat: add `register_thread` and `new_tokio_exit_rx` --- util/stop-handler/src/lib.rs | 151 ++----------------------- util/stop-handler/src/stop_register.rs | 74 ++++++++++++ 2 files changed, 82 insertions(+), 143 deletions(-) create mode 100644 util/stop-handler/src/stop_register.rs diff --git a/util/stop-handler/src/lib.rs b/util/stop-handler/src/lib.rs index d9ceddf268..fe80839dd3 100644 --- a/util/stop-handler/src/lib.rs +++ b/util/stop-handler/src/lib.rs @@ -1,147 +1,12 @@ //! TODO(doc): @keroro520 -use ckb_logger::error; -use parking_lot::Mutex; -use std::fmt::Debug; -use std::sync::mpsc; -use std::sync::{Arc, Weak}; -use std::thread::JoinHandle; -use tokio::sync::oneshot as tokio_oneshot; -use tokio::sync::watch as tokio_watch; -/// init flags -pub const WATCH_INIT: u8 = 0; -/// stop flags -pub const WATCH_STOP: u8 = 1; +pub use stop_register::{ + broadcast_exit_signals, new_crossbeam_exit_rx, new_tokio_exit_rx, register_thread, + wait_all_ckb_services_exit, +}; -/// TODO(doc): @keroro520 -#[derive(Debug)] -pub enum SignalSender { - /// TODO(doc): @keroro520 - Crossbeam(ckb_channel::Sender), - /// TODO(doc): @keroro520 - Std(mpsc::Sender), - /// TODO(doc): @keroro520 - Tokio(tokio_oneshot::Sender), - /// A single-producer, multi-consumer channel that only retains the last sent value. - Watch(tokio_watch::Sender), - /// Do nothing, for tests - Dummy, -} +pub use tokio_util::sync::CancellationToken; -impl SignalSender { - /// TODO(doc): @keroro520 - pub fn send(self, cmd: T) { - match self { - SignalSender::Crossbeam(tx) => { - if let Err(e) = tx.try_send(cmd) { - error!("handler signal send error {:?}", e); - }; - } - SignalSender::Std(tx) => { - if let Err(e) = tx.send(cmd) { - error!("handler signal send error {:?}", e); - }; - } - SignalSender::Tokio(tx) => { - if let Err(e) = tx.send(cmd) { - error!("handler signal send error {:?}", e); - }; - } - SignalSender::Watch(tx) => { - if let Err(e) = tx.send(WATCH_STOP) { - error!("handler signal send error {:?}", e); - }; - } - SignalSender::Dummy => {} - } - } -} - -#[derive(Debug)] -struct Handler { - signal: SignalSender, - thread: Option>, -} - -/// Weak is a version of Arc that holds a non-owning reference to the managed allocation. -/// Since a Weak reference does not count towards ownership, -/// it will not prevent the value stored in the allocation from being dropped, -/// and Weak itself makes no guarantees about the value still being present. -#[derive(Debug)] -enum Ref { - Arc(Arc), - Weak(Weak), -} - -impl Clone for Ref { - #[inline] - fn clone(&self) -> Ref { - match self { - Self::Arc(arc) => Self::Arc(Arc::clone(arc)), - Self::Weak(weak) => Self::Weak(Weak::clone(weak)), - } - } -} - -impl Ref { - fn downgrade(&self) -> Ref { - match self { - Self::Arc(arc) => Self::Weak(Arc::downgrade(arc)), - Self::Weak(weak) => Self::Weak(Weak::clone(weak)), - } - } -} - -/// TODO(doc): @keroro520 -//the outer Option take ownership for `Arc::try_unwrap` -//the inner Option take ownership for `JoinHandle` or `oneshot::Sender` -#[derive(Clone, Debug)] -pub struct StopHandler { - inner: Option>>>>, - name: String, -} - -impl StopHandler { - /// TODO(doc): @keroro520 - pub fn new( - signal: SignalSender, - thread: Option>, - name: String, - ) -> StopHandler { - let handler = Handler { signal, thread }; - StopHandler { - inner: Some(Ref::Arc(Arc::new(Mutex::new(Some(handler))))), - name, - } - } - - /// Creates a new Weak pointer. - pub fn downgrade_clone(&self) -> StopHandler { - StopHandler { - inner: self.inner.as_ref().map(|inner| inner.downgrade()), - name: self.name.clone(), - } - } - - /// TODO(doc): @keroro520 - pub fn try_send(&mut self, cmd: T) { - let inner = self - .inner - .take() - .expect("Stop signal can only be sent once"); - - if let Ref::Arc(inner) = inner { - if let Ok(lock) = Arc::try_unwrap(inner) { - ckb_logger::info!("StopHandler({}) send signal", self.name); - let handler = lock.lock().take().expect("Handler can only be taken once"); - let Handler { signal, thread } = handler; - signal.send(cmd); - if let Some(thread) = thread { - if let Err(e) = thread.join() { - error!("handler thread join error {:?}", e); - }; - } - }; - } - } -} +mod stop_register; +#[cfg(test)] +mod tests; diff --git a/util/stop-handler/src/stop_register.rs b/util/stop-handler/src/stop_register.rs new file mode 100644 index 0000000000..e329565ae8 --- /dev/null +++ b/util/stop-handler/src/stop_register.rs @@ -0,0 +1,74 @@ +use ckb_logger::{info, trace, warn}; +use ckb_util::Mutex; +use tokio_util::sync::CancellationToken; + +struct CkbServiceHandles { + thread_handles: Vec<(String, std::thread::JoinHandle<()>)>, +} + +/// Wait all ckb services exit +pub fn wait_all_ckb_services_exit() { + info!("waiting exit signal..."); + let exit_signal = new_crossbeam_exit_rx(); + let _ = exit_signal.recv(); + info!("received exit signal, broadcasting exit signal to all threads"); + let mut handles = CKB_HANDLES.lock(); + for (name, join_handle) in handles.thread_handles.drain(..) { + match join_handle.join() { + Ok(_) => { + info!("wait thread {} done", name); + } + Err(e) => { + warn!("wait thread {}: ERROR: {:?}", name, e) + } + } + } + info!("all ckb threads have been stopped"); +} + +static CKB_HANDLES: once_cell::sync::Lazy> = + once_cell::sync::Lazy::new(|| { + Mutex::new(CkbServiceHandles { + thread_handles: vec![], + }) + }); + +static TOKIO_EXIT: once_cell::sync::Lazy = + once_cell::sync::Lazy::new(CancellationToken::new); + +static CROSSBEAM_EXIT_SENDERS: once_cell::sync::Lazy>>> = + once_cell::sync::Lazy::new(|| Mutex::new(vec![])); + +/// Create a new CancellationToken for exit signal +pub fn new_tokio_exit_rx() -> CancellationToken { + TOKIO_EXIT.clone() +} + +/// Create a new crossbeam Receiver for exit signal +pub fn new_crossbeam_exit_rx() -> ckb_channel::Receiver<()> { + let (tx, rx) = ckb_channel::bounded(1); + CROSSBEAM_EXIT_SENDERS.lock().push(tx); + rx +} + +/// Broadcast exit signals to all threads and all tokio tasks +pub fn broadcast_exit_signals() { + TOKIO_EXIT.cancel(); + CROSSBEAM_EXIT_SENDERS.lock().iter().for_each(|tx| { + if let Err(e) = tx.try_send(()) { + println!("broadcast thread: ERROR: {:?}", e) + } else { + println!("send a crossbeam exit signal"); + } + }); +} + +/// Register a thread `JoinHandle` to `CKB_HANDLES` +pub fn register_thread(name: &str, thread_handle: std::thread::JoinHandle<()>) { + trace!("register thread {}", name); + CKB_HANDLES + .lock() + .thread_handles + .push((name.into(), thread_handle)); + trace!("register thread done {}", name); +} From a64c2ff640cd69e48a0fc429c183fc73850912eb Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 20 Jun 2023 17:02:38 +0800 Subject: [PATCH 18/47] test: add basic unit test for ckb shutdown --- util/stop-handler/src/tests.rs | 142 +++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 util/stop-handler/src/tests.rs diff --git a/util/stop-handler/src/tests.rs b/util/stop-handler/src/tests.rs new file mode 100644 index 0000000000..3141512bb7 --- /dev/null +++ b/util/stop-handler/src/tests.rs @@ -0,0 +1,142 @@ +use crate::{ + broadcast_exit_signals, new_crossbeam_exit_rx, new_tokio_exit_rx, register_thread, + wait_all_ckb_services_exit, +}; +use ckb_async_runtime::{new_global_runtime, Handle}; +use ckb_channel::select; +use rand::Rng; +use std::sync::atomic::{AtomicI64, Ordering}; +use std::sync::Arc; +use std::time::Duration; +use tokio_util::sync::CancellationToken; + +fn send_ctrlc_later(duration: Duration) { + std::thread::spawn(move || { + std::thread::sleep(duration); + // send SIGINT to myself + unsafe { + libc::raise(libc::SIGINT); + println!("[ $$ sent SIGINT to myself $$ ]"); + } + }); +} + +#[derive(Default)] +struct TestStopMemo { + spawned_threads_count: Arc, + stopped_threads_count: Arc, + + spawned_tokio_task_count: Arc, + stopped_tokio_task_count: Arc, +} + +impl TestStopMemo { + fn start_many_threads(&self) { + for i in 0..rand::thread_rng().gen_range(3..7) { + let join = std::thread::spawn({ + let stopped_threads_count = Arc::clone(&self.stopped_threads_count); + move || { + let ticker = ckb_channel::tick(Duration::from_millis(500)); + let deadline = ckb_channel::after(Duration::from_millis( + (rand::thread_rng().gen_range(1.0..5.0) * 1000.0) as u64, + )); + + let stop = new_crossbeam_exit_rx(); + + loop { + select! { + recv(ticker) -> _ => { + println!("thread {} received tick signal", i); + }, + recv(stop) -> _ => { + println!("thread {} received crossbeam exit signal", i); + stopped_threads_count.fetch_add(1, Ordering::SeqCst); + return; + }, + recv(deadline) -> _ =>{ + println!("thread {} finish its job", i); + stopped_threads_count.fetch_add(1, Ordering::SeqCst); + return + } + } + } + } + }); + + self.spawned_threads_count.fetch_add(1, Ordering::SeqCst); + register_thread(&format!("test thread {}", i), join); + } + } + + fn start_many_tokio_tasks(&self, handle: &Handle) { + for i in 0..rand::thread_rng().gen_range(3..7) { + let stop: CancellationToken = new_tokio_exit_rx(); + + handle.spawn({ + let spawned_tokio_task_count = Arc::clone(&self.spawned_tokio_task_count); + let stopped_tokio_task_count = Arc::clone(&self.stopped_tokio_task_count); + async move { + spawned_tokio_task_count.fetch_add(1, Ordering::SeqCst); + + let mut interval = tokio::time::interval(Duration::from_millis(500)); + + let duration = Duration::from_millis( + (rand::thread_rng().gen_range(1.0..5.0) * 1000.0) as u64, + ); + let deadline = tokio::time::sleep(duration); + tokio::pin!(deadline); + + loop { + tokio::select! { + _ = &mut deadline =>{ + println!("tokio task {} finish its job", i); + stopped_tokio_task_count.fetch_add(1, Ordering::SeqCst); + break; + } + _ = interval.tick()=> { + println!("tokio task {} received tick signal", i); + }, + _ = stop.cancelled() => { + println!("tokio task {} receive exit signal", i); + stopped_tokio_task_count.fetch_add(1, Ordering::SeqCst); + break + }, + else => break, + } + } + } + }); + } + } +} +#[test] +fn basic() { + let (mut handle, mut stop_recv, _runtime) = new_global_runtime(); + + ctrlc::set_handler(move || { + broadcast_exit_signals(); + }) + .expect("Error setting Ctrl-C handler"); + + send_ctrlc_later(Duration::from_secs(3)); + + let test_memo = TestStopMemo::default(); + + test_memo.start_many_threads(); + test_memo.start_many_tokio_tasks(&handle); + + handle.drop_guard(); + wait_all_ckb_services_exit(); + handle.block_on(async move { + stop_recv.recv().await; + }); + + assert_eq!( + test_memo.spawned_threads_count.load(Ordering::SeqCst), + test_memo.stopped_threads_count.load(Ordering::SeqCst), + ); + assert_eq!( + test_memo.spawned_tokio_task_count.load(Ordering::SeqCst), + test_memo.stopped_tokio_task_count.load(Ordering::SeqCst), + ); +} From 2d6409c42a0098fcd5def0950788bce257824c82 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 20 Jun 2023 17:04:09 +0800 Subject: [PATCH 19/47] wait all thread and tokio tasks exit before process exit --- Cargo.lock | 29 ++++++----- benches/benches/benchmarks/overall.rs | 3 +- block-filter/src/filter.rs | 16 +++--- chain/src/chain.rs | 34 +++---------- chain/src/tests/util.rs | 3 +- ckb-bin/Cargo.toml | 1 + ckb-bin/src/helper.rs | 40 ++++++++++----- ckb-bin/src/lib.rs | 46 +++++++++++++---- ckb-bin/src/subcommand/miner.rs | 25 ++++------ ckb-bin/src/subcommand/run.rs | 28 +++-------- miner/src/client.rs | 47 +++++++++--------- miner/src/miner.rs | 18 +++---- network/src/network.rs | 46 ++++++----------- network/src/protocols/tests/mod.rs | 4 +- notify/src/lib.rs | 21 ++------ rpc/src/module/subscription.rs | 1 + rpc/src/tests/examples.rs | 3 +- rpc/src/tests/mod.rs | 5 +- shared/Cargo.toml | 1 - shared/src/shared.rs | 19 +++---- sync/src/relayer/tests/helper.rs | 7 ++- sync/src/synchronizer/mod.rs | 7 ++- sync/src/tests/net_time_checker.rs | 9 ++-- sync/src/types/header_map/mod.rs | 24 ++++----- test/src/net.rs | 7 ++- tx-pool/Cargo.toml | 1 + tx-pool/src/chunk_process.rs | 13 +++-- tx-pool/src/process.rs | 2 +- tx-pool/src/service.rs | 49 +++++++++---------- util/channel/src/lib.rs | 4 +- util/indexer/src/service.rs | 46 +++++------------ util/launcher/Cargo.toml | 1 - util/launcher/src/lib.rs | 14 ++---- util/launcher/src/shared_builder.rs | 10 ++-- .../src/tests/utils/chain.rs | 3 +- util/metrics-service/Cargo.toml | 1 + util/metrics-service/src/lib.rs | 10 +++- util/network-alert/Cargo.toml | 1 - util/network-alert/src/tests/test_notifier.rs | 10 ++-- util/runtime/Cargo.toml | 1 - util/runtime/src/lib.rs | 48 ++++++++++++------ util/stop-handler/Cargo.toml | 11 ++++- 42 files changed, 315 insertions(+), 354 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cdf443d006..4011129135 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -437,7 +437,6 @@ version = "0.111.0-rc8" dependencies = [ "ckb-logger", "ckb-spawn", - "ckb-stop-handler", "tokio", ] @@ -492,6 +491,7 @@ dependencies = [ "ckb-network", "ckb-resource", "ckb-shared", + "ckb-stop-handler", "ckb-store", "ckb-types", "ckb-util", @@ -804,7 +804,6 @@ dependencies = [ "ckb-rpc", "ckb-shared", "ckb-snapshot", - "ckb-stop-handler", "ckb-store", "ckb-sync", "ckb-systemtime", @@ -934,6 +933,7 @@ dependencies = [ "ckb-logger", "ckb-metrics", "ckb-metrics-config", + "ckb-stop-handler", "ckb-util", "hyper", "prometheus", @@ -1020,7 +1020,7 @@ dependencies = [ "tempfile", "tentacle", "tokio", - "tokio-util 0.7.7", + "tokio-util 0.7.8", "trust-dns-resolver", ] @@ -1037,7 +1037,6 @@ dependencies = [ "ckb-multisig", "ckb-network", "ckb-notify", - "ckb-stop-handler", "ckb-systemtime", "ckb-types", "ckb-util", @@ -1243,7 +1242,6 @@ dependencies = [ "arc-swap", "ckb-async-runtime", "ckb-chain-spec", - "ckb-channel", "ckb-constant", "ckb-db", "ckb-db-schema", @@ -1284,10 +1282,16 @@ version = "0.111.0-rc8" name = "ckb-stop-handler" version = "0.111.0-rc8" dependencies = [ + "ckb-async-runtime", "ckb-channel", "ckb-logger", - "parking_lot 0.12.1", + "ckb-util", + "ctrlc", + "libc", + "once_cell", + "rand 0.8.5", "tokio", + "tokio-util 0.7.8", ] [[package]] @@ -1429,6 +1433,7 @@ dependencies = [ "slab", "tempfile", "tokio", + "tokio-util 0.7.8", ] [[package]] @@ -2403,7 +2408,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util 0.7.7", + "tokio-util 0.7.8", "tracing", ] @@ -4479,7 +4484,7 @@ dependencies = [ "tentacle-secio", "thiserror", "tokio", - "tokio-util 0.7.7", + "tokio-util 0.7.8", "tokio-yamux", "wasm-bindgen", "wasm-bindgen-futures", @@ -4521,7 +4526,7 @@ dependencies = [ "secp256k1", "sha2", "tokio", - "tokio-util 0.7.7", + "tokio-util 0.7.8", "unsigned-varint", "x25519-dalek", ] @@ -4733,9 +4738,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes 1.4.0", "futures-core", @@ -4756,7 +4761,7 @@ dependencies = [ "log", "nohash-hasher", "tokio", - "tokio-util 0.7.7", + "tokio-util 0.7.8", ] [[package]] diff --git a/benches/benches/benchmarks/overall.rs b/benches/benches/benchmarks/overall.rs index af98fe6bae..15a76de599 100644 --- a/benches/benches/benchmarks/overall.rs +++ b/benches/benches/benchmarks/overall.rs @@ -6,7 +6,7 @@ use ckb_chain_spec::consensus::{ConsensusBuilder, ProposalWindow}; use ckb_dao_utils::genesis_dao_data; 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_shared::Shared; use ckb_store::ChainStore; use ckb_types::{ @@ -77,7 +77,6 @@ fn dummy_network(shared: &Shared) -> NetworkController { "test".to_string(), Flags::COMPATIBILITY, ), - DefaultExitHandler::default(), ) .start(shared.async_handle()) .expect("Start network service failed") diff --git a/block-filter/src/filter.rs b/block-filter/src/filter.rs index 71ffca1c80..56fcc92f6b 100644 --- a/block-filter/src/filter.rs +++ b/block-filter/src/filter.rs @@ -1,7 +1,7 @@ -use ckb_async_runtime::tokio::{self, sync::oneshot, task::block_in_place}; -use ckb_logger::{debug, warn}; +use ckb_async_runtime::tokio::{self, task::block_in_place}; +use ckb_logger::{debug, info, warn}; use ckb_shared::Shared; -use ckb_stop_handler::{SignalSender, StopHandler}; +use ckb_stop_handler::{new_tokio_exit_rx, CancellationToken}; use ckb_store::{ChainDB, ChainStore}; use ckb_types::{ core::HeaderView, @@ -43,10 +43,10 @@ impl BlockFilter { } /// start background single-threaded service to create block filter data - pub fn start(self) -> StopHandler<()> { + pub fn start(self) { let notify_controller = self.shared.notify_controller().clone(); let async_handle = self.shared.async_handle().clone(); - let (stop, mut stop_rx) = oneshot::channel::<()>(); + let stop_rx: CancellationToken = new_tokio_exit_rx(); let filter_data_builder = self.clone(); let build_filter_data = @@ -62,12 +62,14 @@ impl BlockFilter { block_in_place(|| self.build_filter_data()); new_block_watcher.borrow_and_update(); } - _ = &mut stop_rx => break, + _ = stop_rx.cancelled() => { + info!("BlockFilter received exit signal, exit now"); + break + }, else => break, } } }); - StopHandler::new(SignalSender::Tokio(stop), None, NAME.to_string()) } /// build block filter data to the latest block diff --git a/chain/src/chain.rs b/chain/src/chain.rs index b6291211d5..8f7e5d8e3c 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -12,7 +12,7 @@ use ckb_proposal_table::ProposalTable; #[cfg(debug_assertions)] use ckb_rust_unstable_port::IsSorted; use ckb_shared::shared::Shared; -use ckb_stop_handler::{SignalSender, StopHandler}; +use ckb_stop_handler::{new_crossbeam_exit_rx, register_thread}; use ckb_store::{attach_block_cell, detach_block_cell, ChainStore, StoreTransaction}; use ckb_systemtime::unix_time_as_millis; use ckb_types::{ @@ -22,7 +22,7 @@ use ckb_types::{ ResolvedTransaction, }, hardfork::HardForks, - service::{Request, DEFAULT_CHANNEL_SIZE, SIGNAL_CHANNEL_SIZE}, + service::{Request, DEFAULT_CHANNEL_SIZE}, BlockExt, BlockNumber, BlockView, Cycle, HeaderView, }, packed::{Byte32, ProposalShortId}, @@ -50,13 +50,6 @@ type TruncateRequest = Request>; pub struct ChainController { process_block_sender: Sender, truncate_sender: Sender, // Used for testing only - stop: Option>, -} - -impl Drop for ChainController { - fn drop(&mut self) { - self.try_stop(); - } } #[cfg_attr(feature = "mock", faux::methods)] @@ -64,12 +57,10 @@ impl ChainController { pub fn new( process_block_sender: Sender, truncate_sender: Sender, - stop: StopHandler<()>, ) -> Self { ChainController { process_block_sender, truncate_sender, - stop: Some(stop), } } /// Inserts the block into database. @@ -109,17 +100,10 @@ impl ChainController { }) } - pub fn try_stop(&mut self) { - if let Some(ref mut stop) = self.stop { - stop.try_send(()); - } - } - /// Since a non-owning reference does not count towards ownership, /// it will not prevent the value stored in the allocation from being dropped pub fn non_owning_clone(&self) -> Self { ChainController { - stop: None, truncate_sender: self.truncate_sender.clone(), process_block_sender: self.process_block_sender.clone(), } @@ -245,7 +229,7 @@ impl ChainService { /// start background single-threaded service with specified thread_name. pub fn start(mut self, thread_name: Option) -> ChainController { - let (signal_sender, signal_receiver) = channel::bounded::<()>(SIGNAL_CHANNEL_SIZE); + let signal_receiver = new_crossbeam_exit_rx(); let (process_block_sender, process_block_receiver) = channel::bounded(DEFAULT_CHANNEL_SIZE); let (truncate_sender, truncate_receiver) = channel::bounded(1); @@ -256,10 +240,11 @@ impl ChainService { } let tx_control = self.shared.tx_pool_controller().clone(); - let thread = thread_builder + let chain_jh = thread_builder .spawn(move || loop { select! { recv(signal_receiver) -> _ => { + info!("ChainService received exit signal, stopped"); break; }, recv(process_block_receiver) -> msg => match msg { @@ -287,13 +272,10 @@ impl ChainService { } }) .expect("Start ChainService failed"); - let stop = StopHandler::new( - SignalSender::Crossbeam(signal_sender), - Some(thread), - "chain".to_string(), - ); - ChainController::new(process_block_sender, truncate_sender, stop) + register_thread("ChainService", chain_jh); + + ChainController::new(process_block_sender, truncate_sender) } fn make_fork_for_truncate(&self, target: &HeaderView, current_tip: &HeaderView) -> ForkChanges { diff --git a/chain/src/tests/util.rs b/chain/src/tests/util.rs index 3051dd775f..7ade19bc53 100644 --- a/chain/src/tests/util.rs +++ b/chain/src/tests/util.rs @@ -6,7 +6,7 @@ use ckb_dao::DaoCalculator; use ckb_dao_utils::genesis_dao_data; use ckb_jsonrpc_types::ScriptHashType; use ckb_launcher::SharedBuilder; -use ckb_network::{DefaultExitHandler, Flags, NetworkController, NetworkService, NetworkState}; +use ckb_network::{Flags, NetworkController, NetworkService, NetworkState}; use ckb_shared::shared::Shared; use ckb_store::ChainStore; pub use ckb_test_chain_utils::MockStore; @@ -314,7 +314,6 @@ pub(crate) fn dummy_network(shared: &Shared) -> NetworkController { "test".to_string(), Flags::COMPATIBILITY, ), - DefaultExitHandler::default(), ) .start(shared.async_handle()) .expect("Start network service failed") diff --git a/ckb-bin/Cargo.toml b/ckb-bin/Cargo.toml index 2609ba6cef..27ee76fa04 100644 --- a/ckb-bin/Cargo.toml +++ b/ckb-bin/Cargo.toml @@ -43,6 +43,7 @@ rayon = "1.0" sentry = { version = "0.26.0", optional = true } is-terminal = "0.4.7" fdlimit = "0.2.1" +ckb-stop-handler = { path = "../util/stop-handler", version = "= 0.111.0-rc8" } [features] deadlock_detection = ["ckb-util/deadlock_detection"] diff --git a/ckb-bin/src/helper.rs b/ckb-bin/src/helper.rs index 142d06226c..21c93732b8 100644 --- a/ckb-bin/src/helper.rs +++ b/ckb-bin/src/helper.rs @@ -1,4 +1,5 @@ use ckb_logger::info; + use std::io::{stdin, stdout, Write}; #[cfg(not(feature = "deadlock_detection"))] @@ -6,27 +7,42 @@ pub fn deadlock_detection() {} #[cfg(feature = "deadlock_detection")] pub fn deadlock_detection() { + use ckb_channel::select; use ckb_logger::warn; + use ckb_stop_handler::{new_crossbeam_exit_rx, register_thread}; use ckb_util::parking_lot::deadlock; use std::{thread, time::Duration}; info!("deadlock_detection enable"); - thread::spawn(move || loop { - thread::sleep(Duration::from_secs(10)); - let deadlocks = deadlock::check_deadlock(); - if deadlocks.is_empty() { - continue; - } + let dead_lock_jh = thread::spawn({ + let ticker = ckb_channel::tick(Duration::from_secs(10)); + let stop_rx = new_crossbeam_exit_rx(); + move || loop { + select! { + recv(ticker) -> _ => { + let deadlocks = deadlock::check_deadlock(); + if deadlocks.is_empty() { + continue; + } + + warn!("{} deadlocks detected", deadlocks.len()); + for (i, threads) in deadlocks.iter().enumerate() { + warn!("Deadlock #{}", i); + for t in threads { + warn!("Thread Id {:#?}", t.thread_id()); + warn!("{:#?}", t.backtrace()); + } + } - warn!("{} deadlocks detected", deadlocks.len()); - for (i, threads) in deadlocks.iter().enumerate() { - warn!("Deadlock #{}", i); - for t in threads { - warn!("Thread Id {:#?}", t.thread_id()); - warn!("{:#?}", t.backtrace()); + }, + recv(stop_rx) -> _ =>{ + info!("deadlock_detection received exit signal, stopped"); + return; + } } } }); + register_thread("dead_lock_detect", dead_lock_jh); } pub fn prompt(msg: &str) -> String { diff --git a/ckb-bin/src/lib.rs b/ckb-bin/src/lib.rs index b047a14086..91c61b813d 100644 --- a/ckb-bin/src/lib.rs +++ b/ckb-bin/src/lib.rs @@ -8,13 +8,15 @@ mod subcommand; use ckb_app_config::{cli, ExitCode, Setup}; use ckb_async_runtime::new_global_runtime; use ckb_build_info::Version; +use ckb_logger::info; +use ckb_network::tokio; +use ckb_stop_handler::broadcast_exit_signals; use helper::raise_fd_limit; use setup_guard::SetupGuard; -use std::time::Duration; +use std::sync::Arc; #[cfg(feature = "with_sentry")] pub(crate) const LOG_TARGET_SENTRY: &str = "sentry"; -const RUNTIME_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(1); /// The executable main entry. /// @@ -58,25 +60,49 @@ pub fn run_app(version: Version) -> Result<(), ExitCode> { .expect("SubcommandRequiredElseHelp"); let is_silent_logging = is_silent_logging(cmd); - let (handle, runtime) = new_global_runtime(); + let (mut handle, mut handle_stop_rx, _runtime) = new_global_runtime(); let setup = Setup::from_matches(bin_name, cmd, matches)?; let _guard = SetupGuard::from_setup(&setup, &version, handle.clone(), is_silent_logging)?; raise_fd_limit(); + // indicate whether the process is terminated by an exit signal + let caught_exit_signal = Arc::new(std::sync::atomic::AtomicBool::new(false)); + + ctrlc::set_handler({ + let caught_exit_signal = Arc::clone(&caught_exit_signal); + move || { + broadcast_exit_signals(); + caught_exit_signal.store(true, std::sync::atomic::Ordering::SeqCst); + } + }) + .expect("Error setting Ctrl-C handler"); + let ret = match cmd { - cli::CMD_RUN => subcommand::run(setup.run(matches)?, version, handle), - cli::CMD_MINER => subcommand::miner(setup.miner(matches)?, handle), - cli::CMD_REPLAY => subcommand::replay(setup.replay(matches)?, handle), - cli::CMD_EXPORT => subcommand::export(setup.export(matches)?, handle), - cli::CMD_IMPORT => subcommand::import(setup.import(matches)?, handle), - cli::CMD_STATS => subcommand::stats(setup.stats(matches)?, handle), + cli::CMD_RUN => subcommand::run(setup.run(matches)?, version, handle.clone()), + cli::CMD_MINER => subcommand::miner(setup.miner(matches)?, handle.clone()), + cli::CMD_REPLAY => subcommand::replay(setup.replay(matches)?, handle.clone()), + cli::CMD_EXPORT => subcommand::export(setup.export(matches)?, handle.clone()), + cli::CMD_IMPORT => subcommand::import(setup.import(matches)?, handle.clone()), + cli::CMD_STATS => subcommand::stats(setup.stats(matches)?, handle.clone()), cli::CMD_RESET_DATA => subcommand::reset_data(setup.reset_data(matches)?), cli::CMD_MIGRATE => subcommand::migrate(setup.migrate(matches)?), _ => unreachable!(), }; - runtime.shutdown_timeout(RUNTIME_SHUTDOWN_TIMEOUT); + if !caught_exit_signal.load(std::sync::atomic::Ordering::SeqCst) { + // if `subcommand` finish normally, and we didn't catch exit signal, broadcast exit signals + broadcast_exit_signals(); + } + + handle.drop_guard(); + + tokio::task::block_in_place(|| { + info!("waiting all tokio tasks done"); + handle_stop_rx.blocking_recv(); + info!("all tokio tasks have been stopped"); + }); + ret } diff --git a/ckb-bin/src/subcommand/miner.rs b/ckb-bin/src/subcommand/miner.rs index dace1cc9a7..fd9a892abc 100644 --- a/ckb-bin/src/subcommand/miner.rs +++ b/ckb-bin/src/subcommand/miner.rs @@ -2,16 +2,15 @@ use ckb_app_config::{ExitCode, MinerArgs, MinerConfig}; use ckb_async_runtime::Handle; use ckb_channel::unbounded; use ckb_miner::{Client, Miner}; -use ckb_network::{DefaultExitHandler, ExitHandler}; +use ckb_stop_handler::{new_crossbeam_exit_rx, register_thread, wait_all_ckb_services_exit}; use std::thread; pub fn miner(args: MinerArgs, async_handle: Handle) -> Result<(), ExitCode> { let (new_work_tx, new_work_rx) = unbounded(); let MinerConfig { client, workers } = args.config; - let exit_handler = DefaultExitHandler::default(); let client = Client::new(new_work_tx, client, async_handle); - let (mut miner, miner_stop) = Miner::new( + let mut miner = Miner::new( args.pow_engine, client.clone(), new_work_rx, @@ -21,21 +20,17 @@ pub fn miner(args: MinerArgs, async_handle: Handle) -> Result<(), ExitCode> { ckb_memory_tracker::track_current_process_simple(args.memory_tracker.interval); - let client_stop = client.spawn_background(); + client.spawn_background(); - thread::Builder::new() - .name("client".to_string()) - .spawn(move || miner.run()) + let stop_rx = new_crossbeam_exit_rx(); + const THREAD_NAME: &str = "client"; + let miner_jh = thread::Builder::new() + .name(THREAD_NAME.into()) + .spawn(move || miner.run(stop_rx)) .expect("Start client failed!"); + register_thread(THREAD_NAME, miner_jh); - let exit_handler_clone = exit_handler.clone(); - ctrlc::set_handler(move || { - exit_handler_clone.notify_exit(); - }) - .expect("Error setting Ctrl-C handler"); - exit_handler.wait_for_exit(); + wait_all_ckb_services_exit(); - drop(client_stop); - drop(miner_stop); Ok(()) } diff --git a/ckb-bin/src/subcommand/run.rs b/ckb-bin/src/subcommand/run.rs index 7878b7b6de..cd7d8c6282 100644 --- a/ckb-bin/src/subcommand/run.rs +++ b/ckb-bin/src/subcommand/run.rs @@ -4,7 +4,8 @@ use ckb_async_runtime::Handle; use ckb_build_info::Version; use ckb_launcher::Launcher; use ckb_logger::info; -use ckb_network::{DefaultExitHandler, ExitHandler}; +use ckb_stop_handler::wait_all_ckb_services_exit; + use ckb_types::core::cell::setup_system_cell_cache; pub fn run(args: RunArgs, version: Version, async_handle: Handle) -> Result<(), ExitCode> { @@ -16,7 +17,6 @@ pub fn run(args: RunArgs, version: Version, async_handle: Handle) -> Result<(), let block_assembler_config = launcher.sanitize_block_assembler_config()?; let miner_enable = block_assembler_config.is_some(); - let exit_handler = DefaultExitHandler::default(); let (shared, mut pack) = launcher.build_shared(block_assembler_config)?; @@ -43,12 +43,11 @@ pub fn run(args: RunArgs, version: Version, async_handle: Handle) -> Result<(), let chain_controller = launcher.start_chain_service(&shared, pack.take_proposal_table()); - let block_filter = launcher.start_block_filter(&shared); + launcher.start_block_filter(&shared); - let (network_controller, rpc_server) = launcher.start_network_and_rpc( + let (network_controller, _rpc_server) = launcher.start_network_and_rpc( &shared, chain_controller.non_owning_clone(), - &exit_handler, miner_enable, pack.take_relay_tx_receiver(), ); @@ -56,22 +55,7 @@ pub fn run(args: RunArgs, version: Version, async_handle: Handle) -> Result<(), let tx_pool_builder = pack.take_tx_pool_builder(); tx_pool_builder.start(network_controller.non_owning_clone()); - let exit_handler_clone = exit_handler.clone(); - ctrlc::set_handler(move || { - exit_handler_clone.notify_exit(); - }) - .expect("Error setting Ctrl-C handler"); - exit_handler.wait_for_exit(); - - info!("Finishing work, please wait..."); - shared.tx_pool_controller().save_pool().map_err(|err| { - eprintln!("TxPool Error: {err}"); - ExitCode::Failure - })?; - - drop(rpc_server); - drop(block_filter); - drop(network_controller); - drop(chain_controller); + wait_all_ckb_services_exit(); + Ok(()) } diff --git a/miner/src/client.rs b/miner/src/client.rs index 57d8e87cb0..dda47570a7 100644 --- a/miner/src/client.rs +++ b/miner/src/client.rs @@ -4,8 +4,8 @@ use ckb_app_config::MinerClientConfig; use ckb_async_runtime::Handle; use ckb_channel::Sender; use ckb_jsonrpc_types::{Block as JsonBlock, BlockTemplate}; -use ckb_logger::{debug, error}; -use ckb_stop_handler::{SignalSender, StopHandler}; +use ckb_logger::{debug, error, info}; +use ckb_stop_handler::{new_tokio_exit_rx, CancellationToken}; use ckb_types::{ packed::{Block, Byte32}, H256, @@ -45,13 +45,12 @@ pub enum RpcError { #[derive(Debug, Clone)] pub struct Rpc { sender: mpsc::Sender, - stop: StopHandler<()>, } impl Rpc { pub fn new(url: Uri, handle: Handle) -> Rpc { let (sender, mut receiver) = mpsc::channel(65_535); - let (stop, mut stop_rx) = oneshot::channel::<()>(); + let stop_rx: CancellationToken = new_tokio_exit_rx(); let https = hyper_tls::HttpsConnector::new(); let client = HttpClient::builder().build(https); @@ -87,16 +86,16 @@ impl Rpc { } }); }, - _ = &mut stop_rx => break, + _ = stop_rx.cancelled() => { + info!("Rpc server received exit signal, exit now"); + break + }, else => break } } }); - Rpc { - sender, - stop: StopHandler::new(SignalSender::Tokio(stop), None, "miner-rpc".to_string()), - } + Rpc { sender } } pub fn request( @@ -128,12 +127,6 @@ impl Rpc { } } -impl Drop for Rpc { - fn drop(&mut self) { - self.stop.try_send(()); - } -} - pub enum Works { New(Work), FailSubmit(Byte32), @@ -200,8 +193,7 @@ impl Client { } /// spawn background update process - pub fn spawn_background(self) -> StopHandler<()> { - let (stop, stop_rx) = oneshot::channel::<()>(); + pub fn spawn_background(self) { let client = self.clone(); if let Some(addr) = self.config.listen { ckb_logger::info!("listen notify mode : {}", addr); @@ -220,19 +212,18 @@ Otherwise ckb-miner does not work properly and will behave as it stopped committ addr ); self.handle.spawn(async move { - client.listen_block_template_notify(addr, stop_rx).await; + client.listen_block_template_notify(addr).await; }); - self.blocking_fetch_block_template() + self.blocking_fetch_block_template(); } else { ckb_logger::info!("loop poll mode: interval {}ms", self.config.poll_interval); self.handle.spawn(async move { - client.poll_block_template(stop_rx).await; + client.poll_block_template().await; }); } - StopHandler::new(SignalSender::Tokio(stop), None, "miner-updater".to_string()) } - async fn listen_block_template_notify(&self, addr: SocketAddr, stop_rx: oneshot::Receiver<()>) { + async fn listen_block_template_notify(&self, addr: SocketAddr) { let client = self.clone(); let make_service = make_service_fn(move |_conn| { let client = client.clone(); @@ -241,8 +232,10 @@ Otherwise ckb-miner does not work properly and will behave as it stopped committ }); let server = Server::bind(&addr).serve(make_service); + let stop_rx: CancellationToken = new_tokio_exit_rx(); let graceful = server.with_graceful_shutdown(async move { - stop_rx.await.ok(); + stop_rx.cancelled().await; + info!("Miner client received exit signal, exit now"); }); if let Err(e) = graceful.await { @@ -250,17 +243,21 @@ Otherwise ckb-miner does not work properly and will behave as it stopped committ } } - async fn poll_block_template(&self, mut stop_rx: oneshot::Receiver<()>) { + async fn poll_block_template(&self) { let poll_interval = time::Duration::from_millis(self.config.poll_interval); let mut interval = tokio::time::interval(poll_interval); interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); + let stop_rx: CancellationToken = new_tokio_exit_rx(); loop { tokio::select! { _ = interval.tick() => { debug!("poll block template..."); self.fetch_block_template().await; } - _ = &mut stop_rx => break, + _ = stop_rx.cancelled() => { + info!("Miner client pool_block_template received exit signal, exit now"); + break + }, else => break, } } diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 8119a7bea9..e14ffef72f 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -5,7 +5,6 @@ use ckb_app_config::MinerWorkerConfig; use ckb_channel::{select, unbounded, Receiver}; use ckb_logger::{debug, error, info}; use ckb_pow::PowEngine; -use ckb_stop_handler::{SignalSender, StopHandler}; use ckb_types::{ packed::{Byte32, Header}, prelude::*, @@ -27,7 +26,6 @@ pub struct Miner { pub(crate) worker_controllers: Vec, pub(crate) work_rx: Receiver, pub(crate) nonce_rx: Receiver<(Byte32, Work, u128)>, - pub(crate) stop_rx: Receiver<()>, pub(crate) pb: ProgressBar, pub(crate) nonces_found: u128, pub(crate) stderr_is_tty: bool, @@ -42,9 +40,8 @@ impl Miner { work_rx: Receiver, workers: &[MinerWorkerConfig], limit: u128, - ) -> (Miner, StopHandler<()>) { + ) -> Miner { let (nonce_tx, nonce_rx) = unbounded(); - let (stop, stop_rx) = unbounded(); let mp = MultiProgress::new(); let worker_controllers = workers @@ -61,9 +58,7 @@ impl Miner { mp.join().expect("MultiProgress join failed"); }); - let stop = StopHandler::new(SignalSender::Crossbeam(stop), None, "miner".to_string()); - - let miner = Miner { + Miner { legacy_work: LruCache::new(WORK_CACHE_SIZE), nonces_found: 0, _pow: pow, @@ -71,16 +66,14 @@ impl Miner { worker_controllers, work_rx, nonce_rx, - stop_rx, pb, stderr_is_tty, limit, - }; - (miner, stop) + } } /// TODO(doc): @quake - pub fn run(&mut self) { + pub fn run(&mut self, stop_rx: Receiver<()>) { loop { select! { recv(self.work_rx) -> msg => match msg { @@ -109,7 +102,8 @@ impl Miner { break; }, }, - recv(self.stop_rx) -> _msg => { + recv(stop_rx) -> _msg => { + info!("miner received exit signal, stopped"); break; } }; diff --git a/network/src/network.rs b/network/src/network.rs index cbe84e2cf2..89bc527652 100644 --- a/network/src/network.rs +++ b/network/src/network.rs @@ -21,7 +21,7 @@ use crate::{Behaviour, CKBProtocol, Peer, PeerIndex, ProtocolId, ServiceControl} use ckb_app_config::{default_support_all_protocols, NetworkConfig, SupportProtocol}; use ckb_logger::{debug, error, info, trace, warn}; use ckb_spawn::Spawn; -use ckb_stop_handler::{SignalSender, StopHandler}; +use ckb_stop_handler::{broadcast_exit_signals, new_tokio_exit_rx, CancellationToken}; use ckb_util::{Condvar, Mutex, RwLock}; use futures::{channel::mpsc::Sender, Future}; use ipnetwork::IpNetwork; @@ -490,18 +490,14 @@ impl NetworkState { } /// Used to handle global events of tentacle, such as session open/close -pub struct EventHandler { +pub struct EventHandler { pub(crate) network_state: Arc, - pub(crate) exit_handler: T, } -impl EventHandler { +impl EventHandler { /// init an event handler - pub fn new(network_state: Arc, exit_handler: T) -> Self { - Self { - network_state, - exit_handler, - } + pub fn new(network_state: Arc) -> Self { + Self { network_state } } } @@ -531,7 +527,7 @@ impl ExitHandler for DefaultExitHandler { } } -impl EventHandler { +impl EventHandler { fn inbound_eviction(&self) -> Vec { if self.network_state.config.bootnode_mode { let status = self.network_state.connection_status(); @@ -560,7 +556,7 @@ impl EventHandler { } #[async_trait] -impl ServiceHandle for EventHandler { +impl ServiceHandle for EventHandler { async fn handle_error(&mut self, context: &mut ServiceContext, error: ServiceError) { match error { ServiceError::DialerError { address, error } => { @@ -658,7 +654,8 @@ impl ServiceHandle for EventHandler { ) }, ); - self.exit_handler.notify_exit(); + + broadcast_exit_signals(); } } } @@ -763,8 +760,8 @@ impl ServiceHandle for EventHandler { } /// Ckb network service, use to start p2p network -pub struct NetworkService { - p2p_service: Service>, +pub struct NetworkService { + p2p_service: Service, network_state: Arc, ping_controller: Option>, // Background services @@ -772,7 +769,7 @@ pub struct NetworkService { version: String, } -impl NetworkService { +impl NetworkService { /// init with all config pub fn new( network_state: Arc, @@ -780,7 +777,6 @@ impl NetworkService { required_protocol_ids: Vec, // name, version, flags identify_announce: (String, String, Flags), - exit_handler: T, ) -> Self { let config = &network_state.config; @@ -891,7 +887,6 @@ impl NetworkService { } let event_handler = EventHandler { network_state: Arc::clone(&network_state), - exit_handler, }; service_builder = service_builder .key_pair(network_state.local_private_key.clone()) @@ -1098,7 +1093,7 @@ impl NetworkService { }) .unzip(); - let (sender, mut receiver) = oneshot::channel(); + let receiver: CancellationToken = new_tokio_exit_rx(); let (start_sender, start_receiver) = mpsc::channel(); { let network_state = Arc::clone(&network_state); @@ -1130,7 +1125,8 @@ impl NetworkService { tokio::spawn(async move { p2p_service.run().await }); loop { tokio::select! { - _ = &mut receiver => { + _ = receiver.cancelled() => { + info!("NetworkService receive exit signal, start shutdown..."); let _ = p2p_control.shutdown().await; // Drop senders to stop all corresponding background task drop(bg_signals); @@ -1163,13 +1159,11 @@ impl NetworkService { return Err(e); } - let stop = StopHandler::new(SignalSender::Tokio(sender), None, "network".to_string()); Ok(NetworkController { version, network_state, p2p_control, ping_controller, - stop: Some(stop), }) } } @@ -1181,7 +1175,6 @@ pub struct NetworkController { network_state: Arc, p2p_control: ServiceControl, ping_controller: Option>, - stop: Option>, } impl NetworkController { @@ -1397,7 +1390,6 @@ impl NetworkController { /// it will not prevent the value stored in the allocation from being dropped pub fn non_owning_clone(&self) -> Self { NetworkController { - stop: None, version: self.version.clone(), network_state: Arc::clone(&self.network_state), p2p_control: self.p2p_control.clone(), @@ -1406,14 +1398,6 @@ impl NetworkController { } } -impl Drop for NetworkController { - fn drop(&mut self) { - if let Some(ref mut stop) = self.stop { - stop.try_send(()); - } - } -} - // Send an optional message before disconnect a peer pub(crate) fn disconnect_with_message( control: &ServiceControl, diff --git a/network/src/protocols/tests/mod.rs b/network/src/protocols/tests/mod.rs index db72949dda..140e9625d8 100644 --- a/network/src/protocols/tests/mod.rs +++ b/network/src/protocols/tests/mod.rs @@ -7,8 +7,7 @@ use super::{ }; use crate::{ - network::{DefaultExitHandler, EventHandler}, - services::protocol_type_checker::ProtocolTypeCheckerService, + network::EventHandler, services::protocol_type_checker::ProtocolTypeCheckerService, NetworkState, PeerIdentifyInfo, SupportProtocols, }; @@ -224,7 +223,6 @@ fn net_service_start( .forever(true) .build(EventHandler { network_state: Arc::clone(&network_state), - exit_handler: DefaultExitHandler::default(), }); let peer_id = network_state.local_peer_id().clone(); diff --git a/notify/src/lib.rs b/notify/src/lib.rs index 9a95336a3a..2b9969ba96 100644 --- a/notify/src/lib.rs +++ b/notify/src/lib.rs @@ -1,8 +1,8 @@ //! TODO(doc): @quake use ckb_app_config::NotifyConfig; use ckb_async_runtime::Handle; -use ckb_logger::{debug, error, trace}; -use ckb_stop_handler::{SignalSender, StopHandler}; +use ckb_logger::{debug, error, info, trace}; +use ckb_stop_handler::{new_tokio_exit_rx, CancellationToken}; use ckb_types::packed::Byte32; use ckb_types::{ core::{tx_pool::Reject, BlockView}, @@ -88,7 +88,6 @@ impl NotifyTimeout { /// TODO(doc): @quake #[derive(Clone)] pub struct NotifyController { - stop: StopHandler<()>, new_block_register: NotifyRegister, new_block_watcher: NotifyWatcher, new_block_notifier: Sender, @@ -103,12 +102,6 @@ pub struct NotifyController { handle: Handle, } -impl Drop for NotifyController { - fn drop(&mut self) { - self.stop.try_send(()); - } -} - /// TODO(doc): @quake pub struct NotifyService { config: NotifyConfig, @@ -142,7 +135,7 @@ impl NotifyService { /// start background tokio spawned task. pub fn start(mut self) -> NotifyController { - let (signal_sender, mut signal_receiver) = oneshot::channel(); + let signal_receiver: CancellationToken = new_tokio_exit_rx(); let handle = self.handle.clone(); let (new_block_register, mut new_block_register_receiver) = @@ -173,7 +166,8 @@ impl NotifyService { handle.spawn(async move { loop { tokio::select! { - _ = &mut signal_receiver => { + _ = signal_receiver.cancelled() => { + info!("NotifyService received exit signal, exit now"); break; } Some(msg) = new_block_register_receiver.recv() => { self.handle_register_new_block(msg) }, @@ -204,11 +198,6 @@ impl NotifyService { reject_transaction_notifier: reject_transaction_sender, network_alert_register, network_alert_notifier: network_alert_sender, - stop: StopHandler::new( - SignalSender::Tokio(signal_sender), - None, - "notify".to_string(), - ), handle, } } diff --git a/rpc/src/module/subscription.rs b/rpc/src/module/subscription.rs index 69d7cc0c88..c5ca5e5160 100644 --- a/rpc/src/module/subscription.rs +++ b/rpc/src/module/subscription.rs @@ -1,5 +1,6 @@ use ckb_jsonrpc_types::Topic; use ckb_notify::NotifyController; + use jsonrpc_core::{Metadata, Result}; use jsonrpc_derive::rpc; use jsonrpc_pubsub::{ diff --git a/rpc/src/tests/examples.rs b/rpc/src/tests/examples.rs index 1164278acd..f134f22e16 100644 --- a/rpc/src/tests/examples.rs +++ b/rpc/src/tests/examples.rs @@ -10,7 +10,7 @@ use ckb_chain_spec::consensus::{Consensus, ConsensusBuilder}; use ckb_chain_spec::versionbits::{ActiveMode, Deployment, DeploymentPos}; use ckb_dao_utils::genesis_dao_data; use ckb_launcher::SharedBuilder; -use ckb_network::{DefaultExitHandler, Flags, NetworkService, NetworkState}; +use ckb_network::{Flags, NetworkService, NetworkState}; use ckb_network_alert::alert_relayer::AlertRelayer; use ckb_notify::NotifyService; use ckb_sync::SyncShared; @@ -151,7 +151,6 @@ fn setup_rpc_test_suite(height: u64) -> RpcTestSuite { "0.1.0".to_string(), Flags::COMPATIBILITY, ), - DefaultExitHandler::default(), ) .start(shared.async_handle()) .expect("Start network service failed") diff --git a/rpc/src/tests/mod.rs b/rpc/src/tests/mod.rs index b35c80844b..70ba66762c 100644 --- a/rpc/src/tests/mod.rs +++ b/rpc/src/tests/mod.rs @@ -4,7 +4,7 @@ use ckb_chain::chain::{ChainController, ChainService}; use ckb_dao::DaoCalculator; use ckb_jsonrpc_types::ScriptHashType; use ckb_launcher::SharedBuilder; -use ckb_network::{DefaultExitHandler, Flags, NetworkService, NetworkState}; +use ckb_network::{Flags, NetworkService, NetworkState}; use ckb_reward_calculator::RewardCalculator; use ckb_shared::{Shared, Snapshot}; use ckb_store::ChainStore; @@ -80,7 +80,7 @@ impl RpcTestResponse { #[allow(dead_code)] struct RpcTestSuite { - rpc_client: reqwest::blocking::Client, + rpc_client: Client, rpc_uri: String, shared: Shared, chain_controller: ChainController, @@ -249,7 +249,6 @@ fn setup() -> RpcTestSuite { "0.1.0".to_string(), Flags::COMPATIBILITY, ), - DefaultExitHandler::default(), ) .start(shared.async_handle()) .expect("Start network service failed") diff --git a/shared/Cargo.toml b/shared/Cargo.toml index f8f7677061..a33b65c3b0 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -24,7 +24,6 @@ ckb-logger = { path = "../util/logger", version = "= 0.111.0-rc8" } ckb-db-schema = { path = "../db-schema", version = "= 0.111.0-rc8" } ckb-async-runtime = { path = "../util/runtime", version = "= 0.111.0-rc8" } ckb-stop-handler = { path = "../util/stop-handler", version = "= 0.111.0-rc8" } -ckb-channel = { path = "../util/channel", version = "= 0.111.0-rc8" } ckb-constant = { path = "../util/constant", version = "= 0.111.0-rc8" } ckb-systemtime = { path = "../util/systemtime", version = "= 0.111.0-rc8" } diff --git a/shared/src/shared.rs b/shared/src/shared.rs index 0ec83eb888..377b941df7 100644 --- a/shared/src/shared.rs +++ b/shared/src/shared.rs @@ -10,12 +10,12 @@ use ckb_db_schema::{COLUMN_BLOCK_BODY, COLUMN_NUMBER_HASH}; use ckb_error::{AnyError, Error}; use ckb_notify::NotifyController; use ckb_proposal_table::ProposalView; -use ckb_stop_handler::{SignalSender, StopHandler}; +use ckb_stop_handler::{new_crossbeam_exit_rx, register_thread}; use ckb_store::{ChainDB, ChainStore}; use ckb_systemtime::unix_time_as_millis; use ckb_tx_pool::{BlockTemplate, TokioRwLock, TxPoolController}; use ckb_types::{ - core::{service, BlockNumber, EpochExt, EpochNumber, HeaderView, Version}, + core::{BlockNumber, EpochExt, EpochNumber, HeaderView, Version}, packed::{self, Byte32}, prelude::*, U256, @@ -35,13 +35,11 @@ const MAX_FREEZE_LIMIT: BlockNumber = 30_000; /// An owned permission to close on a freezer thread pub struct FreezerClose { stopped: Arc, - stop: StopHandler<()>, } impl Drop for FreezerClose { fn drop(&mut self) { self.stopped.store(true, Ordering::SeqCst); - self.stop.try_send(()); } } @@ -86,10 +84,9 @@ impl Shared { pub fn spawn_freeze(&self) -> Option { if let Some(freezer) = self.store.freezer() { ckb_logger::info!("Freezer enable"); - let (signal_sender, signal_receiver) = - ckb_channel::bounded::<()>(service::SIGNAL_CHANNEL_SIZE); + let signal_receiver = new_crossbeam_exit_rx(); let shared = self.clone(); - let thread = thread::Builder::new() + let freeze_jh = thread::Builder::new() .spawn(move || loop { match signal_receiver.recv_timeout(FREEZER_INTERVAL) { Err(_) => { @@ -106,14 +103,10 @@ impl Shared { }) .expect("Start FreezerService failed"); - let stop = StopHandler::new( - SignalSender::Crossbeam(signal_sender), - Some(thread), - "freezer".to_string(), - ); + register_thread("freeze", freeze_jh); + return Some(FreezerClose { stopped: Arc::clone(&freezer.stopped), - stop, }); } None diff --git a/sync/src/relayer/tests/helper.rs b/sync/src/relayer/tests/helper.rs index 2f738f66f2..eb6b3c0a08 100644 --- a/sync/src/relayer/tests/helper.rs +++ b/sync/src/relayer/tests/helper.rs @@ -4,9 +4,9 @@ use ckb_chain::chain::ChainService; use ckb_chain_spec::consensus::{build_genesis_epoch_ext, ConsensusBuilder}; use ckb_launcher::SharedBuilder; use ckb_network::{ - async_trait, bytes::Bytes as P2pBytes, Behaviour, CKBProtocolContext, DefaultExitHandler, - Error, Flags, NetworkController, NetworkService, NetworkState, Peer, PeerIndex, ProtocolId, - SupportProtocols, TargetSession, + async_trait, bytes::Bytes as P2pBytes, Behaviour, CKBProtocolContext, Error, Flags, + NetworkController, NetworkService, NetworkState, Peer, PeerIndex, ProtocolId, SupportProtocols, + TargetSession, }; use ckb_shared::Shared; use ckb_store::ChainStore; @@ -122,7 +122,6 @@ pub(crate) fn dummy_network(shared: &Shared) -> NetworkController { "test".to_string(), Flags::COMPATIBILITY, ), - DefaultExitHandler::default(), ) .start(shared.async_handle()) .expect("Start network service failed") diff --git a/sync/src/synchronizer/mod.rs b/sync/src/synchronizer/mod.rs index 55e8edf394..a2ab6cf46b 100644 --- a/sync/src/synchronizer/mod.rs +++ b/sync/src/synchronizer/mod.rs @@ -37,6 +37,7 @@ use ckb_network::{ async_trait, bytes::Bytes, tokio, CKBProtocolContext, CKBProtocolHandler, PeerIndex, ServiceControl, SupportProtocols, }; +use ckb_stop_handler::register_thread; use ckb_systemtime::unix_time_as_millis; use ckb_types::{ core::{self, BlockNumber}, @@ -625,8 +626,9 @@ impl Synchronizer { self.fetch_channel = Some(sender); let thread = ::std::thread::Builder::new(); let number = self.shared.state().shared_best_header_ref().number(); - thread - .name("BlockDownload".to_string()) + const THREAD_NAME: &str = "BlockDownload"; + let blockdownload_jh = thread + .name(THREAD_NAME.into()) .spawn(move || { BlockFetchCMD { sync, @@ -638,6 +640,7 @@ impl Synchronizer { .run(); }) .expect("download thread can't start"); + register_thread(THREAD_NAME, blockdownload_jh); } }, None => { diff --git a/sync/src/tests/net_time_checker.rs b/sync/src/tests/net_time_checker.rs index 890e0e218b..d849458754 100644 --- a/sync/src/tests/net_time_checker.rs +++ b/sync/src/tests/net_time_checker.rs @@ -2,8 +2,8 @@ use crate::net_time_checker::{NetTimeChecker, NetTimeProtocol, TOLERANT_OFFSET}; use ckb_app_config::NetworkConfig; use ckb_network::{ multiaddr::{Multiaddr, Protocol}, - CKBProtocol, DefaultExitHandler, EventHandler, NetworkState, ServiceBuilder, ServiceControl, - SessionId, SupportProtocols, TargetProtocol, + CKBProtocol, EventHandler, NetworkState, ServiceBuilder, ServiceControl, SessionId, + SupportProtocols, TargetProtocol, }; use std::{ borrow::Cow, @@ -102,10 +102,7 @@ fn net_service_start() -> Node { .key_pair(network_state.local_private_key().clone()) .upnp(config.upnp) .forever(true) - .build(EventHandler::new( - Arc::clone(&network_state), - DefaultExitHandler::default(), - )); + .build(EventHandler::new(Arc::clone(&network_state))); let peer_id = network_state.local_peer_id().clone(); diff --git a/sync/src/types/header_map/mod.rs b/sync/src/types/header_map/mod.rs index 5210e482f6..78939164b6 100644 --- a/sync/src/types/header_map/mod.rs +++ b/sync/src/types/header_map/mod.rs @@ -1,10 +1,11 @@ use ckb_async_runtime::Handle; -use ckb_stop_handler::{SignalSender, StopHandler}; +use ckb_logger::info; +use ckb_stop_handler::{new_tokio_exit_rx, CancellationToken}; use ckb_types::packed::Byte32; use std::sync::Arc; use std::time::Duration; use std::{mem::size_of, path}; -use tokio::sync::oneshot; + use tokio::time::MissedTickBehavior; mod backend; @@ -21,13 +22,6 @@ use super::HeaderIndexView; pub struct HeaderMap { inner: Arc>, - stop: StopHandler<()>, -} - -impl Drop for HeaderMap { - fn drop(&mut self) { - self.stop.try_send(()); - } } const INTERVAL: Duration = Duration::from_millis(500); @@ -51,7 +45,7 @@ impl HeaderMap { let size_limit = memory_limit / ITEM_BYTES_SIZE; let inner = Arc::new(HeaderMapKernel::new(tmpdir, size_limit)); let map = Arc::clone(&inner); - let (stop, mut stop_rx) = oneshot::channel::<()>(); + let stop_rx: CancellationToken = new_tokio_exit_rx(); async_handle.spawn(async move { let mut interval = tokio::time::interval(INTERVAL); @@ -61,15 +55,15 @@ impl HeaderMap { _ = interval.tick() => { map.limit_memory(); } - _ = &mut stop_rx => break, + _ = stop_rx.cancelled() => { + info!("HeaderMap limit_memory received exit signal, exit now"); + break + }, } } }); - Self { - inner, - stop: StopHandler::new(SignalSender::Tokio(stop), None, "HeaderMap".to_string()), - } + Self { inner } } pub(crate) fn contains_key(&self, hash: &Byte32) -> bool { diff --git a/test/src/net.rs b/test/src/net.rs index 5cf87930ad..56c4f5676e 100644 --- a/test/src/net.rs +++ b/test/src/net.rs @@ -7,8 +7,8 @@ use ckb_channel::{self as channel, unbounded, Receiver, RecvTimeoutError, Sender use ckb_logger::info; use ckb_network::{ async_trait, bytes::Bytes, extract_peer_id, CKBProtocol, CKBProtocolContext, - CKBProtocolHandler, DefaultExitHandler, Flags, NetworkController, NetworkService, NetworkState, - PeerIndex, ProtocolId, SupportProtocols, + CKBProtocolHandler, Flags, NetworkController, NetworkService, NetworkState, PeerIndex, + ProtocolId, SupportProtocols, }; use ckb_util::Mutex; use std::collections::HashMap; @@ -63,7 +63,7 @@ impl Net { ) }) .collect(); - let (async_handle, async_runtime) = new_global_runtime(); + let (async_handle, _handle_recv, async_runtime) = new_global_runtime(); let controller = NetworkService::new( Arc::clone(&network_state), ckb_protocols, @@ -73,7 +73,6 @@ impl Net { "0.1.0".to_string(), Flags::COMPATIBILITY, ), - DefaultExitHandler::default(), ) .start(&async_handle) .unwrap(); diff --git a/tx-pool/Cargo.toml b/tx-pool/Cargo.toml index 1ed8428ccf..95e4aa1294 100644 --- a/tx-pool/Cargo.toml +++ b/tx-pool/Cargo.toml @@ -39,6 +39,7 @@ hyper = { version = "0.14", features = ["http1", "client", "tcp"] } multi_index_map = "0.5.0" slab = "0.4" rustc-hash = "1.1" +tokio-util = "0.7.8" [dev-dependencies] tempfile.workspace = true diff --git a/tx-pool/src/chunk_process.rs b/tx-pool/src/chunk_process.rs index c86a2966cb..b35e547a21 100644 --- a/tx-pool/src/chunk_process.rs +++ b/tx-pool/src/chunk_process.rs @@ -4,6 +4,7 @@ use crate::try_or_return_with_snapshot; use crate::{error::Reject, service::TxPoolService}; use ckb_chain_spec::consensus::Consensus; use ckb_error::Error; +use ckb_logger::info; use ckb_snapshot::Snapshot; use ckb_store::data_loader_wrapper::AsDataLoader; use ckb_traits::{CellDataProvider, ExtensionProvider, HeaderProvider}; @@ -21,6 +22,7 @@ use std::sync::Arc; use tokio::sync::watch; use tokio::sync::RwLock; use tokio::task::block_in_place; +use tokio_util::sync::CancellationToken; const MIN_STEP_CYCLE: Cycle = 10_000_000; @@ -41,15 +43,15 @@ enum State { pub(crate) struct ChunkProcess { service: TxPoolService, recv: watch::Receiver, - signal: watch::Receiver, current_state: ChunkCommand, + signal: CancellationToken, } impl ChunkProcess { pub fn new( service: TxPoolService, recv: watch::Receiver, - signal: watch::Receiver, + signal: CancellationToken, ) -> Self { ChunkProcess { service, @@ -73,7 +75,10 @@ impl ChunkProcess { } } }, - _ = self.signal.changed() => break, + _ = self.signal.cancelled() => { + info!("TxPool received exit signal, exit now"); + break + }, _ = interval.tick() => { if matches!(self.current_state, ChunkCommand::Resume) { let stop = self.try_process().await; @@ -136,7 +141,7 @@ impl ChunkProcess { let mut tmp_state: Option = None; let completed: Cycle = loop { - if self.signal.has_changed().unwrap_or(false) { + if self.signal.is_cancelled() { return Ok(State::Stopped); } if self.recv.has_changed().unwrap_or(false) { diff --git a/tx-pool/src/process.rs b/tx-pool/src/process.rs index 678a9fbad5..0013d5cf33 100644 --- a/tx-pool/src/process.rs +++ b/tx-pool/src/process.rs @@ -916,7 +916,7 @@ impl TxPoolService { } } - pub(crate) async fn save_pool(&mut self) { + pub(crate) async fn save_pool(&self) { let mut tx_pool = self.tx_pool.write().await; if let Err(err) = tx_pool.save_into_file() { error!("failed to save pool, error: {:?}", err) diff --git a/tx-pool/src/service.rs b/tx-pool/src/service.rs index a4184809a1..f405129201 100644 --- a/tx-pool/src/service.rs +++ b/tx-pool/src/service.rs @@ -17,7 +17,7 @@ use ckb_logger::error; use ckb_logger::info; use ckb_network::{NetworkController, PeerIndex}; use ckb_snapshot::Snapshot; -use ckb_stop_handler::{SignalSender, StopHandler, WATCH_INIT}; +use ckb_stop_handler::new_tokio_exit_rx; use ckb_types::core::tx_pool::{TransactionWithStatus, TxStatus}; use ckb_types::{ core::{ @@ -37,6 +37,7 @@ use std::time::Duration; use tokio::sync::watch; use tokio::sync::{mpsc, RwLock}; use tokio::task::block_in_place; +use tokio_util::sync::CancellationToken; #[cfg(feature = "internal")] use crate::{component::entry::TxEntry, process::PlugTarget}; @@ -128,18 +129,9 @@ pub struct TxPoolController { reorg_sender: mpsc::Sender>, chunk_tx: Arc>, handle: Handle, - stop: StopHandler<()>, started: Arc, } -impl Drop for TxPoolController { - fn drop(&mut self) { - if self.service_started() { - self.stop.try_send(()); - } - } -} - macro_rules! send_message { ($self:ident, $msg_type:ident, $args:expr) => {{ let (responder, response) = oneshot::channel(); @@ -378,7 +370,7 @@ pub struct TxPoolServiceBuilder { pub(crate) callbacks: Callbacks, pub(crate) receiver: mpsc::Receiver, pub(crate) reorg_receiver: mpsc::Receiver>, - pub(crate) signal_receiver: watch::Receiver, + pub(crate) signal_receiver: CancellationToken, pub(crate) handle: Handle, pub(crate) tx_relay_sender: ckb_channel::Sender, pub(crate) chunk_rx: watch::Receiver, @@ -403,22 +395,16 @@ impl TxPoolServiceBuilder { let (sender, receiver) = mpsc::channel(DEFAULT_CHANNEL_SIZE); let block_assembler_channel = mpsc::channel(BLOCK_ASSEMBLER_CHANNEL_SIZE); let (reorg_sender, reorg_receiver) = mpsc::channel(DEFAULT_CHANNEL_SIZE); - let (signal_sender, signal_receiver) = watch::channel(WATCH_INIT); + let signal_receiver: CancellationToken = new_tokio_exit_rx(); let (chunk_tx, chunk_rx) = watch::channel(ChunkCommand::Resume); let chunk = Arc::new(RwLock::new(ChunkQueue::new())); let started = Arc::new(AtomicBool::new(false)); - let stop = StopHandler::new( - SignalSender::Watch(signal_sender), - None, - "tx-pool".to_string(), - ); let controller = TxPoolController { sender, reorg_sender, handle: handle.clone(), chunk_tx: Arc::new(chunk_tx), - stop, started: Arc::clone(&started), }; @@ -515,7 +501,7 @@ impl TxPoolServiceBuilder { let handle_clone = self.handle.clone(); let process_service = service.clone(); - let mut signal_receiver = self.signal_receiver.clone(); + let signal_receiver = self.signal_receiver.clone(); self.handle.spawn(async move { loop { tokio::select! { @@ -523,7 +509,11 @@ impl TxPoolServiceBuilder { let service_clone = process_service.clone(); handle_clone.spawn(process(service_clone, message)); }, - _ = signal_receiver.changed() => break, + _ = signal_receiver.cancelled() => { + info!("TxPool is saving, please wait..."); + process_service.save_pool().await; + break + }, else => break, } } @@ -531,7 +521,7 @@ impl TxPoolServiceBuilder { let process_service = service.clone(); if let Some(ref block_assembler) = service.block_assembler { - let mut signal_receiver = self.signal_receiver.clone(); + let signal_receiver = self.signal_receiver.clone(); let interval = Duration::from_millis(block_assembler.config.update_interval_millis); if interval.is_zero() { // block_assembler.update_interval_millis set zero interval should only be used for tests, @@ -547,7 +537,10 @@ impl TxPoolServiceBuilder { let service_clone = process_service.clone(); block_assembler::process(service_clone, &message).await; }, - _ = signal_receiver.changed() => break, + _ = signal_receiver.cancelled() => { + info!("TxPool received exit signal, exit now"); + break + }, else => break, } } @@ -579,7 +572,10 @@ impl TxPoolServiceBuilder { } queue.clear(); } - _ = signal_receiver.changed() => break, + _ = signal_receiver.cancelled() => { + info!("TxPool received exit signal, exit now"); + break + }, else => break, } } @@ -587,7 +583,7 @@ impl TxPoolServiceBuilder { } } - let mut signal_receiver = self.signal_receiver; + let signal_receiver = self.signal_receiver; self.handle.spawn(async move { loop { tokio::select! { @@ -614,7 +610,10 @@ impl TxPoolServiceBuilder { service.update_block_assembler_after_tx_pool_reorg().await; }, - _ = signal_receiver.changed() => break, + _ = signal_receiver.cancelled() => { + info!("TxPool received exit signal, exit now"); + break + }, else => break, } } diff --git a/util/channel/src/lib.rs b/util/channel/src/lib.rs index 90755a11f3..a250f5f104 100644 --- a/util/channel/src/lib.rs +++ b/util/channel/src/lib.rs @@ -1,7 +1,7 @@ //! Reexports `crossbeam_channel` to uniform the dependency version. pub use crossbeam_channel::{ - bounded, select, unbounded, Receiver, RecvError, RecvTimeoutError, Select, SendError, Sender, - TrySendError, + after, bounded, select, tick, unbounded, Receiver, RecvError, RecvTimeoutError, Select, + SendError, Sender, TrySendError, }; pub mod oneshot { diff --git a/util/indexer/src/service.rs b/util/indexer/src/service.rs index d104eb3646..ef8f876aee 100644 --- a/util/indexer/src/service.rs +++ b/util/indexer/src/service.rs @@ -7,7 +7,7 @@ use crate::store::{IteratorDirection, RocksdbStore, SecondaryDB, Store}; use crate::error::Error; use ckb_app_config::{DBConfig, IndexerConfig}; use ckb_async_runtime::{ - tokio::{self, sync::watch, time}, + tokio::{self, time}, Handle, }; use ckb_db_schema::{COLUMN_BLOCK_BODY, COLUMN_BLOCK_HEADER, COLUMN_INDEX, COLUMN_META}; @@ -18,7 +18,7 @@ use ckb_jsonrpc_types::{ }; use ckb_logger::{error, info}; use ckb_notify::NotifyController; -use ckb_stop_handler::{SignalSender, StopHandler, WATCH_INIT}; +use ckb_stop_handler::{new_tokio_exit_rx, CancellationToken}; use ckb_store::ChainStore; use ckb_types::{core, packed, prelude::*, H256}; use rocksdb::{prelude::*, Direction, IteratorMode}; @@ -39,8 +39,6 @@ pub struct IndexerService { pool: Option>>, poll_interval: Duration, async_handle: Handle, - stop_handler: StopHandler<()>, - stop: watch::Receiver, block_filter: Option, cell_filter: Option, } @@ -48,13 +46,6 @@ pub struct IndexerService { impl IndexerService { /// Construct new Indexer service instance from DBConfig and IndexerConfig pub fn new(ckb_db_config: &DBConfig, config: &IndexerConfig, async_handle: Handle) -> Self { - let (stop_sender, stop) = watch::channel(WATCH_INIT); - let stop_handler = StopHandler::new( - SignalSender::Watch(stop_sender), - None, - "indexer".to_string(), - ); - let store_opts = Self::indexer_store_options(config); let store = RocksdbStore::new(&store_opts, &config.store); let pool = if config.index_tx_pool { @@ -82,8 +73,6 @@ impl IndexerService { secondary_db, pool, async_handle, - stop_handler, - stop, poll_interval: Duration::from_secs(config.poll_interval), block_filter: config.block_filter.clone(), cell_filter: config.cell_filter.clone(), @@ -98,14 +87,13 @@ impl IndexerService { IndexerHandle { store: self.store.clone(), pool: self.pool.clone(), - stop_handler: self.stop_handler.clone(), } } /// Processes that handle index pool transaction and expect to be spawned to run in tokio runtime pub fn index_tx_pool(&self, notify_controller: NotifyController) { let service = self.clone(); - let mut stop = self.stop.clone(); + let stop: CancellationToken = new_tokio_exit_rx(); self.async_handle.spawn(async move { let mut new_transaction_receiver = notify_controller @@ -129,7 +117,10 @@ impl IndexerService { .transaction_rejected(&tx_entry.transaction); } } - _ = stop.changed() => break, + _ = stop.cancelled() => { + info!("Indexer received exit signal, exit now"); + break + }, else => break, } } @@ -183,7 +174,7 @@ impl IndexerService { let initial_syncing = self .async_handle .spawn_blocking(move || initial_service.try_loop_sync()); - let mut stop = self.stop.clone(); + let stop: CancellationToken = new_tokio_exit_rx(); let async_handle = self.async_handle.clone(); let poll_service = self.clone(); self.async_handle.spawn(async move { @@ -212,7 +203,10 @@ impl IndexerService { error!("ckb indexer syncing join error {:?}", e); } } - _ = stop.changed() => break, + _ = stop.cancelled() => { + info!("Indexer received exit signal, exit now"); + break + }, } } }); @@ -262,13 +256,6 @@ impl IndexerService { pub struct IndexerHandle { pub(crate) store: RocksdbStore, pub(crate) pool: Option>>, - stop_handler: StopHandler<()>, -} - -impl Drop for IndexerHandle { - fn drop(&mut self) { - self.stop_handler.try_send(()); - } } impl IndexerHandle { @@ -984,11 +971,9 @@ mod tests { let store = new_store("rpc"); let pool = Arc::new(RwLock::new(Pool::default())); let indexer = Indexer::new(store.clone(), 10, 100, None, CustomFilters::new(None, None)); - let stop_handler = StopHandler::new(SignalSender::Dummy, None, "indexer-test".to_string()); let rpc = IndexerHandle { store, pool: Some(Arc::clone(&pool)), - stop_handler, }; // setup test data @@ -1573,12 +1558,7 @@ mod tests { fn script_search_mode_rpc() { let store = new_store("script_search_mode_rpc"); let indexer = Indexer::new(store.clone(), 10, 100, None, CustomFilters::new(None, None)); - let stop_handler = StopHandler::new(SignalSender::Dummy, None, "indexer-test".to_string()); - let rpc = IndexerHandle { - store, - pool: None, - stop_handler, - }; + let rpc = IndexerHandle { store, pool: None }; // setup test data let lock_script1 = ScriptBuilder::default() diff --git a/util/launcher/Cargo.toml b/util/launcher/Cargo.toml index d9577d93db..aafb19269a 100644 --- a/util/launcher/Cargo.toml +++ b/util/launcher/Cargo.toml @@ -39,7 +39,6 @@ ckb-freezer = { path = "../../freezer", version = "= 0.111.0-rc8" } ckb-notify = { path = "../../notify", version = "= 0.111.0-rc8" } ckb-snapshot = { path = "../snapshot", version = "= 0.111.0-rc8" } ckb-tx-pool = { path = "../../tx-pool", version = "= 0.111.0-rc8" } -ckb-stop-handler = { path = "../stop-handler", version = "= 0.111.0-rc8" } ckb-light-client-protocol-server = { path = "../light-client-protocol-server", version = "= 0.111.0-rc8" } ckb-block-filter = { path = "../../block-filter", version = "= 0.111.0-rc8" } ckb-hash = { path = "../hash", version = "= 0.111.0-rc8" } diff --git a/util/launcher/src/lib.rs b/util/launcher/src/lib.rs index 96259acb5b..ad56947f35 100644 --- a/util/launcher/src/lib.rs +++ b/util/launcher/src/lib.rs @@ -23,15 +23,15 @@ use ckb_jsonrpc_types::ScriptHashType; use ckb_light_client_protocol_server::LightClientProtocol; use ckb_logger::info; use ckb_network::{ - observe_listen_port_occupancy, CKBProtocol, DefaultExitHandler, Flags, NetworkController, - NetworkService, NetworkState, SupportProtocols, + observe_listen_port_occupancy, CKBProtocol, Flags, NetworkController, NetworkService, + NetworkState, SupportProtocols, }; use ckb_network_alert::alert_relayer::AlertRelayer; use ckb_proposal_table::ProposalTable; use ckb_resource::Resource; use ckb_rpc::{RpcServer, ServiceBuilder}; use ckb_shared::Shared; -use ckb_stop_handler::StopHandler; + use ckb_store::{ChainDB, ChainStore}; use ckb_sync::{BlockFilter, NetTimeProtocol, Relayer, SyncShared, Synchronizer}; use ckb_tx_pool::service::TxVerificationResult; @@ -250,7 +250,7 @@ impl Launcher { } /// start block filter service - pub fn start_block_filter(&self, shared: &Shared) -> Option> { + pub fn start_block_filter(&self, shared: &Shared) { if self .args .config @@ -258,9 +258,7 @@ impl Launcher { .support_protocols .contains(&SupportProtocol::Filter) { - Some(BlockFilterService::new(shared.clone()).start()) - } else { - None + BlockFilterService::new(shared.clone()).start(); } } @@ -269,7 +267,6 @@ impl Launcher { &self, shared: &Shared, chain_controller: ChainController, - exit_handler: &DefaultExitHandler, miner_enable: bool, relay_tx_receiver: Receiver, ) -> (NetworkController, RpcServer) { @@ -383,7 +380,6 @@ impl Launcher { self.version.to_string(), flags, ), - exit_handler.clone(), ) .start(shared.async_handle()) .expect("Start network service failed"); diff --git a/util/launcher/src/shared_builder.rs b/util/launcher/src/shared_builder.rs index 7c1a096953..09f9fd862c 100644 --- a/util/launcher/src/shared_builder.rs +++ b/util/launcher/src/shared_builder.rs @@ -19,7 +19,7 @@ use ckb_proposal_table::ProposalTable; use ckb_proposal_table::ProposalView; use ckb_shared::Shared; use ckb_snapshot::{Snapshot, SnapshotMgr}; -use ckb_stop_handler::StopHandler; + use ckb_store::ChainDB; use ckb_store::ChainStore; use ckb_tx_pool::{ @@ -151,7 +151,7 @@ impl SharedBuilder { thread_local! { // NOTICE:we can't put the runtime directly into thread_local here, // on windows the runtime in thread_local will get stuck when dropping - static RUNTIME_HANDLE: unsync::OnceCell<(Handle, StopHandler<()>)> = unsync::OnceCell::new(); + static RUNTIME_HANDLE: unsync::OnceCell = unsync::OnceCell::new(); } static DB_COUNT: AtomicUsize = AtomicUsize::new(0); @@ -177,11 +177,7 @@ impl SharedBuilder { notify_config: None, store_config: None, block_assembler_config: None, - async_handle: runtime - .borrow() - .get_or_init(new_background_runtime) - .0 - .clone(), + async_handle: runtime.borrow().get_or_init(new_background_runtime).clone(), }) } } diff --git a/util/light-client-protocol-server/src/tests/utils/chain.rs b/util/light-client-protocol-server/src/tests/utils/chain.rs index a87805c486..fcfd483a86 100644 --- a/util/light-client-protocol-server/src/tests/utils/chain.rs +++ b/util/light-client-protocol-server/src/tests/utils/chain.rs @@ -9,7 +9,7 @@ use ckb_chain_spec::consensus::{build_genesis_epoch_ext, ConsensusBuilder}; use ckb_dao_utils::genesis_dao_data; use ckb_jsonrpc_types::ScriptHashType; use ckb_launcher::SharedBuilder; -use ckb_network::{DefaultExitHandler, Flags, NetworkController, NetworkService, NetworkState}; +use ckb_network::{Flags, NetworkController, NetworkService, NetworkState}; use ckb_shared::Shared; use ckb_systemtime::unix_time_as_millis; use ckb_test_chain_utils::always_success_cell; @@ -242,7 +242,6 @@ fn dummy_network(shared: &Shared) -> NetworkController { "test".to_string(), Flags::all(), ), - DefaultExitHandler::default(), ) .start(shared.async_handle()) .expect("Start network service failed") diff --git a/util/metrics-service/Cargo.toml b/util/metrics-service/Cargo.toml index cb757ee005..7dd9ff098f 100644 --- a/util/metrics-service/Cargo.toml +++ b/util/metrics-service/Cargo.toml @@ -16,3 +16,4 @@ ckb-async-runtime = { path = "../runtime", version = "= 0.111.0-rc8" } ckb-util = { path = "..", version = "= 0.111.0-rc8" } prometheus = "0.13.3" hyper = { version = "0.14", features = ["http1", "tcp", "server"] } +ckb-stop-handler = { path = "../stop-handler", version = "= 0.111.0-rc8" } diff --git a/util/metrics-service/src/lib.rs b/util/metrics-service/src/lib.rs index 6d7fb3ebfc..1b88171de0 100644 --- a/util/metrics-service/src/lib.rs +++ b/util/metrics-service/src/lib.rs @@ -10,7 +10,9 @@ use hyper::{ use prometheus::Encoder as _; use ckb_async_runtime::Handle; +use ckb_logger::info; use ckb_metrics_config::{Config, Exporter, Target}; +use ckb_stop_handler::{new_tokio_exit_rx, CancellationToken}; use ckb_util::strings; /// Ensures the metrics service can shutdown gracefully. @@ -59,7 +61,13 @@ fn run_exporter(exporter: Exporter, handle: &Handle) -> Result<(), String> { }); ckb_logger::info!("start prometheus exporter at {}", addr); handle.spawn(async move { - let server = Server::bind(&addr).serve(make_svc); + let server = Server::bind(&addr) + .serve(make_svc) + .with_graceful_shutdown(async { + let exit_rx: CancellationToken = new_tokio_exit_rx(); + exit_rx.cancelled().await; + info!("prometheus server received exit signal, exit now"); + }); if let Err(err) = server.await { ckb_logger::error!("prometheus server error: {}", err); } diff --git a/util/network-alert/Cargo.toml b/util/network-alert/Cargo.toml index 747236dcd4..4a3cfeaa99 100644 --- a/util/network-alert/Cargo.toml +++ b/util/network-alert/Cargo.toml @@ -25,7 +25,6 @@ semver = "1.0" [dev-dependencies] ckb-crypto = { path = "../crypto", version = "= 0.111.0-rc8" } ckb-async-runtime = { path = "../runtime", version = "= 0.111.0-rc8" } -ckb-stop-handler = { path = "../stop-handler", version = "= 0.111.0-rc8" } once_cell = "1.8.0" ckb-systemtime = {path = "../systemtime", version = "= 0.111.0-rc8", features = ["enable_faketime"]} faster-hex = "0.6" diff --git a/util/network-alert/src/tests/test_notifier.rs b/util/network-alert/src/tests/test_notifier.rs index 6b6a1f9bd8..fc793dc5e8 100644 --- a/util/network-alert/src/tests/test_notifier.rs +++ b/util/network-alert/src/tests/test_notifier.rs @@ -1,7 +1,7 @@ use crate::notifier::Notifier; use ckb_async_runtime::{new_background_runtime, Handle}; use ckb_notify::NotifyService; -use ckb_stop_handler::StopHandler; + use ckb_types::{packed, prelude::*}; use once_cell::unsync; use std::borrow::Borrow; @@ -27,17 +27,13 @@ fn new_notifier(version: &str) -> Notifier { thread_local! { // NOTICE:we can't put the runtime directly into thread_local here, // on windows the runtime in thread_local will get stuck when dropping - static RUNTIME_HANDLE: unsync::OnceCell<(Handle, StopHandler<()>)> = unsync::OnceCell::new(); + static RUNTIME_HANDLE: unsync::OnceCell = unsync::OnceCell::new(); } let notify_controller = RUNTIME_HANDLE.with(|runtime| { NotifyService::new( Default::default(), - runtime - .borrow() - .get_or_init(new_background_runtime) - .0 - .clone(), + runtime.borrow().get_or_init(new_background_runtime).clone(), ) .start() }); diff --git a/util/runtime/Cargo.toml b/util/runtime/Cargo.toml index 3cf4c0d88b..0588089a23 100644 --- a/util/runtime/Cargo.toml +++ b/util/runtime/Cargo.toml @@ -10,6 +10,5 @@ repository = "https://github.com/nervosnetwork/ckb" [dependencies] tokio = { version = "1", features = ["full"] } -ckb-stop-handler = { path = "../stop-handler", version = "= 0.111.0-rc8" } ckb-logger = { path = "../logger", version = "= 0.111.0-rc8" } ckb-spawn = { path = "../spawn", version = "= 0.111.0-rc8" } diff --git a/util/runtime/src/lib.rs b/util/runtime/src/lib.rs index 6984ded8e4..17a60a9d53 100644 --- a/util/runtime/src/lib.rs +++ b/util/runtime/src/lib.rs @@ -1,17 +1,17 @@ //! Utilities for tokio runtime. use ckb_spawn::Spawn; -use ckb_stop_handler::{SignalSender, StopHandler}; use core::future::Future; use std::sync::atomic::{AtomicU32, Ordering}; -use std::thread; + use tokio::runtime::Builder; use tokio::runtime::Handle as TokioHandle; -use tokio::sync::oneshot; + use tokio::task::JoinHandle; pub use tokio; pub use tokio::runtime::Runtime; +use tokio::sync::mpsc::{Receiver, Sender}; // Handle is a newtype wrap and unwrap tokio::Handle, it is workaround with Rust Orphan Rules. // We need `Handle` impl ckb spawn trait decouple tokio dependence @@ -20,6 +20,19 @@ pub use tokio::runtime::Runtime; #[derive(Debug, Clone)] pub struct Handle { pub(crate) inner: TokioHandle, + guard: Option>, +} + +impl Handle { + /// Create a new Handle + pub fn new(inner: TokioHandle, guard: Option>) -> Self { + Self { inner, guard } + } + + /// Drop the guard + pub fn drop_guard(&mut self) { + let _ = self.guard.take(); + } } impl Handle { @@ -42,7 +55,15 @@ impl Handle { F: Future + Send + 'static, F::Output: Send + 'static, { - self.inner.spawn(future) + let tokio_task_guard = self.guard.clone(); + + self.inner.spawn(async move { + // move tokio_task_guard into the spawned future + // so that it will be dropped when the future is finished + let _guard = tokio_task_guard; + + future.await + }) } /// Run a future to completion on the Tokio runtime from a synchronous context. @@ -101,32 +122,31 @@ fn new_runtime() -> Runtime { } /// Create new threaded_scheduler tokio Runtime, return `Runtime` -pub fn new_global_runtime() -> (Handle, Runtime) { +pub fn new_global_runtime() -> (Handle, Receiver<()>, Runtime) { let runtime = new_runtime(); let handle = runtime.handle().clone(); + let (guard, handle_stop_rx): (Sender<()>, Receiver<()>) = tokio::sync::mpsc::channel::<()>(1); - (Handle { inner: handle }, runtime) + (Handle::new(handle, Some(guard)), handle_stop_rx, runtime) } /// Create new threaded_scheduler tokio Runtime, return `Handle` and background thread join handle, /// NOTICE: This is only used in testing -pub fn new_background_runtime() -> (Handle, StopHandler<()>) { +pub fn new_background_runtime() -> Handle { let runtime = new_runtime(); let handle = runtime.handle().clone(); - let (tx, rx) = oneshot::channel(); - let thread = thread::Builder::new() + let (guard, mut handle_stop_rx): (Sender<()>, Receiver<()>) = + tokio::sync::mpsc::channel::<()>(1); + let _thread = std::thread::Builder::new() .name("GlobalRtBuilder".to_string()) .spawn(move || { - let ret = runtime.block_on(rx); + let ret = runtime.block_on(async move { handle_stop_rx.recv().await }); ckb_logger::debug!("global runtime finish {:?}", ret); }) .expect("tokio runtime started"); - ( - Handle { inner: handle }, - StopHandler::new(SignalSender::Tokio(tx), Some(thread), "GT".to_string()), - ) + Handle::new(handle, Some(guard)) } impl Spawn for Handle { diff --git a/util/stop-handler/Cargo.toml b/util/stop-handler/Cargo.toml index 1d300c494a..2245ddfdcf 100644 --- a/util/stop-handler/Cargo.toml +++ b/util/stop-handler/Cargo.toml @@ -9,7 +9,16 @@ homepage = "https://github.com/nervosnetwork/ckb" repository = "https://github.com/nervosnetwork/ckb" [dependencies] -parking_lot = "0.12" ckb-logger = { path = "../logger", version = "= 0.111.0-rc8" } tokio = { version = "1", features = ["sync", "rt-multi-thread"] } ckb-channel = { path = "../channel", version = "= 0.111.0-rc8" } +ckb-util = { path = "..", version = "= 0.111.0-rc8" } +once_cell = "1.8.0" +ckb-async-runtime = { path = "../runtime", version = "= 0.111.0-rc8" } +tokio-util = "0.7.8" + + +[dev-dependencies] +ctrlc = { version = "3.1", features = ["termination"] } +libc = "0.2" +rand = "0.8.5" From daefd226f8ffa1fc6c51f05fd9e39c23f3ff819c Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 20 Jun 2023 17:04:55 +0800 Subject: [PATCH 20/47] exit when `ProtocolHandleErrorKind::AbnormallyClosed` received Signed-off-by: Eval EXEC --- network/src/network.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/network/src/network.rs b/network/src/network.rs index 89bc527652..eaf3f7576b 100644 --- a/network/src/network.rs +++ b/network/src/network.rs @@ -654,6 +654,7 @@ impl ServiceHandle for EventHandler { ) }, ); + error!("ProtocolHandleError: AbnormallyClosed, proto_id: {opt_session_id:?}, session id: {opt_session_id:?}"); broadcast_exit_signals(); } From 5108122270e360ad337650d767259f47c74a779d Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 20 Jun 2023 17:55:56 +0800 Subject: [PATCH 21/47] Fix BlockDownload thread exit Signed-off-by: Eval EXEC --- sync/src/synchronizer/mod.rs | 104 ++++++++++++++----------- util/stop-handler/src/stop_register.rs | 20 +++-- 2 files changed, 71 insertions(+), 53 deletions(-) diff --git a/sync/src/synchronizer/mod.rs b/sync/src/synchronizer/mod.rs index a2ab6cf46b..7341ce4bc8 100644 --- a/sync/src/synchronizer/mod.rs +++ b/sync/src/synchronizer/mod.rs @@ -27,6 +27,7 @@ use crate::{Status, StatusCode}; use ckb_chain::chain::ChainController; use ckb_channel as channel; +use ckb_channel::{select, Receiver}; use ckb_constant::sync::{ BAD_MESSAGE_BAN_TIME, CHAIN_SYNC_TIMEOUT, EVICTION_HEADERS_RESPONSE_TIME, INIT_BLOCKS_IN_TRANSIT_PER_PEER, MAX_TIP_AGE, @@ -37,7 +38,7 @@ use ckb_network::{ async_trait, bytes::Bytes, tokio, CKBProtocolContext, CKBProtocolHandler, PeerIndex, ServiceControl, SupportProtocols, }; -use ckb_stop_handler::register_thread; +use ckb_stop_handler::{new_crossbeam_exit_rx, register_thread}; use ckb_systemtime::unix_time_as_millis; use ckb_types::{ core::{self, BlockNumber}, @@ -87,58 +88,70 @@ struct BlockFetchCMD { } impl BlockFetchCMD { - fn run(&mut self) { - while let Ok(cmd) = self.recv.recv() { - match cmd { - FetchCMD::Fetch((peers, state)) => match self.can_start() { - CanStart::Ready => { - for peer in peers { - if let Some(fetch) = BlockFetcher::new(&self.sync, peer, state).fetch() - { - for item in fetch { - BlockFetchCMD::send_getblocks(item, &self.p2p_control, peer); - } + fn process_fetch_cmd(&mut self, cmd: FetchCMD) { + match cmd { + FetchCMD::Fetch((peers, state)) => match self.can_start() { + CanStart::Ready => { + for peer in peers { + if let Some(fetch) = BlockFetcher::new(&self.sync, peer, state).fetch() { + for item in fetch { + BlockFetchCMD::send_getblocks(item, &self.p2p_control, peer); } } } - CanStart::MinWorkNotReach => { - let best_known = self.sync.shared.state().shared_best_header_ref(); - let number = best_known.number(); - if number != self.number && (number - self.number) % 10000 == 0 { - self.number = number; - info!( - "best known header number: {}, total difficulty: {:#x}, \ + } + CanStart::MinWorkNotReach => { + let best_known = self.sync.shared.state().shared_best_header_ref(); + let number = best_known.number(); + if number != self.number && (number - self.number) % 10000 == 0 { + self.number = number; + info!( + "best known header number: {}, total difficulty: {:#x}, \ require min header number on 500_000, min total difficulty: {:#x}, \ then start to download block", - number, - best_known.total_difficulty(), - self.sync.shared.state().min_chain_work() - ); - } + number, + best_known.total_difficulty(), + self.sync.shared.state().min_chain_work() + ); } - CanStart::AssumeValidNotFound => { - let state = self.sync.shared.state(); - let best_known = state.shared_best_header_ref(); - let number = best_known.number(); - let assume_valid_target: Byte32 = state - .assume_valid_target() - .as_ref() - .map(Pack::pack) - .expect("assume valid target must exist"); - - if number != self.number && (number - self.number) % 10000 == 0 { - self.number = number; - info!( - "best known header number: {}, hash: {:#?}, \ + } + CanStart::AssumeValidNotFound => { + let state = self.sync.shared.state(); + let best_known = state.shared_best_header_ref(); + let number = best_known.number(); + let assume_valid_target: Byte32 = state + .assume_valid_target() + .as_ref() + .map(Pack::pack) + .expect("assume valid target must exist"); + + if number != self.number && (number - self.number) % 10000 == 0 { + self.number = number; + info!( + "best known header number: {}, hash: {:#?}, \ can't find assume valid target temporarily, hash: {:#?} \ please wait", - number, - best_known.hash(), - assume_valid_target - ); - } + number, + best_known.hash(), + assume_valid_target + ); } - }, + } + }, + } + } + fn run(&mut self, stop_signal: Receiver<()>) { + loop { + select! { + recv(self.recv) -> msg => { + if let Ok(cmd) = msg { + self.process_fetch_cmd(cmd) + } + } + recv(stop_signal) -> _ => { + info!("thread BlockDownload received exit signal, exit now"); + return; + } } } } @@ -630,6 +643,7 @@ impl Synchronizer { let blockdownload_jh = thread .name(THREAD_NAME.into()) .spawn(move || { + let stop_signal = new_crossbeam_exit_rx(); BlockFetchCMD { sync, p2p_control, @@ -637,7 +651,7 @@ impl Synchronizer { number, can_start: CanStart::MinWorkNotReach, } - .run(); + .run(stop_signal); }) .expect("download thread can't start"); register_thread(THREAD_NAME, blockdownload_jh); diff --git a/util/stop-handler/src/stop_register.rs b/util/stop-handler/src/stop_register.rs index e329565ae8..e496866383 100644 --- a/util/stop-handler/src/stop_register.rs +++ b/util/stop-handler/src/stop_register.rs @@ -1,4 +1,5 @@ -use ckb_logger::{info, trace, warn}; +use ckb_channel::TrySendError; +use ckb_logger::{error, info, trace, warn}; use ckb_util::Mutex; use tokio_util::sync::CancellationToken; @@ -54,13 +55,16 @@ pub fn new_crossbeam_exit_rx() -> ckb_channel::Receiver<()> { /// Broadcast exit signals to all threads and all tokio tasks pub fn broadcast_exit_signals() { TOKIO_EXIT.cancel(); - CROSSBEAM_EXIT_SENDERS.lock().iter().for_each(|tx| { - if let Err(e) = tx.try_send(()) { - println!("broadcast thread: ERROR: {:?}", e) - } else { - println!("send a crossbeam exit signal"); - } - }); + CROSSBEAM_EXIT_SENDERS + .lock() + .iter() + .for_each(|tx| match tx.try_send(()) { + Ok(_) => {} + Err(TrySendError::Full(_)) => error!("send exit signal to channel failed since the channel is full, this should not happen"), + Err(TrySendError::Disconnected(_)) => { + info!("broadcast thread: channel is disconnected") + } + }); } /// Register a thread `JoinHandle` to `CKB_HANDLES` From 8358b268ba056f2541a66d75d376c490ace22d8e Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Mon, 26 Jun 2023 10:48:38 +0800 Subject: [PATCH 22/47] Re-order ckb workspace members --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b280ac8d31..d6b1cb20d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,8 +40,8 @@ members = [ "util/occupied-capacity/macros", "util/fixed-hash/macros", "util/logger-service", - "util/stop-handler", "util/runtime", + "util/stop-handler", "util/metrics", "util/metrics-service", "util/fixed-hash", From 37f2482aa5a824c039709f62d9e69226cd68b9c7 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Mon, 3 Jul 2023 15:34:48 +0800 Subject: [PATCH 23/47] Fix bats test for ckb run Signed-off-by: Eval EXEC --- util/app-config/src/tests/ckb_run_replay.bats | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/app-config/src/tests/ckb_run_replay.bats b/util/app-config/src/tests/ckb_run_replay.bats index 6ca4dd5405..dc9f87ef18 100644 --- a/util/app-config/src/tests/ckb_run_replay.bats +++ b/util/app-config/src/tests/ckb_run_replay.bats @@ -24,7 +24,7 @@ function ckb_run { #@test run _ckb_run [ "$status" -eq 0 ] # assert_output --regexp "ckb_chain::chain.*block number:.*, hash:.*, size:.*, cycles:.*" - assert_output --regexp "ckb_bin::subcommand::run Finishing work, please wait" + assert_output --regexp "ckb_bin all tokio tasks have been stopped" } function ckb_replay { #@test From e95b8c70a621a2307b68623a3ed93c0bab1cf638 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Wed, 12 Jul 2023 09:31:05 +0800 Subject: [PATCH 24/47] Only catch exit signal for `ckb run` --- ckb-bin/src/lib.rs | 33 ++++++++------------------------- ckb-bin/src/subcommand/run.rs | 7 ++++++- notify/src/lib.rs | 8 ++++---- 3 files changed, 18 insertions(+), 30 deletions(-) diff --git a/ckb-bin/src/lib.rs b/ckb-bin/src/lib.rs index 91c61b813d..c8373224d7 100644 --- a/ckb-bin/src/lib.rs +++ b/ckb-bin/src/lib.rs @@ -10,10 +10,8 @@ use ckb_async_runtime::new_global_runtime; use ckb_build_info::Version; use ckb_logger::info; use ckb_network::tokio; -use ckb_stop_handler::broadcast_exit_signals; use helper::raise_fd_limit; use setup_guard::SetupGuard; -use std::sync::Arc; #[cfg(feature = "with_sentry")] pub(crate) const LOG_TARGET_SENTRY: &str = "sentry"; @@ -66,18 +64,6 @@ pub fn run_app(version: Version) -> Result<(), ExitCode> { raise_fd_limit(); - // indicate whether the process is terminated by an exit signal - let caught_exit_signal = Arc::new(std::sync::atomic::AtomicBool::new(false)); - - ctrlc::set_handler({ - let caught_exit_signal = Arc::clone(&caught_exit_signal); - move || { - broadcast_exit_signals(); - caught_exit_signal.store(true, std::sync::atomic::Ordering::SeqCst); - } - }) - .expect("Error setting Ctrl-C handler"); - let ret = match cmd { cli::CMD_RUN => subcommand::run(setup.run(matches)?, version, handle.clone()), cli::CMD_MINER => subcommand::miner(setup.miner(matches)?, handle.clone()), @@ -90,18 +76,15 @@ pub fn run_app(version: Version) -> Result<(), ExitCode> { _ => unreachable!(), }; - if !caught_exit_signal.load(std::sync::atomic::Ordering::SeqCst) { - // if `subcommand` finish normally, and we didn't catch exit signal, broadcast exit signals - broadcast_exit_signals(); - } - - handle.drop_guard(); + if matches!(cmd, cli::CMD_RUN) { + handle.drop_guard(); - tokio::task::block_in_place(|| { - info!("waiting all tokio tasks done"); - handle_stop_rx.blocking_recv(); - info!("all tokio tasks have been stopped"); - }); + tokio::task::block_in_place(|| { + info!("waiting all tokio tasks done"); + handle_stop_rx.blocking_recv(); + info!("all tokio tasks have been stopped"); + }); + } ret } diff --git a/ckb-bin/src/subcommand/run.rs b/ckb-bin/src/subcommand/run.rs index cd7d8c6282..2ce70792b9 100644 --- a/ckb-bin/src/subcommand/run.rs +++ b/ckb-bin/src/subcommand/run.rs @@ -4,7 +4,7 @@ use ckb_async_runtime::Handle; use ckb_build_info::Version; use ckb_launcher::Launcher; use ckb_logger::info; -use ckb_stop_handler::wait_all_ckb_services_exit; +use ckb_stop_handler::{broadcast_exit_signals, wait_all_ckb_services_exit}; use ckb_types::core::cell::setup_system_cell_cache; @@ -55,6 +55,11 @@ pub fn run(args: RunArgs, version: Version, async_handle: Handle) -> Result<(), let tx_pool_builder = pack.take_tx_pool_builder(); tx_pool_builder.start(network_controller.non_owning_clone()); + ctrlc::set_handler(|| { + broadcast_exit_signals(); + }) + .expect("Error setting Ctrl-C handler"); + wait_all_ckb_services_exit(); Ok(()) diff --git a/notify/src/lib.rs b/notify/src/lib.rs index 2b9969ba96..b6a0172a8a 100644 --- a/notify/src/lib.rs +++ b/notify/src/lib.rs @@ -166,10 +166,6 @@ impl NotifyService { handle.spawn(async move { loop { tokio::select! { - _ = signal_receiver.cancelled() => { - info!("NotifyService received exit signal, exit now"); - break; - } Some(msg) = new_block_register_receiver.recv() => { self.handle_register_new_block(msg) }, Some(msg) = new_block_watcher_receiver.recv() => { self.handle_watch_new_block(msg) }, Some(msg) = new_block_receiver.recv() => { self.handle_notify_new_block(msg) }, @@ -181,6 +177,10 @@ impl NotifyService { Some(msg) = reject_transaction_receiver.recv() => { self.handle_notify_reject_transaction(msg) }, Some(msg) = network_alert_register_receiver.recv() => { self.handle_register_network_alert(msg) }, Some(msg) = network_alert_receiver.recv() => { self.handle_notify_network_alert(msg) }, + _ = signal_receiver.cancelled() => { + info!("NotifyService received exit signal, exit now"); + break; + } else => break, } } From 7012fbabc6cad90835c84b70d70176d9b46c4e38 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Wed, 12 Jul 2023 09:54:28 +0800 Subject: [PATCH 25/47] Use debug level to print exit signal log --- block-filter/src/filter.rs | 4 ++-- chain/src/chain.rs | 8 ++++---- ckb-bin/src/helper.rs | 4 ++-- ckb-bin/src/lib.rs | 6 +++--- ckb-bin/src/subcommand/run.rs | 1 + miner/src/client.rs | 8 ++++---- miner/src/miner.rs | 2 +- network/src/network.rs | 2 +- notify/src/lib.rs | 4 ++-- sync/src/synchronizer/mod.rs | 2 +- sync/src/tests/synchronizer/functions.rs | 2 -- sync/src/types/header_map/mod.rs | 4 ++-- tx-pool/src/chunk_process.rs | 10 +++++----- tx-pool/src/process.rs | 2 ++ tx-pool/src/service.rs | 8 ++++---- util/indexer/src/service.rs | 6 +++--- util/metrics-service/src/lib.rs | 4 ++-- util/stop-handler/src/stop_register.rs | 8 ++++---- 18 files changed, 43 insertions(+), 42 deletions(-) diff --git a/block-filter/src/filter.rs b/block-filter/src/filter.rs index 56fcc92f6b..04e8a6566b 100644 --- a/block-filter/src/filter.rs +++ b/block-filter/src/filter.rs @@ -1,5 +1,5 @@ use ckb_async_runtime::tokio::{self, task::block_in_place}; -use ckb_logger::{debug, info, warn}; +use ckb_logger::{debug, warn}; use ckb_shared::Shared; use ckb_stop_handler::{new_tokio_exit_rx, CancellationToken}; use ckb_store::{ChainDB, ChainStore}; @@ -63,7 +63,7 @@ impl BlockFilter { new_block_watcher.borrow_and_update(); } _ = stop_rx.cancelled() => { - info!("BlockFilter received exit signal, exit now"); + debug!("BlockFilter received exit signal, exit now"); break }, else => break, diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 8f7e5d8e3c..3323492032 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -243,10 +243,6 @@ impl ChainService { let chain_jh = thread_builder .spawn(move || loop { select! { - recv(signal_receiver) -> _ => { - info!("ChainService received exit signal, stopped"); - break; - }, recv(process_block_receiver) -> msg => match msg { Ok(Request { responder, arguments: (block, verify) }) => { let _ = tx_control.suspend_chunk_process(); @@ -268,6 +264,10 @@ impl ChainService { error!("truncate_receiver closed"); break; }, + }, + recv(signal_receiver) -> _ => { + debug!("ChainService received exit signal, exit now"); + break; } } }) diff --git a/ckb-bin/src/helper.rs b/ckb-bin/src/helper.rs index 21c93732b8..7dee9de15d 100644 --- a/ckb-bin/src/helper.rs +++ b/ckb-bin/src/helper.rs @@ -8,7 +8,7 @@ pub fn deadlock_detection() {} #[cfg(feature = "deadlock_detection")] pub fn deadlock_detection() { use ckb_channel::select; - use ckb_logger::warn; + use ckb_logger::{debug, warn}; use ckb_stop_handler::{new_crossbeam_exit_rx, register_thread}; use ckb_util::parking_lot::deadlock; use std::{thread, time::Duration}; @@ -36,7 +36,7 @@ pub fn deadlock_detection() { }, recv(stop_rx) -> _ =>{ - info!("deadlock_detection received exit signal, stopped"); + debug!("deadlock_detection received exit signal, stopped"); return; } } diff --git a/ckb-bin/src/lib.rs b/ckb-bin/src/lib.rs index c8373224d7..8596f504d0 100644 --- a/ckb-bin/src/lib.rs +++ b/ckb-bin/src/lib.rs @@ -8,7 +8,7 @@ mod subcommand; use ckb_app_config::{cli, ExitCode, Setup}; use ckb_async_runtime::new_global_runtime; use ckb_build_info::Version; -use ckb_logger::info; +use ckb_logger::{debug, info}; use ckb_network::tokio; use helper::raise_fd_limit; use setup_guard::SetupGuard; @@ -80,9 +80,9 @@ pub fn run_app(version: Version) -> Result<(), ExitCode> { handle.drop_guard(); tokio::task::block_in_place(|| { - info!("waiting all tokio tasks done"); + debug!("waiting all tokio tasks done"); handle_stop_rx.blocking_recv(); - info!("all tokio tasks have been stopped"); + info!("ckb shutdown"); }); } diff --git a/ckb-bin/src/subcommand/run.rs b/ckb-bin/src/subcommand/run.rs index 2ce70792b9..726a415944 100644 --- a/ckb-bin/src/subcommand/run.rs +++ b/ckb-bin/src/subcommand/run.rs @@ -56,6 +56,7 @@ pub fn run(args: RunArgs, version: Version, async_handle: Handle) -> Result<(), tx_pool_builder.start(network_controller.non_owning_clone()); ctrlc::set_handler(|| { + info!("Trapped exit signal, exiting..."); broadcast_exit_signals(); }) .expect("Error setting Ctrl-C handler"); diff --git a/miner/src/client.rs b/miner/src/client.rs index dda47570a7..c598f5af9a 100644 --- a/miner/src/client.rs +++ b/miner/src/client.rs @@ -4,7 +4,7 @@ use ckb_app_config::MinerClientConfig; use ckb_async_runtime::Handle; use ckb_channel::Sender; use ckb_jsonrpc_types::{Block as JsonBlock, BlockTemplate}; -use ckb_logger::{debug, error, info}; +use ckb_logger::{debug, error}; use ckb_stop_handler::{new_tokio_exit_rx, CancellationToken}; use ckb_types::{ packed::{Block, Byte32}, @@ -87,7 +87,7 @@ impl Rpc { }); }, _ = stop_rx.cancelled() => { - info!("Rpc server received exit signal, exit now"); + debug!("Rpc server received exit signal, exit now"); break }, else => break @@ -235,7 +235,7 @@ Otherwise ckb-miner does not work properly and will behave as it stopped committ let stop_rx: CancellationToken = new_tokio_exit_rx(); let graceful = server.with_graceful_shutdown(async move { stop_rx.cancelled().await; - info!("Miner client received exit signal, exit now"); + debug!("Miner client received exit signal, exit now"); }); if let Err(e) = graceful.await { @@ -255,7 +255,7 @@ Otherwise ckb-miner does not work properly and will behave as it stopped committ self.fetch_block_template().await; } _ = stop_rx.cancelled() => { - info!("Miner client pool_block_template received exit signal, exit now"); + debug!("Miner client pool_block_template received exit signal, exit now"); break }, else => break, diff --git a/miner/src/miner.rs b/miner/src/miner.rs index e14ffef72f..110fad5514 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -103,7 +103,7 @@ impl Miner { }, }, recv(stop_rx) -> _msg => { - info!("miner received exit signal, stopped"); + debug!("miner received exit signal, stopped"); break; } }; diff --git a/network/src/network.rs b/network/src/network.rs index eaf3f7576b..93bccc1a9f 100644 --- a/network/src/network.rs +++ b/network/src/network.rs @@ -1127,7 +1127,7 @@ impl NetworkService { loop { tokio::select! { _ = receiver.cancelled() => { - info!("NetworkService receive exit signal, start shutdown..."); + debug!("NetworkService receive exit signal, start shutdown..."); let _ = p2p_control.shutdown().await; // Drop senders to stop all corresponding background task drop(bg_signals); diff --git a/notify/src/lib.rs b/notify/src/lib.rs index b6a0172a8a..41d1451e04 100644 --- a/notify/src/lib.rs +++ b/notify/src/lib.rs @@ -1,7 +1,7 @@ //! TODO(doc): @quake use ckb_app_config::NotifyConfig; use ckb_async_runtime::Handle; -use ckb_logger::{debug, error, info, trace}; +use ckb_logger::{debug, error, trace}; use ckb_stop_handler::{new_tokio_exit_rx, CancellationToken}; use ckb_types::packed::Byte32; use ckb_types::{ @@ -178,7 +178,7 @@ impl NotifyService { Some(msg) = network_alert_register_receiver.recv() => { self.handle_register_network_alert(msg) }, Some(msg) = network_alert_receiver.recv() => { self.handle_notify_network_alert(msg) }, _ = signal_receiver.cancelled() => { - info!("NotifyService received exit signal, exit now"); + debug!("NotifyService received exit signal, exit now"); break; } else => break, diff --git a/sync/src/synchronizer/mod.rs b/sync/src/synchronizer/mod.rs index 7341ce4bc8..b348226560 100644 --- a/sync/src/synchronizer/mod.rs +++ b/sync/src/synchronizer/mod.rs @@ -149,7 +149,7 @@ impl BlockFetchCMD { } } recv(stop_signal) -> _ => { - info!("thread BlockDownload received exit signal, exit now"); + debug!("thread BlockDownload received exit signal, exit now"); return; } } diff --git a/sync/src/tests/synchronizer/functions.rs b/sync/src/tests/synchronizer/functions.rs index bd0a55740c..bbdd902a3d 100644 --- a/sync/src/tests/synchronizer/functions.rs +++ b/sync/src/tests/synchronizer/functions.rs @@ -1226,8 +1226,6 @@ fn test_internal_db_error() { InternalErrorKind::Database.other("mocked db error").into(), )); - faux::when!(chain_controller.try_stop()).then_return(()); - let synchronizer = Synchronizer::new(chain_controller, sync_shared); let status = synchronizer diff --git a/sync/src/types/header_map/mod.rs b/sync/src/types/header_map/mod.rs index 78939164b6..975c7b9075 100644 --- a/sync/src/types/header_map/mod.rs +++ b/sync/src/types/header_map/mod.rs @@ -1,5 +1,5 @@ use ckb_async_runtime::Handle; -use ckb_logger::info; +use ckb_logger::debug; use ckb_stop_handler::{new_tokio_exit_rx, CancellationToken}; use ckb_types::packed::Byte32; use std::sync::Arc; @@ -56,7 +56,7 @@ impl HeaderMap { map.limit_memory(); } _ = stop_rx.cancelled() => { - info!("HeaderMap limit_memory received exit signal, exit now"); + debug!("HeaderMap limit_memory received exit signal, exit now"); break }, } diff --git a/tx-pool/src/chunk_process.rs b/tx-pool/src/chunk_process.rs index b35e547a21..73e4f246eb 100644 --- a/tx-pool/src/chunk_process.rs +++ b/tx-pool/src/chunk_process.rs @@ -4,7 +4,7 @@ use crate::try_or_return_with_snapshot; use crate::{error::Reject, service::TxPoolService}; use ckb_chain_spec::consensus::Consensus; use ckb_error::Error; -use ckb_logger::info; +use ckb_logger::debug; use ckb_snapshot::Snapshot; use ckb_store::data_loader_wrapper::AsDataLoader; use ckb_traits::{CellDataProvider, ExtensionProvider, HeaderProvider}; @@ -75,10 +75,6 @@ impl ChunkProcess { } } }, - _ = self.signal.cancelled() => { - info!("TxPool received exit signal, exit now"); - break - }, _ = interval.tick() => { if matches!(self.current_state, ChunkCommand::Resume) { let stop = self.try_process().await; @@ -87,6 +83,10 @@ impl ChunkProcess { } } }, + _ = self.signal.cancelled() => { + debug!("TxPool received exit signal, exit now"); + break + }, else => break, } } diff --git a/tx-pool/src/process.rs b/tx-pool/src/process.rs index 0013d5cf33..b5062b3b35 100644 --- a/tx-pool/src/process.rs +++ b/tx-pool/src/process.rs @@ -920,6 +920,8 @@ impl TxPoolService { let mut tx_pool = self.tx_pool.write().await; if let Err(err) = tx_pool.save_into_file() { error!("failed to save pool, error: {:?}", err) + } else { + info!("TxPool save successfully") } } diff --git a/tx-pool/src/service.rs b/tx-pool/src/service.rs index f405129201..b11564ea11 100644 --- a/tx-pool/src/service.rs +++ b/tx-pool/src/service.rs @@ -13,8 +13,8 @@ use ckb_chain_spec::consensus::Consensus; use ckb_channel::oneshot; use ckb_error::AnyError; use ckb_jsonrpc_types::BlockTemplate; -use ckb_logger::error; use ckb_logger::info; +use ckb_logger::{debug, error}; use ckb_network::{NetworkController, PeerIndex}; use ckb_snapshot::Snapshot; use ckb_stop_handler::new_tokio_exit_rx; @@ -538,7 +538,7 @@ impl TxPoolServiceBuilder { block_assembler::process(service_clone, &message).await; }, _ = signal_receiver.cancelled() => { - info!("TxPool received exit signal, exit now"); + debug!("TxPool received exit signal, exit now"); break }, else => break, @@ -573,7 +573,7 @@ impl TxPoolServiceBuilder { queue.clear(); } _ = signal_receiver.cancelled() => { - info!("TxPool received exit signal, exit now"); + debug!("TxPool received exit signal, exit now"); break }, else => break, @@ -611,7 +611,7 @@ impl TxPoolServiceBuilder { service.update_block_assembler_after_tx_pool_reorg().await; }, _ = signal_receiver.cancelled() => { - info!("TxPool received exit signal, exit now"); + debug!("TxPool received exit signal, exit now"); break }, else => break, diff --git a/util/indexer/src/service.rs b/util/indexer/src/service.rs index ef8f876aee..bcdc89c7ce 100644 --- a/util/indexer/src/service.rs +++ b/util/indexer/src/service.rs @@ -16,7 +16,7 @@ use ckb_jsonrpc_types::{ IndexerScriptSearchMode, IndexerScriptType, IndexerSearchKey, IndexerTip, IndexerTx, IndexerTxWithCell, IndexerTxWithCells, JsonBytes, Uint32, }; -use ckb_logger::{error, info}; +use ckb_logger::{debug, error, info}; use ckb_notify::NotifyController; use ckb_stop_handler::{new_tokio_exit_rx, CancellationToken}; use ckb_store::ChainStore; @@ -118,7 +118,7 @@ impl IndexerService { } } _ = stop.cancelled() => { - info!("Indexer received exit signal, exit now"); + debug!("Indexer received exit signal, exit now"); break }, else => break, @@ -204,7 +204,7 @@ impl IndexerService { } } _ = stop.cancelled() => { - info!("Indexer received exit signal, exit now"); + debug!("Indexer received exit signal, exit now"); break }, } diff --git a/util/metrics-service/src/lib.rs b/util/metrics-service/src/lib.rs index 1b88171de0..4206a3d0aa 100644 --- a/util/metrics-service/src/lib.rs +++ b/util/metrics-service/src/lib.rs @@ -10,7 +10,7 @@ use hyper::{ use prometheus::Encoder as _; use ckb_async_runtime::Handle; -use ckb_logger::info; +use ckb_logger::debug; use ckb_metrics_config::{Config, Exporter, Target}; use ckb_stop_handler::{new_tokio_exit_rx, CancellationToken}; use ckb_util::strings; @@ -66,7 +66,7 @@ fn run_exporter(exporter: Exporter, handle: &Handle) -> Result<(), String> { .with_graceful_shutdown(async { let exit_rx: CancellationToken = new_tokio_exit_rx(); exit_rx.cancelled().await; - info!("prometheus server received exit signal, exit now"); + debug!("prometheus server received exit signal, exit now"); }); if let Err(err) = server.await { ckb_logger::error!("prometheus server error: {}", err); diff --git a/util/stop-handler/src/stop_register.rs b/util/stop-handler/src/stop_register.rs index e496866383..8948217c19 100644 --- a/util/stop-handler/src/stop_register.rs +++ b/util/stop-handler/src/stop_register.rs @@ -1,5 +1,5 @@ use ckb_channel::TrySendError; -use ckb_logger::{error, info, trace, warn}; +use ckb_logger::{debug, error, info, trace, warn}; use ckb_util::Mutex; use tokio_util::sync::CancellationToken; @@ -12,19 +12,19 @@ pub fn wait_all_ckb_services_exit() { info!("waiting exit signal..."); let exit_signal = new_crossbeam_exit_rx(); let _ = exit_signal.recv(); - info!("received exit signal, broadcasting exit signal to all threads"); + debug!("received exit signal, broadcasting exit signal to all threads"); let mut handles = CKB_HANDLES.lock(); for (name, join_handle) in handles.thread_handles.drain(..) { match join_handle.join() { Ok(_) => { - info!("wait thread {} done", name); + debug!("wait thread {} done", name); } Err(e) => { warn!("wait thread {}: ERROR: {:?}", name, e) } } } - info!("all ckb threads have been stopped"); + debug!("all ckb threads have been stopped"); } static CKB_HANDLES: once_cell::sync::Lazy> = From c4aca9ad3a5660b4c65c39b10388d124bbba0692 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Wed, 12 Jul 2023 09:59:50 +0800 Subject: [PATCH 26/47] Add exit handler for `ckb miner` --- ckb-bin/src/subcommand/miner.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ckb-bin/src/subcommand/miner.rs b/ckb-bin/src/subcommand/miner.rs index fd9a892abc..0bc7312e42 100644 --- a/ckb-bin/src/subcommand/miner.rs +++ b/ckb-bin/src/subcommand/miner.rs @@ -1,8 +1,11 @@ use ckb_app_config::{ExitCode, MinerArgs, MinerConfig}; use ckb_async_runtime::Handle; use ckb_channel::unbounded; +use ckb_logger::info; use ckb_miner::{Client, Miner}; -use ckb_stop_handler::{new_crossbeam_exit_rx, register_thread, wait_all_ckb_services_exit}; +use ckb_stop_handler::{ + broadcast_exit_signals, new_crossbeam_exit_rx, register_thread, wait_all_ckb_services_exit, +}; use std::thread; pub fn miner(args: MinerArgs, async_handle: Handle) -> Result<(), ExitCode> { @@ -30,6 +33,12 @@ pub fn miner(args: MinerArgs, async_handle: Handle) -> Result<(), ExitCode> { .expect("Start client failed!"); register_thread(THREAD_NAME, miner_jh); + ctrlc::set_handler(|| { + info!("Trapped exit signal, exiting..."); + broadcast_exit_signals(); + }) + .expect("Error setting Ctrl-C handler"); + wait_all_ckb_services_exit(); Ok(()) From ba6a5dfe9499cf23fe3720261413c8daf2e915e8 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Wed, 12 Jul 2023 10:45:47 +0800 Subject: [PATCH 27/47] Add bats test for graceful shutdown Signed-off-by: Eval EXEC --- util/app-config/src/tests/ckb_run_replay.bats | 2 +- util/app-config/src/tests/cli_test.sh | 4 +- .../src/tests/graceful_shutdown.bats | 45 +++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 util/app-config/src/tests/graceful_shutdown.bats diff --git a/util/app-config/src/tests/ckb_run_replay.bats b/util/app-config/src/tests/ckb_run_replay.bats index dc9f87ef18..c6943eeb5b 100644 --- a/util/app-config/src/tests/ckb_run_replay.bats +++ b/util/app-config/src/tests/ckb_run_replay.bats @@ -24,7 +24,7 @@ function ckb_run { #@test run _ckb_run [ "$status" -eq 0 ] # assert_output --regexp "ckb_chain::chain.*block number:.*, hash:.*, size:.*, cycles:.*" - assert_output --regexp "ckb_bin all tokio tasks have been stopped" + assert_output --regexp "ckb_bin ckb shutdown" } function ckb_replay { #@test diff --git a/util/app-config/src/tests/cli_test.sh b/util/app-config/src/tests/cli_test.sh index 56e30dbab8..707b2b1dea 100755 --- a/util/app-config/src/tests/cli_test.sh +++ b/util/app-config/src/tests/cli_test.sh @@ -38,7 +38,7 @@ bash ${CKB_BATS_CORE_DIR}/bats-assert/load.bash cd ${CKB_BATS_TESTBED} -./ckb init --force && ./ckb import ckb_mainnet_4000.json +./ckb init --force && sed -i 's/filter = "info"/filter = "debug"/g' ckb.toml && ./ckb import ckb_mainnet_4000.json export PATH=${CKB_BATS_TESTBED}:/tmp/ckb_bats_bin/tmp_install/bin:${PATH} export BATS_LIB_PATH=${CKB_BATS_CORE_DIR} @@ -47,7 +47,7 @@ export TMP_DIR=${CKB_BATS_TESTBED}/tmp_dir mkdir ${TMP_DIR} for bats_cases in *.bats; do - bats --trace "$bats_cases" + bats "$bats_cases" ret=$? if [ "$ret" -ne "0" ]; then exit "$ret" diff --git a/util/app-config/src/tests/graceful_shutdown.bats b/util/app-config/src/tests/graceful_shutdown.bats new file mode 100644 index 0000000000..eb906c3949 --- /dev/null +++ b/util/app-config/src/tests/graceful_shutdown.bats @@ -0,0 +1,45 @@ +#!/usr/bin/env bats +bats_load_library 'bats-assert' +bats_load_library 'bats-support' + +_ckb_graceful_shutdown() { + ckb run -C ${CKB_DIRNAME} &> ${TMP_DIR}/ckb_run.log & + PID=$! + sleep 10 + kill ${PID} + + while kill -0 ${PID}; do + echo "waiting for ckb to exit" + sleep 1 + done + + tail -n 500 ${TMP_DIR}/ckb_run.log +} + +function ckb_graceful_shutdown { #@test + run _ckb_graceful_shutdown + + [ "$status" -eq 0 ] + assert_output --regexp "INFO ckb_bin::subcommand::run Trapped exit signal, exiting..." + assert_output --regexp "DEBUG ckb_stop_handler::stop_register received exit signal, broadcasting exit signal to all threads" + assert_output --regexp "DEBUG ckb_tx_pool::chunk_process TxPool received exit signal, exit now" + assert_output --regexp "DEBUG ckb_sync::types::header_map HeaderMap limit_memory received exit signal, exit now" + assert_output --regexp "DEBUG ckb_chain::chain ChainService received exit signal, exit now" + assert_output --regexp "DEBUG ckb_sync::synchronizer thread BlockDownload received exit signal, exit now" + assert_output --regexp "DEBUG ckb_network::network NetworkService receive exit signal, start shutdown..." + assert_output --regexp "INFO ckb_tx_pool::service TxPool is saving, please wait..." + assert_output --regexp "DEBUG ckb_tx_pool::service TxPool received exit signal, exit now" + assert_output --regexp "DEBUG ckb_block_filter::filter BlockFilter received exit signal, exit now" + assert_output --regexp "DEBUG ckb_network::services::dump_peer_store dump peer store before exit" + assert_output --regexp "DEBUG ckb_notify NotifyService received exit signal, exit now" + assert_output --regexp "DEBUG ckb_stop_handler::stop_register wait thread ChainService done" + assert_output --regexp "DEBUG ckb_stop_handler::stop_register wait thread BlockDownload done" + assert_output --regexp "DEBUG ckb_stop_handler::stop_register all ckb threads have been stopped" + assert_output --regexp "DEBUG ckb_bin waiting all tokio tasks done" + assert_output --regexp "INFO ckb_tx_pool::process TxPool save successfully" + assert_output --regexp "INFO ckb_bin ckb shutdown" +} + +teardown_file() { + rm -f ${TMP_DIR}/ckb_run.log +} From 6936766f529bc0edbcf385a8021a2cd7a5271a26 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 18 Jul 2023 16:12:23 +0800 Subject: [PATCH 28/47] fix: set `TxPoolService.started` to `true` before `tx_pool_controller.load_persisted_data` --- tx-pool/src/service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tx-pool/src/service.rs b/tx-pool/src/service.rs index b11564ea11..5dc54018b4 100644 --- a/tx-pool/src/service.rs +++ b/tx-pool/src/service.rs @@ -618,10 +618,10 @@ impl TxPoolServiceBuilder { } } }); + self.started.store(true, Ordering::Relaxed); if let Err(err) = self.tx_pool_controller.load_persisted_data(txs) { error!("Failed to import persisted txs, cause: {}", err); } - self.started.store(true, Ordering::Relaxed); } } From 437f13daa59acb9c89aad23778172e348b068a72 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 18 Jul 2023 17:42:34 +0800 Subject: [PATCH 29/47] Add `winapi` dep to `dev-dependencies` --- Cargo.lock | 1 + util/stop-handler/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 4011129135..96c6bb6469 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1292,6 +1292,7 @@ dependencies = [ "rand 0.8.5", "tokio", "tokio-util 0.7.8", + "winapi 0.3.9", ] [[package]] diff --git a/util/stop-handler/Cargo.toml b/util/stop-handler/Cargo.toml index 2245ddfdcf..62da631172 100644 --- a/util/stop-handler/Cargo.toml +++ b/util/stop-handler/Cargo.toml @@ -21,4 +21,5 @@ tokio-util = "0.7.8" [dev-dependencies] ctrlc = { version = "3.1", features = ["termination"] } libc = "0.2" +winapi = "0.3.9" rand = "0.8.5" From 142e4bf21424d8d1b0deea9e3c9683f86bd019e3 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 18 Jul 2023 17:43:04 +0800 Subject: [PATCH 30/47] Fix unit test: handle windows platform for signal-handle Signed-off-by: Eval EXEC --- util/stop-handler/src/tests.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/util/stop-handler/src/tests.rs b/util/stop-handler/src/tests.rs index 3141512bb7..099aa32b90 100644 --- a/util/stop-handler/src/tests.rs +++ b/util/stop-handler/src/tests.rs @@ -13,7 +13,18 @@ use tokio_util::sync::CancellationToken; fn send_ctrlc_later(duration: Duration) { std::thread::spawn(move || { std::thread::sleep(duration); - // send SIGINT to myself + + // send CTRL_C event to myself on windows platform + #[cfg(windows)] + { + let pid = std::process::id(); + unsafe { + winapi::um::wincon::GenerateConsoleCtrlEvent(winapi::um::wincon::CTRL_C_EVENT, pid); + } + } + + // send SIGINT to myself on Linux and MacOS platform + #[cfg(not(windows))] unsafe { libc::raise(libc::SIGINT); println!("[ $$ sent SIGINT to myself $$ ]"); From e019245e70d488fd72585e55485fe53200f753f6 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Mon, 17 Jul 2023 11:17:52 +0800 Subject: [PATCH 31/47] docs: Fix `PendingCompactBlockMap` comment --- sync/src/types/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync/src/types/mod.rs b/sync/src/types/mod.rs index d00fcf137a..73ce7935d0 100644 --- a/sync/src/types/mod.rs +++ b/sync/src/types/mod.rs @@ -1269,7 +1269,7 @@ fn get_skip_height(height: BlockNumber) -> BlockNumber { } } -// , timestamp)> +// , Vec)>, timestamp)> pub(crate) type PendingCompactBlockMap = HashMap< Byte32, ( From 9019a454994d1f1dd0bfbdf5f234b5ad507e263d Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 18 Jul 2023 22:40:11 +0800 Subject: [PATCH 32/47] Remove stop-handler unit test for Windows platform --- Cargo.lock | 1 - util/stop-handler/Cargo.toml | 1 - util/stop-handler/src/lib.rs | 3 ++- util/stop-handler/src/tests.rs | 11 +---------- 4 files changed, 3 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96c6bb6469..4011129135 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1292,7 +1292,6 @@ dependencies = [ "rand 0.8.5", "tokio", "tokio-util 0.7.8", - "winapi 0.3.9", ] [[package]] diff --git a/util/stop-handler/Cargo.toml b/util/stop-handler/Cargo.toml index 62da631172..2245ddfdcf 100644 --- a/util/stop-handler/Cargo.toml +++ b/util/stop-handler/Cargo.toml @@ -21,5 +21,4 @@ tokio-util = "0.7.8" [dev-dependencies] ctrlc = { version = "3.1", features = ["termination"] } libc = "0.2" -winapi = "0.3.9" rand = "0.8.5" diff --git a/util/stop-handler/src/lib.rs b/util/stop-handler/src/lib.rs index fe80839dd3..48309b03e5 100644 --- a/util/stop-handler/src/lib.rs +++ b/util/stop-handler/src/lib.rs @@ -8,5 +8,6 @@ pub use stop_register::{ pub use tokio_util::sync::CancellationToken; mod stop_register; -#[cfg(test)] + +#[cfg(all(test, unix))] mod tests; diff --git a/util/stop-handler/src/tests.rs b/util/stop-handler/src/tests.rs index 099aa32b90..f45c200a83 100644 --- a/util/stop-handler/src/tests.rs +++ b/util/stop-handler/src/tests.rs @@ -14,17 +14,7 @@ fn send_ctrlc_later(duration: Duration) { std::thread::spawn(move || { std::thread::sleep(duration); - // send CTRL_C event to myself on windows platform - #[cfg(windows)] - { - let pid = std::process::id(); - unsafe { - winapi::um::wincon::GenerateConsoleCtrlEvent(winapi::um::wincon::CTRL_C_EVENT, pid); - } - } - // send SIGINT to myself on Linux and MacOS platform - #[cfg(not(windows))] unsafe { libc::raise(libc::SIGINT); println!("[ $$ sent SIGINT to myself $$ ]"); @@ -120,6 +110,7 @@ impl TestStopMemo { } } } + #[test] fn basic() { let (mut handle, mut stop_recv, _runtime) = new_global_runtime(); From 75b05b296f799e05fe1129e633b7c1f80cbe35a9 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 18 Jul 2023 18:54:56 +0800 Subject: [PATCH 33/47] docs: note the `send_transaction` is asynchronous --- rpc/src/module/pool.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rpc/src/module/pool.rs b/rpc/src/module/pool.rs index d2832c734b..dfd4d9531d 100644 --- a/rpc/src/module/pool.rs +++ b/rpc/src/module/pool.rs @@ -16,6 +16,10 @@ pub trait PoolRpc { /// Submits a new transaction into the transaction pool. If the transaction is already in the /// pool, rebroadcast it to peers. /// + /// Please note that `send_transaction` is an asynchronous process. + /// The return of `send_transaction` does NOT indicate that the transaction have been fully verified. + /// If you want to track the status of the transaction, please use the `get_transaction`rpc. + /// /// ## Params /// /// * `transaction` - The transaction. From ed2fb5fc6bec2ed2010bbe3510dd4357c02dbcf5 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 18 Jul 2023 18:55:28 +0800 Subject: [PATCH 34/47] docs: re-execute `make gen-rpc-doc` Signed-off-by: Eval EXEC --- rpc/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rpc/README.md b/rpc/README.md index 166d922b30..6db0bf3d40 100644 --- a/rpc/README.md +++ b/rpc/README.md @@ -4343,6 +4343,8 @@ RPC Module Pool for transaction memory pool. Submits a new transaction into the transaction pool. If the transaction is already in the pool, rebroadcast it to peers. +Please note that `send_transaction` is an asynchronous process. The return of `send_transaction` does NOT indicate that the transaction have been fully verified. If you want to track the status of the transaction, please use the `get_transaction`rpc. + ###### Params * `transaction` - The transaction. From 379b7adecf27df39a9ec600327a919328ab178bd Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 18 Jul 2023 19:20:45 +0800 Subject: [PATCH 35/47] terminate process when nonce limit reached --- miner/src/miner.rs | 4 +++- util/stop-handler/src/stop_register.rs | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 110fad5514..101f156b4d 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -5,6 +5,7 @@ use ckb_app_config::MinerWorkerConfig; use ckb_channel::{select, unbounded, Receiver}; use ckb_logger::{debug, error, info}; use ckb_pow::PowEngine; +use ckb_stop_handler::broadcast_exit_signals; use ckb_types::{ packed::{Byte32, Header}, prelude::*, @@ -94,7 +95,8 @@ impl Miner { Ok((pow_hash, work, nonce)) => { self.submit_nonce(pow_hash, work, nonce); if self.limit != 0 && self.nonces_found >= self.limit { - break; + debug!("miner nonce limit reached, terminate ..."); + broadcast_exit_signals(); } }, _ => { diff --git a/util/stop-handler/src/stop_register.rs b/util/stop-handler/src/stop_register.rs index 8948217c19..d7f2a7f560 100644 --- a/util/stop-handler/src/stop_register.rs +++ b/util/stop-handler/src/stop_register.rs @@ -12,8 +12,8 @@ pub fn wait_all_ckb_services_exit() { info!("waiting exit signal..."); let exit_signal = new_crossbeam_exit_rx(); let _ = exit_signal.recv(); - debug!("received exit signal, broadcasting exit signal to all threads"); let mut handles = CKB_HANDLES.lock(); + debug!("wait_all_ckb_services_exit wait all threads to exit"); for (name, join_handle) in handles.thread_handles.drain(..) { match join_handle.join() { Ok(_) => { @@ -54,6 +54,7 @@ pub fn new_crossbeam_exit_rx() -> ckb_channel::Receiver<()> { /// Broadcast exit signals to all threads and all tokio tasks pub fn broadcast_exit_signals() { + debug!("received exit signal, broadcasting exit signal to all threads"); TOKIO_EXIT.cancel(); CROSSBEAM_EXIT_SENDERS .lock() From 26764cefa15a1425cddb498680400a04f35b9c39 Mon Sep 17 00:00:00 2001 From: mohanson Date: Fri, 21 Jul 2023 13:35:26 +0800 Subject: [PATCH 36/47] Update ckb-vm to v0.24.4 --- Cargo.lock | 11 +++++++---- script/Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4011129135..3503b236b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1528,9 +1528,9 @@ dependencies = [ [[package]] name = "ckb-vm" -version = "0.24.3" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f5747a877a71ff164fa0f17daf6e9abca036c2381b8576679fb3ac07ae77bbc" +checksum = "40894adbde925bfc6584d324a06228e19d78bd877146fc7df085927552d29f50" dependencies = [ "byteorder", "bytes 1.4.0", @@ -1546,9 +1546,12 @@ dependencies = [ [[package]] name = "ckb-vm-definitions" -version = "0.24.3" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83869c9d322de1ddbfde5b54b7376f9a1ac32273c50e21cdd5e8a1bd1a1cf632" +checksum = "0253bdea8dc20db90b58fe54e01392f71989e0567d42e09e7f8e588f156551db" +dependencies = [ + "paste", +] [[package]] name = "clang-sys" diff --git a/script/Cargo.toml b/script/Cargo.toml index 708bd6fc58..da018ecfdb 100644 --- a/script/Cargo.toml +++ b/script/Cargo.toml @@ -22,7 +22,7 @@ ckb-traits = { path = "../traits", version = "= 0.111.0-rc8" } byteorder = "1.3.1" ckb-types = { path = "../util/types", version = "= 0.111.0-rc8" } ckb-hash = { path = "../util/hash", version = "= 0.111.0-rc8" } -ckb-vm = { version = "=0.24.3", default-features = false } +ckb-vm = { version = "=0.24.4", default-features = false } faster-hex = "0.6" ckb-logger = { path = "../util/logger", version = "= 0.111.0-rc8", optional = true } serde = { version = "1.0", features = ["derive"] } From 932834b17b5069000d2e91edd7ccf7571762f1e6 Mon Sep 17 00:00:00 2001 From: zhangsoledad <787953403@qq.com> Date: Fri, 28 Jul 2023 10:29:55 +0800 Subject: [PATCH 37/47] chore: light client activation parameters --- spec/src/consensus.rs | 2 +- spec/src/lib.rs | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/spec/src/consensus.rs b/spec/src/consensus.rs index 40dcec7449..4f39d87a77 100644 --- a/spec/src/consensus.rs +++ b/spec/src/consensus.rs @@ -92,7 +92,7 @@ pub(crate) const SATOSHI_PUBKEY_HASH: H160 = h160!("0x62e907b15cbf27d5425399ebf6 // only affects genesis cellbase's satoshi lock cells. pub(crate) const SATOSHI_CELL_OCCUPIED_RATIO: Ratio = Ratio::new(6, 10); -// pub(crate) const MAINNET_ACTIVATION_THRESHOLD: Ratio = Ratio::new(9, 10); +pub(crate) const LC_MAINNET_ACTIVATION_THRESHOLD: Ratio = Ratio::new(8, 10); pub(crate) const TESTNET_ACTIVATION_THRESHOLD: Ratio = Ratio::new(3, 4); /// The struct represent CKB two-step-transaction-confirmation params diff --git a/spec/src/lib.rs b/spec/src/lib.rs index 40f8560b2e..c08eb123e3 100644 --- a/spec/src/lib.rs +++ b/spec/src/lib.rs @@ -12,8 +12,8 @@ use crate::consensus::{ build_genesis_dao_data, build_genesis_epoch_ext, Consensus, ConsensusBuilder, - SATOSHI_CELL_OCCUPIED_RATIO, SATOSHI_PUBKEY_HASH, TESTNET_ACTIVATION_THRESHOLD, - TYPE_ID_CODE_HASH, + LC_MAINNET_ACTIVATION_THRESHOLD, SATOSHI_CELL_OCCUPIED_RATIO, SATOSHI_PUBKEY_HASH, + TESTNET_ACTIVATION_THRESHOLD, TYPE_ID_CODE_HASH, }; use crate::versionbits::{ActiveMode, Deployment, DeploymentPos}; use ckb_constant::hardfork::{mainnet, testnet}; @@ -506,7 +506,20 @@ impl ChainSpec { fn softfork_deployments(&self) -> Option> { match self.name.as_str() { - mainnet::CHAIN_SPEC_NAME => None, + mainnet::CHAIN_SPEC_NAME => { + let mut deployments = HashMap::new(); + let light_client = Deployment { + bit: 1, + start: 8_282, // 2023/09/01 00:00:00 utc + timeout: 8_552, // 8_282 + 270 + min_activation_epoch: 8_648, // 2023/11/01 00:00:00 utc + period: 42, + active_mode: ActiveMode::Normal, + threshold: LC_MAINNET_ACTIVATION_THRESHOLD, + }; + deployments.insert(DeploymentPos::LightClient, light_client); + Some(deployments) + } testnet::CHAIN_SPEC_NAME => { let mut deployments = HashMap::new(); let light_client = Deployment { From 769b681dac62b0de5bc76080be0c24b842a7f1dc Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 2 Aug 2023 12:21:21 +0800 Subject: [PATCH 38/47] add ctrl hander for test main --- test/Cargo.toml | 1 + test/src/main.rs | 36 ++++++++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/test/Cargo.toml b/test/Cargo.toml index d3ec359d14..57263cb189 100644 --- a/test/Cargo.toml +++ b/test/Cargo.toml @@ -37,6 +37,7 @@ serde_json = "1.0" lazy_static = "1.4.0" byteorder = "1.3.1" jsonrpc-core = "18.0" +ctrlc = { version = "3.1", features = ["termination"] } [target.'cfg(not(target_os="windows"))'.dependencies] nix = { version = "0.24.0", default-features = false, features = ["signal"] } diff --git a/test/src/main.rs b/test/src/main.rs index 0ef0feafff..227e2c0b0d 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -12,6 +12,7 @@ use clap::{App, Arg}; use rand::{seq::SliceRandom, thread_rng}; use std::any::Any; use std::cmp::min; +use std::collections::HashSet; use std::env; use std::fs::{self, read_to_string, File}; use std::io::{self, BufRead, BufReader, Write}; @@ -113,6 +114,8 @@ fn main() { info!("max time: {:?}", max_time); let specs = filter_specs(all_specs(), spec_names_to_run); + let running_spec_names = Arc::new(Mutex::new(HashSet::new())); + let total = specs.len(); let worker_count = min(worker_count, total); let specs = Arc::new(Mutex::new(specs)); @@ -122,6 +125,22 @@ fn main() { let (notify_tx, notify_rx) = unbounded(); + let cloned_running_names = running_spec_names.clone(); + ctrlc::set_handler(move || { + std::thread::sleep(Duration::from_secs(1)); + warn!( + "Total {} specs are not finished", + cloned_running_names.lock().len() + ); + for name in cloned_running_names.lock().iter() { + warn!("spec {} is still not finished", name); + } + // sleep 1 second to wait for the log flush + std::thread::sleep(Duration::from_secs(1)); + std::process::exit(1); + }) + .expect("Error setting Ctrl-C handler"); + info!("start {} workers...", worker_count); let mut workers = Workers::new(worker_count, Arc::clone(&specs), notify_tx, start_port); workers.start(); @@ -148,6 +167,7 @@ fn main() { match msg { Notify::Start { spec_name } => { info!("[{}] Start executing", spec_name); + running_spec_names.lock().insert(spec_name); } Notify::Error { spec_error, @@ -166,6 +186,7 @@ fn main() { workers.shutdown(); worker_running -= 1; } + running_spec_names.lock().remove(&spec_name); spec_errors.push(Some(spec_error)); if verbose { info!("[{}] Error", spec_name); @@ -189,6 +210,7 @@ fn main() { worker_running -= 1; } spec_errors.push(None); + running_spec_names.lock().remove(&spec_name); if verbose { info!("[{}] Panic", spec_name); print_panicked_logs(&node_log_paths); @@ -204,6 +226,7 @@ fn main() { status: TestResultStatus::Passed, duration: seconds, }); + running_spec_names.lock().remove(&spec_name); done_specs += 1; info!( "{}/{} .............. [{}] Done in {} seconds", @@ -222,6 +245,7 @@ fn main() { } } } + // join all workers threads workers.join_all(); @@ -294,8 +318,12 @@ fn clap_app() -> App<'static> { .value_name("SECONDS") .help("Exit when total running time exceeds this limit"), ) - .arg(Arg::with_name("list-specs").long("list-specs")) - .arg(Arg::with_name("specs").multiple(true)) + .arg( + Arg::with_name("list-specs") + .long("list-specs") + .help("list all specs"), + ) + .arg(Arg::with_name("specs").multiple(true).help("Specs to run")) .arg( Arg::with_name("concurrent") .short('c') @@ -626,13 +654,13 @@ fn log_failed_specs(error_spec_names: &[String]) -> Result<(), io::Error> { fn print_results(mut test_results: Vec) { println!("{}", "-".repeat(20)); - println!("{:50} | {:10} | {:10}", "TEST", "STATUS", "DURATION"); + println!("{:65} | {:10} | {:10}", "TEST", "STATUS", "DURATION"); test_results.sort_by(|a, b| (&a.status, a.duration).cmp(&(&b.status, b.duration))); for result in test_results.iter() { println!( - "{:50} | {:10} | {:<10}", + "{:65} | {:10} | {:<10}", result.spec_name, format!("{:?}", result.status), format!("{} s", result.duration), From ff0e470b014958ecf991ff39c19e6ac74664fa42 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 2 Aug 2023 12:25:10 +0800 Subject: [PATCH 39/47] fix the timeout issue in integeration main --- devtools/ci/ci_main.sh | 2 +- test/src/main.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/devtools/ci/ci_main.sh b/devtools/ci/ci_main.sh index c48a7382c6..377da7e939 100755 --- a/devtools/ci/ci_main.sh +++ b/devtools/ci/ci_main.sh @@ -51,7 +51,7 @@ case $GITHUB_WORKFLOW in if [[ $github_workflow_os == 'macos' ]]; then export CKB_FEATURES="deadlock_detection,with_sentry,portable" fi - make CKB_TEST_SEC_COEFFICIENT=5 CKB_TEST_ARGS="-c 4 --no-report" integration + make CKB_TEST_SEC_COEFFICIENT=5 CKB_TEST_ARGS="-c 4 --no-report --max-time 3600 " integration ;; ci_quick_checks*) echo "ci_quick_check" diff --git a/test/src/main.rs b/test/src/main.rs index 227e2c0b0d..f650e7ab35 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -125,7 +125,7 @@ fn main() { let (notify_tx, notify_rx) = unbounded(); - let cloned_running_names = running_spec_names.clone(); + let cloned_running_names = Arc::clone(&running_spec_names); ctrlc::set_handler(move || { std::thread::sleep(Duration::from_secs(1)); warn!( @@ -153,6 +153,7 @@ fn main() { if max_time > 0 && start_time.elapsed().as_secs() > max_time { // shutdown, specs running to long workers.shutdown(); + break; } let msg = match notify_rx.recv_timeout(Duration::from_secs(5)) { From 565d382cb82e019de106ecc46daaf36cf9311f90 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 2 Aug 2023 14:38:14 +0800 Subject: [PATCH 40/47] node start will not panic when child process crashed --- test/Cargo.toml | 1 + test/src/main.rs | 3 +-- test/src/node.rs | 7 ++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/test/Cargo.toml b/test/Cargo.toml index 57263cb189..283eb30871 100644 --- a/test/Cargo.toml +++ b/test/Cargo.toml @@ -38,6 +38,7 @@ lazy_static = "1.4.0" byteorder = "1.3.1" jsonrpc-core = "18.0" ctrlc = { version = "3.1", features = ["termination"] } +log = "0.4" [target.'cfg(not(target_os="windows"))'.dependencies] nix = { version = "0.24.0", default-features = false, features = ["signal"] } diff --git a/test/src/main.rs b/test/src/main.rs index f650e7ab35..02e09c809b 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -135,8 +135,7 @@ fn main() { for name in cloned_running_names.lock().iter() { warn!("spec {} is still not finished", name); } - // sleep 1 second to wait for the log flush - std::thread::sleep(Duration::from_secs(1)); + log::logger().flush(); std::process::exit(1); }) .expect("Error setting Ctrl-C handler"); diff --git a/test/src/node.rs b/test/src/node.rs index 50a8c8f21d..168370bcaa 100644 --- a/test/src/node.rs +++ b/test/src/node.rs @@ -22,7 +22,7 @@ use std::collections::HashSet; use std::convert::Into; use std::fs; use std::path::PathBuf; -use std::process::{self, Child, Command, Stdio}; +use std::process::{Child, Command, Stdio}; use std::thread::sleep; use std::time::{Duration, Instant}; @@ -609,7 +609,8 @@ impl Node { status, self.log_path().display() ); - process::exit(status.code().unwrap()); + // parent process will exit + return; } Err(error) => { error!( @@ -617,7 +618,7 @@ impl Node { error, self.log_path().display() ); - process::exit(255); + return; } } }; From 0dfb57f9774bf81091e29b786f0c2c1284707c71 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Fri, 4 Aug 2023 09:07:06 +0800 Subject: [PATCH 41/47] Increase integration CI timeout to 2 hours --- devtools/ci/ci_main.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/ci/ci_main.sh b/devtools/ci/ci_main.sh index 377da7e939..25623ed7f9 100755 --- a/devtools/ci/ci_main.sh +++ b/devtools/ci/ci_main.sh @@ -51,7 +51,7 @@ case $GITHUB_WORKFLOW in if [[ $github_workflow_os == 'macos' ]]; then export CKB_FEATURES="deadlock_detection,with_sentry,portable" fi - make CKB_TEST_SEC_COEFFICIENT=5 CKB_TEST_ARGS="-c 4 --no-report --max-time 3600 " integration + make CKB_TEST_SEC_COEFFICIENT=5 CKB_TEST_ARGS="-c 4 --no-report --max-time 7200 " integration ;; ci_quick_checks*) echo "ci_quick_check" From a4468af160276ab0e91d67ee927347214b9e97cd Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Fri, 4 Aug 2023 09:17:48 +0800 Subject: [PATCH 42/47] Print node Spec name when killed the node --- test/src/node.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/test/src/node.rs b/test/src/node.rs index 168370bcaa..143367a148 100644 --- a/test/src/node.rs +++ b/test/src/node.rs @@ -27,6 +27,7 @@ use std::thread::sleep; use std::time::{Duration, Instant}; struct ProcessGuard { + pub name: String, pub child: Child, pub killed: bool, } @@ -35,8 +36,8 @@ impl Drop for ProcessGuard { fn drop(&mut self) { if !self.killed { match self.child.kill() { - Err(e) => error!("Could not kill ckb process: {}", e), - Ok(_) => debug!("Successfully killed ckb process"), + Err(e) => error!("Could not kill ckb process ({}): {}", self.name, e), + Ok(_) => debug!("Successfully killed ckb process ({})", self.name), } let _ = self.child.wait(); } @@ -44,6 +45,7 @@ impl Drop for ProcessGuard { } pub struct Node { + spec_node_name: String, working_dir: PathBuf, consensus: Consensus, p2p_listen: String, @@ -74,8 +76,9 @@ impl Node { .unwrap_or_else(|_| panic!("cp {:?} {}", src.display(), dest.display())); } + let spec_node_name = format!("{}_{}", spec_name, node_name); // Allocate rpc port and p2p port, and fill into app config - let mut node = Self::init(working_dir); + let mut node = Self::init(working_dir, spec_node_name); node.modify_app_config(|app_config| { let rpc_port = find_available_port(); let p2p_port = find_available_port(); @@ -99,7 +102,7 @@ impl Node { modifier(&mut app_config); fs::write(&app_config_path, toml::to_string(&app_config).unwrap()).unwrap(); - *self = Self::init(self.working_dir()); + *self = Self::init(self.working_dir(), self.spec_node_name.clone()); } pub fn modify_chain_spec(&mut self, modifier: M) @@ -112,11 +115,11 @@ impl Node { modifier(&mut chain_spec); fs::write(&chain_spec_path, toml::to_string(&chain_spec).unwrap()).unwrap(); - *self = Self::init(self.working_dir()); + *self = Self::init(self.working_dir(), self.spec_node_name.clone()); } // Initialize Node instance based on working directory - fn init(working_dir: PathBuf) -> Self { + fn init(working_dir: PathBuf, spec_node_name: String) -> Self { let app_config = { let app_config_path = working_dir.join("ckb.toml"); let toml = fs::read(app_config_path).unwrap(); @@ -144,6 +147,7 @@ impl Node { chain_spec.build_consensus().unwrap() }; Self { + spec_node_name, working_dir, consensus, p2p_listen, @@ -626,6 +630,7 @@ impl Node { self.wait_tx_pool_ready(); self.guard = Some(ProcessGuard { + name: self.spec_node_name.clone(), child: child_process, killed: false, }); From 5f933965e2a0cfe7d2005bc9939f4868866e14d1 Mon Sep 17 00:00:00 2001 From: zhangsoledad <787953403@qq.com> Date: Wed, 9 Aug 2023 16:49:56 +0800 Subject: [PATCH 43/47] fix: data2 value --- rpc/README.md | 4 +- util/jsonrpc-types/src/blockchain.rs | 10 +- util/types/src/core/blockchain.rs | 13 +- util/types/src/core/tests/blockchain.rs | 4 +- util/types/src/extension/tests/check_data.rs | 133 ++++++++++--------- 5 files changed, 92 insertions(+), 72 deletions(-) diff --git a/rpc/README.md b/rpc/README.md index 6db0bf3d40..35de2c0e32 100644 --- a/rpc/README.md +++ b/rpc/README.md @@ -6681,10 +6681,12 @@ Describes the lock script and type script for a cell. Specifies how the script `code_hash` is used to match the script code and how to run the code. -Allowed kinds: “data”, “type” and “data1”. +Allowed kinds: “data”, “type”, “data1” and “data2” Refer to the section [Code Locating](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md#code-locating) and [Upgradable Script](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md#upgradable-script) in the RFC *CKB Transaction Structure*. +The hash type is split into the high 7 bits and the low 1 bit, when the low 1 bit is 1, it indicates the type, when the low 1 bit is 0, it indicates the data, and then it relies on the high 7 bits to indicate that the data actually corresponds to the version. + `ScriptHashType` is equivalent to `"data" | "type" | "data1" | "data2"`. * Type “data” matches script code via cell data hash, and run the script code in v0 CKB VM. diff --git a/util/jsonrpc-types/src/blockchain.rs b/util/jsonrpc-types/src/blockchain.rs index 8acaf95ce7..2df38a7959 100644 --- a/util/jsonrpc-types/src/blockchain.rs +++ b/util/jsonrpc-types/src/blockchain.rs @@ -13,11 +13,17 @@ use std::fmt; /// Specifies how the script `code_hash` is used to match the script code and how to run the code. /// -/// Allowed kinds: "data", "type" and "data1". +/// Allowed kinds: "data", "type", "data1" and “data2” /// /// Refer to the section [Code Locating](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md#code-locating) /// and [Upgradable Script](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md#upgradable-script) /// in the RFC *CKB Transaction Structure*. +/// +/// The hash type is split into the high 7 bits and the low 1 bit, +/// when the low 1 bit is 1, it indicates the type, +/// when the low 1 bit is 0, it indicates the data, +/// and then it relies on the high 7 bits to indicate +/// that the data actually corresponds to the version. #[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug)] #[serde(rename_all = "snake_case")] pub enum ScriptHashType { @@ -28,7 +34,7 @@ pub enum ScriptHashType { /// Type "data1" matches script code via cell data hash, and run the script code in v1 CKB VM. Data1 = 2, /// Type "data2" matches script code via cell data hash, and run the script code in v2 CKB VM. - Data2 = 3, + Data2 = 4, } impl Default for ScriptHashType { diff --git a/util/types/src/core/blockchain.rs b/util/types/src/core/blockchain.rs index b28a126433..7121bf09de 100644 --- a/util/types/src/core/blockchain.rs +++ b/util/types/src/core/blockchain.rs @@ -3,6 +3,11 @@ use ckb_error::OtherError; use crate::packed; /// Specifies how the script `code_hash` is used to match the script code and how to run the code. +/// The hash type is split into the high 7 bits and the low 1 bit, +/// when the low 1 bit is 1, it indicates the type, +/// when the low 1 bit is 0, it indicates the data, +/// and then it relies on the high 7 bits to indicate +/// that the data actually corresponds to the version. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum ScriptHashType { /// Type "data" matches script code via cell data hash, and run the script code in v0 CKB VM. @@ -12,7 +17,7 @@ pub enum ScriptHashType { /// Type "data1" matches script code via cell data hash, and run the script code in v1 CKB VM. Data1 = 2, /// Type "data2" matches script code via cell data hash, and run the script code in v2 CKB VM. - Data2 = 3, + Data2 = 4, } impl Default for ScriptHashType { @@ -29,7 +34,7 @@ impl TryFrom for ScriptHashType { 0 => Ok(ScriptHashType::Data), 1 => Ok(ScriptHashType::Type), 2 => Ok(ScriptHashType::Data1), - 3 => Ok(ScriptHashType::Data2), + 4 => Ok(ScriptHashType::Data2), _ => Err(OtherError::new(format!("Invalid script hash type {v}"))), } } @@ -46,7 +51,7 @@ impl TryFrom for ScriptHashType { impl ScriptHashType { #[inline] pub(crate) fn verify_value(v: u8) -> bool { - v <= 3 + v <= 4 && v != 3 } } @@ -57,7 +62,7 @@ impl Into for ScriptHashType { Self::Data => 0, Self::Type => 1, Self::Data1 => 2, - Self::Data2 => 3, + Self::Data2 => 4, } } } diff --git a/util/types/src/core/tests/blockchain.rs b/util/types/src/core/tests/blockchain.rs index 0fa63847de..2c37578c28 100644 --- a/util/types/src/core/tests/blockchain.rs +++ b/util/types/src/core/tests/blockchain.rs @@ -10,10 +10,10 @@ fn test_script_hash_type() { let default_value: u8 = default.into(); assert_eq!(default_value, 0); - let max_value = 3u8; + let max_value = 4u8; for v in 0..32 { let res = ScriptHashType::try_from(v); - if v <= max_value { + if v <= max_value && v != 3 { let value: u8 = res.unwrap().into(); assert_eq!(value, v); } else { diff --git a/util/types/src/extension/tests/check_data.rs b/util/types/src/extension/tests/check_data.rs index 05489411dd..e8f4943e42 100644 --- a/util/types/src/extension/tests/check_data.rs +++ b/util/types/src/extension/tests/check_data.rs @@ -29,74 +29,81 @@ fn test_check_data_via_transaction( #[test] fn check_data() { for ht in 0..4 { - for dt in 0..2 { - let ht_right = ht.into(); - let dt_right = dt.into(); - let ht_error = 4.into(); - let dt_error = 2.into(); + if ht != 3 { + for dt in 0..2 { + let ht_right = ht.into(); + let dt_right = dt.into(); + let ht_error = 3.into(); + let dt_error = 2.into(); - let script_right = packed::Script::new_builder().hash_type(ht_right).build(); - let script_error = packed::Script::new_builder().hash_type(ht_error).build(); + let script_right = packed::Script::new_builder().hash_type(ht_right).build(); + let script_error = packed::Script::new_builder().hash_type(ht_error).build(); - let script_opt_right = packed::ScriptOpt::new_builder() - .set(Some(script_right.clone())) - .build(); - let script_opt_error = packed::ScriptOpt::new_builder() - .set(Some(script_error.clone())) - .build(); + let script_opt_right = packed::ScriptOpt::new_builder() + .set(Some(script_right.clone())) + .build(); + let script_opt_error = packed::ScriptOpt::new_builder() + .set(Some(script_error.clone())) + .build(); - let output_right1 = packed::CellOutput::new_builder() - .lock(script_right.clone()) - .build(); - let output_right2 = packed::CellOutput::new_builder() - .type_(script_opt_right.clone()) - .build(); - let output_error1 = packed::CellOutput::new_builder() - .lock(script_error.clone()) - .build(); - let output_error2 = packed::CellOutput::new_builder() - .type_(script_opt_error.clone()) - .build(); - let output_error3 = packed::CellOutput::new_builder() - .lock(script_right) - .type_(script_opt_error) - .build(); - let output_error4 = packed::CellOutput::new_builder() - .lock(script_error) - .type_(script_opt_right) - .build(); + let output_right1 = packed::CellOutput::new_builder() + .lock(script_right.clone()) + .build(); + let output_right2 = packed::CellOutput::new_builder() + .type_(script_opt_right.clone()) + .build(); + let output_error1 = packed::CellOutput::new_builder() + .lock(script_error.clone()) + .build(); + let output_error2 = packed::CellOutput::new_builder() + .type_(script_opt_error.clone()) + .build(); + let output_error3 = packed::CellOutput::new_builder() + .lock(script_right) + .type_(script_opt_error) + .build(); + let output_error4 = packed::CellOutput::new_builder() + .lock(script_error) + .type_(script_opt_right) + .build(); - let cell_dep_right = packed::CellDep::new_builder().dep_type(dt_right).build(); - let cell_dep_error = packed::CellDep::new_builder().dep_type(dt_error).build(); + let cell_dep_right = packed::CellDep::new_builder().dep_type(dt_right).build(); + let cell_dep_error = packed::CellDep::new_builder().dep_type(dt_error).build(); - test_check_data_via_transaction(true, &[], &[], &[]); - test_check_data_via_transaction(true, &[&output_right1], &[&[]], &[&cell_dep_right]); - test_check_data_via_transaction( - true, - &[&output_right1, &output_right2], - &[&[], &[]], - &[&cell_dep_right, &cell_dep_right], - ); - test_check_data_via_transaction(false, &[&output_error1], &[&[]], &[]); - test_check_data_via_transaction(false, &[&output_error2], &[&[]], &[]); - test_check_data_via_transaction(false, &[&output_error3], &[&[]], &[]); - test_check_data_via_transaction(false, &[&output_error4], &[&[]], &[]); - test_check_data_via_transaction(false, &[], &[], &[&cell_dep_error]); - test_check_data_via_transaction( - false, - &[ - &output_right1, - &output_right2, - &output_error1, - &output_error2, - &output_error3, - &output_error4, - ], - &[&[], &[], &[], &[], &[], &[]], - &[&cell_dep_right, &cell_dep_error], - ); - test_check_data_via_transaction(false, &[&output_right1], &[], &[&cell_dep_right]); - test_check_data_via_transaction(false, &[], &[&[]], &[&cell_dep_right]); + test_check_data_via_transaction(true, &[], &[], &[]); + test_check_data_via_transaction( + true, + &[&output_right1], + &[&[]], + &[&cell_dep_right], + ); + test_check_data_via_transaction( + true, + &[&output_right1, &output_right2], + &[&[], &[]], + &[&cell_dep_right, &cell_dep_right], + ); + test_check_data_via_transaction(false, &[&output_error1], &[&[]], &[]); + test_check_data_via_transaction(false, &[&output_error2], &[&[]], &[]); + test_check_data_via_transaction(false, &[&output_error3], &[&[]], &[]); + test_check_data_via_transaction(false, &[&output_error4], &[&[]], &[]); + test_check_data_via_transaction(false, &[], &[], &[&cell_dep_error]); + test_check_data_via_transaction( + false, + &[ + &output_right1, + &output_right2, + &output_error1, + &output_error2, + &output_error3, + &output_error4, + ], + &[&[], &[], &[], &[], &[], &[]], + &[&cell_dep_right, &cell_dep_error], + ); + test_check_data_via_transaction(false, &[&output_right1], &[], &[&cell_dep_right]); + test_check_data_via_transaction(false, &[], &[&[]], &[&cell_dep_right]); + } } } } From 464c7697aad9a24efac21b7f9094dafa3ac909bc Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Thu, 20 Jul 2023 15:37:46 +0800 Subject: [PATCH 44/47] Fix `FeeOfMultipleMaxBlockProposalsLimit` failed --- test/src/specs/mining/fee.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/specs/mining/fee.rs b/test/src/specs/mining/fee.rs index ecf6a10676..12a77cab7a 100644 --- a/test/src/specs/mining/fee.rs +++ b/test/src/specs/mining/fee.rs @@ -146,7 +146,7 @@ impl Spec for FeeOfMultipleMaxBlockProposalsLimit { }); (0..multiple).for_each(|_| { - let block = node.new_block(None, None, None); + let block = node.new_block_with_blocking(|template| template.proposals.is_empty()); node.submit_block(&block); assert_eq!( max_block_proposals_limit as usize, From 0f5c7709b5674ef6527f28a25f02771dc7770ff6 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Mon, 14 Aug 2023 08:22:53 +0800 Subject: [PATCH 45/47] Improve code comment --- script/src/verify.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/src/verify.rs b/script/src/verify.rs index af1182af12..653689e6dd 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -1076,7 +1076,7 @@ impl Date: Tue, 15 Aug 2023 15:32:51 +0800 Subject: [PATCH 46/47] fix typos in rpc readme. --- rpc/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpc/README.md b/rpc/README.md index 35de2c0e32..b361043232 100644 --- a/rpc/README.md +++ b/rpc/README.md @@ -6785,7 +6785,7 @@ Refer to RFC [CKB Transaction Structure](https://github.com/nervosnetwork/rfcs/b * `cell_deps`: `Array<` [`CellDep`](#type-celldep) `>` - An array of cell deps. - CKB locates lock script and type script code via cell deps. The script also can uses syscalls to read the cells here. + CKB locates lock script and type script code via cell deps. The script also can use syscalls to read the cells here. Unlike inputs, the live cells can be used as cell deps in multiple transactions. @@ -6947,7 +6947,7 @@ The JSON view of a transaction as well as its status. * `cycles`: [`Cycle`](#type-cycle) `|` `null` - The transaction consumed cycles. -* `time_added_to_pool`: [`Uint64`](#type-uint64) `|` `null` - If the transaction is in tx-pool, `time_added_to_pool` represent when it enter the tx-pool. unit: Millisecond +* `time_added_to_pool`: [`Uint64`](#type-uint64) `|` `null` - If the transaction is in tx-pool, `time_added_to_pool` represent when it enters the tx-pool. unit: Millisecond * `tx_status`: [`TxStatus`](#type-txstatus) - The Transaction status. From 07de5e91063f09d29a0bd9763ef6a6a1edf39881 Mon Sep 17 00:00:00 2001 From: EthanYuan Date: Tue, 15 Aug 2023 15:34:38 +0800 Subject: [PATCH 47/47] fixing typos in comments --- util/jsonrpc-types/src/blockchain.rs | 8 ++++---- util/types/src/core/blockchain.rs | 2 +- util/types/src/core/tx_pool.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/util/jsonrpc-types/src/blockchain.rs b/util/jsonrpc-types/src/blockchain.rs index 2df38a7959..bf40d24f8e 100644 --- a/util/jsonrpc-types/src/blockchain.rs +++ b/util/jsonrpc-types/src/blockchain.rs @@ -13,7 +13,7 @@ use std::fmt; /// Specifies how the script `code_hash` is used to match the script code and how to run the code. /// -/// Allowed kinds: "data", "type", "data1" and “data2” +/// Allowed kinds: "data", "type", "data1" and "data2" /// /// Refer to the section [Code Locating](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md#code-locating) /// and [Upgradable Script](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md#upgradable-script) @@ -384,7 +384,7 @@ pub struct Transaction { pub version: Version, /// An array of cell deps. /// - /// CKB locates lock script and type script code via cell deps. The script also can uses syscalls + /// CKB locates lock script and type script code via cell deps. The script also can use syscalls /// to read the cells here. /// /// Unlike inputs, the live cells can be used as cell deps in multiple transactions. @@ -536,7 +536,7 @@ pub struct TransactionWithStatusResponse { pub transaction: Option>, /// The transaction consumed cycles. pub cycles: Option, - /// If the transaction is in tx-pool, `time_added_to_pool` represent when it enter the tx-pool. unit: Millisecond + /// If the transaction is in tx-pool, `time_added_to_pool` represent when it enters the tx-pool. unit: Millisecond pub time_added_to_pool: Option, /// The Transaction status. pub tx_status: TxStatus, @@ -1461,7 +1461,7 @@ pub struct Buried { pub status: SoftForkStatus, /// Whether the rules are active pub active: bool, - /// The first epoch which the rules will be enforced + /// The first epoch which the rules will be enforced pub epoch: EpochNumber, } diff --git a/util/types/src/core/blockchain.rs b/util/types/src/core/blockchain.rs index 7121bf09de..9dc2e7cb73 100644 --- a/util/types/src/core/blockchain.rs +++ b/util/types/src/core/blockchain.rs @@ -6,7 +6,7 @@ use crate::packed; /// The hash type is split into the high 7 bits and the low 1 bit, /// when the low 1 bit is 1, it indicates the type, /// when the low 1 bit is 0, it indicates the data, -/// and then it relies on the high 7 bits to indicate +/// and then it relies on the high 7 bits to indicate /// that the data actually corresponds to the version. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum ScriptHashType { diff --git a/util/types/src/core/tx_pool.rs b/util/types/src/core/tx_pool.rs index d5b41e1d4d..a1f182905d 100644 --- a/util/types/src/core/tx_pool.rs +++ b/util/types/src/core/tx_pool.rs @@ -161,7 +161,7 @@ pub struct TransactionWithStatus { pub tx_status: TxStatus, /// The transaction verification consumed cycles pub cycles: Option, - /// If the transaction is in tx-pool, `time_added_to_pool` represent when it enter the tx-pool. unit: Millisecond + /// If the transaction is in tx-pool, `time_added_to_pool` represent when it enters the tx-pool. unit: Millisecond pub time_added_to_pool: Option, }