-
Notifications
You must be signed in to change notification settings - Fork 117
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
WIP: Add all necessary sled trees to zebra-state as defined in RFC0005 #1172
Conversation
I'm not sure how long our database format will stay the same. It's probably going to be stable for at least 6 months. But future network upgrades could change that. And if we fix a data bug, we might need to rebuild the database from Genesis. What's the plan for future database format upgrades / bug fixes? Should we also add some kind of database file or tree path versioning as part of this PR? Or should we schedule database versioning in a future alpha/beta release, before the first stable? |
The plan for future database format changes is to blow away the database and start over. Because the database is a cache of chain state, we don't lose any information by doing so, and it's much simpler and more reliable than trying to perform a migration. Adding a version number to the path (e.g., That said, it would be nice to minimize the frequency of changes to the database format, which I think is the goal of this PR. |
1e15f7a
to
d2dd26c
Compare
I have added this task to the TODO list for this PR. |
Can Zebra compute sprout and sapling anchors yet? If not, can we exclude them from the scope of this PR and the first alpha release? |
7b8f8f7
to
a689832
Compare
I don't think it's important for this PR that we check whether an older version is present and delete it, or implement any version handling at all. We just need to have a version separator in the path, so that it's possible to implement that in later changes. I think it would be sufficient to define a const SLED_FORMAT_VERSION: u32 = 0; and change let path = self.cache_dir.join(net_dir).join("state"); we do let path = self.cache_dir
.join("state")
.join(format!("v{}", SLED_FORMAT_VERSION))
.join(net_dir); (I changed the order of the path entries in a way that made more sense to me, so that someone who opens the cache directory sees Then, in a later change, we can implement logic that handles different versions, but that work doesn't need to block this change. |
These tracking items are currently in the state tracking issue. |
I opened #1213 for the "delete previous state versions" implementation. |
@yaahc can you please rebase on |
I've added the following TODOs to this PR, because they impact the state format (or state validity):
When we can compute anchors: |
Actually there are a few more changes, see the TODO list in the PR summary for details. |
Picking this up before finishing the request/response implementation because I'm concerned about merge conflicts. |
5f03e23
to
9f5314e
Compare
9f5314e
to
85d2645
Compare
I rebased this onto |
I was working off If they're done in this PR, that's all I wanted to double-check. |
@teor2345 Great, I just wanted to check to make sure that there wasn't an issue identified with the existing code. I think that all of the TODO items are addressed, except for the ones that are to be done later (when we can compute anchors). |
So to be clear, the current database format is v1... |
I think we should do the former |
@hdevalence what do you think about merging this PR as-is? |
|
||
#[cfg(test)] | ||
mod tests { | ||
#[test] | ||
fn it_works() { | ||
assert_eq!(2 + 2, 4); | ||
} | ||
} |
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.
This change could go in a separate PR, if you'd like - along with the identical change in zebra-rpc/src/lib.rs
// sprout_nullifiers: db.open_tree(b"sprout_nullifiers").unwrap(), | ||
// sapling_nullifiers: db.open_tree(b"sapling_nullifiers").unwrap(), | ||
sprout_nullifiers: db.open_tree(b"sprout_nullifiers").unwrap(), | ||
sapling_nullifiers: db.open_tree(b"sapling_nullifiers").unwrap(), | ||
debug_stop_at_height: config.debug_stop_at_height.map(block::Height), |
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.
debug_stop_at_height: config.debug_stop_at_height.map(block::Height), | |
// TODO: sprout and sapling anchors | |
debug_stop_at_height: config.debug_stop_at_height.map(block::Height), |
// total_flushed += self.sprout_nullifiers.flush()?; | ||
// total_flushed += self.sapling_nullifiers.flush()?; | ||
total_flushed += self.sprout_nullifiers.flush()?; | ||
total_flushed += self.sapling_nullifiers.flush()?; | ||
|
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.
// TODO: sprout and sapling anchors | |
// TODO: sprout and sapling anchors (per block) | ||
|
||
// Consensus-critical bug in zcashd: transactions in the | ||
// genesis block are ignored. | ||
if block.header.previous_block_hash == block::Hash([0; 32]) { | ||
return Ok(hash); | ||
} |
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.
I think the sprout anchor from the genesis block is also ignored by zcashd
, but let's confirm that.
Edit: there are no sprout anchors until block 100, due to the coinbase rules.
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.
@dconnolly do we only need to store one sprout anchor per block?
Or is every sprout treestate, after every transaction, a valid sprout anchor for future transactions?
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.
Hypothetically, if there were Sapling anchors at genesis, zcashd
would ignore them.
I don't know what Zebra should do with both the sprout and sapling edge cases, see PR #1232 for a potential RFC update.
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.
I have some minor suggestions about comments and PR structure, which shouldn't block merging.
We also need to work out if the genesis sprout anchor is valid in zcashd
, but we shouldn't block the PR on finding that out. (I suspect that it isn't, as zcashd
doesn't do a lot of the normal block processing on genesis blocks.)
Edit: there are no sprout anchors until block 100, due to the coinbase rules.
Motivation
At least for the near future, zebrad will not have the full test infrastructure
that we need to properly test new code paths that only get called on blocks
created after the sapling network upgrade, such as the
script::Verifier
. As aresult we are likely going to rely heavily on manual testing to verify new
features work as intended. We will then improve the speed with which we can
manually test zebra by backing up a copy of the
zebra-state
sled databasesynced up to the sapling activation height, where we can easily reset by wiping
out the current sled database and replacing it with the backed up copy.
This plan however requires makes changes to the sled database format costly.
Each time we add a new tree to the sled database the backed up database must be
deleted and re-created from genesis. To alleviate this issue we need to get
sled as close to the final format as we can as quickly as possible.
Solution
This change adds the expected sled trees as defined in the RFC. At the time of
writing the precise set of trees needed is a known unknown. Once we've finished
implementing incremental merkle trees however we should be able to determine
the proper format of the rest of the trees needed and include them in this PR,
hopefully bringing us to our final stable sled database format.
As part of this PR I've introduced a set of helper traits for consolidating the
definitions for how our types are stored and retrieved from sled. This should
help improve auditability by isolating related logic to one part of the file,
and ensuring that we use a single definition for the conversion across
sled_state.rs
.Related Issues
Test Plan
The introduction of
IntoSled
andFromSled
makes it possible to unit testour conversion formats in a way that wasn't possible before. Now it should be
relatively trivial to add a set of proptests that test each type that has both
an
IntoSled
and aFromSled
implementation to verify that the round tripconversion always returns the correct value.
sled_state.rs
IntoSled
andFromSled
TODOs
Reviews
Commits
andFiles Changed
only show changes from this PRBugs
zcashd
rejects.Incomplete
TransparentInput::PrevOut { outpoint, .. }
in the transaction'sinputs()
, removeoutpoint
fromutxo_by_output
(transaction_hash, BE32(block_height) || BE32(tx_index))
totx_by_hash
JoinSplit
description in the transaction, insert(nullifiers[0],())
and(nullifiers[1],())
intosprout_nullifiers
Spend
description in the transaction, insert(nullifier,())
intosapling_nullifiers
When we can compute anchors:
FinalizedState