Skip to content

Commit

Permalink
Fix plugin registration and add registration int test (#185)
Browse files Browse the repository at this point in the history
* fix: Fix operator plugin ctx assignment

* test: Add registration integration test

* test: Add registration test to CI

* fix: Set mock metrics ip port address on plugin

* test: Set anvil address on plugin config

* test: Register operator in EL on registration test

* test: Clean up after test is done
  • Loading branch information
Hyodar authored May 27, 2024
1 parent a70030d commit bf9601f
Show file tree
Hide file tree
Showing 8 changed files with 319 additions and 114 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ jobs:
cache-from: type=gha,scope=relayer
cache-to: type=gha,mode=max,scope=relayer

- name: Build plugin container
uses: docker/build-push-action@v5
with:
load: true
context: .
file: ./plugin/cmd/Dockerfile
tags: near-sffl-operator-plugin
cache-from: type=gha,scope=plugin
cache-to: type=gha,mode=max,scope=plugin

- name: Install Node.js
uses: actions/setup-node@v3
with:
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,5 @@ tests-contract: ## runs all forge tests

tests-integration: ## runs all integration tests
go test ./tests/integration/integration_test.go -v -count=1
go test ./tests/integration/registration_test.go -v -count=1

15 changes: 15 additions & 0 deletions config-files/plugin.anvil.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

# Operator ECDSA address
operator_address: 0xD5A0359da7B310917d7760385516B2426E86ab7f

# AVS contract addresses
avs_registry_coordinator_address: 0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf
operator_state_retriever_address: 0x4c5859f0F772848b2D91F1D83E2Fe57935348029

# AVS network RPCs
eth_rpc_url: http://mainnet-anvil:8545
eth_ws_url: ws://mainnet-anvil:8545

# EigenLayer ECDSA and BLS private key paths
ecdsa_private_key_store_path: /near-sffl/keys/ecdsa/1/key.json
bls_private_key_store_path: /near-sffl/keys/bls/1/key.json
6 changes: 3 additions & 3 deletions plugin/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ func main() {
operationType := ctx.GlobalString(OperationFlag.Name)
switch operationType {
case "opt-in":
return operatorPlugin.OptIn()
return operatorPlugin.OptIn(ctx)
case "opt-out":
return operatorPlugin.OptOut()
return operatorPlugin.OptOut(ctx)
case "deposit":
return operatorPlugin.Deposit()
return operatorPlugin.Deposit(ctx)
default:
return cli.NewExitError(fmt.Sprintf("Invalid operation type: %v", operationType), 1)
}
Expand Down
25 changes: 8 additions & 17 deletions plugin/cmd/operator_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,9 @@ type CliOperatorPlugin struct {
avsReader *chainio.AvsReader
avsWriter *chainio.AvsWriter

ctx *cli.Context
logger logging.Logger
}

type OperatorPlugin interface {
OptIn() error
OptOut() error
Deposit() error
}

var _ OperatorPlugin = &CliOperatorPlugin{}

func NewOperatorPluginFromCLIContext(ctx *cli.Context) (*CliOperatorPlugin, error) {
goCtx := context.Background()
logger, _ := logging.NewZapLogger(logging.Development)
Expand All @@ -66,7 +57,7 @@ func NewOperatorPluginFromCLIContext(ctx *cli.Context) (*CliOperatorPlugin, erro
RegistryCoordinatorAddr: avsConfig.AVSRegistryCoordinatorAddress,
OperatorStateRetrieverAddr: avsConfig.OperatorStateRetrieverAddress,
AvsName: "super-fast-finality-layer",
PromMetricsIpPortAddress: avsConfig.EigenMetricsIpPortAddress,
PromMetricsIpPortAddress: "127.0.0.1:9090",
}

ethHttpClient, err := eth.NewClient(avsConfig.EthRpcUrl)
Expand Down Expand Up @@ -149,8 +140,8 @@ func NewOperatorPluginFromCLIContext(ctx *cli.Context) (*CliOperatorPlugin, erro
}, nil
}

func (o *CliOperatorPlugin) OptIn() error {
blsKeyPassword := o.ctx.GlobalString(BlsKeyPasswordFlag.Name)
func (o *CliOperatorPlugin) OptIn(ctx *cli.Context) error {
blsKeyPassword := ctx.GlobalString(BlsKeyPasswordFlag.Name)

blsKeypair, err := bls.ReadPrivateKeyFromFile(o.avsConfig.BlsPrivateKeyStorePath, blsKeyPassword)
if err != nil {
Expand All @@ -176,8 +167,8 @@ func (o *CliOperatorPlugin) OptIn() error {
return nil
}

func (o *CliOperatorPlugin) OptOut() error {
blsKeyPassword := o.ctx.GlobalString(BlsKeyPasswordFlag.Name)
func (o *CliOperatorPlugin) OptOut(ctx *cli.Context) error {
blsKeyPassword := ctx.GlobalString(BlsKeyPasswordFlag.Name)

blsKeypair, err := bls.ReadPrivateKeyFromFile(o.avsConfig.BlsPrivateKeyStorePath, blsKeyPassword)
if err != nil {
Expand All @@ -194,14 +185,14 @@ func (o *CliOperatorPlugin) OptOut() error {
return nil
}

func (o *CliOperatorPlugin) Deposit() error {
strategy := o.ctx.GlobalString(StrategyAddrFlag.Name)
func (o *CliOperatorPlugin) Deposit(ctx *cli.Context) error {
strategy := ctx.GlobalString(StrategyAddrFlag.Name)
if len(strategy) == 0 {
o.logger.Error("Strategy address is required for deposit operation")
return errors.New("strategy address is required for deposit operation")
}

strategyAddr := common.HexToAddress(o.ctx.GlobalString(StrategyAddrFlag.Name))
strategyAddr := common.HexToAddress(ctx.GlobalString(StrategyAddrFlag.Name))
_, tokenAddr, err := o.clients.ElChainReader.GetStrategyAndUnderlyingToken(&bind.CallOpts{}, strategyAddr)
if err != nil {
o.logger.Error("Failed to fetch strategy contract", "err", err)
Expand Down
97 changes: 3 additions & 94 deletions tests/integration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,13 @@ import (
"testing"
"time"

"github.com/Layr-Labs/eigensdk-go/chainio/clients/eth"
"github.com/Layr-Labs/eigensdk-go/crypto/bls"
sdkEcdsa "github.com/Layr-Labs/eigensdk-go/crypto/ecdsa"
sdklogging "github.com/Layr-Labs/eigensdk-go/logging"
sdkutils "github.com/Layr-Labs/eigensdk-go/utils"
"github.com/docker/go-connections/nat"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/assert"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/rabbitmq"
Expand Down Expand Up @@ -197,10 +194,10 @@ func setupTestEnv(t *testing.T, ctx context.Context) *testEnv {
rollup1AnvilContainerName := "rollup1-anvil"
rmqContainerName := "rmq"

mainnetAnvil := startAnvilTestContainer(t, containersCtx, mainnetAnvilContainerName, "8545", "1", true, networkName)
mainnetAnvil := utils.StartAnvilTestContainer(t, containersCtx, mainnetAnvilContainerName, "8545", "1", true, networkName)
rollupAnvils := []*utils.AnvilInstance{
startAnvilTestContainer(t, containersCtx, rollup0AnvilContainerName, "8546", "2", false, networkName),
startAnvilTestContainer(t, containersCtx, rollup1AnvilContainerName, "8547", "3", false, networkName),
utils.StartAnvilTestContainer(t, containersCtx, rollup0AnvilContainerName, "8546", "2", false, networkName),
utils.StartAnvilTestContainer(t, containersCtx, rollup1AnvilContainerName, "8547", "3", false, networkName),
}
rabbitMq := startRabbitMqContainer(t, containersCtx, rmqContainerName, networkName)
indexerContainer, relayers := startIndexer(t, containersCtx, indexerContainerName, rollupAnvils, rabbitMq, networkName)
Expand Down Expand Up @@ -465,94 +462,6 @@ func buildConfig(t *testing.T, sfflDeploymentRaw config.SFFLDeploymentRaw, addre
}
}

func startAnvilTestContainer(t *testing.T, ctx context.Context, name, exposedPort, chainId string, isMainnet bool, networkName string) *utils.AnvilInstance {
integrationDir, err := os.Getwd()
if err != nil {
panic(err)
}

req := testcontainers.ContainerRequest{
Image: "ghcr.io/foundry-rs/foundry:latest@sha256:8b843eb65cc7b155303b316f65d27173c862b37719dc095ef3a2ef27ce8d3c00",
Name: name,
Entrypoint: []string{"anvil"},
ExposedPorts: []string{exposedPort + "/tcp"},
WaitingFor: wait.ForLog("Listening on"),
Networks: []string{networkName},
}

if isMainnet {
req.Mounts = testcontainers.ContainerMounts{
testcontainers.ContainerMount{
Source: testcontainers.GenericBindMountSource{
HostPath: filepath.Join(integrationDir, "../anvil/data/avs-and-eigenlayer-deployed-anvil-state.json"),
},
Target: "/root/.anvil/state.json",
},
}
req.Cmd = []string{"--host", "0.0.0.0", "--load-state", "/root/.anvil/state.json", "--port", exposedPort, "--chain-id", chainId}
} else {
req.Cmd = []string{"--host", "0.0.0.0", "--port", exposedPort, "--block-time", "10", "--chain-id", chainId}
}

anvilC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
if err != nil {
t.Fatalf("Error starting anvil container: %s", err.Error())
}

anvilEndpoint, err := anvilC.PortEndpoint(ctx, nat.Port(exposedPort), "")
if err != nil {
t.Fatalf("Error getting anvil endpoint: %s", err.Error())
}

httpUrl := "http://" + anvilEndpoint
httpClient, err := eth.NewClient(httpUrl)
if err != nil {
t.Fatalf("Failed to create anvil HTTP client: %s", err.Error())
}
rpcClient, err := rpc.Dial(httpUrl)
if err != nil {
t.Fatalf("Failed to create anvil RPC client: %s", err.Error())
}

wsUrl := "ws://" + anvilEndpoint
wsClient, err := eth.NewClient(wsUrl)
if err != nil {
t.Fatalf("Failed to create anvil WS client: %s", err.Error())
}

expectedChainId, ok := big.NewInt(0).SetString(chainId, 10)
if !ok {
t.Fatalf("Bad chain ID: %s", chainId)
}

fetchedChainId, err := httpClient.ChainID(ctx)
if err != nil {
t.Fatalf("Failed to get anvil chainId: %s", err.Error())
}
if fetchedChainId.Cmp(expectedChainId) != 0 {
t.Fatalf("Anvil chainId is not the expected: expected %s, got %s", expectedChainId.String(), fetchedChainId.String())
}

anvil := &utils.AnvilInstance{
Container: anvilC,
HttpClient: httpClient,
HttpUrl: httpUrl,
WsClient: wsClient,
WsUrl: wsUrl,
RpcClient: rpcClient,
ChainID: fetchedChainId,
}

if isMainnet {
anvil.Mine(big.NewInt(100), big.NewInt(1))
}

return anvil
}

func deployRegistryRollups(t *testing.T, anvils []*utils.AnvilInstance) ([]common.Address, []*registryrollup.ContractSFFLRegistryRollup, []*bind.TransactOpts, []*bind.TransactOpts) {
var registryRollups []*registryrollup.ContractSFFLRegistryRollup
var ownerAuths []*bind.TransactOpts
Expand Down
Loading

0 comments on commit bf9601f

Please sign in to comment.