wormhole/algorand/README.md

106 lines
8.3 KiB
Markdown
Raw Normal View History

2022-04-29 12:53:48 -07:00
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`](./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.
2022-04-29 12:53:48 -07:00
* **Token bridge contract ([`token_bridge.py`](./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.
2022-04-29 12:53:48 -07:00
* **VAA verification stateless program ([`vaa_verify.py`](./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.
2022-04-29 12:53:48 -07:00
* **Dynamic storage stateless program ([`TmplSig.py`](./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`](./local_blob.py). This will be referred as _TmplSig_ in this document.
2022-04-29 12:53:48 -07:00
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.
2022-04-29 12:53:48 -07:00
| 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
2022-04-29 12:53:48 -07:00
* 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.
2022-04-29 12:53:48 -07:00
* 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
2022-04-29 12:53:48 -07:00
> NOTE: A more detailed overview of _TmplSig_ can be found in [MEMORY.md](./MEMORY.md).
2022-04-29 12:53:48 -07:00
## 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 | [sigs<sub>0..n</sub>, keyset<sub>0..n</sub>, digest] | seq_addr, guardian_addr | vaa_verify_stateless |
| verifySigs | ... | seq_addr, guardian_addr | vaa_verify_stateless |
| verifyVAA | vaa | seq_addr, guardian_addr | foundation |
2022-04-29 12:53:48 -07:00
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
2022-04-29 12:53:48 -07:00
* 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.