-
Notifications
You must be signed in to change notification settings - Fork 102
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
Add a builtin for decoding TokenMessage for hyperlane SPI #1344
Conversation
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.
My approval is waiting on @ak3n's
pact.cabal
Outdated
@@ -207,6 +207,7 @@ library | |||
, base >= 4.18.0.0 | |||
, base16-bytestring >=0.1.1.6 | |||
, base64-bytestring >=1.0.0.1 | |||
, binary |
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.
Needs a lower bound
src/Pact/Native.hs
Outdated
|
||
-- Parse the size of the following amount field. | ||
amountSize <- fromIntegral @Word256 @Int <$> getWord256be | ||
unless (amountSize == 96) |
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.
Why is this 96? Does @ak3n know?
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's not an amountSize
but the offset of the recipient
which is a string.
recipient
is a first field of the TokenMessageERC20
structure and since it was encoded with abi.encode
there is an offset:
0000000000000000000000000000000000000000000000000000000000000060 # offset of the recipient string = 96, because first three lines are 32 bytes each
0000000000000000000000000000000000000000000000008ac7230489e80000 # amount = 10000000000000000000
0000000000000000000000000000000000000000000000000000000000000000 # chainId = 0
000000000000000000000000000000000000000000000000000000000000002a # recipientSize = 42
3078373143373635364543376162383862303938646566423735314237343031 # "0x71C7656EC7ab88b098defB751B7401B5f6d8976F"
4235663664383937364600000000000000000000000000000000000000000000
Let's leave this comment in the code
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.
@ak3n Thanks for the comment example! The only part I don't understand is the example recipient "0x71C7656EC7ab88b098defB751B7401B5f6d8976F". Our recipients are now JSON-encoded guards, e.g. { "pred": "keys-any", "keys": [...] }
. Should we replace the hex string with that?
@@ -276,7 +276,7 @@ pact410Natives :: [Text] | |||
pact410Natives = ["poseidon-hash-hack-a-chain"] | |||
|
|||
pact411Natives :: [Text] | |||
pact411Natives = ["enforce-verifier", "hyperlane-message-id"] | |||
pact411Natives = ["enforce-verifier", "hyperlane-message-id", "hyperlane-decode-token-message"] |
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.
Either we need to specify the version hyperlane-v3-decode-token-message
or pass an object with {"version": 3, ...}
field.
@edmundnoble, should we also specify the type of the token? hyperlane-decode-token-message-erc20
.
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 don't think that's necessary, because tokenmessage is not actually part of the Hyperlane spec, so it's not versioned with it. We can make future versions, if they're needed, use -v2
, -v3
, etc.
src/Pact/Native.hs
Outdated
|
||
-- Parse the size of the following amount field. | ||
amountSize <- fromIntegral @Word256 @Int <$> getWord256be | ||
unless (amountSize == 96) |
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's not an amountSize
but the offset of the recipient
which is a string.
recipient
is a first field of the TokenMessageERC20
structure and since it was encoded with abi.encode
there is an offset:
0000000000000000000000000000000000000000000000000000000000000060 # offset of the recipient string = 96, because first three lines are 32 bytes each
0000000000000000000000000000000000000000000000008ac7230489e80000 # amount = 10000000000000000000
0000000000000000000000000000000000000000000000000000000000000000 # chainId = 0
000000000000000000000000000000000000000000000000000000000000002a # recipientSize = 42
3078373143373635364543376162383862303938646566423735314237343031 # "0x71C7656EC7ab88b098defB751B7401B5f6d8976F"
4235663664383937364600000000000000000000000000000000000000000000
Let's leave this comment in the code
src/Pact/Native.hs
Outdated
where | ||
getWord256be = get @Word256 | ||
|
||
-- TODO: We check the size. Is this ok? |
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 good 👍
But my comment was about the take
and fromIntegral
functions since size :: Word256
and we convert it to Int
.
* Add hyperlane-decode-token-message with gas * include chainid in TokenMessage encoding * add principal check for recipient * TokenMessage recipient parsed as guard * add new builtin to pact411natives and suppress a debugging error message * exhaust the TokenMessage when parsing * use wide-word instead of doubleword * remove stale TODOs * cleanup more comments * Set the empirically measured cas cost for TokenMessage decoding * fix example in native definition * fix examples * rename builtin to hyperlane-decode-token-message * use base64-unpadded encoding/decoding for tokenmessage * fix gas costing and add gas tests * lower bound for binary dependency * cleanup tokenmessage decoder comments and variable names * remove padding from encoded message in tokenmessage decoding example * gasmodelspec remove buildin from list of gas-untested * update example encoding
Part of the SPI interface is a
TokenMessage
: a tuple of a recipient, and amount, and a chain id:The wire format for a
TokenMessage
is a packed binary encoding of these fields, followed by base64url encoding.Pact needs to provide a builtin for decoding such an encoded message into its original form, to support the larger SPI scheme. This PR implements that builtin, named
hyperlane-decode-token-message
. It also provides a convenience function for encoding aTokenMessage
, useful for testing.Usage:
Todo:
Gas analysis:
The following code was used to benchmark decoding:
The results are: 2 microseconds for a 256-byte message, 11 microseconds for an 10880-byte message, 21 microseconds for a 21548-byte message.
400 MilliGas = 1 microsecond by policy. 10k bytes = 10 microseconds by benchmarks. 100 bytes = 0.1 microseconds = 40 MilliGas. We round up to 50 MilliGas as a safety buffer.
PR checklist:
cabal run tests
. If they pass locally, docs are generated.pact -t
), make sure pact-lsp is in sync.Additionally, please justify why you should or should not do the following: