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

test: create anvil devnet for tests #448

Open
wants to merge 1 commit into
base: base/consumer-chain-support
Choose a base branch
from
Open
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
101 changes: 101 additions & 0 deletions itest/ethereum_node_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package e2e_utils

import (
"bytes"
"os"
"os/exec"
"path/filepath"
"runtime"
"testing"

"github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/require"
)

type EthereumNodeHandler struct {
t *testing.T
client *rpc.Client
}

func NewEthereumNodeHandler(t *testing.T) (*EthereumNodeHandler, error) {
// Log current working directory
wd, err := os.Getwd()
if err != nil {
return nil, err
}
t.Logf("Current working directory: %s", wd)

// Start Anvil
projectRoot, err := findProjectRoot()
if err != nil {
return nil, err
}
startScriptPath := filepath.Join(projectRoot, "scripts/start_anvil_devnet.sh")
if err != nil {
return nil, err
}
if err := os.Chmod(startScriptPath, 0755); err != nil {
return nil, err
}

var stdout, stderr bytes.Buffer
startCmd := exec.Command("/bin/sh", startScriptPath)
startCmd.Stdout = &stdout
startCmd.Stderr = &stderr
if err := startCmd.Start(); err != nil {
return nil, err
}

// Wait for the command to complete
startCmd.Wait()

// Log output and errors
if stdout.Len() > 0 {
t.Logf("Anvil stdout: %s", stdout.String())
}
if stderr.Len() > 0 {
t.Logf("Anvil stderr: %s", stderr.String())
}

// Connect to local RPC node
client, err := rpc.DialHTTP("http://localhost:8545")
if err != nil {
return nil, err
}

return &EthereumNodeHandler{
t: t,
client: client,
}, nil
}

func (eh *EthereumNodeHandler) Close() {
if eh.client != nil {
eh.client.Close()
}

// Stop Anvil
projectRoot, err := findProjectRoot()
require.NoError(eh.t, err)
stopScriptPath := filepath.Join(projectRoot, "scripts/stop_anvil_devnet.sh")
os.Chmod(stopScriptPath, 0755)
stopCmd := exec.Command("/bin/sh", stopScriptPath)
stopCmd.Run()
}

// Helper function to find root directory of project
func findProjectRoot() (string, error) {
_, b, _, _ := runtime.Caller(0)
dir := filepath.Dir(b)
for {
if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
return dir, nil
}
if parentDir := filepath.Dir(dir); parentDir == dir {
break
} else {
dir = parentDir
}
}
return "", os.ErrNotExist
}
6 changes: 6 additions & 0 deletions itest/opstackl2/op_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ func TestBlockBabylonFinalized(t *testing.T) {
ctm := StartOpL2ConsumerManager(t)
defer ctm.Stop(t)

defer func() {
if r := recover(); r != nil {
t.Fatalf("Test panicked: %v", r)
}
}()

// A BTC delegation has to stake to at least one Babylon finality provider
// https://github.com/babylonchain/babylon-private/blob/base/consumer-chain-support/x/btcstaking/keeper/msg_server.go#L169-L213
// So we have to start Babylon chain FP
Expand Down
22 changes: 16 additions & 6 deletions itest/opstackl2/op_test_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ import (
const (
opFinalityGadgetContractPath = "../bytecode/op_finality_gadget_1947cc6.wasm"
opConsumerId = "op-stack-l2-12345"
// it has to be a valid EVM RPC which doesn't timeout
opStackL2RPCAddress = "https://eth.drpc.org"
opStackL2RPCAddress = "http://localhost:8545"
)

type BaseTestManager = base_test_manager.BaseTestManager

type OpL2ConsumerTestManager struct {
BaseTestManager
BabylonHandler *e2eutils.BabylonNodeHandler
EthNodeHandler *e2eutils.EthereumNodeHandler
EOTSClient *client.EOTSManagerGRpcClient
EOTSConfig *eotsconfig.Config
EOTSServerHandler *e2eutils.EOTSServerHandler
Expand Down Expand Up @@ -89,19 +89,26 @@ func StartOpL2ConsumerManager(t *testing.T) *OpL2ConsumerTestManager {
require.NoError(t, err)
t.Logf("Register consumer %s to Babylon", opConsumerId)

// 4. new op consumer controller
// 4. Create local Ethereum devnet
ethNodeHandler, err := e2eutils.NewEthereumNodeHandler(t)
require.NoError(t, err)
t.Logf("Started local Ethereum node")

// 5. new op consumer controller
opcc, err := opstackl2.NewOPStackL2ConsumerController(mockOpL2ConsumerCtrlConfig(bh.GetNodeDataDir()), logger)
require.NoError(t, err)
t.Logf("Started op consumer controller")

// 5. store op-finality-gadget contract
// 6. store op-finality-gadget contract
err = storeWasmCode(opcc, opFinalityGadgetContractPath)
require.NoError(t, err)
t.Logf("Stored op finality contract")

opFinalityGadgetContractWasmId, err := getLatestCodeId(opcc)
require.NoError(t, err)
require.Equal(t, uint64(1), opFinalityGadgetContractWasmId, "first deployed contract code_id should be 1")

// 6. instantiate op contract
// 7. instantiate op contract
opFinalityGadgetInitMsg := map[string]interface{}{
"admin": opcc.CwClient.MustGetAddr(),
"consumer_id": opConsumerId,
Expand All @@ -112,6 +119,7 @@ func StartOpL2ConsumerManager(t *testing.T) *OpL2ConsumerTestManager {
require.NoError(t, err)
err = instantiateWasmContract(opcc, opFinalityGadgetContractWasmId, opFinalityGadgetInitMsgBytes)
require.NoError(t, err)
t.Logf("Instantiated op finality contract")

// get op contract address
resp, err := opcc.CwClient.ListContractsByCode(opFinalityGadgetContractWasmId, &sdkquerytypes.PageRequest{})
Expand All @@ -123,7 +131,7 @@ func StartOpL2ConsumerManager(t *testing.T) *OpL2ConsumerTestManager {
opcc.Cfg.OPFinalityGadgetAddress = resp.Contracts[0]
t.Logf("Deployed op finality contract address: %s", resp.Contracts[0])

// 7. prepare EOTS manager
// 8. prepare EOTS manager
eotsHomeDir := filepath.Join(testDir, "eots-home")
eotsCfg := eotsconfig.DefaultConfigWithHomePath(eotsHomeDir)
eh := e2eutils.NewEOTSServerHandler(t, eotsCfg, eotsHomeDir)
Expand All @@ -149,6 +157,7 @@ func StartOpL2ConsumerManager(t *testing.T) *OpL2ConsumerTestManager {
ctm := &OpL2ConsumerTestManager{
BaseTestManager: BaseTestManager{BBNClient: bc, CovenantPrivKeys: covenantPrivKeys},
BabylonHandler: bh,
EthNodeHandler: ethNodeHandler,
EOTSClient: eotsCli,
EOTSConfig: eotsCfg,
EOTSServerHandler: eh,
Expand Down Expand Up @@ -430,6 +439,7 @@ func (ctm *OpL2ConsumerTestManager) Stop(t *testing.T) {
require.NoError(t, err)
err = ctm.BabylonHandler.Stop()
require.NoError(t, err)
ctm.EthNodeHandler.Close()
ctm.EOTSServerHandler.Stop()
err = os.RemoveAll(ctm.BaseDir)
require.NoError(t, err)
Expand Down
24 changes: 24 additions & 0 deletions scripts/start_anvil_devnet.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/bash

# Detect the project root directory
PROJECT_ROOT=$(cd "$(dirname "$0")/.." && pwd)

# Check if anvil binary is available
if ! command -v anvil &> /dev/null; then
echo "Anvil not found. Installing Anvil..."
curl -L https://foundry.paradigm.xyz | bash
foundryup
export PATH=$PATH:$HOME/.foundry/bin
echo "Anvil installed and added to PATH."
fi

# Check if the anvil process is running
if pgrep -x "anvil" > /dev/null; then
echo "Anvil is already running, stopping it..."
pkill -x "anvil"
fi

# Start the anvil process with nohup
echo "Starting anvil process..."
nohup anvil -b 3 --optimism > "$PROJECT_ROOT/anvil.log" 2>&1 &
echo "Anvil process started, outputting to anvil.log"
12 changes: 12 additions & 0 deletions scripts/stop_anvil_devnet.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

# Check if anvil binary is available
if ! command -v anvil &> /dev/null; then
exit 1
fi

# Check if the anvil process is running
if pgrep -x "anvil" > /dev/null; then
echo "Stopping Anvil..."
pkill -x "anvil"
fi