Skip to content

Architecture Overview

PoisonPhang edited this page Aug 17, 2023 · 12 revisions

Architecture Overview

This page provides an in-depth overview of the projects that make up the main Union repository. The goal of this page is to ensure that auditors and contributors are familiar with Union's projects and how these projects work together.

Projects

While the Union repo is host to many projects, the projects below makeup our core infrastructure.

  • The Union Node (uniond) - Our Cosmos Node running CometBLS.
  • Unionvisor - A supervisor for the uniond binary, ensuring it is updated correctly.
  • Galois - The Union prover, used to conduct zero-knowledge proofs.
  • Voyager - A relayer between Union's projects and it's counterparties.

The Union Node

The Union Node, often referred to by its binary uniond, is our Cosmos Node running CometBLS for consensus.

You can find information on how to run and build uniond in the uniond project root.

The Union Node is running our fork of the cosmos-sdk. In our fork of the cosmos-sdk, we have implemented epoch staking, CometBLS, and the bn254 signature scheme.

Testing & QA

The Union Node contains a basic go test suite to ensure our cryptographic primitives are functioning and that the app/modules build successfully.

We also supply several linting tools via Nix commands in uniond/uniond.nix

Unionvisor

Inspired by programs such as cosmovisor, Unionvisor is built to monitor and preform upgrades of the uniond binary.

You can find information on how to run and build Unionvisor in the unionvisor project root.

Testing & QA

The project files contain extensive test data to simulate such upgrades within our cargo test suite.

Galois

Galois, the Union prover, can be found in the galoisd project root.

CLI definitions: galoisd/cmd/galoisd.

The GRPC interface definitions: galoisd/grpc/api/v1

Testing & QA

Minimal testing for non-adjacent blocks can be found in galoisd/pkg/lightclient/nonadjacent/circuit_test.go.

Voyager

Voyager is pending a major rewrite. The current implementation can be found in the relayer project root.

Testing & QA

Voyager has minimal testing for converting between events.

Primary Workflows

Besides running our binaries, there are several workflows to be aware of to understand how our products work together.

This sections will walk you through those workflows and help you understand what parts of the codebase they touch.

Opening a Connection

Before transactions between Union and its counterparties can begin, a connection and channel needs to be opened. This can be accomplished by interfacing with the Voyager following the workflow below.

These steps will demonstrate opening a connection between a local Union and Ethereum devnet.

Creating Clients

Before creating a connection and channel to conduct transactions over, the Voyager needs to be made aware of the client networks. This can be done with the client create sub-command of Voyager:

# Create a union client
relayer client create union ethereum08-wasm \
    --on union-devnet \
    --counterparty ethereum-devnet \
    --evm-preset minimal

# Create an evm client
relayer client create evm cometbls \
    --on ethereum-devnet \
    --counterparty union-devnet

The client create command has two sub-commands used above: union ethereum08-wasm and evm cometbls.

This will use the call the create_client function implemented by both Union and Evm. This function will contact either the Union or Ethereum chain to get a client ID that is unique to the network.

The entry-point for the client create command can be found here. After this point, the command follows this sequence diagram:

sequenceDiagram
    participant Union
    participant Relayer
    participant Evm

    par Create WASM Client
        Relayer->>+Union: create_client
        Union-->>-Relayer: client_id
    and Create IBC Handler Instance
        Relayer->>+Evm: create_client
        Evm-->>-Relayer: client_id
    end
Loading

With the client ID retrieved, the connection handshake can begin.

Connection Handshake

To start the connection handshake, we can use the connection open sub-command of Voyager.

relayer connection open \
    --to-chain union-devnet \
    --to-client 08-wasm-0 \
    --from-chain ethereum-devnet \
    --from-client cometbls-new-0

The example above creates a connection to the Union devnet from the Ethereum devnet.

This will start the process of collecting state data from both chains, submitting a proof request to Galois, and relaying the chain state and proof between networks. While relaying this data, a connection attempt is made and confirmed.

The entry-point for this command is here. After this point, the command follows this sequence diagram:

sequenceDiagram
    participant Union
    participant Relayer
    participant Evm

		note over Union, Evm: connection handshake

    Relayer->>+Evm: MsgConnectionOpenInit
    Evm-->>-Relayer: connection_id

    Relayer->>+Union: MsgConnectionOpenTry
    Union-->>-Relayer: <<success>>

    Relayer->>+Evm: MsgConnectionOpenAck
    Evm-->>-Relayer: <<success>>

    Relayer->>+Union: MsgConnectionOpenConfirm
    Union-->>-Relayer: <<success>>
Loading

Once success has been reported, the IBC connection is established.

Channel Handshake

Finally, before transactions can be conducted - a channel needs to be opened for the transaction to be conducted on.

To start a channel handshake, you can use the channel open sub-command of Voyager.

relayer channel open \
    --from-chain union-devnet \
    --from-connection connection-1 \
    --from-port wasm.CONTRACT_ADDRESS \
    --to-chain ethereum-devnet \
    --to-connection connection-2 \
    --to-port transfer

Similar to the connection open sub-command, the channel open sub-command will collect state data from both chains, submit a proof request to Galois, and relay the chain state and proof between networks.

The entry-point of this command can be found here. After this point, the command follows this sequence diagram:

sequenceDiagram
    participant Union
    participant Relayer
    participant Evm

		note over Union, Evm: channel handshake

    Relayer->>+Evm: MsgChannelOpenInit
    Evm-->>-Relayer: channel_id

    Relayer->>+Union: MsgChannelOpenTry
    Union-->>-Relayer: <<success>>

    Relayer->>+Evm: MsgChannelOpenAck
    Evm-->>-Relayer: <<success>>

    Relayer->>+Union: MsgChannelOpenConfirm
    Union-->>-Relayer: <<success>>
Loading

Once success has been reported, the IBC channel is established.

Instantiating Union's ICS20 Contract

Voyager and our bridged transactions depend on our ICS20 contract being deployed and instantiated via the uniond wasm module.

In our devnet, we use nix to deploy our ICS20 transfer and ping-pong contract through our devnet genesis. However, after the contract is deployed - it still needs to be instantiated with the following command:

# Instantiate the contract
uniond tx wasm instantiate 1 \
  '{"default_timeout":10000,"gov_contract":"union1jk9psyhvgkrt2cumz8eytll2244m2nnz4yt2g2","allowlist":[]}' \
  --label blah \
  --from alice \
  --gas auto \
  --keyring-backend test \
  --gas-adjustment 1.3 \
  --amount 100stake \
  --no-admin \
  --chain-id union-devnet-1 \
  -y

# Check for success
uniond query wasm list-contracts-by-code 1 | yq '.contracts[-1]' --raw-output

Sending Transactions

Currently, there are two main transaction workflows: Cosmos → Ethereum and Ethereum → Cosmos.

Cosmos → Ethereum

To start a transaction from Cosmos to Ethereum, you can use the wasm command that we import into uniond.

We use the tx wasm execute sub-command of uniond to call the ICS20 contract we have deployed.

uniond tx wasm execute \
  union14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s3e9fe2 \
  '{"transfer":{"channel":"channel-7","remote_address":"be68fc2d8249eb60bfcf0e71d5a0d2f2e292c4ed"}}' \
  --amount 100stake \
  --from alice \
  --keyring-backend test \
  --chain-id union-devnet-1 \
  --gas 10000000 \
  -y

Ethereum → Cosmos

To conduct a transaction from Ethereum to Cosmos, Voyager can be used to initiate the transaction. This can be done with the transfer sub-command.

The entry point for the transfer command can be found here.

This will call into the send_transfer function of our ICS20 contract.

relayer transfer \
  --from ethereum-devnet --to union-devnet \
  --amount 10 \
  --denom "transfer/channel-0/stake" \
  --receiver union1jk9psyhvgkrt2cumz8eytll2244m2nnz4yt2g2 \
  --source-port transfer \
  --source-channel channel-0