Skip to content

Commit

Permalink
Optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
coderofstuff committed Mar 22, 2024
1 parent 25aca5f commit 7d1b663
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 46 deletions.
8 changes: 6 additions & 2 deletions components/consensusmanager/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,12 @@ impl ConsensusSessionOwned {
self.clone().spawn_blocking(|c| c.get_chain_block_samples()).await
}

pub async fn async_get_utxo_return_address(&self, txid: Hash, accepting_block_daa_score: u64) -> Option<ScriptPublicKey> {
self.clone().spawn_blocking(move |c| c.get_utxo_return_address(txid, accepting_block_daa_score)).await
pub async fn async_get_utxo_return_script_public_key(
&self,
txid: Hash,
accepting_block_daa_score: u64,
) -> Option<ScriptPublicKey> {
self.clone().spawn_blocking(move |c| c.get_utxo_return_script_public_key(txid, accepting_block_daa_score)).await
}

/// Returns the antipast of block `hash` from the POV of `context`, i.e. `antipast(hash) ∩ past(context)`.
Expand Down
2 changes: 1 addition & 1 deletion consensus/core/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ pub trait ConsensusApi: Send + Sync {
unimplemented!()
}

fn get_utxo_return_address(&self, txid: Hash, daa_score: u64) -> Option<ScriptPublicKey> {
fn get_utxo_return_script_public_key(&self, txid: Hash, daa_score: u64) -> Option<ScriptPublicKey> {
unimplemented!()
}

Expand Down
85 changes: 49 additions & 36 deletions consensus/src/consensus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ use crossbeam_channel::{
use itertools::Itertools;
use kaspa_consensusmanager::{SessionLock, SessionReadGuard};

use kaspa_core::{trace, warn};
use kaspa_database::prelude::StoreResultExtensions;
use kaspa_hashes::Hash;
use kaspa_muhash::MuHash;
Expand Down Expand Up @@ -614,83 +615,95 @@ impl ConsensusApi for Consensus {
sample_headers
}

fn get_utxo_return_address(&self, txid: Hash, daa_score: u64) -> Option<ScriptPublicKey> {
fn get_utxo_return_script_public_key(&self, txid: Hash, target_daa_score: u64) -> Option<ScriptPublicKey> {
// We need consistency between the past pruning points, selected chain and header store reads
let _guard = self.pruning_lock.blocking_read();

let sc_read = self.selected_chain_store.read();

let low = self.pruning_point_store.read().get().unwrap().pruning_point;
let high = sc_read.get_tip().unwrap().1;
let pp_hash = self.pruning_point_store.read().get().unwrap().pruning_point;
let pp_index = sc_read.get_by_hash(pp_hash).unwrap();
let (tip_index, tip_hash) = sc_read.get_tip().unwrap();
let tip_daa_score = self.headers_store.get_compact_header_data(tip_hash).unwrap().daa_score;

let mut low_index = sc_read.get_by_hash(low).unwrap();
let mut high_index = sc_read.get_by_hash(high).unwrap();
let mut low_index = tip_index.saturating_sub(tip_daa_score.saturating_sub(target_daa_score)).max(pp_index);
let mut high_index = tip_index;

// let mut locator = Vec::with_capacity((high_index - low_index).ceiling_log_base_2() as usize);
// let mut current_index = high_index;
let mut matching_chain_block_hash: Option<Hash> = None;
while low_index <= high_index {
let mid = low_index + (high_index - low_index) / 2;

if let Ok(hash) = sc_read.get_by_index(mid) {
if let Ok(compact_header) = self.headers_store.get_compact_header_data(hash) {
if compact_header.daa_score == daa_score {
if compact_header.daa_score == target_daa_score {
// We found the chain block we need
matching_chain_block_hash = Some(hash);
break;
} else if compact_header.daa_score < daa_score {
} else if compact_header.daa_score < target_daa_score {
low_index = mid + 1;
} else {
high_index = mid - 1;
}
} else {
println!("Did not find a compact header with hash {}", hash);
break;
trace!("Did not find a compact header with hash {}", hash);
return None;
}
} else {
println!("Did not find a hash at index {}", mid);
break;
trace!("Did not find a hash at index {}", mid);
return None;
}
}

if matching_chain_block_hash.is_none() {
println!("No matching chain block hash found");
return None;
}

let matching_chain_block_hash = matching_chain_block_hash?;

if let Ok(acceptance_data) = self.acceptance_data_store.get(matching_chain_block_hash) {
let containing_acceptance = acceptance_data
.iter()
.find(|&mbad| mbad.accepted_transactions.iter().find(|&tx| tx.transaction_id == txid).is_some())
.cloned();

if let Some(containing_acceptance) = containing_acceptance {
// I found the merged block containing the TXID
// Now I need to find the txid
let tx = self
.block_transactions_store
.get(containing_acceptance.block_hash)
.unwrap()
.iter()
.find(|&tx| tx.id() == txid)
.cloned()
.unwrap();
let maybe_index_and_containing_acceptance =
acceptance_data.iter().find_map(|mbad| {
let tx_arr_index = mbad.accepted_transactions.iter().enumerate().find_map(|(index, &ref tx)| {
if tx.transaction_id == txid {
Some(index)
} else {
None
}
});

if let Some(index) = tx_arr_index {
Some((index, mbad.clone()))
} else {
None
}
});

if let Some((index, containing_acceptance)) = maybe_index_and_containing_acceptance {
// Found Merged block containing the TXID
let tx = &self.block_transactions_store.get(containing_acceptance.block_hash).unwrap()[index];

if tx.id() != txid {
// Should never happen, but do a sanity check. This would mean something went wrong with storing block transactions
// Sanity check is necessary to guarantee that this function will never give back a wrong address (err on the side of None)
warn!(
"Expected {} to match {} when checking block_transaction_store using array index of transaction",
tx.id(),
txid
);
return None;
}

if tx.inputs.is_empty() {
// A transaction may have no inputs (like a coinbase transaction)
return None;
}

let first_input = &tx.inputs[0];

let prev_outpoint = &first_input.previous_outpoint;

let first_input_prev_outpoint = &tx.inputs[0].previous_outpoint;
// Expected to never fail, since
let utxo_diff = self.utxo_diffs_store.get(matching_chain_block_hash).unwrap();

let removed_diffs = utxo_diff.removed();

return Some(removed_diffs.get(prev_outpoint)?.script_public_key.clone());
return Some(removed_diffs.get(first_input_prev_outpoint)?.script_public_key.clone());
}
};

Expand Down
16 changes: 9 additions & 7 deletions rpc/service/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ use kaspa_rpc_core::{
notify::connection::ChannelConnection,
Notification, RpcError, RpcResult,
};
use kaspa_txscript::opcodes::codes;
use kaspa_txscript::{extract_script_pub_key_address, pay_to_address_script};
use kaspa_utils::{channel::Channel, triggers::SingleTrigger};
use kaspa_utils_tower::counters::TowerConnectionCounters;
Expand Down Expand Up @@ -623,23 +624,24 @@ NOTE: This error usually indicates an RPC conversion error between the node and
async fn get_utxo_return_address_call(&self, request: GetUtxoReturnAddressRequest) -> RpcResult<GetUtxoReturnAddressResponse> {
let session = self.consensus_manager.consensus().session().await;

let maybe_spk = session.async_get_utxo_return_address(request.txid, request.accepting_block_daa_score).await;

let mut return_address = None;

// Convert a SPK to an Address
if let Some(spk) = maybe_spk {
if let Some(spk) = session.async_get_utxo_return_script_public_key(request.txid, request.accepting_block_daa_score).await {
let script = spk.script();

// Address scripts are only either 34 or 35 in length:
if script.len() == 34 && script[0] == 0x20 && script[33] == 0xac {
// Standard Address scripts are only either 34 or 35 in length:
if script.len() == 34 && script[0] == codes::OpData32 && script[33] == codes::OpCheckSig {
// This is a standard Schnorr Address
return_address = Some(RpcAddress::new(self.config.prefix(), kaspa_addresses::Version::PubKey, &script[1..33]));
} else if script.len() == 35 {
// Could be ECDSA address OR P2SH
if script[0] == 0x21 && script[34] == 0xab {
if script[0] == codes::OpData33 && script[34] == codes::OpCheckSigECDSA {
// This is an standard ECDSA Address
return_address =
Some(RpcAddress::new(self.config.prefix(), kaspa_addresses::Version::PubKeyECDSA, &script[1..34]));
} else if script[0] == 0xaa && script[1] == 0x20 && script[34] == 0x87 {
} else if script[0] == codes::OpBlake2b && script[1] == codes::OpData32 && script[34] == codes::OpEqual {
// This is a standard P2SH Address
return_address = Some(RpcAddress::new(self.config.prefix(), kaspa_addresses::Version::ScriptHash, &script[2..34]));
}
}
Expand Down

0 comments on commit 7d1b663

Please sign in to comment.