wormhole/algorand
Josh Siegel 133523bd57 algo/fix: switch to using last round 2022-12-02 09:51:51 -05:00
..
audit_test WH-1816: add new .gitignore @ Closes #1816 2022-10-28 11:06:42 -05:00
sandbox-algorand algo/fix: switch to using last round 2022-12-02 09:51:51 -05:00
teal algo/cleanup: cleanup 2022-09-28 13:42:09 -05:00
test rename dev.v2 to main 2022-11-29 10:43:07 -05:00
.gitignore algo/builds: algorand mainnet builds 2022-09-20 10:37:59 -05:00
Dockerfile Docker FROM image pinning (#1337) 2022-07-06 15:05:30 -04:00
Dockerfile.build algo/builds: algorand mainnet builds 2022-09-20 10:37:59 -05:00
MEMORY.md certusone -> wormhole-foundation 2022-08-26 12:48:14 -04:00
Makefile algo/cleanup: cleanup 2022-09-28 13:42:09 -05:00
NOTES.md 1) Add payload3 support into typescript 2022-05-11 07:29:56 -05:00
Pipfile add: new and adversarial tests 2022-10-19 06:38:19 -05:00
Pipfile.lock algo/builds: algorand mainnet builds 2022-09-20 10:37:59 -05:00
README.md algo: Update README.md 2022-05-02 14:29:11 -04:00
TmplSig.py Test created by the C3 team. (#1796) 2022-10-26 09:55:53 -05:00
admin.py Added option to fund predefined dev accounts in Algorand deployment (#1997) 2022-11-28 08:12:10 -06:00
deploy.sh Added option to fund predefined dev accounts in Algorand deployment (#1997) 2022-11-28 08:12:10 -06:00
gentest.py add: new and adversarial tests 2022-10-19 06:38:19 -05:00
globals.py algo: contracts 2022-04-29 20:56:17 -04:00
inlineasm.py algo: contracts 2022-04-29 20:56:17 -04:00
local_blob.py algo: contracts 2022-04-29 20:56:17 -04:00
package-lock.json algo/typo: type fix, algorand tests, near tests 2022-09-26 05:26:56 -05:00
package.json algo/typo: type fix, algorand tests, near tests 2022-09-26 05:26:56 -05:00
requirements.txt algo/make: add Makefile and test script (#1153) 2022-05-31 16:47:31 -04:00
runPythonUnitTests.sh algo/fixTest: Fix python tests (#1547) 2022-09-07 09:53:55 -05:00
sandbox algo: contracts 2022-04-29 20:56:17 -04:00
test_contract.py New ABI selector support for algorand 2022-05-16 14:54:47 -05:00
testnet-update algo: contracts 2022-04-29 20:56:17 -04:00
token_bridge.py Test created by the C3 team. (#1796) 2022-10-26 09:55:53 -05:00
vaa_verify.py Test created by the C3 team. (#1796) 2022-10-26 09:55:53 -05:00
wormhole_core.py Test created by the C3 team. (#1796) 2022-10-26 09:55:53 -05:00

README.md

Wormhole Support for Algorand

This directory contains the components needed to support full Wormhole functionality under the Algorand blockchain platform.

Component overview


This system is comprised of the following main components:

  • Core contract (wormhole_core.py): Algorand stateful contract with entrypoints for publishing messages (VAAs), verification of VAA signatures, and triggering of governance chores. This will be referred as CoreContract in this document.

  • Token bridge contract (token_bridge.py): Algorand stateful contract supporting cross-chain bridging, exposing entrypoints for exchanging attestations, native tokens and ASAs, and triggering of governance. This will be referred as TokenBridge in this document.

  • VAA verification stateless program (vaa_verify.py): Stateless program for verifying the signatures of a Wormhole VAA payload against the set of active guardian public keys. This will be referred as VaaVerify in this document.

  • Dynamic storage stateless program (TmplSig.py): A stateless program that is bound to the main core and token bridge contracts to provide dynamic storage spaces addressable as a raw blob of bytes. See local_blob.py. This will be referred as TmplSig in this document.

Helper utilities and code include support PyTEAL code, deployment tools and tests.

System Architecture


TmplSig details


This stateless program code is parameterized with several values that give different output address. The stateless code will check for several transaction parameters accordingly.

Text Replaced by
TMPL_ADDR_IDX Where storage starts interpreting the space as a raw array of bytes
TMPL_EMITTER_ID Concatenation of chain Id + emitter Id in VAAs to be processed, or a hardcoded string identifying the type of information stored e.g guardian utf8 string stored in hex.
TMPL_APP_ID Application Id of CoreContract, TokenBridge, etc that is specified as the opt-in target transaction
TMPL_APP_ADDRESS Escrow address of the stateful contract specified in APP_ID. Used for rekey target in the transaction
  • Local-state associated with the TmplSig accounts are used as dynamic storage. The technique is to access this local storage as a plain array of bytes instead of the typical key/value structure. With the current Algorand parameters, we have 127 * 15 ~ 2K of storage to be used random-access-like.
  • The contract accounts addresses are generated by compilation of a stateless code parameterized by several parameters. In the system, the following contract accounts are generated:
    • Account (seq_addr) for storing verified sequence number bits based on chainId,emitter,int(vaa.sequence / MAX_BITS) where MAX_BITS = 15240. This allows the system to reject duplicated VAAs for the last 2K sequence numbers.
    • Account (guardian_addr and new_guardian_addr) for storing total guardian count , the guardian public keys and guardian set expiration time.
  • Once generated, the accounts are opted-in and rekeyed to the core application.

Briefly, the semantics of the transaction when TmplSig is "attached" to a stateful app is:

  1. Optin of LogicSig to target stateful contract TMPL_APP_ID for the app to use LogicSig account local storage
  2. Rekey of LogicSig to escrow address for the smart contract to become the sole "governor" of the LogicSig account address

NOTE: A more detailed overview of TmplSig can be found in MEMORY.md.

Core Contract: Functional Description


Initialization stage

The initialization call needs a governance VAA to be passed in, typically to setup initial guardian list. The init call will:

  • store the VaaVerify hash in the vphash global state key
  • check for the creator address, set booted global state to 1
  • check for duplicate VAA
  • handle the governance VAA passed as argument.

See below on how governance VAAs are processed, and how duplicate detection technique is used.

publishMessage

The publishMessage call will retrieve the current sequence number from related TmplSig local store, increment in by 1, store the new sequence number and emit a Log message which can be picked by Wormhole network for subsequently creating a guardian-signed VAA message.

hdlGovernance

Governance messages can carry requests for:

  • Update the active guardian set
  • Upgrade contracts: For Algorand, an upgrade-contract governance VAA must contain the hash of the program that is approved as an upgrade (stored in global validUpdateApproveHash). The upgrade process itself is triggered with the update action, where the clear and approval program hashes are checked against what the governance VAA carried. If they differ, an assertion is thrown and the update call is aborted. A successful call writes an onchain Log with the new hashes and allows the update process to go on.
  • Setting the per-message fee
  • Retrieving previously paid message fees

A governance request packed in a VAA must be verified by a verifyVaa call in the transaction group.

vaaVerify

The VAA verify call will work by design only in a transaction group structured as:

TX args accounts sender
verifySigs [sigs0..n, keyset0..n, digest] seq_addr, guardian_addr vaa_verify_stateless
verifySigs ... seq_addr, guardian_addr vaa_verify_stateless
verifyVAA vaa seq_addr, guardian_addr foundation

Keep in mind that depending on the number of signatures to verify there can be one or several verifySigs calls working in tandem with the VaaVerify stateless program. This depends on how many signatures we can verify on a single TX. At time of this writing, considering the opcode budget limitation of AVM 1.1, a total of nine (9) signatures can be verified at once, so for the current 19 guardians three verifySigs calls would be needed for verifying signatures 0..8, 9..17, 18.

A successful call must:

  • Retrieve the guardian keys from the proper local dynamic storage
  • Validate if the VAA passed in Argument #1 has enough guardians to be verified
  • Check that it's not expired.
  • Check that each guardian signed at most once
  • Verify that each verifySigs TX is validated by the correct stateless VerifyVaa
  • Verify that each verifySigs TX is verifying the expected signature subset.
  • Verify that each verifySigs TX is verifying against the same guardian keys.
  • Verify that each verifySigs TX is verifying the same VAA.

The vaaVerify call does allow nop (dummy) TX in the group to maximize opcode budgets and/or storage capacity. After the verifyVAA call, a client can issue more transactions with the fact that the VAA was verified.

Appendix: Duplicate verification


To detect duplicate VAA sequence numbers the following technique is used:

  • For each key in local state, there is an associated value entry. The total space of value-entries is 127*15, we have 2K of addressable space using the LocalBlob class.
  • A TmplSig stateless account is generated using the 2K space as a bit field, yielding 15240 bits. So for ~16K consecutive VAA numbers, the contract code sets a bit for identifying already verified VAAs. Based on setting the stateless TMPL_ADDR_IDX to formula vaa_sequence_number / 15240, we have designated storage for marking VAAs in consecutive 16k-bit blocks.