Skip to content

Commit

Permalink
feat: optimize transaction validation db queries (#6196)
Browse files Browse the repository at this point in the history
Description
---
Optimized transaction validation SQLite queries to run in batch mode
wherever possible to minimise db operations.

Motivation and Context
---
See #6195

How Has This Been Tested?
---
Updated unit tests
Added a raw query regression test 
System-level testing

What process can a PR reviewer use to test or verify this change?
---
Review code and tests

<!-- Checklist -->
<!-- 1. Is the title of your PR in the form that would make nice release
notes? The title, excluding the conventional commit
tag, will be included exactly as is in the CHANGELOG, so please think
about it carefully. -->


Breaking Changes
---

- [x] None
- [ ] Requires data directory on base node to be deleted
- [ ] Requires hard fork
- [ ] Other - Please specify

<!-- Does this include a breaking change? If so, include this line as a
footer -->
<!-- BREAKING CHANGE: Description what the user should do, e.g. delete a
database, resync the chain -->
  • Loading branch information
hansieodendaal committed Mar 20, 2024
1 parent 1452535 commit 213a885
Show file tree
Hide file tree
Showing 9 changed files with 838 additions and 323 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::output_manager_service::{
storage::{
database::{DbKey, DbValue, OutputBackendQuery, WriteOperation},
models::DbWalletOutput,
sqlite_db::{ReceivedOutputInfoForBatch, SpentOutputInfoForBatch},
},
};

Expand All @@ -37,29 +38,20 @@ pub trait OutputManagerBackend: Send + Sync + Clone {
/// Modify the state the of the backend with a write operation
fn write(&self, op: WriteOperation) -> Result<Option<DbValue>, OutputManagerStorageError>;
fn fetch_pending_incoming_outputs(&self) -> Result<Vec<DbWalletOutput>, OutputManagerStorageError>;

fn set_received_output_mined_height_and_status(
/// Perform a batch update of the received outputs' mined height and status
fn set_received_outputs_mined_height_and_statuses(
&self,
hash: FixedHash,
mined_height: u64,
mined_in_block: FixedHash,
confirmed: bool,
mined_timestamp: u64,
updates: Vec<ReceivedOutputInfoForBatch>,
) -> Result<(), OutputManagerStorageError>;

fn set_output_to_unmined_and_invalid(&self, hash: FixedHash) -> Result<(), OutputManagerStorageError>;
fn update_last_validation_timestamp(&self, hash: FixedHash) -> Result<(), OutputManagerStorageError>;
/// Perform a batch update of the outputs' unmined and invalid state
fn set_outputs_to_unmined_and_invalid(&self, hashes: Vec<FixedHash>) -> Result<(), OutputManagerStorageError>;
/// Perform a batch update of the outputs' last validation timestamp
fn update_last_validation_timestamps(&self, hashes: Vec<FixedHash>) -> Result<(), OutputManagerStorageError>;
fn set_outputs_to_be_revalidated(&self) -> Result<(), OutputManagerStorageError>;

fn mark_output_as_spent(
&self,
hash: FixedHash,
mark_deleted_at_height: u64,
mark_deleted_in_block: FixedHash,
confirmed: bool,
) -> Result<(), OutputManagerStorageError>;

fn mark_output_as_unspent(&self, hash: FixedHash, confirmed: bool) -> Result<(), OutputManagerStorageError>;
/// Perform a batch update of the outputs' spent status
fn mark_outputs_as_spent(&self, updates: Vec<SpentOutputInfoForBatch>) -> Result<(), OutputManagerStorageError>;
/// Perform a batch update of the outputs' unspent status
fn mark_outputs_as_unspent(&self, hashes: Vec<(FixedHash, bool)>) -> Result<(), OutputManagerStorageError>;
/// This method encumbers the specified outputs into a `PendingTransactionOutputs` record. This is a short term
/// encumberance in case the app is closed or crashes before transaction neogtiation is complete. These will be
/// cleared on startup of the service.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub use backend::OutputManagerBackend;
use log::*;
use tari_common_types::{
transaction::TxId,
types::{Commitment, HashOutput},
types::{Commitment, FixedHash, HashOutput},
};
use tari_core::transactions::{
tari_amount::MicroMinotari,
Expand All @@ -44,6 +44,7 @@ use crate::output_manager_service::{
service::Balance,
storage::{
models::{DbWalletOutput, KnownOneSidedPaymentScript},
sqlite_db::{ReceivedOutputInfoForBatch, SpentOutputInfoForBatch},
OutputStatus,
},
};
Expand Down Expand Up @@ -380,22 +381,18 @@ where T: OutputManagerBackend + 'static
Ok(())
}

pub fn set_received_output_mined_height_and_status(
pub fn set_received_outputs_mined_height_and_statuses(
&self,
hash: HashOutput,
mined_height: u64,
mined_in_block: HashOutput,
confirmed: bool,
mined_timestamp: u64,
updates: Vec<ReceivedOutputInfoForBatch>,
) -> Result<(), OutputManagerStorageError> {
let db = self.db.clone();
db.set_received_output_mined_height_and_status(hash, mined_height, mined_in_block, confirmed, mined_timestamp)?;
db.set_received_outputs_mined_height_and_statuses(updates)?;
Ok(())
}

pub fn set_output_to_unmined_and_invalid(&self, hash: HashOutput) -> Result<(), OutputManagerStorageError> {
pub fn set_outputs_to_unmined_and_invalid(&self, hashes: Vec<FixedHash>) -> Result<(), OutputManagerStorageError> {
let db = self.db.clone();
db.set_output_to_unmined_and_invalid(hash)?;
db.set_outputs_to_unmined_and_invalid(hashes)?;
Ok(())
}

Expand All @@ -405,27 +402,24 @@ where T: OutputManagerBackend + 'static
Ok(())
}

pub fn update_last_validation_timestamp(&self, hash: HashOutput) -> Result<(), OutputManagerStorageError> {
pub fn update_last_validation_timestamps(&self, hashes: Vec<FixedHash>) -> Result<(), OutputManagerStorageError> {
let db = self.db.clone();
db.update_last_validation_timestamp(hash)?;
db.update_last_validation_timestamps(hashes)?;
Ok(())
}

pub fn mark_output_as_spent(
pub fn mark_outputs_as_spent(
&self,
hash: HashOutput,
deleted_height: u64,
deleted_in_block: HashOutput,
confirmed: bool,
updates: Vec<SpentOutputInfoForBatch>,
) -> Result<(), OutputManagerStorageError> {
let db = self.db.clone();
db.mark_output_as_spent(hash, deleted_height, deleted_in_block, confirmed)?;
db.mark_outputs_as_spent(updates)?;
Ok(())
}

pub fn mark_output_as_unspent(&self, hash: HashOutput, confirmed: bool) -> Result<(), OutputManagerStorageError> {
pub fn mark_outputs_as_unspent(&self, hashes: Vec<(FixedHash, bool)>) -> Result<(), OutputManagerStorageError> {
let db = self.db.clone();
db.mark_output_as_unspent(hash, confirmed)?;
db.mark_outputs_as_unspent(hashes)?;
Ok(())
}

Expand Down
Loading

0 comments on commit 213a885

Please sign in to comment.