certusone -> wormhole-foundation

This commit is contained in:
Evan Gray 2022-08-26 12:35:22 -04:00 committed by Evan Gray
parent 4a42c29c0f
commit f28e39c490
28 changed files with 236 additions and 210 deletions

View File

@ -1,42 +1,49 @@
---
name: Wormhole issue Template
about: Default issue template
title: ''
labels: ''
assignees: ''
title: ""
labels: ""
assignees: ""
---
Github issues are **ONLY** for reporting bugs. Before contributing new features (such as a new chain) please first read the [contribution frequently asked questions](https://github.com/certusone/wormhole/blob/dev.v2/CONTRIBUTING.md#contributions-faq).
Github issues are **ONLY** for reporting bugs. Before contributing new features (such as a new chain) please first read the [contribution frequently asked questions](https://github.com/wormhole-foundation/wormhole/blob/dev.v2/CONTRIBUTING.md#contributions-faq).
For user support questions such as VAA not found, please use the [Wormhole Official Discord](https://discord.gg/wormholecrypto). Do not give your wallet private key or mnemonic words to anyone.
<!--- Provide a general summary of the issue in the Title above -->
## Expected Behavior
<!--- Tell us what should happen -->
## Current Behavior
<!--- Tell us what happens instead of the expected behavior -->
## Possible Solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
## Steps to Reproduce
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
<!--- reproduce this bug. Include code to reproduce, if relevant -->
1.
2.
3.
## Context (Environment)
<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
<!--- Provide a general summary of the issue in the Title above -->
## Detailed Description
<!--- Provide a detailed description of the change or addition you are proposing -->
## Possible Implementation
<!--- Not obligatory, but suggest an idea for implementing addition or change -->

View File

@ -10,7 +10,7 @@ on:
env:
REGISTRY: ghcr.io
IMAGE_NAME: certusone/guardiand
IMAGE_NAME: wormhole-foundation/guardiand
jobs:
build-and-push-image:

View File

@ -7,7 +7,7 @@ on:
env:
REGISTRY: ghcr.io
IMAGE_NAME: certusone/payloadv1-relayer
IMAGE_NAME: wormhole-foundation/payloadv1-relayer
jobs:
build-and-push-relayer-image:

View File

@ -1,4 +1,4 @@
githubRepoOwner: certusone
githubRepoOwner: wormhole-foundation
githubRepoName: wormhole
githubHost: github.com
requireChecks: true

View File

@ -10,18 +10,15 @@ and code reviews are our most important tools to accomplish that.
complex features, it can be useful to submit a [formal design document](design/template.md).
- Development happens on a long-lived development branch (`dev.v2` and `dev.v1`).
Every change going into a development branch is reviewed individually (see below). Release branches may be used
Every change going into a development branch is reviewed individually (see below). Release branches may be used
to support in-the-wild releases of Wormhole. We aim to support at most two release
branches at the same time. Changes can be cherry-picked from the development branch to release branches, but
never from release branches to a development branch.
- Releases are first tested on a testnet.
- Commits should be small and have a meaningful commit message. One commit should, roughly, be "one idea" and
be as atomic as possible. A feature can consist of many such commits.
- Feature flags and interface evolution are better than breaking changes and long-lived feature branches.
- We optimize for reading, not for writing - over its lifetime, code is read much more often than written.
Small commits, meaningful commit messages and useful comments make it easier to review code and improve the
quality of code review as well as review turnaround times. It's much easier to spot mistakes in small,
@ -42,12 +39,10 @@ The answer is... maybe? The following things are needed in order to fully suppor
a node or light client for every chain supported by Wormhole. This adds up, and the barrier to support new
chains is pretty high. Your proposal should clearly outline the value proposition of supporting the new chain.
**Convincing the DAO to run nodes for your chain is the first step in supporting a new chain.**
- The chain needs to support smart contracts capable of verifying 19 individual secp256k1 signatures.
- The smart contract needs to be built and audited. In some cases, existing contracts can be used, like with
EVM-compatible chains.
- Support for observing the chain needs to be added to guardiand.
- Web wallet integration needs to be built to actually interact with Wormhole.
@ -68,13 +63,17 @@ own features on top of, without requiring any changes in Wormhole itself.
Please open a GitHub issue outlining your use case, and we can help you build it!
# Pre-Commit checks
Run `./scripts/lint.sh -d format` and `./scripts/lint.sh lint`.
Run `./scripts/lint.sh -d format` and `./scripts/lint.sh lint`.
## IDE Integration
### Golang formatting
You must format your code with `goimports` before submitting.
You can install it with `go install golang.org/x/tools/cmd/goimports@latest` and run it with `goimports -d ./`.
You can enable it in VSCode with the following in your `settings.json`.
You must format your code with `goimports` before submitting.
You can install it with `go install golang.org/x/tools/cmd/goimports@latest` and run it with `goimports -d ./`.
You can enable it in VSCode with the following in your `settings.json`.
```json
"go.useLanguageServer": true,
"go.formatTool": "goimports",
@ -95,22 +94,22 @@ We believe automated tests ensure the integrity of all Wormhole components. Anyo
Places to find out more about existing test coverage and how to run those tests:
- **Guardian Node**
- Tests: `./node/**/*_test.go`
- Run: `cd node && make test`
- Tests: `./node/**/*_test.go`
- Run: `cd node && make test`
- **Ethereum Smart Contracts**
- Tests: `./ethereum/test/*.[js|sol]`
- Run: `cd ethereum && make test`
- Tests: `./ethereum/test/*.[js|sol]`
- Run: `cd ethereum && make test`
- **Solana Smart Contracts**
- Tests: `./solana/bridge/program/tests/*.rs`
- Run: `cd solana && make test`
- Tests: `./solana/bridge/program/tests/*.rs`
- Run: `cd solana && make test`
- **Terra Smart Contracts**
- Tests: `./terra/test/*`
- Run: `cd terra && make test`
- Tests: `./terra/test/*`
- Run: `cd terra && make test`
- **Cosmwasm Smart Contracts**
- Tests: `./cosmwasm/test/*`
- Run: `cd cosmwasm && make test`
- Tests: `./cosmwasm/test/*`
- Run: `cd cosmwasm && make test`
- **Algorand Smart Contracts**
- Tests: `./algorand/test/*`
- Run: `cd algorand && make test`
- Tests: `./algorand/test/*`
- Run: `cd algorand && make test`
The best place to understand how we invoke these tests via GitHub Actions on every commit can be found via `./.github/workflows/*.yml` and the best place to observe the results of these builds can be found via [https://github.com/certusone/wormhole/actions](https://github.com/certusone/wormhole/actions).
The best place to understand how we invoke these tests via GitHub Actions on every commit can be found via `./.github/workflows/*.yml` and the best place to observe the results of these builds can be found via [https://github.com/wormhole-foundation/wormhole/actions](https://github.com/wormhole-foundation/wormhole/actions).

View File

@ -84,7 +84,7 @@ First, create an SSH key on the VM:
You can then [add your public key on GitHub](https://github.com/settings/keys) and clone the repository:
git clone git@github.com:certusone/wormhole.git
git clone git@github.com:wormhole-foundation/wormhole.git
Configure your Git identity:

View File

@ -1,5 +1,5 @@
#syntax=docker/dockerfile:1.2@sha256:e2a8561e419ab1ba6b2fe6cbdf49fd92b95912df1cf7d313c3e2230a333fdbcc
FROM ghcr.io/certusone/solana:1.10.31@sha256:d31e8db926a1d3fbaa9d9211d9979023692614b7b64912651aba0383e8c01bad AS solana
FROM ghcr.io/wormhole-foundation/solana:1.10.31@sha256:d31e8db926a1d3fbaa9d9211d9979023692614b7b64912651aba0383e8c01bad AS solana
# libudev is needed by spl-token-cli, and ncat is needed by the devnet setup
# script to be able to signal a health status for tilt

View File

@ -8,46 +8,47 @@ If you find a security issue in wormhole, we ask that you immediately **[report
## 3rd Party Security Audits
We engage 3rd party firms to conduct independent security audits of Wormhole. At any given time, we likely have multiple audit streams in progress.
We engage 3rd party firms to conduct independent security audits of Wormhole. At any given time, we likely have multiple audit streams in progress.
As these 3rd party audits are completed and issues are sufficiently addressed, we make those audit reports public.
- **[January, 10, 2022 - Neodyme](https://storage.googleapis.com/wormhole-audits/2022-01-10_neodyme.pdf)**
- **Scopes**: *Ethereum Contracts, Solana Contracts, Terra Contracts, Guardian, and Solitaire*
- **Scopes**: _Ethereum Contracts, Solana Contracts, Terra Contracts, Guardian, and Solitaire_
- **[July 1, 2022 - Kudelski](https://storage.googleapis.com/wormhole-audits/2022-07-01_kudelski.pdf)**
- **Scopes**: *Ethereum Contracts, Solana Contracts, Terra Contracts, and Guardian*
- **Scopes**: _Ethereum Contracts, Solana Contracts, Terra Contracts, and Guardian_
## White-Hat Hacking on Wormhole
We want to lower the bar for White-hat hackers to find security bugs in Wormhole. Why? The easier we make this process, the more likely it will be for white-hats to find bugs in Wormhole and responsibly disclose them, helping to secure the network.
We want to lower the bar for White-hat hackers to find security bugs in Wormhole. Why? The easier we make this process, the more likely it will be for white-hats to find bugs in Wormhole and responsibly disclose them, helping to secure the network.
Here's a list of strategies we've found helpful for getting started on Wormhole:
- Review the existing unit and integration testing (found in [CONTRIBUTING.md](https://github.com/certusone/wormhole/blob/dev.v2/CONTRIBUTING.md)) and see what we're already testing for.
* Check out places were we might be missing test coverage entirely. This could be a ripe spot to look for something we missed.
* Check out places were we have unit/integration tests, but we lack sufficient [negative test](https://en.wikipedia.org/wiki/Negative_testing) coverage.
- Review the existing unit and integration testing (found in [CONTRIBUTING.md](https://github.com/wormhole-foundation/wormhole/blob/dev.v2/CONTRIBUTING.md)) and see what we're already testing for.
- Check out places were we might be missing test coverage entirely. This could be a ripe spot to look for something we missed.
- Check out places were we have unit/integration tests, but we lack sufficient [negative test](https://en.wikipedia.org/wiki/Negative_testing) coverage.
- Review our different smart contract implementations (eg. Solana, EVM, CosmWasm, Move) and attempt to understand how and why they are different.
* Does one chain have a safety check that another chain doesn't?
* Does one chain have a specific set of nuances / gotchas that that were missed on another chain?
- Does one chain have a safety check that another chain doesn't?
- Does one chain have a specific set of nuances / gotchas that that were missed on another chain?
- Consider going beyond the source code
* Review the deployed contracts on chain. Is something odd that we missed?
- Review the deployed contracts on chain. Is something odd that we missed?
We'll continue to iterate on this list of white-hat bootstrap strategies as we grow our lessons learned internally hacking on Wormhole and from other white-hats who have been successful via our bug bounty program.
It's important to remember this is an iterative process. If you spend the time to come up with a new test case, but didn't actually find a bug, we'd be extremely appreciative if you'd be willing to send a [pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) with additional positive and negative test cases. This process has shown repeatedly to improve your ability to understand Wormhole, and will increase your odds of success.
It's important to remember this is an iterative process. If you spend the time to come up with a new test case, but didn't actually find a bug, we'd be extremely appreciative if you'd be willing to send a [pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) with additional positive and negative test cases. This process has shown repeatedly to improve your ability to understand Wormhole, and will increase your odds of success.
## Guidance to Chain Integrators
As the list of chains connected to Wormhole increases, so does the risk that a given connected could introduce risks to the Wormhole network. As a result, Wormhole does have built-in safety features (e.g.: [Governor white-paper](https://github.com/certusone/wormhole/blob/dev.v2/whitepapers/0007_governor.md)) to reduce the "blast radius" of such case. That said, a defense in depth strategy is required to do as much as possible to secure the network. As part of this methodology, the Wormhole project recommends that all connected chains current and future implement robust security programs of their own to do their part in managing chain compromise risk to the wormhole network.
As the list of chains connected to Wormhole increases, so does the risk that a given connected could introduce risks to the Wormhole network. As a result, Wormhole does have built-in safety features (e.g.: [Governor white-paper](https://github.com/wormhole-foundation/wormhole/blob/dev.v2/whitepapers/0007_governor.md)) to reduce the "blast radius" of such case. That said, a defense in depth strategy is required to do as much as possible to secure the network. As part of this methodology, the Wormhole project recommends that all connected chains current and future implement robust security programs of their own to do their part in managing chain compromise risk to the wormhole network.
Here are a few ways in which connected chains can maintain high security standards:
For source code ensure relevant bits are:
- All open source
- Audited by an independent third party with public audit reports
- Included in a public bug bounty program. The bounty rewards should be sufficiently large to incentivize white-hat mindshare in finding security bugs and responsibly disclosing them
- Version control systems contain adequate access controls and mandatory code review (e.g.: In github, use of branch protection and a minimum of one independent reviewer to merge code)
- Maintaining a [SECURITY.md](https://github.com/certusone/wormhole/blob/dev.v2/SECURITY.md) in the root of the repository (like this one) to offer guidance and transparency on security relevant topics
- Maintaining a [SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/dev.v2/SECURITY.md) in the root of the repository (like this one) to offer guidance and transparency on security relevant topics
- Includes sufficient unit and integration test coverage (including negative tests), which are run on every commit via continuous integration. Ensure that the results of those test runs are visible to the public
Additionally, ensure:
@ -55,4 +56,4 @@ Additionally, ensure:
- The Wormhole team has sufficient contact information and an associated call or page tree to reach you in the event of a security incident.
- That Wormhole has the full upgrade authority on relevant bridge contracts to act quickly in the case of a security incident.
- You have an established incident response program in place, with established patterns and playbooks to ensure deterministic outcomes for containment.
- When security issues do occur, that the chain makes every attempt to inform affected parties and leads with transparency.
- When security issues do occur, that the chain makes every attempt to inform affected parties and leads with transparency.

View File

@ -4,10 +4,10 @@
1. [Background](about:blank#orgea5c5c2)
2. [The “allocator” program](about:blank#org85bc975)
1. [Instantiating template variables](about:blank#orgf176818)
1. [Instantiation, off-chain](about:blank#org2091dfe)
2. [Instantiation, on-chain](about:blank#orga6fa146)
2. [Allocating, client-side](about:blank#org74c4227)
1. [Instantiating template variables](about:blank#orgf176818)
1. [Instantiation, off-chain](about:blank#org2091dfe)
2. [Instantiation, on-chain](about:blank#orga6fa146)
2. [Allocating, client-side](about:blank#org74c4227)
<a id="orgea5c5c2"></a>
@ -27,7 +27,7 @@ Algorand contracts can only store a fixed amount of state. This is a major limit
# The “allocator” program
The main allocator code resides in [/algorand/TmplSig.py](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py). Lets work backwards in this file:
The main allocator code resides in [/algorand/TmplSig.py](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py). Lets work backwards in this file:
```python
if __name__ == '__main__':
@ -36,7 +36,8 @@ if __name__ == '__main__':
with open("sig.tmpl.teal", "w") as f:
f.write(core.get_sig_tmpl())
```
[/algorand/TmplSig.py#L136-L142](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L136-L142)
[/algorand/TmplSig.py#L136-L142](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L136-L142)
If we run this program, it will generate a file called `sig.tmpl.teal` based on whatever `get_sig_tmpl()` returns from the `TmplSig` class. The first few lines of `sig.tmpl.teal` look like this:
@ -86,14 +87,16 @@ Lets look at the `get_sig_tmpl` function.
```python
def get_sig_tmpl(self):
```
[/algorand/TmplSig.py#L111](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L111)
[/algorand/TmplSig.py#L111](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L111)
its return statement is a call to `compileTeal`:
```python
return compileTeal(sig_tmpl(), mode=Mode.Signature, version=6, assembleConstants=True)
```
[/algorand/TmplSig.py#L134](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L134)
[/algorand/TmplSig.py#L134](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L134)
From the `mode=Mode.Signature` argument in `compileTeal` we can see that this program is a signature program, also known as a LogicSig. LogicSigs are special programs that belong to an account, and their purpose is to authorise transactions from that account (or more generally, to act as a signing authority for the account). If the LogicSig program executes successfully (without reverting), then the transaction is authorised. Algorand allows running such programs as a way of implementing domain-specific account authorisation, such as for escrow systems, etc. The address of the LogicSigs account is deterministically derived from the hash of the LogicSigs bytecode (this will be very important very soon).
@ -105,11 +108,12 @@ The `sig_tmpl` function returns a sequence of TEAL instructions, the first two o
Pop(Tmpl.Int("TMPL_ADDR_IDX")),
Pop(Tmpl.Bytes("TMPL_EMITTER_ID")),
```
[/algorand/TmplSig.py#L117-L120](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L117-L120)
[/algorand/TmplSig.py#L117-L120](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L117-L120)
Here are the two pop statements we looked at in the TEAL code. The pyTEAL compiler knows to generate push instructions for arguments whenever necessary, so we dont explicitly push `TMPL_ADDR_IDX` and `TMPL_EMITTER_ID`. These variables immediately get popped, because the LogicSig doesnt actually make use of them, and theyre only there so when replaced with different values in the bytecode, we get an operationally equivalent, yet distinct bytecode.
`Tmpl.Int("TMPL_ADDR_IDX")` and `Tmpl.Bytes("TMPL_EMITTER_ID")` are *template variables*. Normally, they can be thought of as variables in a TEAL program that get replaced at compile time by the compiler, sort of like CPP macros. In fact, this already hints at how the LogicSig is going to be used: these variables will be programmatically replaced (albeit not just at compile time, but more on that later) with distinct values to generate distinct LogicSigs, with deterministic addresses. The wormhole contract will then be able to use the memory of the associated accounts of these LogicSigs. To see how, well first go through what the LogicSig does in the first place.
`Tmpl.Int("TMPL_ADDR_IDX")` and `Tmpl.Bytes("TMPL_EMITTER_ID")` are _template variables_. Normally, they can be thought of as variables in a TEAL program that get replaced at compile time by the compiler, sort of like CPP macros. In fact, this already hints at how the LogicSig is going to be used: these variables will be programmatically replaced (albeit not just at compile time, but more on that later) with distinct values to generate distinct LogicSigs, with deterministic addresses. The wormhole contract will then be able to use the memory of the associated accounts of these LogicSigs. To see how, well first go through what the LogicSig does in the first place.
When using a LogicSig to sign a transaction (like in our case), the LogicSig program can query information about the transaction from the Algorand runtime. If the LogicSig doesn't revert, then the transaction will be executed on-chain. It is the LogicSigs responsibility to decide whether it wants to approve this transaction, so it will perform a number of checks to ensure the transaction does whats expected. Importantly, anyone can pass in their own transactions and use the LogicSig to sign it, so forgetting a check here could result in hijacking the LogicSigs associated account. That's because (by default), transactions that are signed (that is, approved) by the LogicSig can acces the LogicSigs account. In fact, that's what LogicSigs were designed for in the first place: to implement arbitrary logic for deciding who can spend money out of some account.
@ -118,7 +122,8 @@ The first instruction after the two `Pop`s above is
```python
Assert(Txn.type_enum() == TxnType.ApplicationCall),
```
[/algorand/TmplSig.py#L122](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L122)
[/algorand/TmplSig.py#L122](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L122)
Which asserts that the transaction being signed is an application call.
Note that `==` here is an overloaded operator, and it doesnt compare two python values. Instead, it generates a piece of pyTEAL abstract syntax that represents an equality operation. In TEALs concrete syntax, this looks like:
@ -139,20 +144,20 @@ Application calls are one of the built-in transaction types defined by Algorand,
Assert(Txn.on_completion() == OnComplete.OptIn),
Assert(Txn.application_id() == Tmpl.Int("TMPL_APP_ID")),
```
[/algorand/TmplSig.py#L123-L124](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L123-L124)
[/algorand/TmplSig.py#L123-L124](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L123-L124)
Opting in means that the current application (which is the `"TMPL_APP_ID"`) can allocate local storage into the _sender_'s account data. When the sender is the LogicSig's associated account, then the transaction opts into the LogicSig's account data. **This is the memory allocation mechanism**. By opting the LogicSigs associated account into the wormhole contract, wormhole can now use it to store memory. Since these accounts are also limited in size, we need multiple of them, and at deterministic locations. This is why `TMPL_ADDR_IDX` and `TMPL_EMITTER_ID` are used in the program. The wormhole contracts populate these templates with actual values which will allow deriving a deterministic address (the LogicSigs associated account address) which will be known to be a writeable account by the wormhole contract (since the LogicSig opted into the wormhole contract here). This mechanism is similar to Solanas Program-Derived Addresses (PDAs). The difference is that in Solana, PDAs are always owned by the program theyre derived from, whereas in Algorand, ownership of an account can be transferred using the `rekey` mechanism. At this point, the LogicSig's account is owned by the LogicSig. Next, we make sure that the transaction transfers ownership of the account to our application:
```python
Assert(Txn.rekey_to() == Tmpl.Bytes("TMPL_APP_ADDRESS")),
```
[/algorand/TmplSig.py#L125](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L125)
[/algorand/TmplSig.py#L125](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L125)
Rekeying is a feature that allows changing an accounts key so that someone else becomes the signing authority for it. Only the current signing authority can authorize rekeying, and in the process it loses authorization. Since this transaction is signed by a LogicSig, the account in question is the LogicSigs associated account, and the current signing authority is the LogicSig itself. Once it approves a rekey on its associated account, then further transactions from the associated account do not require running the LogicSig logic, and could just use whatever the new key is (in this case, the wormhole application will be able to use this memory freely).
This means that at this stage, the LogicSig transfers ownership of its associated account to the wormhole program. This has two functions. First, a safety mechanism, because it means that the LogicSig is no longer able to sign any further transactions, the wormhole program owns it now. With this ownership assignment, the LogicSics account truly behaves like a Solana PDA: its an account at a deterministic address thats owned (and thus only writeable) by the program. Second, we can allow assets to get created into this account (which gets over the asset limitation issue) but the main wormhole contract can still sign for transactions against it.
This means that at this stage, the LogicSig transfers ownership of its associated account to the wormhole program. This has two functions. First, a safety mechanism, because it means that the LogicSig is no longer able to sign any further transactions, the wormhole program owns it now. With this ownership assignment, the LogicSics account truly behaves like a Solana PDA: its an account at a deterministic address thats owned (and thus only writeable) by the program. Second, we can allow assets to get created into this account (which gets over the asset limitation issue) but the main wormhole contract can still sign for transactions against it.
Finally, 3 more checks:
@ -161,16 +166,18 @@ Finally, 3 more checks:
Assert(Txn.close_remainder_to() == Global.zero_address()),
Assert(Txn.asset_close_to() == Global.zero_address()),
```
[/algorand/TmplSig.py#L127-L129](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L127-L129)
We check that the transaction fee is 0. `close_remainder_to` could request the account to be closed and the funds to be sent to another account. This has to be zero, otherwise the account would be deleted. Similarly, `asset_close_to` is also the zero address.
[/algorand/TmplSig.py#L127-L129](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L127-L129)
We check that the transaction fee is 0. `close_remainder_to` could request the account to be closed and the funds to be sent to another account. This has to be zero, otherwise the account would be deleted. Similarly, `asset_close_to` is also the zero address.
Finally, if all the checks succeeded, the LogicSig succeeds:
```python
Approve()
```
[/algorand/TmplSig.py#L152](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L152)
[/algorand/TmplSig.py#L152](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L152)
To summarize, this is how allocation works: a special program opts in to the wormhole contract, thereby allowing wormhole to write memory into the programs account, then transfers ownership of the account to wormhole. Since the address of this account is derived from the programs bytecode, the addresses are reconstructable deterministically, and a given account with such an address cannot have been created any other way than by executing that program with the expected arguments.
@ -196,7 +203,8 @@ The constructor of the `TmplSig` class starts by initializing the following data
},
}
```
[/algorand/TmplSig.py#L39-L47](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L39-L47)
[/algorand/TmplSig.py#L39-L47](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L39-L47)
`bytecode` is a base64 encoded binary blob, the assembled binary of the `sig.tmpl.teal` program. The `template_labels` then encodes offsets into the binary where occurrences of the template variables are. In addition to `position`, they all store a `bytes` flag too. This stores whether the template variable is a byte array or not. The importance of this will be that byte arrays can be arbitrary length, and they have an additional byte at the beginning that describes the length of the byte array. Ints on the other hand, are encoded as varints, which are variable width integers that do not contain an additional length byte (see [https://www.sqlite.org/src4/doc/trunk/www/varint.wiki](https://www.sqlite.org/src4/doc/trunk/www/varint.wiki)). The code that patches the binary will need to make sure to write an additional length byte for byte arrays, hence the flag.
@ -253,7 +261,8 @@ The python code that constructs the bytecode is defined as
# Create a new LogicSigAccount given the populated bytecode,
return LogicSigAccount(bytes(contract))
```
[/algorand/TmplSig.py#L58-L85](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L58-L85)
[/algorand/TmplSig.py#L58-L85](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/TmplSig.py#L58-L85)
It loops through the template variables, and replaces them with values defined in the `values` dictionary. For byte arrays, it inserts the length byte first. The `shift` variable maintains the number of extra bytes inserted so far, as the subsequent byte offsets all shift by this amount.
@ -268,7 +277,7 @@ The on-chain program is similar to the above, but it just concatenates the byte
def get_sig_address(acct_seq_start: Expr, emitter: Expr):
# We could iterate over N items and encode them for a more general interface
# but we inline them directly here
return Sha512_256(
Concat(
Bytes("Program"),
@ -295,7 +304,8 @@ The on-chain program is similar to the above, but it just concatenates the byte
)
)
```
[/algorand/wormhole_core.py#L86-L115](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/wormhole_core.py#L86-L115)
[/algorand/wormhole_core.py#L86-L115](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/wormhole_core.py#L86-L115)
It writes the string “Program” first. Thats because program addresses are derived by hashing the string “Program” appended to the programs bytecode. The `get_sig_address` function generates exactly this hash. Notice that the arguments it takes are both of type `Expr`. Thats again because `get_sig_address` is a python program that operates on TEAL expressions to construct a TEAL expression. The bytecode chunks are constructed at compile time, but the concatenation happens at runtime (since the template variables are TEAL expressions, whose values are only available at runtime). This works similarly to the off-chain typescript code.
@ -310,7 +320,8 @@ The function that does this is `optin`:
```python
def optin(self, client, sender, app_id, idx, emitter, doCreate=True):
```
[/algorand/admin.py#L485](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/admin.py#L485)
[/algorand/admin.py#L485](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/admin.py#L485)
First, construct the bytecode with the variables filled in
@ -324,33 +335,37 @@ First, construct the bytecode with the variables filled in
}
)
```
[/algorand/admin.py#L488-L495](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/admin.py#L488-L495)
[/algorand/admin.py#L488-L495](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/admin.py#L488-L495)
Then grab the address of the associated account
```python
sig_addr = lsa.address()
```
[/algorand/admin.py#L497](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/admin.py#L497)
[/algorand/admin.py#L497](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/admin.py#L497)
Then check if weve already allocated this account
```python
if sig_addr not in self.cache and not self.account_exists(client, app_id, sig_addr):
```
[/algorand/admin.py#L499](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/admin.py#L499)
[/algorand/admin.py#L499](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/admin.py#L499)
if not, construct the optin transaction which will also rekey the LogicSig's account to our application.
First, we construct a "seed" transaction, which will pay enough money from the user's wallet into the LogicSig's account to cover for the execution cost:
```python
seed_txn = transaction.PaymentTxn(sender = sender.getAddress(),
sp = sp,
receiver = sig_addr,
seed_txn = transaction.PaymentTxn(sender = sender.getAddress(),
sp = sp,
receiver = sig_addr,
amt = self.seed_amt)
seed_txn.fee = seed_txn.fee * 2
```
[/algorand/admin.py#L506-L510](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/admin.py#L506-L510)
[/algorand/admin.py#L506-L510](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/admin.py#L506-L510)
Next, the actual opt-in transaction. The sender (the first argument to `ApplicationOptInTxn`) is the `sig_address`, so our application will allocate memory into it via opting in.
@ -358,7 +373,8 @@ Next, the actual opt-in transaction. The sender (the first argument to `Applicat
optin_txn = transaction.ApplicationOptInTxn(sig_addr, sp, app_id, rekey_to=get_application_address(app_id))
optin_txn.fee = 0
```
[/algorand/admin.py#L512-L513](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/admin.py#L512-L513)
[/algorand/admin.py#L512-L513](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/admin.py#L512-L513)
remember that this code is not trusted, and the LogicSig will verify this transaction is doing the correct thing.
@ -368,7 +384,8 @@ Next, sign the transactions:
signed_seed = seed_txn.sign(sender.getPrivateKey())
signed_optin = transaction.LogicSigTransaction(optin_txn, lsa)
```
[/algorand/admin.py#L517-L518](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/admin.py#L517-L518)
[/algorand/admin.py#L517-L518](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/admin.py#L517-L518)
The first one is signed by the user's wallet, as it's only used to send money from the user's account. The transaction is signed by the logic sig (so it has signing authority over the associated account). Next, send the transactions
@ -376,6 +393,7 @@ The first one is signed by the user's wallet, as it's only used to send money fr
client.send_transactions([signed_seed, signed_optin])
self.waitForTransaction(client, signed_optin.get_txid())
```
[/algorand/admin.py#L520-L521](https://github.com/certusone/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/admin.py#L520-L521)
[/algorand/admin.py#L520-L521](https://github.com/wormhole-foundation/wormhole/blob/0af600ddde4f507b30ea043de66033d7383f53af/algorand/admin.py#L520-L521)
With that, an account is allocated. The client can now pass this account to wormhole, which, after validating that the address is right, will be able to use it to read and write values to.

View File

@ -383,39 +383,50 @@ export class TestLib {
);
}
genTransfer( signers :any, guardianSet :number, nonce:number, seq:number, amount:number, tokenAddress:string, tokenChain:number, toAddress:string, toChain:number, fee:number) {
const b = [
"0x",
this.encoder("uint8", 1),
this.encoder("uint256", Math.floor(amount * 100000000)),
this.zeroBytes.slice(0, (64 - tokenAddress.length)),
tokenAddress,
this.encoder("uint16", tokenChain),
this.zeroBytes.slice(0, (64 - toAddress.length)),
toAddress,
this.encoder("uint16", toChain),
this.encoder("uint256", Math.floor(fee * 100000000)),
];
genTransfer(
signers: any,
guardianSet: number,
nonce: number,
seq: number,
amount: number,
tokenAddress: string,
tokenChain: number,
toAddress: string,
toChain: number,
fee: number
) {
const b = [
"0x",
this.encoder("uint8", 1),
this.encoder("uint256", Math.floor(amount * 100000000)),
this.zeroBytes.slice(0, 64 - tokenAddress.length),
tokenAddress,
this.encoder("uint16", tokenChain),
this.zeroBytes.slice(0, 64 - toAddress.length),
toAddress,
this.encoder("uint16", toChain),
this.encoder("uint256", Math.floor(fee * 100000000)),
];
let emitter = "0x" + this.getTokenEmitter(tokenChain);
let seconds = Math.floor(new Date().getTime() / 1000.0);
let emitter = "0x" + this.getTokenEmitter(tokenChain);
let seconds = Math.floor(new Date().getTime() / 1000.0);
return this.createSignedVAA(
guardianSet,
signers,
seconds,
nonce,
tokenChain,
emitter,
seq,
32,
b.join("")
);
}
return this.createSignedVAA(
guardianSet,
signers,
seconds,
nonce,
tokenChain,
emitter,
seq,
32,
b.join("")
);
}
/**
* Create a packed and signed VAA for testing.
* See https://github.com/certusone/wormhole/blob/dev.v2/design/0001_generic_message_passing.md
* See https://github.com/wormhole-foundation/wormhole/blob/dev.v2/design/0001_generic_message_passing.md
*
* @param {} guardianSetIndex The guardian set index
* @param {*} signers The list of private keys for signing the VAA

View File

@ -1,6 +1,6 @@
---
version: v1beta1
name: buf.build/certusone/wormhole
name: buf.build/wormhole-foundation/wormhole
deps:
- buf.build/googleapis/googleapis
- buf.build/grpc-ecosystem/grpc-gateway

View File

@ -25,13 +25,13 @@ The mitigation for this is a polling control loop in the case of Solana or chain
node will consistently poll for unprocessed observations, resulting in re-observation by nodes and another round of
consensus. During chain replay, nodes will re-process events from connected chains up from a given block height, check
whether a VAA has already been submitted to Solana, and initiate a round of consensus for missed observations.
This carries no risk and can be done any number of times. VAAs are fully deterministic and idempotent - any
given observation will always result in the same VAA body hash. All connected chains keep a permanent record
of whether a given VAA body - identified by its hash - has already been executed, therefore, VAAs can safely
undergo multiple rounds of consensus until they are executed on all chains.
The bridge does not yet implement chain replay (see https://github.com/certusone/wormhole/issues/123). Network outages
The bridge does not yet implement chain replay (see https://github.com/wormhole-foundation/wormhole/issues/123). Network outages
can therefore result in missed observations from chains other than Solana in the case of a prolonged network outage. It
will be possible to retroactively replay blocks after chain replay has been implemented to catch up on missed events.
@ -59,7 +59,7 @@ Wormhole contracts charge in excess of the (very cheap) transaction fee, but a s
still execute a sustained attack by simply paying said fee.
A possible future improvement would be dynamic fees on the Solana side, but this is currently blocked by runtime
limitations (see https://github.com/certusone/wormhole/issues/125). Even with dynamic fees, raising the fees beyond the
limitations (see https://github.com/wormhole-foundation/wormhole/issues/125). Even with dynamic fees, raising the fees beyond the
amount that a reasonable user would pay may already constitute a successful attack against the protocol.
DDoS attacks on decentralized protocols are a tricky thing in general, and mostly a matter of game theory/incentives.
@ -126,4 +126,3 @@ to serialize and deserialize data without incurring the overhead of a memory-saf
This follows current best practices for Solana contract development. It assumes that invalid operations or out-of-bounds
accesses will always cause a crash and be caught by the bytecode interpreter, and safely halt contract execution like
any other error during contract execution would.

View File

@ -40,7 +40,7 @@ Your Solana RPC node needs the following parameters enabled:
--enable-cpi-and-log-storage
```
`--enable-rpc-transaction-history` enables historic transactions to be retrieved via the *getConfirmedBlock* API,
`--enable-rpc-transaction-history` enables historic transactions to be retrieved via the _getConfirmedBlock_ API,
which is required for Wormhole to find transactions.
`--enable-cpi-and-log-storage` stores metadata about CPI calls.
@ -88,7 +88,7 @@ node can be operated in the full, quick or light modes with no impact on securit
As long as the node supports the Ethereum JSON RPC API, it will be compatible with the bridge so all major
implementations will work fine.
Generally, full-nodes will work better and be more reliable than light clients which are susceptible to DoS attacks
Generally, full-nodes will work better and be more reliable than light clients which are susceptible to DoS attacks
since only very few nodes support the light client protocol.
Running a full node typically requires ~500G of SSD storage, 8G of RAM and 4-8 CPU threads (depending on clock
@ -104,7 +104,7 @@ To build the Wormhole node, you need [Go](https://golang.org/dl/) >= 1.17.5.
First, check out the version of the Wormhole repo that you want to deploy:
```bash
git clone https://github.com/certusone/wormhole && cd wormhole
git clone https://github.com/wormhole-foundation/wormhole && cd wormhole
git checkout v2.0.x
```
@ -113,7 +113,7 @@ Then, compile the release binary as an unprivileged build user:
```bash
make node
```
You'll end up with a `guardiand` binary in `build/`.
Consider these recommendations, not a tutorial to be followed blindly. You'll want to integrate this with your
@ -171,7 +171,7 @@ You can use a command line argument to expose it publicly: `--statusAddr=[::]:60
This endpoint returns a 200 OK status code once the Wormhole node is ready to serve requests. A node is
considered ready as soon as it has successfully connected to all chains and started processing requests.
This is **only for startup signalling** - it will not tell whether it *stopped*
This is **only for startup signalling** - it will not tell whether it _stopped_
processing requests at some later point. Once it's true, it stays true! Use metrics to figure that out.
#### `/metrics`
@ -231,18 +231,18 @@ This can be accomplished by either adding the capability to the binary (like in
You'll have to manage the following keys:
- The **guardian key**, which is the bridge consensus key. This key is very critical - your node uses it to certify
VAA messages. The public key's hash is stored in the guardian set on all connected chains. It does not accrue rewards.
It's your share of the multisig mechanism that protect the Wormhole network. The guardian set can be replaced
if a majority of the guardians agree to sign and publish a new guardian set.
- A **node key**, which identifies it on the gossip network, similar to Solana's node identity or a Tendermint
node key. It is used by the peer-to-peer network for routing and transport layer encryption.
An attacker could potentially use it to censor your messages on the network. Other than that, it's not very
critical and can be rotated. The node will automatically create a node key at the path you specify if it doesn't exist.
While the node key can be replaced, we recommend using a persistent node key. This will make it easier to identify your
node in monitoring data and improves p2p connectivity.
- The **guardian key**, which is the bridge consensus key. This key is very critical - your node uses it to certify
VAA messages. The public key's hash is stored in the guardian set on all connected chains. It does not accrue rewards.
It's your share of the multisig mechanism that protect the Wormhole network. The guardian set can be replaced
if a majority of the guardians agree to sign and publish a new guardian set.
- A **node key**, which identifies it on the gossip network, similar to Solana's node identity or a Tendermint
node key. It is used by the peer-to-peer network for routing and transport layer encryption.
An attacker could potentially use it to censor your messages on the network. Other than that, it's not very
critical and can be rotated. The node will automatically create a node key at the path you specify if it doesn't exist.
While the node key can be replaced, we recommend using a persistent node key. This will make it easier to identify your
node in monitoring data and improves p2p connectivity.
For production, we strongly recommend to either encrypt your disks, and/or take care to never have hot guardian keys touch the disk.
One way to accomplish is to store keys on an in-memory ramfs, which can't be swapped out, and restore it from cold
storage or an HSM/vault whenever the node is rebooted. You might want to disable swap altogether. None of that is

View File

@ -5,7 +5,7 @@ set -euo pipefail
(
cd third_party/abigen-celo
docker build -t localhost/certusone/wormhole-abigen-celo:latest .
docker build -t localhost/wormhole-foundation/wormhole-abigen-celo:latest .
)
function gen() {
@ -15,7 +15,7 @@ function gen() {
kubectl exec -c tests eth-devnet-0 -- npx truffle@5.4.1 run abigen $name
kubectl exec -c tests eth-devnet-0 -- cat abigenBindings/abi/${name}.abi | \
docker run --rm -i localhost/certusone/wormhole-abigen-celo:latest /bin/abigen --abi - --pkg ${pkg} > \
docker run --rm -i localhost/wormhole-foundation/wormhole-abigen-celo:latest /bin/abigen --abi - --pkg ${pkg} > \
node/pkg/celo/${pkg}/abi.go
}

View File

@ -4,7 +4,7 @@ set -euo pipefail
(
cd third_party/abigen
docker build -t localhost/certusone/wormhole-abigen:latest .
docker build -t localhost/wormhole-foundation/wormhole-abigen:latest .
)
function gen() {
@ -14,7 +14,7 @@ function gen() {
kubectl exec -c tests eth-devnet-0 -- npx truffle@5.4.1 run abigen $name
kubectl exec -c tests eth-devnet-0 -- cat abigenBindings/abi/${name}.abi | \
docker run --rm -i localhost/certusone/wormhole-abigen:latest /bin/abigen --abi - --pkg ${pkg} > \
docker run --rm -i localhost/wormhole-foundation/wormhole-abigen:latest /bin/abigen --abi - --pkg ${pkg} > \
node/pkg/ethereum/${pkg}/abi.go
}

View File

@ -1,6 +1,11 @@
# first build the image
DOCKER_BUILDKIT=1 docker build -f Dockerfile.base -t near .
# tag the image with the appropriate version
docker tag near:latest ghcr.io/certusone/near:0.1
docker tag near:latest ghcr.io/wormhole-foundation/near:0.1
# push to ghcr
docker push ghcr.io/certusone/near:0.1
docker push ghcr.io/wormhole-foundation/near:0.1

View File

@ -1 +1 @@
FROM ghcr.io/certusone/near:0.1@sha256:b04512f6b2cab77615cd6d5177bb4c671fd704eb92b961e8d81a341599a5d47c as near-node
FROM ghcr.io/wormhole-foundation/near:0.1@sha256:b04512f6b2cab77615cd6d5177bb4c671fd704eb92b961e8d81a341599a5d47c as near-node

View File

@ -264,7 +264,7 @@ export class TestLib {
this.encoder("uint8", this.ord("e")),
this.encoder("uint8", 1),
this.encoder("uint16", tchain),
hash
hash,
];
let emitter = "0x" + this.zeroBytes.slice(0, 31 * 2) + "04";
@ -308,7 +308,7 @@ export class TestLib {
this.encoder("uint8", this.ord("e")),
this.encoder("uint8", 2),
this.encoder("uint16", tchain),
hash
hash,
];
let emitter = "0x" + this.zeroBytes.slice(0, 31 * 2) + "04";
@ -567,7 +567,7 @@ export class TestLib {
/**
* Create a packed and signed VAA for testing.
* See https://github.com/certusone/wormhole/blob/dev.v2/design/0001_generic_message_passing.md
* See https://github.com/wormhole-foundation/wormhole/blob/dev.v2/design/0001_generic_message_passing.md
*
* @param {} guardianSetIndex The guardian set index
* @param {*} signers The list of private keys for signing the VAA

View File

@ -12,7 +12,7 @@ RUN apk add python3 \
COPY . .
LABEL org.opencontainers.image.source="https://github.com/certusone/wormhole/tree/dev.v2/relayer/spy_relayer#readme"
LABEL org.opencontainers.image.source="https://github.com/wormhole-foundation/wormhole/tree/dev.v2/relayer/spy_relayer#readme"
WORKDIR ./relayer/spy_relayer

View File

@ -1,5 +1,4 @@
Relayer
=======
# Relayer
The wormhole relayer is designed to answer one main question:
@ -8,22 +7,19 @@ The wormhole relayer is designed to answer one main question:
It was originally designed for payload version 1 token transfers, but should be extensible to other payload types as well.
## Architecture
Architecture
------------
| Component | Description |
|----------------|------------------------------------------------------------------------------------|
| Guardian Spy | Connects to the wormhole p2p network and publishes all VAAs to a websocket |
| Spy Listener | Filters VAAs from the Spy and adds them to the incoming queue in Redis |
| REST Listener | Accepts HTTP requests to relay VAAs and writes them to the incoming queue in Redis |
| Redis | A durable queue for storing VAAs before they are relayed |
| Relayer | Scans the Redis incoming queue and moves acceptable VAAs to the working queue. It then completes the transfer and pays gas fees on the destination chain. |
| Wallet Monitor | Presents a prometheus endpoint for monitoring wallet balances of native tokens (for paying gas fees) and non-native tokens as relayer profit |
| Component | Description |
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Guardian Spy | Connects to the wormhole p2p network and publishes all VAAs to a websocket |
| Spy Listener | Filters VAAs from the Spy and adds them to the incoming queue in Redis |
| REST Listener | Accepts HTTP requests to relay VAAs and writes them to the incoming queue in Redis |
| Redis | A durable queue for storing VAAs before they are relayed |
| Relayer | Scans the Redis incoming queue and moves acceptable VAAs to the working queue. It then completes the transfer and pays gas fees on the destination chain. |
| Wallet Monitor | Presents a prometheus endpoint for monitoring wallet balances of native tokens (for paying gas fees) and non-native tokens as relayer profit |
If Redis is temporarily down, the Listener will queue outstanding transactions in memory. When Redis comes back online, the Listener writes them all to Redis.
### Architecture Diagram
This is a rough diagram of how the components fit together:
@ -52,46 +48,39 @@ This is a rough diagram of how the components fit together:
│ Wallet Monitor │
└────────────────┘
Environment Variables
---------------------
## Environment Variables
### Listener
These are for configuring the spy and rest listener. See [.env.tilt.listener](.env.tilt.listener) for examples:
| Name | Description |
|------|-------------|
| `SPY_SERVICE_HOST` | host & port string to connect to the spy |
| Name | Description |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `SPY_SERVICE_HOST` | host & port string to connect to the spy |
| `SPY_SERVICE_FILTERS` | Addresses to monitor (Wormhole core bridge contract addresses) array of ["chainId","emitterAddress"]. Emitter addresses are native strings. |
| `REDIS_HOST` | Redis host / ip to connect to |
| `REDIS_PORT` | Redis port |
| `REST_PORT` | Rest listener port to listen on. |
| `READINESS_PORT` | Kubernetes readiness probe port to listen on. |
| `LOG_LEVEL` | log level, such as debug |
| `SUPPORTED_TOKENS` | Origin assets that will attempt to be relayed. Array of ["chainId","address"], address should be a native string. |
| `REDIS_HOST` | Redis host / ip to connect to |
| `REDIS_PORT` | Redis port |
| `REST_PORT` | Rest listener port to listen on. |
| `READINESS_PORT` | Kubernetes readiness probe port to listen on. |
| `LOG_LEVEL` | log level, such as debug |
| `SUPPORTED_TOKENS` | Origin assets that will attempt to be relayed. Array of ["chainId","address"], address should be a native string. |
### Relayer
These are for configuring the actual relayer. See [.env.tilt.relayer](.env.tilt.relayer) for examples:
| Name | Description |
|------|-------------|
| `SUPPORTED_CHAINS` | The configuration for each chain which will be relayed. See [chainConfigs.example.json](src/chainConfigs.example.json) for the format. Of note, `walletPrivateKey` is an array, and a separate worker will be spun up for every private key provided. |
| `REDIS_HOST` | host of the redis service, should be the same as in the spy_listener |
| `REDIS_PORT` | port for redis to connect to |
| `PROM_PORT` | port where prometheus monitoring will listen |
| `READINESS_PORT` | port for kubernetes readiness probe |
| `CLEAR_REDIS_ON_INIT` | boolean, if `true` the relayer will clear the INCOMING and WORKING Redis tables before it starts up. |
| `DEMOTE_WORKING_ON_INIT` | boolean, if `true` the relayer will move everything from the WORKING Redis table to the INCOMING one. |
| `LOG_LEVEL` | log level, debug or info |
Building
--------
| Name | Description |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SUPPORTED_CHAINS` | The configuration for each chain which will be relayed. See [chainConfigs.example.json](src/chainConfigs.example.json) for the format. Of note, `walletPrivateKey` is an array, and a separate worker will be spun up for every private key provided. |
| `REDIS_HOST` | host of the redis service, should be the same as in the spy_listener |
| `REDIS_PORT` | port for redis to connect to |
| `PROM_PORT` | port where prometheus monitoring will listen |
| `READINESS_PORT` | port for kubernetes readiness probe |
| `CLEAR_REDIS_ON_INIT` | boolean, if `true` the relayer will clear the INCOMING and WORKING Redis tables before it starts up. |
| `DEMOTE_WORKING_ON_INIT` | boolean, if `true` the relayer will move everything from the WORKING Redis table to the INCOMING one. |
| `LOG_LEVEL` | log level, debug or info |
## Building
### Building the Spy
@ -112,13 +101,10 @@ npm ci
npm run build
```
Running the Whole Stack For Testing
-----------------------------------
## Running the Whole Stack For Testing
This config is mostly for development.
### Run Redis
Start a redis container:
@ -129,7 +115,7 @@ docker run --rm -p6379:6379 --name redis-docker -d redis
### Run the Guardian Spy
The spy connects to the wormhole guardian peer to peer network and listens for new VAAs. It publishes those via a socket and websocket that the listener subscribes to. If you want to run the spy built from source, change `ghcr.io/certusone/guardiand:latest` to `guardian` after building the `guardian` image.
The spy connects to the wormhole guardian peer to peer network and listens for new VAAs. It publishes those via a socket and websocket that the listener subscribes to. If you want to run the spy built from source, change `ghcr.io/wormhole-foundation/guardiand:latest` to `guardian` after building the `guardian` image.
Start the spy against the testnet wormhole guardian:
@ -138,7 +124,7 @@ docker run \
--platform=linux/amd64 \
-p 7073:7073 \
--entrypoint /guardiand \
ghcr.io/certusone/guardiand:latest \
ghcr.io/wormhole-foundation/guardiand:latest \
spy --nodeKey /node.key --spyRPC "[::]:7073" --network /wormhole/testnet/2/1 --bootstrap /dns4/wormhole-testnet-v2-bootstrap.certus.one/udp/8999/quic/p2p/12D3KooWBY9ty9CXLBXGQzMuqkziLntsVcyz4pk1zWaJRvJn6Mmt
```

View File

@ -49,7 +49,7 @@ It is important to note that Wormhole wrapped tokens are distinct from and incom
## Examples
The integration tests in the [source code](https://github.com/certusone/wormhole/blob/dev.v2/sdk/js/src/token_bridge/__tests__/integration.ts) have many full-path examples, while the [example Token Bridge UI](https://github.com/certusone/wormhole/tree/dev.v2/bridge_ui) demonstrates how to integrate it.
The integration tests in the [source code](https://github.com/wormhole-foundation/wormhole/blob/dev.v2/sdk/js/src/token_bridge/__tests__/integration.ts) have many full-path examples, while the [example Token Bridge UI](https://github.com/wormhole-foundation/wormhole/tree/dev.v2/bridge_ui) demonstrates how to integrate it.
### Attest

View File

@ -423,7 +423,7 @@ export class TestLib {
/**
* Create a packed and signed VAA for testing.
* See https://github.com/certusone/wormhole/blob/dev.v2/design/0001_generic_message_passing.md
* See https://github.com/wormhole-foundation/wormhole/blob/dev.v2/design/0001_generic_message_passing.md
*
* @param {} guardianSetIndex The guardian set index
* @param {*} signers The list of private keys for signing the VAA

View File

@ -1,7 +1,7 @@
# Docker images
To speed up builds and ensure that upstream dependencies remain available, we
publish prebuilt docker images to https://github.com/orgs/certusone/packages.
publish prebuilt docker images to https://github.com/orgs/wormhole-foundation/packages.
The base images have names ending in `*.base`, such as `Dockerfile.base`.
To push a new image:
@ -10,9 +10,9 @@ To push a new image:
# first build the image
DOCKER_BUILDKIT=1 docker build -f Dockerfile.base -t solana .
# tag the image with the appropriate version
docker tag solana:latest ghcr.io/certusone/solana:1.10.31
docker tag solana:latest ghcr.io/wormhole-foundation/solana:1.10.31
# push to ghcr
docker push ghcr.io/certusone/solana:1.10.31
docker push ghcr.io/wormhole-foundation/solana:1.10.31
```
Finally, modify the reference in `Dockerfile` (make sure to update the sha256 hash too).

View File

@ -1,5 +1,5 @@
#syntax=docker/dockerfile:1.2@sha256:e2a8561e419ab1ba6b2fe6cbdf49fd92b95912df1cf7d313c3e2230a333fdbcc
FROM ghcr.io/certusone/solana:1.10.31@sha256:d31e8db926a1d3fbaa9d9211d9979023692614b7b64912651aba0383e8c01bad AS solana
FROM ghcr.io/wormhole-foundation/solana:1.10.31@sha256:d31e8db926a1d3fbaa9d9211d9979023692614b7b64912651aba0383e8c01bad AS solana
# Support additional root CAs
COPY cert.pem* /certs/

View File

@ -18,4 +18,4 @@ stream.on("data", ({ vaaBytes }) => {
});
```
Also see [integration tests](https://github.com/certusone/wormhole/blob/dev.v2/spydk/js/src/__tests__/integration.ts)
Also see [integration tests](https://github.com/wormhole-foundation/wormhole/blob/dev.v2/spydk/js/src/__tests__/integration.ts)

View File

@ -11,7 +11,7 @@ import { clusterApiUrl } from "@solana/web3.js";
import { ethers } from "ethers";
import { getAddress } from "ethers/lib/utils";
//Devnet here means the locahost kubernetes environment used by the certusone/wormhole official git repository.
//Devnet here means the locahost kubernetes environment used by the wormhole-foundation/wormhole official git repository.
//Testnet is the official Wormhole testnet
export type Environment = "devnet" | "testnet" | "mainnet";
export const CLUSTER: Environment = "devnet" as Environment; //This is the currently selected environment.

View File

@ -12,7 +12,7 @@ functionality from the core protocol.
Wormhole was originally designed to support a very specific kind of cross-chain message passing - token wrapping/swaps
between Solana and Ethereum. Read more about the original design and its goals in
the [announcement blog post](https://medium.com/certus-one/introducing-the-wormhole-bridge-24911b7335f7) and
the [protocol documentation](https://github.com/certusone/wormhole/blob/48b3c0a3f8b35818952f61c38d89850eb8924b55/docs/protocol.md)
the [protocol documentation](https://github.com/wormhole-foundation/wormhole/blob/48b3c0a3f8b35818952f61c38d89850eb8924b55/docs/protocol.md)
Since then, it has become clear that there is strong demand for using Wormhole's simple cross-chain state attestation
model for applications beyond its original design. This includes third-party projects wanting to transfer tokens other
@ -25,16 +25,16 @@ from the application logic.
The core problem that both the current and future Wormhole design is solving is that of **enabling contracts on one
chain to verify messages from a different chain**. Smart contract engines on chains are often insufficiently powerful to
independently verify expensive state proofs from other chains due to the amount of storage and compute required. They
therefore need to rely on off-chain oracles to observe and verify messages and then re-sign them such that they *can* be
therefore need to rely on off-chain oracles to observe and verify messages and then re-sign them such that they _can_ be
verified on any of the connected chains, by trusting the oracle network as an intermediary rather than trusting the
remote chain.
We previously designed a similar protocol extension for the current Wormhole design, called EE-VAAs, which is the
precursor to this fully generic design:
- [External Entity VAAs](https://github.com/certusone/wormhole/issues/147)
- [External Entity: Account State Attestation](https://github.com/certusone/wormhole/issues/149)
- [External Entity: Relayer mode](https://github.com/certusone/wormhole/issues/150)
- [External Entity VAAs](https://github.com/wormhole-foundation/wormhole/issues/147)
- [External Entity: Account State Attestation](https://github.com/wormhole-foundation/wormhole/issues/149)
- [External Entity: Relayer mode](https://github.com/wormhole-foundation/wormhole/issues/150)
This design doc assumes basic familiarity with the current design of Wormhole.
@ -89,7 +89,7 @@ VAA struct {
// --------------------------------------------------------------------
// HEADER - these values are not part of the observation and instead
// carry metadata used to interpret the observation. It is not signed.
// Protocol version of the entire VAA.
Version uint8
@ -143,7 +143,7 @@ VAA struct {
//
// The semantic meaning of this field is specific to the target
// chain (like a commitment level on Solana, number of
// confirmations on Ethereum, or no meaning with instant finality).
// confirmations on Ethereum, or no meaning with instant finality).
ConsistencyLevel uint8 // <-- NEW
// Payload of the message.
@ -240,7 +240,7 @@ A peg zone is the closest analogy to Wormhole in the IBC model, with some import
security properties. Nodes cannot initiate consensus on their own.
- By only reacting to finalized state on chains, each with strong finality guarantees, the Wormhole protocol does not
need complex consensus, finality or leader election. It signs *observations* of finalized state, which all nodes do
need complex consensus, finality or leader election. It signs _observations_ of finalized state, which all nodes do
synchronously, and broadcasts them to a peer-to-peer network. There's no possibility of equivocation or eclipse
attacks leading to disagreements.

View File

@ -16,7 +16,7 @@ However, while this design worked great for v1 which was bridging only two chain
- It adds an unnecessary point of failure. A Solana outage would also prevent token transfers between unrelated chains (it's called mainnet-beta for a reason!). Messages would also incur unnecessary extra latency waiting for Solana to include the transaction. At the time of writing, this is exacerbated by high mainnet-beta skip rate which causes a significant percentage of transactions to fail to be included within a reasonable interval.
- It puts extra strain on Solana's network. In particular, for messages *originating* from Solana, it would cause write amplification.
- It puts extra strain on Solana's network. In particular, for messages _originating_ from Solana, it would cause write amplification.
- The race mechanism would be too expensive at scale and hard to incentivize, since we cannot use preflight and nodes would pay for failed messages, likely unequally. A leader selection mechanism would have to be implemented.
@ -76,7 +76,7 @@ Locally persisted state is crucial to maintain data availability across the netw
We can't rely on gossip to provide atomic or reliable broadcast - messages may be lost, or nodes may be down. We need to assume that nodes can and will lose all of their local state, and be down for maintenance, including nodes used to serve a public API. Clients relying on the API therefore have to rely on multiple nodes to provide fault tolerance. Typically, clients would implement this by rotating through a set of known API endpoints operated by different service providers, alternating or randomizing them while polling for VAA completion.
Each individual API endpoint may in turn be backed by multiple nodes operated behind a load balancer operated by each API endpoint's service provider.
Each individual API endpoint may in turn be backed by multiple nodes operated behind a load balancer operated by each API endpoint's service provider.
To facilitate this, a new "non-voting" mode will be added to guardiand to allow operators to run read-only nodes that listen to the gossip network and locally persist any signed VAA they receive.
@ -100,7 +100,7 @@ Nodes could do idempotent writes to a single shared K/V store (like Bigtable or
However, we decided against this approach:
- It creates a false sense of security by allowing clients to rely on a single API service provider, reducing the network's overall level of fault tolerance.
- It creates a false sense of security by allowing clients to rely on a single API service provider, reducing the network's overall level of fault tolerance.
- We want to mitigate gossip message propagation issues or operational mistakes that could affect many nodes.
@ -142,8 +142,8 @@ This proposal affects only data availability of data that was already validated
API endpoints may be subject to denial of service attacks. If an attacker manages to take down all public API endpoints, clients would be unable to retrieve signed messages.
VAAs would still be persisted locally during such an attack and can be requested once availability is restored.
VAAs would still be persisted locally during such an attack and can be requested once availability is restored.
We believe this risk is easily mitigated - protecting web APIs from denial of service attacks is a well-understood problem, with a robust ecosystem of both technological solutions and service providers.
(robustness of libp2p pubsub itself against flooding by non-guardian nodes is an orthogonal concern tracked in https://github.com/certusone/wormhole/issues/22 as well as the [official libp2p docs](https://docs.libp2p.io/concepts/security-considerations/))
(robustness of libp2p pubsub itself against flooding by non-guardian nodes is an orthogonal concern tracked in https://github.com/wormhole-foundation/wormhole/issues/22 as well as the [official libp2p docs](https://docs.libp2p.io/concepts/security-considerations/))