kadena-io / pact

The Pact Smart Contract Language
https://pact-language.readthedocs.io/en/stable/
BSD 3-Clause "New" or "Revised" License
580 stars 100 forks source link

Add a builtin for decoding TokenMessage for hyperlane SPI #1344

Closed imalsogreg closed 5 months ago

imalsogreg commented 5 months ago

Part of the SPI interface is a TokenMessage: a tuple of a recipient, and amount, and a chain id:

{
  amount: Decimal,
  chainId: Text,
  recipient: Guard
}

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 a TokenMessage, useful for testing.

Usage:

pact>   (hyperlane-decode-token-message "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAewAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGF7InByZWQiOiAia2V5cy1hbGwiLCAia2V5cyI6WyJkYTFhMzM5YmQ4MmQyYzJlOTE4MDYyNmEwMGRjMDQzMjc1ZGViM2FiYWJiMjdiNTczOGFiZjZiOWRjZWU4ZGI2Il19AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==")
{"amount": 0.000000000000000123
,"chainId": "4"
,"recipient": KeySet {keys: [ da1a339bd82d2c2e9180626a00dc043275deb3ababb27b5738abf6b9dcee8db6 ]
,pred: keys-all}}

Todo:

Gas analysis:

The following code was used to benchmark decoding:

benchTokenMessages :: [Benchmark]
benchTokenMessages = 
  let
    !msg1 = mkTokenMessage 1
    name1 = "tokenmessage-" ++ show (T.length msg1)
    !msg1000 = mkTokenMessage 1000
    name1000 = "tokenmessage-" ++ show (T.length msg1000)
    !msg2000 = mkTokenMessage 2000
    name2000 = "tokenmessage-" ++ show (T.length msg2000)
  in
  [ bench name1 $ whnf hyperlaneDecodeTokenMessage msg1
  , bench name1000 $ whnf hyperlaneDecodeTokenMessage msg1000
  , bench name2000 $ whnf hyperlaneDecodeTokenMessage msg2000
  ]

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:

Additionally, please justify why you should or should not do the following: