Skip to content

Commit b14537f

Browse files
virtual chain from block batching. (#454)
* expose vspc_from_block batching possibilities to rpc. * fmt * limit by merged blocks, set source as def. start. * small clean-up * fmt * actually bound by num of merged blocks, in include transactions case. * fmt * update. * update_2 * new_high = high * remove high hash in consensus api.. as it is not required. * fmt * make proto comment more accurate. * fix tests, and lints, add to ser / der correctly. * change two freq warns to debug * remove option, default to pp. not source. * fix integration test, some Option<Hash> left. * bump version: ´0.15.1 => 0.15.2` * remove "optional" startHash * add to cli rpc.rs * remove comment. * edit comment in .proto referencing def. startHash behavior. * only batch added chain blocks, not removed, add check if source is a chain ancestor of high. * remove dangling code in comment * remove error from some prev. commit. * Optionalize limts. --------- Co-authored-by: Michael Sutton <msutton@cs.huji.ac.il>
1 parent 613d082 commit b14537f

File tree

14 files changed

+247
-148
lines changed

14 files changed

+247
-148
lines changed

Cargo.lock

Lines changed: 58 additions & 58 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 56 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ members = [
6363

6464
[workspace.package]
6565
rust-version = "1.81.0"
66-
version = "0.15.1"
66+
version = "0.15.2"
6767
authors = ["Kaspa developers"]
6868
license = "ISC"
6969
repository = "https://github.com/kaspanet/rusty-kaspa"
@@ -80,61 +80,61 @@ include = [
8080
]
8181

8282
[workspace.dependencies]
83-
# kaspa-testing-integration = { version = "0.15.1", path = "testing/integration" }
84-
kaspa-addresses = { version = "0.15.1", path = "crypto/addresses" }
85-
kaspa-addressmanager = { version = "0.15.1", path = "components/addressmanager" }
86-
kaspa-bip32 = { version = "0.15.1", path = "wallet/bip32" }
87-
kaspa-cli = { version = "0.15.1", path = "cli" }
88-
kaspa-connectionmanager = { version = "0.15.1", path = "components/connectionmanager" }
89-
kaspa-consensus = { version = "0.15.1", path = "consensus" }
90-
kaspa-consensus-core = { version = "0.15.1", path = "consensus/core" }
91-
kaspa-consensus-client = { version = "0.15.1", path = "consensus/client" }
92-
kaspa-consensus-notify = { version = "0.15.1", path = "consensus/notify" }
93-
kaspa-consensus-wasm = { version = "0.15.1", path = "consensus/wasm" }
94-
kaspa-consensusmanager = { version = "0.15.1", path = "components/consensusmanager" }
95-
kaspa-core = { version = "0.15.1", path = "core" }
96-
kaspa-daemon = { version = "0.15.1", path = "daemon" }
97-
kaspa-database = { version = "0.15.1", path = "database" }
98-
kaspa-grpc-client = { version = "0.15.1", path = "rpc/grpc/client" }
99-
kaspa-grpc-core = { version = "0.15.1", path = "rpc/grpc/core" }
100-
kaspa-grpc-server = { version = "0.15.1", path = "rpc/grpc/server" }
101-
kaspa-hashes = { version = "0.15.1", path = "crypto/hashes" }
102-
kaspa-index-core = { version = "0.15.1", path = "indexes/core" }
103-
kaspa-index-processor = { version = "0.15.1", path = "indexes/processor" }
104-
kaspa-math = { version = "0.15.1", path = "math" }
105-
kaspa-merkle = { version = "0.15.1", path = "crypto/merkle" }
106-
kaspa-metrics-core = { version = "0.15.1", path = "metrics/core" }
107-
kaspa-mining = { version = "0.15.1", path = "mining" }
108-
kaspa-mining-errors = { version = "0.15.1", path = "mining/errors" }
109-
kaspa-muhash = { version = "0.15.1", path = "crypto/muhash" }
110-
kaspa-notify = { version = "0.15.1", path = "notify" }
111-
kaspa-p2p-flows = { version = "0.15.1", path = "protocol/flows" }
112-
kaspa-p2p-lib = { version = "0.15.1", path = "protocol/p2p" }
113-
kaspa-perf-monitor = { version = "0.15.1", path = "metrics/perf_monitor" }
114-
kaspa-pow = { version = "0.15.1", path = "consensus/pow" }
115-
kaspa-rpc-core = { version = "0.15.1", path = "rpc/core" }
116-
kaspa-rpc-macros = { version = "0.15.1", path = "rpc/macros" }
117-
kaspa-rpc-service = { version = "0.15.1", path = "rpc/service" }
118-
kaspa-txscript = { version = "0.15.1", path = "crypto/txscript" }
119-
kaspa-txscript-errors = { version = "0.15.1", path = "crypto/txscript/errors" }
120-
kaspa-utils = { version = "0.15.1", path = "utils" }
121-
kaspa-utils-tower = { version = "0.15.1", path = "utils/tower" }
122-
kaspa-utxoindex = { version = "0.15.1", path = "indexes/utxoindex" }
123-
kaspa-wallet = { version = "0.15.1", path = "wallet/native" }
124-
kaspa-wallet-cli-wasm = { version = "0.15.1", path = "wallet/wasm" }
125-
kaspa-wallet-keys = { version = "0.15.1", path = "wallet/keys" }
126-
kaspa-wallet-pskt = { version = "0.15.1", path = "wallet/pskt" }
127-
kaspa-wallet-core = { version = "0.15.1", path = "wallet/core" }
128-
kaspa-wallet-macros = { version = "0.15.1", path = "wallet/macros" }
129-
kaspa-wasm = { version = "0.15.1", path = "wasm" }
130-
kaspa-wasm-core = { version = "0.15.1", path = "wasm/core" }
131-
kaspa-wrpc-client = { version = "0.15.1", path = "rpc/wrpc/client" }
132-
kaspa-wrpc-proxy = { version = "0.15.1", path = "rpc/wrpc/proxy" }
133-
kaspa-wrpc-server = { version = "0.15.1", path = "rpc/wrpc/server" }
134-
kaspa-wrpc-wasm = { version = "0.15.1", path = "rpc/wrpc/wasm" }
135-
kaspa-wrpc-example-subscriber = { version = "0.15.1", path = "rpc/wrpc/examples/subscriber" }
136-
kaspad = { version = "0.15.1", path = "kaspad" }
137-
kaspa-alloc = { version = "0.15.1", path = "utils/alloc" }
83+
# kaspa-testing-integration = { version = "0.15.2", path = "testing/integration" }
84+
kaspa-addresses = { version = "0.15.2", path = "crypto/addresses" }
85+
kaspa-addressmanager = { version = "0.15.2", path = "components/addressmanager" }
86+
kaspa-bip32 = { version = "0.15.2", path = "wallet/bip32" }
87+
kaspa-cli = { version = "0.15.2", path = "cli" }
88+
kaspa-connectionmanager = { version = "0.15.2", path = "components/connectionmanager" }
89+
kaspa-consensus = { version = "0.15.2", path = "consensus" }
90+
kaspa-consensus-core = { version = "0.15.2", path = "consensus/core" }
91+
kaspa-consensus-client = { version = "0.15.2", path = "consensus/client" }
92+
kaspa-consensus-notify = { version = "0.15.2", path = "consensus/notify" }
93+
kaspa-consensus-wasm = { version = "0.15.2", path = "consensus/wasm" }
94+
kaspa-consensusmanager = { version = "0.15.2", path = "components/consensusmanager" }
95+
kaspa-core = { version = "0.15.2", path = "core" }
96+
kaspa-daemon = { version = "0.15.2", path = "daemon" }
97+
kaspa-database = { version = "0.15.2", path = "database" }
98+
kaspa-grpc-client = { version = "0.15.2", path = "rpc/grpc/client" }
99+
kaspa-grpc-core = { version = "0.15.2", path = "rpc/grpc/core" }
100+
kaspa-grpc-server = { version = "0.15.2", path = "rpc/grpc/server" }
101+
kaspa-hashes = { version = "0.15.2", path = "crypto/hashes" }
102+
kaspa-index-core = { version = "0.15.2", path = "indexes/core" }
103+
kaspa-index-processor = { version = "0.15.2", path = "indexes/processor" }
104+
kaspa-math = { version = "0.15.2", path = "math" }
105+
kaspa-merkle = { version = "0.15.2", path = "crypto/merkle" }
106+
kaspa-metrics-core = { version = "0.15.2", path = "metrics/core" }
107+
kaspa-mining = { version = "0.15.2", path = "mining" }
108+
kaspa-mining-errors = { version = "0.15.2", path = "mining/errors" }
109+
kaspa-muhash = { version = "0.15.2", path = "crypto/muhash" }
110+
kaspa-notify = { version = "0.15.2", path = "notify" }
111+
kaspa-p2p-flows = { version = "0.15.2", path = "protocol/flows" }
112+
kaspa-p2p-lib = { version = "0.15.2", path = "protocol/p2p" }
113+
kaspa-perf-monitor = { version = "0.15.2", path = "metrics/perf_monitor" }
114+
kaspa-pow = { version = "0.15.2", path = "consensus/pow" }
115+
kaspa-rpc-core = { version = "0.15.2", path = "rpc/core" }
116+
kaspa-rpc-macros = { version = "0.15.2", path = "rpc/macros" }
117+
kaspa-rpc-service = { version = "0.15.2", path = "rpc/service" }
118+
kaspa-txscript = { version = "0.15.2", path = "crypto/txscript" }
119+
kaspa-txscript-errors = { version = "0.15.2", path = "crypto/txscript/errors" }
120+
kaspa-utils = { version = "0.15.2", path = "utils" }
121+
kaspa-utils-tower = { version = "0.15.2", path = "utils/tower" }
122+
kaspa-utxoindex = { version = "0.15.2", path = "indexes/utxoindex" }
123+
kaspa-wallet = { version = "0.15.2", path = "wallet/native" }
124+
kaspa-wallet-cli-wasm = { version = "0.15.2", path = "wallet/wasm" }
125+
kaspa-wallet-keys = { version = "0.15.2", path = "wallet/keys" }
126+
kaspa-wallet-pskt = { version = "0.15.2", path = "wallet/pskt" }
127+
kaspa-wallet-core = { version = "0.15.2", path = "wallet/core" }
128+
kaspa-wallet-macros = { version = "0.15.2", path = "wallet/macros" }
129+
kaspa-wasm = { version = "0.15.2", path = "wasm" }
130+
kaspa-wasm-core = { version = "0.15.2", path = "wasm/core" }
131+
kaspa-wrpc-client = { version = "0.15.2", path = "rpc/wrpc/client" }
132+
kaspa-wrpc-proxy = { version = "0.15.2", path = "rpc/wrpc/proxy" }
133+
kaspa-wrpc-server = { version = "0.15.2", path = "rpc/wrpc/server" }
134+
kaspa-wrpc-wasm = { version = "0.15.2", path = "rpc/wrpc/wasm" }
135+
kaspa-wrpc-example-subscriber = { version = "0.15.2", path = "rpc/wrpc/examples/subscriber" }
136+
kaspad = { version = "0.15.2", path = "kaspad" }
137+
kaspa-alloc = { version = "0.15.2", path = "utils/alloc" }
138138

139139
# external
140140
aes = "0.8.3"

cli/src/modules/rpc.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,20 @@ impl Rpc {
121121
// let result = rpc.get_subnetwork_call(GetSubnetworkRequest { }).await?;
122122
// self.println(&ctx, result);
123123
// }
124-
// RpcApiOps::GetVirtualChainFromBlock => {
125-
// let result = rpc.get_virtual_chain_from_block_call(GetVirtualChainFromBlockRequest { }).await?;
126-
// self.println(&ctx, result);
127-
// }
124+
RpcApiOps::GetVirtualChainFromBlock => {
125+
if argv.is_empty() {
126+
return Err(Error::custom("Missing startHash argument"));
127+
};
128+
let start_hash = RpcHash::from_hex(argv.remove(0).as_str())?;
129+
let include_accepted_transaction_ids = argv.remove(0).parse::<bool>().unwrap_or_default();
130+
let result = rpc
131+
.get_virtual_chain_from_block_call(
132+
None,
133+
GetVirtualChainFromBlockRequest { start_hash, include_accepted_transaction_ids },
134+
)
135+
.await?;
136+
self.println(&ctx, result);
137+
}
128138
// RpcApiOps::GetBlocks => {
129139
// let result = rpc.get_blocks_call(GetBlocksRequest { }).await?;
130140
// self.println(&ctx, result);

components/consensusmanager/src/session.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,12 @@ impl ConsensusSessionOwned {
267267
self.clone().spawn_blocking(|c| c.is_nearly_synced()).await
268268
}
269269

270-
pub async fn async_get_virtual_chain_from_block(&self, hash: Hash) -> ConsensusResult<ChainPath> {
271-
self.clone().spawn_blocking(move |c| c.get_virtual_chain_from_block(hash)).await
270+
pub async fn async_get_virtual_chain_from_block(
271+
&self,
272+
low: Hash,
273+
chain_path_added_limit: Option<usize>,
274+
) -> ConsensusResult<ChainPath> {
275+
self.clone().spawn_blocking(move |c| c.get_virtual_chain_from_block(low, chain_path_added_limit)).await
272276
}
273277

274278
pub async fn async_get_virtual_utxos(
@@ -380,8 +384,12 @@ impl ConsensusSessionOwned {
380384
/// Returns acceptance data for a set of blocks belonging to the selected parent chain.
381385
///
382386
/// See `self::get_virtual_chain`
383-
pub async fn async_get_blocks_acceptance_data(&self, hashes: Vec<Hash>) -> ConsensusResult<Vec<Arc<AcceptanceData>>> {
384-
self.clone().spawn_blocking(move |c| c.get_blocks_acceptance_data(&hashes)).await
387+
pub async fn async_get_blocks_acceptance_data(
388+
&self,
389+
hashes: Vec<Hash>,
390+
merged_blocks_limit: Option<usize>,
391+
) -> ConsensusResult<Vec<Arc<AcceptanceData>>> {
392+
self.clone().spawn_blocking(move |c| c.get_blocks_acceptance_data(&hashes, merged_blocks_limit)).await
385393
}
386394

387395
pub async fn async_is_chain_block(&self, hash: Hash) -> ConsensusResult<bool> {

consensus/core/src/api/mod.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,12 @@ pub trait ConsensusApi: Send + Sync {
157157
unimplemented!()
158158
}
159159

160-
fn get_virtual_chain_from_block(&self, hash: Hash) -> ConsensusResult<ChainPath> {
160+
/// Gets the virtual chain paths from `low` to the `sink` hash, or until `chain_path_added_limit` is reached
161+
///
162+
/// Note:
163+
/// 1) `chain_path_added_limit` will populate removed fully, and then the added chain path, up to `chain_path_added_limit` amount of hashes.
164+
/// 1.1) use `None to impose no limit with optimized backward chain iteration, for better performance in cases where batching is not required.
165+
fn get_virtual_chain_from_block(&self, low: Hash, chain_path_added_limit: Option<usize>) -> ConsensusResult<ChainPath> {
161166
unimplemented!()
162167
}
163168

@@ -297,7 +302,11 @@ pub trait ConsensusApi: Send + Sync {
297302
/// Returns acceptance data for a set of blocks belonging to the selected parent chain.
298303
///
299304
/// See `self::get_virtual_chain`
300-
fn get_blocks_acceptance_data(&self, hashes: &[Hash]) -> ConsensusResult<Vec<Arc<AcceptanceData>>> {
305+
fn get_blocks_acceptance_data(
306+
&self,
307+
hashes: &[Hash],
308+
merged_blocks_limit: Option<usize>,
309+
) -> ConsensusResult<Vec<Arc<AcceptanceData>>> {
301310
unimplemented!()
302311
}
303312

consensus/src/consensus/mod.rs

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -607,14 +607,26 @@ impl ConsensusApi for Consensus {
607607
self.config.is_nearly_synced(compact.timestamp, compact.daa_score)
608608
}
609609

610-
fn get_virtual_chain_from_block(&self, hash: Hash) -> ConsensusResult<ChainPath> {
611-
// Calculate chain changes between the given hash and the
612-
// sink. Note that we explicitly don't
610+
fn get_virtual_chain_from_block(&self, low: Hash, chain_path_added_limit: Option<usize>) -> ConsensusResult<ChainPath> {
611+
// Calculate chain changes between the given `low` and the current sink hash (up to `limit` amount of block hashes).
612+
// Note:
613+
// 1) that we explicitly don't
613614
// do the calculation against the virtual itself so that we
614615
// won't later need to remove it from the result.
616+
// 2) supplying `None` as `chain_path_added_limit` will result in the full chain path, with optimized performance.
615617
let _guard = self.pruning_lock.blocking_read();
616-
self.validate_block_exists(hash)?;
617-
Ok(self.services.dag_traversal_manager.calculate_chain_path(hash, self.get_sink()))
618+
619+
// Verify that the block exists
620+
self.validate_block_exists(low)?;
621+
622+
// Verify that source is on chain(block)
623+
self.services
624+
.reachability_service
625+
.is_chain_ancestor_of(self.get_source(), low)
626+
.then_some(())
627+
.ok_or(ConsensusError::General("the queried hash does not have source on its chain"))?;
628+
629+
Ok(self.services.dag_traversal_manager.calculate_chain_path(low, self.get_sink(), chain_path_added_limit))
618630
}
619631

620632
/// Returns a Vec of header samples since genesis
@@ -914,11 +926,35 @@ impl ConsensusApi for Consensus {
914926
self.acceptance_data_store.get(hash).unwrap_option().ok_or(ConsensusError::MissingData(hash))
915927
}
916928

917-
fn get_blocks_acceptance_data(&self, hashes: &[Hash]) -> ConsensusResult<Vec<Arc<AcceptanceData>>> {
929+
fn get_blocks_acceptance_data(
930+
&self,
931+
hashes: &[Hash],
932+
merged_blocks_limit: Option<usize>,
933+
) -> ConsensusResult<Vec<Arc<AcceptanceData>>> {
934+
// Note: merged_blocks_limit will limit after the sum of merged blocks is breached along the supplied hash's acceptance data
935+
// and not limit the acceptance data within a queried hash. i.e. It has mergeset_size_limit granularity, this is to guarantee full acceptance data coverage.
936+
if merged_blocks_limit.is_none() {
937+
return hashes
938+
.iter()
939+
.copied()
940+
.map(|hash| self.acceptance_data_store.get(hash).unwrap_option().ok_or(ConsensusError::MissingData(hash)))
941+
.collect::<ConsensusResult<Vec<_>>>();
942+
}
943+
let merged_blocks_limit = merged_blocks_limit.unwrap(); // we handle `is_none`, so may unwrap.
944+
let mut num_of_merged_blocks = 0usize;
945+
918946
hashes
919947
.iter()
920948
.copied()
921-
.map(|hash| self.acceptance_data_store.get(hash).unwrap_option().ok_or(ConsensusError::MissingData(hash)))
949+
.map_while(|hash| {
950+
let entry = self.acceptance_data_store.get(hash).unwrap_option().ok_or(ConsensusError::MissingData(hash));
951+
num_of_merged_blocks += entry.as_ref().map_or(0, |entry| entry.len());
952+
if num_of_merged_blocks > merged_blocks_limit {
953+
None
954+
} else {
955+
Some(entry)
956+
}
957+
})
922958
.collect::<ConsensusResult<Vec<_>>>()
923959
}
924960

consensus/src/pipeline/virtual_processor/processor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ impl VirtualStateProcessor {
290290
assert_eq!(virtual_ghostdag_data.selected_parent, new_sink);
291291

292292
let sink_multiset = self.utxo_multisets_store.get(new_sink).unwrap();
293-
let chain_path = self.dag_traversal_manager.calculate_chain_path(prev_sink, new_sink);
293+
let chain_path = self.dag_traversal_manager.calculate_chain_path(prev_sink, new_sink, None);
294294
let new_virtual_state = self
295295
.calculate_and_commit_virtual_state(
296296
virtual_read,

consensus/src/processes/sync/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ impl<
111111
(blocks, highest_reached)
112112
}
113113

114-
fn find_highest_common_chain_block(&self, low: Hash, high: Hash) -> Hash {
114+
pub fn find_highest_common_chain_block(&self, low: Hash, high: Hash) -> Hash {
115115
self.reachability_service
116116
.default_backward_chain_iterator(low)
117117
.find(|candidate| self.reachability_service.is_chain_ancestor_of(*candidate, high))

consensus/src/processes/traversal_manager.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ impl<T: GhostdagStoreReader, U: ReachabilityStoreReader, V: RelationsStoreReader
3131
Self { genesis_hash, ghostdag_store, relations_store, reachability_service }
3232
}
3333

34-
pub fn calculate_chain_path(&self, from: Hash, to: Hash) -> ChainPath {
34+
pub fn calculate_chain_path(&self, from: Hash, to: Hash, chain_path_added_limit: Option<usize>) -> ChainPath {
3535
let mut removed = Vec::new();
3636
let mut common_ancestor = from;
3737
for current in self.reachability_service.default_backward_chain_iterator(from) {
@@ -42,9 +42,20 @@ impl<T: GhostdagStoreReader, U: ReachabilityStoreReader, V: RelationsStoreReader
4242
break;
4343
}
4444
}
45-
// It is more intuitive to use forward iterator here, but going downwards the selected chain is faster.
46-
let mut added = self.reachability_service.backward_chain_iterator(to, common_ancestor, false).collect_vec();
47-
added.reverse();
45+
if chain_path_added_limit.is_none() {
46+
// Use backward chain iterator
47+
// It is more intuitive to use forward iterator here, but going downwards the selected chain is faster.
48+
let mut added = self.reachability_service.backward_chain_iterator(to, common_ancestor, false).collect_vec();
49+
added.reverse();
50+
return ChainPath { added, removed };
51+
}
52+
// Use forward chain iterator, to ascertain a path from the common ancestor to the target.
53+
let added = self
54+
.reachability_service
55+
.forward_chain_iterator(common_ancestor, to, true)
56+
.skip(1)
57+
.take(chain_path_added_limit.unwrap()) // we handle is_none so we may unwrap.
58+
.collect_vec();
4859
ChainPath { added, removed }
4960
}
5061

mining/src/mempool/remove_transaction.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::mempool::{
44
Mempool,
55
};
66
use kaspa_consensus_core::tx::TransactionId;
7-
use kaspa_core::{debug, warn};
7+
use kaspa_core::debug;
88
use kaspa_utils::iter::IterExtensions;
99

1010
impl Mempool {
@@ -43,8 +43,8 @@ impl Mempool {
4343
TxRemovalReason::Muted => {}
4444
TxRemovalReason::DoubleSpend => match removed_transactions.len() {
4545
0 => {}
46-
1 => warn!("Removed transaction ({}) {}{}", reason, removed_transactions[0], extra_info),
47-
n => warn!(
46+
1 => debug!("Removed transaction ({}) {}{}", reason, removed_transactions[0], extra_info),
47+
n => debug!(
4848
"Removed {} transactions ({}): {}{}",
4949
n,
5050
reason,

0 commit comments

Comments
 (0)