-
Notifications
You must be signed in to change notification settings - Fork 118
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
TLV encoding: add forward-compatibility #1037
Conversation
Rebased. |
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.
Solid approach!
No major comments, other than one re how we can de-risk enforcing strict decode in a short time horizon.
Also need to circle back re the interaction with the test vectors and the new type constants, as well as some of the forward compat unit tests.
asset/asset.go
Outdated
@@ -2000,7 +2000,8 @@ func (a *Asset) Decode(r io.Reader) error { | |||
if err != nil { | |||
return err | |||
} | |||
return stream.Decode(r) | |||
|
|||
return TlvStrictDecode(stream, r, KnownAssetLeafTypes) |
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 to be slightly more conservative, we should put this behind a flag that's disabled for now. This protects us in the off chain that someone is using a modified version of the daemon with their own custom flag, or is using a fresh implementation.
We could check for this in the wild by running the new decode method on the existing assets in proofs uploaded to our Universe.
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.
But wouldn't that break the intended forward compatibility?
Isn't the intention that when we ship v0.4.2
with this code enabled (e.g. no flag, allow new unknown odd types) that we could then with v0.5.0
add new fields with odd types, being backward compatible to v0.4.2
?
With the intention that users can remain on v0.4.2
without their nodes complaining when syncing new proofs created with v0.5.0
. If they first have to turn on a flag to allow that, doesn't that kind of defeat the purpose?
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.
Related, a useful itest could be that, if a proof is created and then extended with an unknown odd field, checking that a client could successfully store that proof (via local Universe, DB, or flat file), and then return the identical proof to another client.
asset/asset.go
Outdated
return err | ||
} | ||
|
||
a.unknownOddTypes = unknownOddTypes |
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.
Dig the implementation!
One gap (still getting through the PR) that may pop up is when we encode a protocol object within the database as a fully featured row vs encoding an encoded blob.
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.
Isn't that what we do for most fields?
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 wouldn't actually store the information in the unknown types. Just keep it in memory so we can validate correctly (e.g. arrive at the correct leaf hash for assets or the correct meta hash for meta reveals).
Only when you upgrade to the version that implements the new value, would we store it, with the corresponding database migration. But then it would be a known type and the value wouldn't end up in unknownOddTypes
anymore.
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.
Looks good overall! I think it could be useful to have some of this exercised in itest, especially for the composite / nested types like proofs.
@guggero, remember to re-request review from reviewers when ready |
Will get back to this PR next week. |
Will look into that tomorrow, but I think for now this is ready for a re-review. |
Pull Request Test Coverage Report for Build 10421878251Details
💛 - Coveralls |
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.
Looks good! Left some comment in existing threads on itest behavior we may want to get better assurances on forwards-compat.
Some of the unit tests already extend data from the BIP test vectors, so I'm not sure if we want/need to add data with unknown types as test vectors themselves.
In this commit, as a follow up to the recent even/odd type split, we add some helper functions to assert that when we decode an asset TLV stream, we bail out if we find any unknown even types.
This commit makes it possible for the protocol to add new odd (optional) types in the future without old clients breaking. By parsing and keeping any left-over unknown odd types, then re-encoding them when calculating the commitment leaf, old software can still correctly use and validate an asset, even if it doesn't fully understand all of its (optional) new fields.
Fixes a temporary TODO and makes the check nil-safe.
I've added test vectors and an integration 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.
Awesome! With the itest, I'm convinced that this should work out.
Since that includes proof decode with an unknown type, I don't think there's particular value on running this over the proofs of our testnet and mainnet universes. IIUC any unknown types should have been dropped when those servers were storing the proofs anyway.
567: []byte("it's committed"), | ||
} | ||
cp.TaprootAssetProof.UnknownOddTypes = tlv.TypeMap{ | ||
789: []byte("there's assets in here..."), |
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.
😆
// there. | ||
require.Equal(t.t, modifiedBlob, transferProof2.RawProofFile) | ||
require.True(t.t, bytes.Contains(modifiedBlob, []byte("it's included"))) | ||
require.True( |
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.
💯
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.
Reviewed 18 of 18 files at r1, 28 of 28 files at r2, all commit messages.
Reviewable status: all files reviewed, 23 unresolved discussions (waiting on @guggero and @jharveyb)
commitment/commitment_test.go
line 1707 at r2 (raw file):
var knownProofBytes []byte test.RunUnknownOddTypeTest(
Nice generalization 👍
Replaces #557.
Fixes #997.
With this PR we add forward-compatibility that will allow us in the future to add new optional (odd-numbered) TLV types to any of our TLV structs without breaking old clients.
This will allow us to implement #956 in the future, once everyone has upgraded to
v0.4.1
(or whichever version this lands in).I opted to not go with any version increases, since this doesn't really change anything in the current behavior yet...
This change is