-
Notifications
You must be signed in to change notification settings - Fork 155
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
block-version-based protocol evolution #1468
block-version-based protocol evolution #1468
Conversation
validate_memos_exist(tx)?; | ||
} else { | ||
validate_no_memos_exist(tx)?; | ||
} | ||
|
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 is one of the main points of the PR
@@ -65,10 +67,11 @@ impl<FPR: FogPubkeyResolver> TransactionBuilder<FPR> { | |||
/// * `memo_builder` - An object which creates memos for the TxOuts in this | |||
/// transaction | |||
pub fn new<MB: MemoBuilder + 'static + Send + Sync>( | |||
block_version: BlockVersion, |
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 is one of the other main points of the PR
@@ -34,15 +38,15 @@ pub trait MemoBuilder: Debug { | |||
value: u64, | |||
recipient: &PublicAddress, | |||
memo_context: MemoContext, | |||
) -> Result<Option<MemoPayload>, NewMemoError>; | |||
) -> Result<MemoPayload, NewMemoError>; |
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 changed this because in the new world it doesn't make sense for a memo builder to sometimes omit the memo and sometimes not -- the block version controls if the memo is present or not, and the memo builder can just write MemoPayload::default
if they don't want to write any content. This also means NoMemoBuilder
goes away and is replaced by EmptyMemoBuilder
everywhere it was used, since it will do the right thing based on Block version.
let result = self.add_output_with_fog_hint_address( | ||
value, | ||
recipient, | ||
recipient, | ||
|memo_ctxt| mb.make_memo_for_output(value, recipient, memo_ctxt), | ||
|memo_ctxt| { | ||
if block_version.e_memo_feature_is_supported() { |
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 is where the transaction builder uses block version to decide whether or not to filter out memos
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.
Comments on BlockVersion (namely, keep it private, and use try_from to check whether a version is supported -- this is where the "this version is not supported" check happens, rather than making everyone that's consuming a chain implement their own version).
Tip for reviewers: consider pulling locally and doing |
Agreed. Fortunately GH also supports ignoring whitespace with |
TIL! Thanks! |
2e3277b
to
86c37a3
Compare
@@ -122,7 +123,7 @@ impl Block { | |||
/// * `root_element` - The root element for membership proofs | |||
/// * `block_contents` - Contents of the block. | |||
pub fn new( | |||
version: u32, | |||
version: BlockVersion, |
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.
we could consider that Block
doesn't use a BlockVersion
and uses a u32
instead, since it is using u32 internally. that would make the ledger db test around adding too recent blocks still possible.
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 personally prefer this version with the transmute hack in the test.
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.
+1 for keeping BlockVersion and using the hack in test
let mut ledger = create_ledger(); | ||
let n_blocks = 1; | ||
initialize_ledger(&mut ledger, n_blocks, &sender, &mut rng); | ||
initialize_ledger( | ||
adapt_hack(&block_version), |
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 would really like to refactor to kill off this adapt_hack
stuff, I think we just have to reorganize the crates a little bit.
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.
That would be nice (in a followup PR)
I think this may be ready to go, I fixed up all the consensus-service plumbing:
|
let invalid_block = Block::new_with_parent( | ||
last_block.version + 1, | ||
unsafe { core::mem::transmute(last_block.version + 1) }, |
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.
let me know if you guys have feelings about this, i think this is a valuable test to keep running, and this lets us bypass the invariant enforced by BlockVersion
that the version can't exceed BlockVersion::MAX
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 guess another option is to make add_block
function of ledger db not take a BlockVersion
, and just take a u32
and internally convert it to a BlockVersion
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 its better to keep using the proper type and doing this hack in the test code.
Co-authored-by: Remoun Metyas <[email protected]>
it looks maybe a little worse to me towards the end of the slam, but peak is still ~40 tps, not sure if the rest of the graph is statistically significant |
i'm going to try deploying this PR a second 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.
LGTM. I think it's okay to merge even if performance is a bit degraded because this is an important piece in many upcoming changes and releases. It would be great if we could find the time to do some profiling of stuff in the enclave and consensus-service. It's been awhile since we went through that exercise..
20s tx completion time is a pretty big difference than 15s I am used to seeing... |
@eranrund yeah i'm not sure what could be causing this, maybe its because we are holding the mutex for the fees for a longer period of time? |
maybe we should try replacing the |
Interesting, maybe? |
I just made a quick patch like this: and pushed it to build, let's see what happens (I didn't see your suggestion before I started working on it this way) |
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 generally looks good to me, the only real question is what BlockVersion::default() should actually default to---it feels to me like it should be ONE
(or MIN
, or whatever), not MAX
, but I'm also not sure where it's actually used...
use mc_transaction_core::{tokens::Mob, Token, TokenId}; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
/// A thread-safe object that contains a map of fee value by token id. | ||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] | ||
#[derive(Clone, Debug, Deserialize, Digestible, Eq, Hash, PartialEq, Serialize)] | ||
pub struct FeeMap { |
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.
Can this get reduced to a newtype struct?
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.
Probably but lets do it in a subsequent PR, it's kind of orthogonal to this PR, and there's a lot more token config stuff coming down the pipeline
fn default() -> Self { | ||
Self { | ||
fee_map: FeeMap::default(), | ||
block_version: BlockVersion::MAX, |
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 we'd want this to be ::MIN
, right?
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.
Remoun had suggested ::MAX
in earlier review. (IIRC)
I think the default doesn't actually matter here, the actual default in the enclave is None
basically, and the struct_opt default I think is 1
for backwards compat
@@ -564,7 +599,7 @@ impl ConsensusEnclave for SgxConsensusEnclave { | |||
|
|||
// Form the block. | |||
let block = Block::new_with_parent( |
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.
If we want to do this, can we make a ticket for it?
use mc_util_from_random::FromRandom; | ||
use rand::{rngs::StdRng, SeedableRng}; | ||
use rand_core::RngCore; | ||
use tempdir::TempDir; | ||
use test::Bencher; | ||
|
||
// TODO: Should these tests run over several block versions? | ||
const BLOCK_VERSION: BlockVersion = BlockVersion::ONE; |
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.
Is this used? The tests below appear to all use BlockVersion::ONE
directly...
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.
In my search I see a lot of uses of BLOCK_VERSION
in this file and no uses of BlockVersion::ONE
. If you prefer we can mass replace them
add once-cell for config in block-version-aware PR
This makes transaction builder and validation aware of BlockVersion.
It also plumbs this config into consensus.
This commit adds support for the change in fog sample paykit
and mobilecoind
See also: mobilecoinfoundation/mcips#26
Checklist:
form_block
, but it might be better to do it differently, e.g. block version is announced on enclave startup, and can change afterform_block
but not in between calls to form block?latest_block.version
and configured block version, but perhaps it should only ever use the configured block version.BlockVersion(1)
orBlockVersion::MAX
because that seemed like the highest value testing. Review these decisions.