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

Introduce CommitOnly variant of Inputs #3419

Merged
merged 16 commits into from
Sep 7, 2020

Conversation

antiochp
Copy link
Member

@antiochp antiochp commented Aug 8, 2020

This PR bumps the node protocol version to to 3.

Inputs in both transactions and blocks are serialized as follows -

(Commitment)

Previously in protocol version 2 they were serialized as -

(Features || Commitment)

Note that the sorting of inputs is affected by this also.

Inputs are now sorted using the following sort key -

Hash(Commitment)

Previously they were sorted with the key -

Hash(Features || Commitment)

This affects the serialization of lists of inputs, not just individual inputs themselves. Inputs are not stored on-chain so this is not a consensus breaking change.
Outputs are unaffected by this change.

Full support for protocol version 2 peers is maintained via the existing version negotiation scheme.

Locally we store full blocks in the db in v3 format. These are converted to v2 before broadcasting to v2 peers as necessary.

Transactions are stored in the txpool (and stempool) in v2 format. This is to allow broadcast and relay with v2 peers in a convenient way. It is non-trivial to convert transactions v3->v2 due to possibility of one transaction spending unconfirmed outputs from another transaction in the txpool. To simplify transaction handling we maintain them in v2 format.
This will be revisited once we have wide support for v3 across the network.

Care has been taken not to introduce malleability here with backward support. Blocks and transactions in v2 format must have a valid and correct features byte.


Why Make This Change?

Uniqueness is enforced across the current utxo set.
It is not valid to have two unspent outputs with the same commitment.
Spending an output is done solely by output commitment. The features bytes is entirely redundant.
Internally we want to simplify the spending logic by removing any reference to the redundant input features byte.

This is one of the outstanding wrinkles in the p2p msg format that we wish to resolve prior to the final scheduled hardfork.
This leaves open the possibility of taking advantage of the final HF to break backward compatibility, simplifying a lot of internal version handling implementation details.


  • Introduce CommitOnly variant of Inputs
  • Introduce CommitWrapper to wrap "commit only" inputs so we can sort them correctly (by hash).
  • v3 -> v2 conversion (need to lookup outputs being spent) for backward compatibility with v2 peers

TODO -

  • v2/v3 serialization for the two Inputs variants.
    • write "commit only" for v3
    • convert "features and commit" to "commit only" for v3
    • write "features and commit" for v2
    • compatibility error if attempt to write "commit only" for v2
    • write provided data for hash serialization mode
  • v2/v3 deserialization for two Inputs variants
    • read "features and commit" for v2
    • read "commit only" for v3
  • test coverage for v2/v3 serialization and deserialization
  • consider cost of maintaining backward compatibility here
    • store in v3 in local db
    • convert to v2 "on demand" if relaying full block to v2 peer?
  • bump default protocol version to 3


TODO -

@antiochp antiochp force-pushed the inputs_enum_variants branch 2 times, most recently from 87f2b89 to 8c06ece Compare August 10, 2020 09:08
@antiochp antiochp changed the title Introduce CommitOnly variant of Inputs. Introduce CommitOnly variant of Inputs Aug 10, 2020
@antiochp antiochp marked this pull request as ready for review August 21, 2020 07:01
@antiochp antiochp force-pushed the inputs_enum_variants branch from e40b54b to 0167a8d Compare August 21, 2020 07:07
Copy link
Member

@quentinlesceller quentinlesceller left a comment

Choose a reason for hiding this comment

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

Wow took me a while to review. Looking good. Few comments below. Also ran it locally for 24 hours without issues.

@@ -171,6 +171,10 @@ impl Chain {
) -> Result<Chain, Error> {
let store = Arc::new(store::ChainStore::new(&db_root)?);

// DB migrations to be run prior to the chain being used.
// Migrate full blocks to protocol version v3.
Chain::migrate_db_v2_v3(&store)?;
Copy link
Member

Choose a reason for hiding this comment

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

Any reason why don't need a lexical scope anymore?

Copy link
Member Author

Choose a reason for hiding this comment

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

It was purely for visual/readability purposes before. It was not needed at the code level.

@@ -291,18 +290,19 @@ impl Chain {

let mut header_pmmr = self.header_pmmr.write();
let mut txhashset = self.txhashset.write();
let outputs =
let inputs: Vec<_> =
Copy link
Member

Choose a reason for hiding this comment

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

I would find it easier to ready if inputs was named unspent_outputs.

chain/src/txhashset/utxo_view.rs Show resolved Hide resolved
@@ -662,12 +663,12 @@ impl Chain {

/// Verify we are not attempting to spend a coinbase output
/// that has not yet sufficiently matured.
pub fn verify_coinbase_maturity(&self, tx: &Transaction) -> Result<(), Error> {
pub fn verify_coinbase_maturity(&self, inputs: Inputs) -> Result<(), Error> {
Copy link
Member

Choose a reason for hiding this comment

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

Wondering if is it any better to change the function signature to:

pub fn verify_coinbase_maturity(&self, inputs: &Inputs) -> Result<(), Error> {

In the current case Rust makes a copy of the Input no?

Copy link
Member Author

Choose a reason for hiding this comment

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

👍 I think this makes sense. Same for verify_inputs().

Comment on lines 103 to 108
if out == input.into() {
Ok((out, pos))
} else {
error!("input mismatch: {:?}, {:?}, {:?}", out, pos, input);
Err(ErrorKind::Other("input mismatch".into()).into())
}
Copy link
Member

Choose a reason for hiding this comment

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

So is this check redundant based on what we have at line 128-136 or the OutputFeatures feature check is important (for Inputs::FeaturesAndCommit variant only)?

Copy link
Member Author

@antiochp antiochp Sep 7, 2020

Choose a reason for hiding this comment

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

Yes, the latter. We need to ensure that if the features are passed in that they are correct.
For CommitOnly variant we can safely skip this.

This is to maintain existing behavior and to avoid introducing malleability with the features being effectively ignored.

pool/src/transaction_pool.rs Outdated Show resolved Hide resolved
pool/src/transaction_pool.rs Show resolved Hide resolved
pool/src/pool.rs Show resolved Hide resolved
core/src/core/transaction.rs Outdated Show resolved Hide resolved
core/src/core/transaction.rs Outdated Show resolved Hide resolved
@antiochp antiochp force-pushed the inputs_enum_variants branch from 7c32e4e to b5dae01 Compare September 7, 2020 09:06
@antiochp antiochp merged commit 7dc9457 into mimblewimble:master Sep 7, 2020
@antiochp antiochp deleted the inputs_enum_variants branch September 7, 2020 15:58
@antiochp antiochp added this to the 4.1.0 milestone Sep 9, 2020
@antiochp antiochp mentioned this pull request Sep 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Transaction (and block) inputs need only include the commitment
2 participants