Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NRD rules and "recent" kernel pos index #3302

Merged
merged 53 commits into from Jun 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
139e24a
variants for output_pos linked list entries (head/tail/middle/unique)
antiochp Mar 18, 2020
978bf60
get_pos on enum
antiochp Mar 18, 2020
e3bd7a3
break list and list entries out into separate enums
antiochp Mar 19, 2020
cabbc44
track output features in the new output_pos index, so we can determin…
antiochp Mar 19, 2020
af889ff
push entry impl for none and unique
antiochp Mar 20, 2020
3fd78ad
some test coverage for output_pos_list
antiochp Mar 20, 2020
34b4ed4
commit
antiochp Mar 21, 2020
7841a3e
wip - FooListEntry
antiochp Mar 23, 2020
2f95e55
use instance of the index
antiochp Mar 23, 2020
f489e77
linked list of output_pos and commit_pos both now supported
antiochp Mar 23, 2020
9cbb550
linked_list
antiochp Mar 23, 2020
c65f09d
cleanup and rename
antiochp Apr 17, 2020
61bd320
rename
antiochp Apr 18, 2020
5e44e2f
peek_pos
antiochp Apr 18, 2020
82e3c99
push some, peek some, pop some
antiochp Apr 18, 2020
536b8ed
cleanup
antiochp Apr 18, 2020
3357273
commit pos
antiochp Apr 18, 2020
f3e589a
split list and entry out into separate db prefixes
antiochp Apr 20, 2020
6e6e498
cleanup and add placeholder for pop_back
antiochp May 14, 2020
888c49b
pop_pos_back (for popping off the back of the linked list)
antiochp May 14, 2020
48d0deb
wip
antiochp May 15, 2020
3f16218
placeholder for prune via a trait
antiochp May 16, 2020
c311be8
rewind kernel_pos_idx when calling rewind_single_block
antiochp May 16, 2020
a55fab8
RewindableListIndex with rewind support.
antiochp May 16, 2020
c830daa
test coverage for rewindable list index
antiochp May 16, 2020
bc26131
test coverage for rewind back to 0
antiochp May 16, 2020
88b6e95
rewind past end of list
antiochp May 16, 2020
ae0a99c
add tests for kernel_pos_idx with multiple commits
antiochp May 17, 2020
cc9c06a
Merge remote-tracking branch 'upstream/master' into kernel_pos
antiochp May 29, 2020
47e9093
commit
antiochp May 29, 2020
e60ab72
cleanup
antiochp May 29, 2020
933b39e
hook NRD relative lock height validation into block processing and tx…
antiochp May 29, 2020
a038389
cleanup
antiochp May 29, 2020
4b64991
set local chain type for kernel_idx tests
antiochp May 31, 2020
8ed26c8
add test coverage for NRD rules in block processing
antiochp May 31, 2020
fa6f1df
NRD test coverage and cleanup
antiochp May 31, 2020
9c87a23
NRD relative height 1 test
antiochp May 31, 2020
3d4fe1f
test coverage for NRD kernels in block processing
antiochp May 31, 2020
f260771
cleanup
antiochp May 31, 2020
188e289
start of test coverage for txpool NRD kernel rules
antiochp Jun 1, 2020
580b414
wip
antiochp Jun 2, 2020
cb885a0
rework pool tests to use real chain (was mock chain) to better reflec…
antiochp Jun 2, 2020
3f1defe
cleanup
antiochp Jun 5, 2020
a544108
Merge branch 'master' into kernel_pos
antiochp Jun 6, 2020
13af16f
Merge branch 'pool_real_chain' into kernel_pos
antiochp Jun 6, 2020
1612201
Merge branch 'master' into kernel_pos
antiochp Jun 7, 2020
fb11b5d
cleanup pruneable trait for kernel pos index
antiochp Jun 7, 2020
f73688b
add clear() to kernel_pos idx and test coverage
antiochp Jun 8, 2020
de8ba23
hook kernel_pos rebuild into node startup, compaction and fast sync
antiochp Jun 8, 2020
7df028b
verify full NRD history on fast sync
antiochp Jun 8, 2020
adca6b0
return early if nrd disabled
antiochp Jun 9, 2020
7435987
Merge remote-tracking branch 'upstream/master' into kernel_pos
antiochp Jun 9, 2020
4acbf8c
fix header sync issue
antiochp Jun 9, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion api/src/handlers/utils.rs
Expand Up @@ -26,7 +26,7 @@ use std::sync::{Arc, Weak};
// boilerplate of dealing with `Weak`.
pub fn w<T>(weak: &Weak<T>) -> Result<Arc<T>, Error> {
weak.upgrade()
.ok_or_else(|| ErrorKind::Internal("failed to upgrade weak refernce".to_owned()).into())
.ok_or_else(|| ErrorKind::Internal("failed to upgrade weak reference".to_owned()).into())
}

/// Internal function to retrieves an output by a given commitment
Expand Down
1 change: 1 addition & 0 deletions chain/Cargo.toml
Expand Up @@ -16,6 +16,7 @@ byteorder = "1"
failure = "0.1"
failure_derive = "0.1"
croaring = { version = "0.4.5", package = "croaring-mw", features = ["compat"] }
enum_primitive = "0.1"
log = "0.4"
serde = "1"
serde_derive = "1"
Expand Down
63 changes: 54 additions & 9 deletions chain/src/chain.rs
Expand Up @@ -19,7 +19,8 @@ use crate::core::core::hash::{Hash, Hashed, ZERO_HASH};
use crate::core::core::merkle_proof::MerkleProof;
use crate::core::core::verifier_cache::VerifierCache;
use crate::core::core::{
Block, BlockHeader, BlockSums, Committed, Output, OutputIdentifier, Transaction, TxKernel,
Block, BlockHeader, BlockSums, Committed, KernelFeatures, Output, OutputIdentifier,
Transaction, TxKernel,
};
use crate::core::global;
use crate::core::pow;
Expand Down Expand Up @@ -195,12 +196,12 @@ impl Chain {
&mut txhashset,
)?;

// Initialize the output_pos index based on UTXO set.
// This is fast as we only look for stale and missing entries
// and do not need to rebuild the entire index.
// Initialize the output_pos index based on UTXO set
// and NRD kernel_pos index based recent kernel history.
{
let batch = store.batch()?;
txhashset.init_output_pos_index(&header_pmmr, &batch)?;
txhashset.init_recent_kernel_pos_index(&header_pmmr, &batch)?;
batch.commit()?;
}

Expand Down Expand Up @@ -296,6 +297,11 @@ impl Chain {
/// Returns true if it has been added to the longest chain
/// or false if it has added to a fork (or orphan?).
fn process_block_single(&self, b: Block, opts: Options) -> Result<Option<Tip>, Error> {
// Process the header first.
// If invalid then fail early.
// If valid then continue with block processing with header_head committed to db etc.
self.process_block_header(&b.header, opts)?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in what cases would we call process_block_single without having validated/processed the header already?
(I would naively expect never)
Does header validation not commit it to db?

Copy link
Member Author

@antiochp antiochp Jun 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In most cases we will have processed "header first".
The first broadcast hop from a miner after mining a new block is done as a "full block" and skips the "header first" propagation as we know nobody has seen this block yet.
In this case the receiving node is here in the code, processing the new block without having seen the header yet.

We were validating the header in the later call to pipe::process_block().
We want to validate/process the header here, in a db transaction and a write to the MMR backend files, before we begin processing/validating the full block.

The issue was that if the full block failed validation for any reason then the entire db transaction rolled back, including the header processing. But leaving the header MMR updated with the latest header.


let (maybe_new_head, prev_head) = {
let mut header_pmmr = self.header_pmmr.write();
let mut txhashset = self.txhashset.write();
Expand Down Expand Up @@ -513,13 +519,38 @@ impl Chain {
})
}

/// Validate the tx against the current UTXO set.
/// Validate the tx against the current UTXO set and recent kernels (NRD relative lock heights).
pub fn validate_tx(&self, tx: &Transaction) -> Result<(), Error> {
self.validate_tx_against_utxo(tx)?;
self.validate_tx_kernels(tx)?;
Ok(())
}

/// Validates NRD relative height locks against "recent" kernel history.
/// Applies the kernels to the current kernel MMR in a readonly extension.
/// The extension and the db batch are discarded.
/// The batch ensures duplicate NRD kernels within the tx are handled correctly.
fn validate_tx_kernels(&self, tx: &Transaction) -> Result<(), Error> {
let has_nrd_kernel = tx.kernels().iter().any(|k| match k.features {
KernelFeatures::NoRecentDuplicate { .. } => true,
_ => false,
});
if !has_nrd_kernel {
return Ok(());
}
let mut header_pmmr = self.header_pmmr.write();
let mut txhashset = self.txhashset.write();
txhashset::extending_readonly(&mut header_pmmr, &mut txhashset, |ext, batch| {
let height = self.next_block_height()?;
ext.extension.apply_kernels(tx.kernels(), height, batch)
})
}

fn validate_tx_against_utxo(&self, tx: &Transaction) -> Result<(), Error> {
let header_pmmr = self.header_pmmr.read();
let txhashset = self.txhashset.read();
txhashset::utxo_view(&header_pmmr, &txhashset, |utxo, batch| {
utxo.validate_tx(tx, batch)?;
Ok(())
utxo.validate_tx(tx, batch)
})
}

Expand Down Expand Up @@ -929,8 +960,16 @@ impl Chain {
Some(&header),
)?;

// Validate the full kernel history (kernel MMR root for every block header).
self.validate_kernel_history(&header, &txhashset)?;
// Validate the full kernel history.
// Check kernel MMR root for every block header.
// Check NRD relative height rules for full kernel history.
{
self.validate_kernel_history(&header, &txhashset)?;

let header_pmmr = self.header_pmmr.read();
let batch = self.store.batch()?;
txhashset.verify_kernel_pos_index(&self.genesis, &header_pmmr, &batch)?;
}

// all good, prepare a new batch and update all the required records
debug!("txhashset_write: rewinding a 2nd time (writeable)");
Expand Down Expand Up @@ -979,6 +1018,9 @@ impl Chain {
// Rebuild our output_pos index in the db based on fresh UTXO set.
txhashset.init_output_pos_index(&header_pmmr, &batch)?;

// Rebuild our NRD kernel_pos index based on recent kernel history.
txhashset.init_recent_kernel_pos_index(&header_pmmr, &batch)?;

// Commit all the changes to the db.
batch.commit()?;

Expand Down Expand Up @@ -1115,6 +1157,9 @@ impl Chain {
// Make sure our output_pos index is consistent with the UTXO set.
txhashset.init_output_pos_index(&header_pmmr, &batch)?;

// Rebuild our NRD kernel_pos index based on recent kernel history.
txhashset.init_recent_kernel_pos_index(&header_pmmr, &batch)?;

// Commit all the above db changes.
batch.commit()?;

Expand Down
3 changes: 3 additions & 0 deletions chain/src/error.rs
Expand Up @@ -122,6 +122,9 @@ pub enum ErrorKind {
/// Tx not valid based on lock_height.
#[fail(display = "Transaction Lock Height")]
TxLockHeight,
/// Tx is not valid due to NRD relative_height restriction.
#[fail(display = "NRD Relative Height")]
NRDRelativeHeight,
/// No chain exists and genesis block is required
#[fail(display = "Genesis Block Required")]
GenesisBlockRequired,
Expand Down
4 changes: 4 additions & 0 deletions chain/src/lib.rs
Expand Up @@ -23,6 +23,9 @@
#[macro_use]
extern crate bitflags;

#[macro_use]
extern crate enum_primitive;

#[macro_use]
extern crate serde_derive;
#[macro_use]
Expand All @@ -35,6 +38,7 @@ use grin_util as util;

mod chain;
mod error;
pub mod linked_list;
pub mod pipe;
pub mod store;
pub mod txhashset;
Expand Down