Skip to content

Commit

Permalink
fix(WalletState): Avoid duplicate MonitoredUTXOs
Browse files Browse the repository at this point in the history
Merge branch 'thv/dev'.

This closes #309.

Co-authored-by: Alan Szepieniec <alan@neptune.cash>
  • Loading branch information
Sword-Smith and aszepieniec committed Jan 9, 2025
2 parents f4a564a + ff4dcb0 commit a0eb24b
Show file tree
Hide file tree
Showing 24 changed files with 1,548 additions and 1,331 deletions.
5 changes: 3 additions & 2 deletions src/connect_to_peers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@ async fn check_if_connection_is_allowed(
let cli_arguments = global_state_lock.cli();
let global_state = global_state_lock.lock_guard().await;
fn versions_are_compatible(own_version: &str, other_version: &str) -> bool {
let own_version = semver::Version::parse(own_version)
.expect("Must be able to parse own version string. Got: {own_version}");
let own_version = semver::Version::parse(own_version).unwrap_or_else(|_| {
panic!("Must be able to parse own version string. Got: {own_version}")
});
let other_version = match semver::Version::parse(other_version) {
Ok(version) => version,
Err(err) => {
Expand Down
14 changes: 10 additions & 4 deletions src/mine_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -964,9 +964,15 @@ pub(crate) mod mine_loop_tests {
block: &mut Block,
threshold: Digest,
rng: &mut StdRng,
) -> bool {
block.set_header_nonce(rng.gen());
block.hash() <= threshold
) -> Option<Digest> {
let nonce_preimage: Digest = rng.gen();
let nonce = nonce_preimage.hash();
block.set_header_nonce(nonce);
if block.hash() <= threshold {
Some(nonce_preimage)
} else {
None
}
}

/// Estimates the hash rate in number of hashes per milliseconds
Expand Down Expand Up @@ -1112,7 +1118,7 @@ pub(crate) mod mine_loop_tests {
.await
.get_wallet_status_for_tip()
.await
.synced_unspent_available_amount(now)
.synced_unspent_liquid_amount(now)
.is_zero(),
"Assumed to be premine-recipient"
);
Expand Down
36 changes: 36 additions & 0 deletions src/models/blockchain/block/block_kernel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,39 @@ impl MastHash for BlockKernel {
sequences
}
}

#[cfg(test)]
mod tests {
use tasm_lib::prelude::Digest;
use tasm_lib::prelude::Tip5;
use tasm_lib::twenty_first::prelude::CpuParallel;
use tasm_lib::twenty_first::prelude::MerkleTreeMaker;

use super::*;
use crate::models::blockchain::block::validity::block_primitive_witness::test::deterministic_block_primitive_witness;
use crate::models::blockchain::block::Block;
use crate::models::proof_abstractions::timestamp::Timestamp;

#[test]
fn kernel_hash_calculation() {
// How do I create an arbitrary new block? Preferably without proof.
let block_primitive_witness = deterministic_block_primitive_witness();
let invalid_block = Block::block_template_invalid_proof_from_witness(
block_primitive_witness,
Timestamp::now(),
Digest::default(),
None,
);
let calculated = invalid_block.hash();
let merkle_tree_leafs = [
Tip5::hash_varlen(&invalid_block.header().mast_hash().encode()),
Tip5::hash_varlen(&invalid_block.body().mast_hash().encode()),
Tip5::hash_varlen(&invalid_block.appendix().encode()),
Digest::default(),
];

let mt = CpuParallel::from_digests(&merkle_tree_leafs).unwrap();
let expected_root = mt.root();
assert_eq!(expected_root, calculated);
}
}
114 changes: 59 additions & 55 deletions src/models/blockchain/block/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,18 +202,15 @@ impl Block {
}
}

/// Create a block template with an invalid block proof.
///
/// To be used in tests where you don't care about block validity.
/// Create a block template with an invalid block proof, from a block
/// primitive witness.
#[cfg(test)]
pub(crate) fn block_template_invalid_proof(
predecessor: &Block,
transaction: Transaction,
pub(crate) fn block_template_invalid_proof_from_witness(
primitive_witness: BlockPrimitiveWitness,
block_timestamp: Timestamp,
nonce_preimage: Digest,
target_block_interval: Option<Timestamp>,
) -> Block {
let primitive_witness = BlockPrimitiveWitness::new(predecessor.to_owned(), transaction);
let body = primitive_witness.body().to_owned();
let header = primitive_witness.header(
block_timestamp,
Expand All @@ -225,6 +222,26 @@ impl Block {
Block::new(header, body, appendix, proof)
}

/// Create a block template with an invalid block proof.
///
/// To be used in tests where you don't care about block validity.
#[cfg(test)]
pub(crate) fn block_template_invalid_proof(
predecessor: &Block,
transaction: Transaction,
block_timestamp: Timestamp,
nonce_preimage: Digest,
target_block_interval: Option<Timestamp>,
) -> Block {
let primitive_witness = BlockPrimitiveWitness::new(predecessor.to_owned(), transaction);
Self::block_template_invalid_proof_from_witness(
primitive_witness,
block_timestamp,
nonce_preimage,
target_block_interval,
)
}

pub(crate) async fn block_template_from_block_primitive_witness(
primitive_witness: BlockPrimitiveWitness,
timestamp: Timestamp,
Expand Down Expand Up @@ -1019,8 +1036,6 @@ impl Block {
mod block_tests {
use rand::thread_rng;
use rand::Rng;
use rayon::iter::IntoParallelRefIterator;
use rayon::iter::ParallelIterator;
use strum::IntoEnumIterator;
use tracing_test::traced_test;

Expand All @@ -1037,7 +1052,6 @@ mod block_tests {
use crate::models::state::wallet::WalletSecret;
use crate::tests::shared::invalid_block_with_transaction;
use crate::tests::shared::make_mock_block;
use crate::tests::shared::make_mock_block_with_valid_pow;
use crate::tests::shared::make_mock_transaction;
use crate::tests::shared::mock_genesis_global_state;
use crate::util_types::mutator_set::archival_mmr::ArchivalMmr;
Expand All @@ -1057,42 +1071,37 @@ mod block_tests {
);
}

#[test]
fn test_difficulty_control_matches() {
#[tokio::test]
async fn test_difficulty_control_matches() {
let network = Network::Main;

let a_wallet_secret = WalletSecret::new_random();
let a_recipient_address = a_wallet_secret
.nth_generation_spending_key_for_tests(0)
.to_address();

// parallelized since this is a slow test.
[1, 10, 100, 1_000, 10_000, 100_000, 1_000_000]
.par_iter()
.for_each(|multiplier| {
let mut block_prev = Block::genesis_block(network);
let mut now = block_prev.kernel.header.timestamp;
let mut rng = thread_rng();

for i in (0..30).step_by(1) {
let duration = i as u64 * multiplier;
now += Timestamp::millis(duration);

let (block, _, _) =
make_mock_block(&block_prev, Some(now), a_recipient_address, rng.gen());

let control = difficulty_control(
block.kernel.header.timestamp,
block_prev.header().timestamp,
block_prev.header().difficulty,
None,
block_prev.header().height,
);
assert_eq!(block.kernel.header.difficulty, control);

block_prev = block;
}
});
let a_key = a_wallet_secret.nth_generation_spending_key_for_tests(0);

// TODO: Can this outer-loop be parallelized?
for multiplier in [1, 10, 100, 1_000, 10_000, 100_000, 1_000_000] {
let mut block_prev = Block::genesis_block(network);
let mut now = block_prev.kernel.header.timestamp;
let mut rng = thread_rng();

for i in (0..30).step_by(1) {
let duration = i as u64 * multiplier;
now += Timestamp::millis(duration);

let (block, _) = make_mock_block(&block_prev, Some(now), a_key, rng.gen()).await;

let control = difficulty_control(
block.kernel.header.timestamp,
block_prev.header().timestamp,
block_prev.header().difficulty,
None,
block_prev.header().height,
);
assert_eq!(block.kernel.header.difficulty, control);

block_prev = block;
}
}
}

#[test]
Expand Down Expand Up @@ -1125,18 +1134,15 @@ mod block_tests {
assert_eq!(bfe_max_elem, some_threshold_actual.values()[3]);
}

#[test]
fn block_with_wrong_mmra_is_invalid() {
#[tokio::test]
async fn block_with_wrong_mmra_is_invalid() {
let mut rng = thread_rng();
let network = Network::RegTest;
let genesis_block = Block::genesis_block(network);

let a_wallet_secret = WalletSecret::new_random();
let a_recipient_address = a_wallet_secret
.nth_generation_spending_key_for_tests(0)
.to_address();
let (mut block_1, _, _) =
make_mock_block_with_valid_pow(&genesis_block, None, a_recipient_address, rng.gen());
let a_key = a_wallet_secret.nth_generation_spending_key_for_tests(0);
let (mut block_1, _) = make_mock_block(&genesis_block, None, a_key, rng.gen()).await;

block_1.kernel.body.block_mmr_accumulator = MmrAccumulator::new_from_leafs(vec![]);
let timestamp = genesis_block.kernel.header.timestamp;
Expand All @@ -1162,11 +1168,9 @@ mod block_tests {

for i in 0..55 {
let wallet_secret = WalletSecret::new_random();
let recipient_address = wallet_secret
.nth_generation_spending_key_for_tests(0)
.to_address();
let (new_block, _, _) =
make_mock_block(blocks.last().unwrap(), None, recipient_address, rng.gen());
let key = wallet_secret.nth_generation_spending_key_for_tests(0);
let (new_block, _) =
make_mock_block(blocks.last().unwrap(), None, key, rng.gen()).await;
if i != 54 {
ammr.append(new_block.hash()).await;
mmra.append(new_block.hash());
Expand Down
Loading

0 comments on commit a0eb24b

Please sign in to comment.