-
Notifications
You must be signed in to change notification settings - Fork 58
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
[Feat:] Time consensus implementation #300
base: master
Are you sure you want to change the base?
Conversation
4772a7d
to
f602686
Compare
My master was behind |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good, some implementation comments.
14dced6
to
4cc0df3
Compare
Applied changes by @Davidson-Souza. 4cc0df3 Tries to implement Note to reviewersIm still not glad with this solution to validate time-related data and still a lot of work to do around this changes. I would like to:
|
6bbe2c9
to
c58203d
Compare
2ceb8e9
to
a67e177
Compare
|
a67e177
to
b247973
Compare
This shouldnt be caught by Anyway... Ill do better local tests, sorry. My next PR will be #260 |
b247973
to
880bffb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking very cool! One thing I'm not sure is whether get_mtp
should be on UpdatableChainState
. Usually these methods are used by who's driving the chainstate only, but mtp is useful elsewhere (e.g. the rpc).
|
So would it be better located at |
880bffb
to
f33bbf7
Compare
Yes! |
f33bbf7
to
567e002
Compare
567e002
to
3fce924
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some small things left. Also, please apply the following formatting diff.
Big scary diff
diff --git a/crates/floresta-chain/src/pruned_utreexo/chain_state.rs b/crates/floresta-chain/src/pruned_utreexo/chain_state.rs
index a35b68c..171bdcd 100644
--- a/crates/floresta-chain/src/pruned_utreexo/chain_state.rs
+++ b/crates/floresta-chain/src/pruned_utreexo/chain_state.rs
@@ -1006,6 +1006,7 @@ impl<PersistedState: ChainStore> BlockchainInterface for ChainState<PersistedSta
let mut inner = write_lock!(self);
inner.broadcast_queue.drain(..).collect()
}
+
fn get_mtp(&self, height: u32) -> Result<u32, BlockchainError> {
let mut initial_array = [0u32; 11];
diff --git a/crates/floresta-chain/src/pruned_utreexo/consensus.rs b/crates/floresta-chain/src/pruned_utreexo/consensus.rs
index 4ca1fb3..019ce31 100644
--- a/crates/floresta-chain/src/pruned_utreexo/consensus.rs
+++ b/crates/floresta-chain/src/pruned_utreexo/consensus.rs
@@ -486,6 +486,7 @@ mod tests {
)),
);
}
+
/// Validates a relative timelock transaction and return its errors if any.
///
/// utxo_lock: is the lock value which can be either a height or a timestamp. Defines the creation time/height of the UTXO.
@@ -607,17 +608,18 @@ mod tests {
)
.err()
}
+
#[test]
fn test_timelock_validation() {
- assert!(test_abstimelock(800, 800 + 1, 0).is_none()); //height locked sucess case.
+ assert!(test_abstimelock(800, 800 + 1, 0).is_none()); // height locked success case.
assert_eq!(
- test_abstimelock(800, 800 - 1, 0), //height locked fail case.
+ test_abstimelock(800, 800 - 1, 0), // height locked fail case.
Some(BlockValidationErrors::BadAbsoluteLockTime)
);
- assert!(test_abstimelock(1358114045, 0, 1358114045 + 1).is_none()); //time locked sucess case
+ assert!(test_abstimelock(1358114045, 0, 1358114045 + 1).is_none()); // time locked success case
assert_eq!(
- test_abstimelock(1358114045, 0, 1358114045 - 1), //time locked fail case
+ test_abstimelock(1358114045, 0, 1358114045 - 1), // time locked fail case
Some(BlockValidationErrors::BadAbsoluteLockTime)
);
@@ -636,7 +638,7 @@ mod tests {
Some(BlockValidationErrors::BadRelativeBlockLock)
);
- // relative time locked sucess case
+ // relative time locked success case
let intervals_to_wait: u16 = 1;
let sequence = Sequence::from_512_second_intervals(intervals_to_wait);
assert!(test_reltimelock(
@@ -658,6 +660,7 @@ mod tests {
Some(BlockValidationErrors::BadRelativeTimeLock)
);
}
+
#[test]
fn test_timelock_tx() {
let utxo = UtxoData {
diff --git a/crates/floresta-chain/src/pruned_utreexo/mod.rs b/crates/floresta-chain/src/pruned_utreexo/mod.rs
index 0de7012..5b0d46e 100644
--- a/crates/floresta-chain/src/pruned_utreexo/mod.rs
+++ b/crates/floresta-chain/src/pruned_utreexo/mod.rs
@@ -366,6 +366,7 @@ impl<T: BlockchainInterface> BlockchainInterface for Arc<T> {
T::get_fork_point(self, block)
}
}
+
/// Module to delegate local-time context.
///
/// The consumer of `Floresta-chain` has the option to implement [`NodeTime`] if on a non-std environment.([`get_time()`] implementation that returns 0u32 will disable time checks.)
@@ -376,8 +377,10 @@ pub mod nodetime {
///
/// Meant to be used in cases to disable time verifications
pub struct DisableTime;
+
/// One Hour in seconds constant.
pub const HOUR: u32 = 60 * 60;
+
/// Trait to return time-related context of the chain.
///
/// [`get_time()`] should return a the latest [unix timestamp](https://en.wikipedia.org/wiki/Unix_time) when the consumer has time-notion.
@@ -387,12 +390,14 @@ pub mod nodetime {
/// Should return a unix timestamp or 0 to skip any time related validation.
fn get_time(&self) -> u32;
}
+
impl NodeTime for DisableTime {
fn get_time(&self) -> u32 {
// we simply return zero to disable time checks
0
}
}
+
#[cfg(feature = "std")]
/// A module to provide the standard implementation of [`NodeTime`] trait. It uses [`std::time::SystemTime`] to get the current time.
pub mod standard_node_time {
@@ -410,6 +415,7 @@ pub mod nodetime {
}
}
}
+
///Module to hold methods and structs related to UTXO data.
pub mod utxo_data {
e58aadc
to
f082575
Compare
Looks like f082575 is doing it. Only need a rebase and there's two places where |
02c1f7f
to
2768279
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @jaoleal, the issue with the CI tests seems to be that the correct attribute is test
, as pointed below. The tests were using the 'canonical' get_mtp
because of this.
Actually the non_canonical
feature is used only for ignoring the mtp for the benches right?
It was my idea too, this was a broken PR that i had to upload just to move the code to another machine so i can test this branch. Looks like that even if i set |
I mean using |
2768279
to
a869130
Compare
I know. This resolves other tests but fail on others. |
a869130
to
be30e39
Compare
Nice! You fixed the other issue by adding the dev dependency to wire ( I will do a deeper review tomorrow but this seems almost ready. |
be30e39
to
bc0fb6a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually there's a straightforward way of removing the non_canonical
feature. The issue we have is that test and benches for verify_block_no_acc
aren't designed to keep the previous 11 blocks for mtp
, so let's instead move get_mtp
outside of the function:
pub fn validate_block_no_acc(
&self,
block: &Block,
height: u32,
inputs: UtxoMap,
// NEW
mtp: u32,
) -> Result<(), BlockchainError> {
#[cfg(not(feature = "std"))]
let time = super::nodetime::DisableTime;
#[cfg(feature = "std")]
let time = super::nodetime::standard_node_time::StdNodeTime;
Consensus::validate_block_time(block.header.time, mtp, time)?;
// Rest of the function
Then we call get_mtp
inside validate_block
and connect_block
, just before validate_block_no_acc
:
// Compute the Median Time Past of the 11 previous blocks
let mtp = self.get_mtp(height - 1)?;
self.validate_block_no_acc(block, height, inputs, mtp)
Then for the tests and benches we simply pass a mtp
of 0, and fixed!
bitcoinconsensus = ["bitcoin/bitcoinconsensus", "dep:bitcoinconsensus"] | ||
metrics = ["dep:metrics"] | ||
|
||
[[bench]] | ||
name = "chain_state_bench" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unresolved nit: remove this line
for i in 0..11 { | ||
let time = match self.get_block_hash(height.saturating_sub(i)) { | ||
Ok(hash) => self.get_block_header(&hash)?.time, | ||
_ => { | ||
info!("Block timestamp : {i} Not found"); | ||
0 | ||
} | ||
}; | ||
initial_array[10 - i as usize] = time; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we call get_mtp
to validate the block it feels like we would already have all the hashes from this block and the previous 10. Or if the height is < 11, we would repeat the genesis time and that's all.
So I feel like the _ => { info! ... }
shouldn't be there, and should be an error. Am I missing something?
pub struct UtxoData { | ||
/// The transaction output that created this UTXO. | ||
pub txout: bitcoin::TxOut, | ||
/// The lock value of the utxo. | ||
pub commited_height: u32, | ||
pub commited_time: u32, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: It should be comitted_height
and comitted_time
, and add a comment for each (in height vs in unix time)
b020831
to
d20bff7
Compare
This commit implement the consensus rules related to: - Median Time Past - Block Timestamp Validation - Transaction locktime validation - Input Sequence relative locktime validation To accomplish that, a new struct `UtxoData`, a `UtxoMap` wrapper type around `HashMap<OutPoint, UtxoData>` and a new module called `nodetime` where added. UtxoData is a wrapper with data related to Utxo commitment, commitment_time and commitment_height. nodetime is a module that holds `NodeTime` a trait that allow one implement its own way of world time notion. `DisableTime` just return zero and is expected to disable time validation. Also changes the "default" feature of floresta-chain to "std". Another change on floresta_chain `cargo.toml` is the non_canonical feature. Which makes get_mtp allways return the genesis mtp. This was needed to still run floresta-chain inside parcial contexts without breaking, for example: benchmark and tests.
d20bff7
to
dd50d76
Compare
Since #198 became abandoned and wasnt updated i decided to reimplement what was done from that PR.
This PR tries to add the validation for Time related data to floresta.
To implement this i ran trough some solutions and here they are:
locktime inside the transactions
: To validate them i need theMTP
and the timestamp of the block when the utxo was created.Block Timestamp
: To validate if a block is inserting the correct timestamp i need theMTP
of the chain.This changes implements a new struct and a trait on
mod
and a new function onConsensus
.validate_locktime
method insideConsensus
to consume the other solutions (MTP, UTXO TIME-DATA) and to validate time itself.The work from now on in this PR is:
validate_locktime
and populate support for it, changing some methods signature(includingvalidate_transactions
,validate_block
and etc...).