Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create cartesi-rollups devnet in Go #289

Merged
merged 4 commits into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.git*
**/target/
4 changes: 3 additions & 1 deletion .github/license-check/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
{
"include": ["**/*.go", "**/*.rs"],
"exclude": [
"offchain/grpc-interfaces/**",
"offchain/target/**",
"offchain/data/src/schema.rs",
"pkg/contracts/*.go",
"pkg/readerclient/generated.go",
"pkg/inspectclient/generated.go"
"pkg/inspectclient/generated.go",
"rollups-contracts/**"
],
"license": ".github/license-check/header.txt"
}
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
build/deployments
**/.idea/
machine-snapshot/**
deployment.json
anvil_state.json
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[submodule "grpc-interfaces"]
path = offchain/grpc-interfaces/grpc-interfaces
url = ../grpc-interfaces.git
[submodule "rollups-contracts"]
path = rollups-contracts
url = https://github.com/cartesi/rollups-contracts
branch = v1.2.0
84 changes: 67 additions & 17 deletions build/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
ARG BASE_IMAGE
ARG RUST_VERSION
ARG GO_VERSION
ARG FOUNDRY_COMMIT_VERSION
ARG FOUNDRY_NIGHTLY_VERSION
ARG SERVER_MANAGER_VERSION
ARG MACHINE_EMULATOR_VERSION
ARG ROOTFS_VERSION
Expand Down Expand Up @@ -38,6 +38,7 @@ FROM ${BASE_IMAGE} as emulator-base

# Install machine-emulator
ARG MACHINE_EMULATOR_VERSION
ARG DEBIAN_FRONTEND=noninteractive
RUN <<EOF
set -e
apt-get update
Expand Down Expand Up @@ -65,6 +66,7 @@ adduser --system --uid 102 \
cartesi
EOF


####################################################################################################
# TARGET: rollups-node-snapshot
#
Expand Down Expand Up @@ -112,6 +114,7 @@ COPY --from=snapshot-builder --chown=cartesi:cartesi ${SNAPSHOT_BUILD_PATH} ${SN
# Set dummy command.
CMD /bin/bash


####################################################################################################
# TARGET: rollups-node-devnet
#
Expand All @@ -131,16 +134,13 @@ apt-get update
apt-get install -y --no-install-recommends \
ca-certificates \
curl \
git \
jq \
wget \
xxd
git
EOF

# Install Foundry from downloaded pre-compiled binaries
ARG FOUNDRY_NIGHTLY_VERSION
RUN curl -sSL https://github.com/foundry-rs/foundry/releases/download/nightly-${FOUNDRY_NIGHTLY_VERSION}/foundry_nightly_linux_$(dpkg --print-architecture).tar.gz | \
tar -zx -C /usr/local/bin
tar -zx -C /usr/local/bin

# STAGE: devnet-builder
#
Expand All @@ -149,34 +149,84 @@ FROM devnet-base as devnet-builder
ARG DEVNET_BUILD_PATH
WORKDIR ${DEVNET_BUILD_PATH}

# Copy machine snapshot hash.
# Install system dependencies.
ARG DEBIAN_FRONTEND=noninteractive
RUN <<EOF
marcelstanley marked this conversation as resolved.
Show resolved Hide resolved
set -e
apt-get update
apt-get install -y --no-install-recommends \
gnupg
EOF

# Install yarn
ARG DEBIAN_FRONTEND=noninteractive
RUN <<EOF
marcelstanley marked this conversation as resolved.
Show resolved Hide resolved
set -e
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
apt-get update
apt-get install -y --no-install-recommends \
nodejs \
yarn
EOF

# Install Go
ARG GO_VERSION
RUN curl -sSL https://go.dev/dl/go${GO_VERSION}.linux-$(dpkg --print-architecture).tar.gz | \
tar -zx -C /usr/local
ENV PATH=$PATH:/usr/local/go/bin

# Copy gen-devnet script and dependencies
# This should be simplified in the future when `COPY --parents` is made available
COPY internal/config internal/config
COPY internal/services internal/services
COPY pkg/addresses pkg/addresses
COPY pkg/contracts pkg/contracts
COPY pkg/ethutil pkg/ethutil
COPY rollups-contracts rollups-contracts
COPY cmd/gen-devnet cmd/gen-devnet

# Download external dependencies
COPY go.mod .
COPY go.sum .
RUN go mod download

# Copy machine snapshot hash
ARG SNAPSHOT_BUILD_PATH
COPY --from=snapshot-builder ${SNAPSHOT_BUILD_PATH}/hash hash.bin

# Generate Anvil state.
COPY scripts scripts
RUN ./scripts/devnet/gen-devnet.sh -v -t hash.bin
# Generate anvil state
RUN go run ./cmd/gen-devnet --template-hash-file hash.bin

# STAGE: rollups-node-devnet
#
# This stage installs the runtime utilities and copies the anvil state from the builder stage.
# This stage copies the anvil state from the builder stage and start the local anvil instance.
FROM devnet-base as rollups-node-devnet

# Copy anvil state file
# Copy anvil state file and devnet deployment info
ARG DEVNET_BUILD_PATH
ENV ANVIL_STATE_PATH=/usr/share/devnet/anvil_state.json
ARG DEVNET_SHARE_PATH=/usr/share/devnet
ENV ANVIL_STATE_PATH=${DEVNET_SHARE_PATH}/anvil_state.json
ENV DEPLOYMENT_JSON_PATH=${DEVNET_SHARE_PATH}/deployment.json
COPY --from=devnet-builder ${DEVNET_BUILD_PATH}/anvil_state.json ${ANVIL_STATE_PATH}

# Copy healthcheck script.
COPY scripts/devnet/lib/anvil_net_listening.sh /usr/bin/anvil_net_listening.sh
HEALTHCHECK --interval=1s --timeout=1s --retries=5 CMD anvil_net_listening.sh
COPY --from=devnet-builder ${DEVNET_BUILD_PATH}/deployment.json ${DEPLOYMENT_JSON_PATH}

# Make Anvil bind to the external network interface.
ENV ANVIL_IP_ADDR="0.0.0.0"
ENV RPC_URL="http://${ANVIL_IP_ADDR}:8545"
HEALTHCHECK --interval=1s --timeout=1s --retries=5 \
CMD curl \
-X \
POST \
-s \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"1","method":"net_listening","params":[]}' \
${RPC_URL}

# Start Anvil.
CMD anvil --block-time 1 --load-state $ANVIL_STATE_PATH


####################################################################################################
# TARGET: rollups-node
#
Expand Down
12 changes: 6 additions & 6 deletions build/compose-devnet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ services:
CARTESI_BLOCKCHAIN_WS_ENDPOINT: "ws://devnet:8545"
CARTESI_BLOCKCHAIN_IS_LEGACY: "false"
CARTESI_BLOCKCHAIN_FINALITY_OFFSET: "1"
CARTESI_CONTRACTS_APPLICATION_ADDRESS: "0x180763470853cAF642Df79a908F9282c61692A45"
CARTESI_CONTRACTS_APPLICATION_DEPLOYMENT_BLOCK_NUMBER: "17"
CARTESI_CONTRACTS_HISTORY_ADDRESS: "0xbCc4067dfdeE8274E531951f0968EC895f397A44"
CARTESI_CONTRACTS_AUTHORITY_ADDRESS: "0xb090149a3cA43000681B74875500854B54355496"
CARTESI_CONTRACTS_INPUT_BOX_ADDRESS: "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9"
CARTESI_CONTRACTS_INPUT_BOX_DEPLOYMENT_BLOCK_NUMBER: "17"
CARTESI_CONTRACTS_APPLICATION_ADDRESS: "0x7FFdf694A877067DE99462A7243b29972D19cf72"
CARTESI_CONTRACTS_APPLICATION_DEPLOYMENT_BLOCK_NUMBER: "19"
CARTESI_CONTRACTS_HISTORY_ADDRESS: "0x325272217ae6815b494bF38cED004c5Eb8a7CdA7"
CARTESI_CONTRACTS_AUTHORITY_ADDRESS: "0x58c93F83fb3304730C95aad2E360cdb88b782010"
CARTESI_CONTRACTS_INPUT_BOX_ADDRESS: "0x59b22D57D4f067708AB0c00552767405926dc768"
CARTESI_CONTRACTS_INPUT_BOX_DEPLOYMENT_BLOCK_NUMBER: "19"
CARTESI_EPOCH_DURATION: "120"
CARTESI_AUTH_MNEMONIC: "test test test test test test test test test test test junk"
24 changes: 24 additions & 0 deletions cmd/gen-devnet/anvil.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

package main

import (
"strconv"

"github.com/cartesi/rollups-node/internal/services"
)

func newAnvilService(anvilStateFilePath string) services.CommandService {
var s services.CommandService
s.Name = "anvil"
s.HealthcheckPort, _ = strconv.Atoi(ANVIL_HTTP_PORT)
s.Path = "anvil"

s.Args = append(s.Args, "--host", ANVIL_IP_ADDR)
s.Args = append(s.Args, "--dump-state", anvilStateFilePath)
s.Args = append(s.Args, "--state-interval", "1")
s.Args = append(s.Args, "--silent")

return s
}
127 changes: 127 additions & 0 deletions cmd/gen-devnet/deployer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

package main

import (
"context"
"encoding/json"
"fmt"
"os/exec"
"strings"

"github.com/cartesi/rollups-node/pkg/addresses"
"github.com/cartesi/rollups-node/pkg/ethutil"
"github.com/ethereum/go-ethereum/common"
)

const (
CONTRACT_OWNER_ADDRESS = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
SALT = "0x0000000000000000000000000000000000000000000000000000000000000000"
)

func deploy(ctx context.Context,
rollupsContractsPath string,
hash string) (DeploymentInfo, error) {
var depInfo DeploymentInfo

fmt.Printf("deployer: deploying %v\n", rollupsContractsPath)
err := deployRollupsContracts(ctx, rollupsContractsPath)
if err != nil {
return depInfo, fmt.Errorf("could not deploy rollups-contracts: %v", err)
}

depInfo, err = createApplication(ctx, hash)
if err != nil {
return depInfo, fmt.Errorf("could not create Application: %v", err)
}

return depInfo, nil
}

// Create a Rollups Application by calling the necessary factories
func createApplication(ctx context.Context, hash string) (DeploymentInfo, error) {
var depInfo DeploymentInfo

// Create the Authority/History pair
contractAddresses, _, err := createContracts(ctx,
common.Address.Hex(addresses.GetTestBook().AuthorityHistoryPairFactory),
"newAuthorityHistoryPair(address,bytes32)(address,address)",
CONTRACT_OWNER_ADDRESS,
SALT)
if err != nil {
return DeploymentInfo{}, fmt.Errorf("could not create authority/history pair: %v", err)
}

depInfo.AuthorityAddress = contractAddresses[0]
depInfo.HistoryAddress = contractAddresses[1]

// Create the Application, passing the address of the newly created Authority
contractAddresses, blockNumber, err := createContracts(ctx,
common.Address.Hex(addresses.GetTestBook().CartesiDAppFactory),
"newApplication(address,address,bytes32,bytes32)(address)",
depInfo.AuthorityAddress,
CONTRACT_OWNER_ADDRESS,
hash,
SALT)
if err != nil {
return DeploymentInfo{}, fmt.Errorf("could not create application: %v", err)
}

depInfo.ApplicationAddress = contractAddresses[0]
depInfo.BlockNumber = blockNumber

return depInfo, nil
}

// Call a contract factory, passing a factory function to be executed.
// Returns the resulting contract address(es) and the corresponding
// block number.
//
// Warning: a second call to a contract with the same arguments will fail.
func createContracts(ctx context.Context,
args ...string) ([]string, string, error) {
commonArgs := []string{"--rpc-url", RPC_URL}
commonArgs = append(commonArgs, args...)

var contractAddresses []string
// Calculate the resulting deterministic address(es)
castCall := exec.CommandContext(ctx,
"cast",
"call")
castCall.Args = append(castCall.Args, commonArgs...)
var outStrBuilder strings.Builder
castCall.Stdout = &outStrBuilder
err := castCall.Run()
if err != nil {
return contractAddresses, "", fmt.Errorf("command failed %v: %v", castCall.Args, err)
}
contractAddresses = strings.Fields(outStrBuilder.String())

// Perform actual transaction on the contract
castSend := exec.CommandContext(ctx,
"cast",
"send",
"--json",
"--mnemonic",
ethutil.FoundryMnemonic)
castSend.Args = append(castSend.Args, commonArgs...)
outStrBuilder.Reset()
castSend.Stdout = &outStrBuilder
err = castSend.Run()
if err != nil {
return contractAddresses, "", fmt.Errorf("command failed %v: %v", castSend.Args, err)
}
fmt.Printf("deployer: command: %s\n", castSend.Args)
fmt.Printf("deployer: output: %s\n", outStrBuilder.String())

// Extract blockNumber from JSON output
jsonMap := make(map[string](any))
err = json.Unmarshal([]byte([]byte(outStrBuilder.String())), &jsonMap)
if err != nil {
return contractAddresses, "", fmt.Errorf("failed to extract block number, %s", err.Error())
}
blockNumber := jsonMap["blockNumber"].(string)

return contractAddresses, blockNumber, nil
}
Loading
Loading