Skip to content

Commit

Permalink
Merge branch 'dev' into refactor/wrap-error-elcontracts
Browse files Browse the repository at this point in the history
  • Loading branch information
MegaRedHand authored Feb 3, 2025
2 parents 4767b5f + 48a3026 commit 622f76d
Show file tree
Hide file tree
Showing 25 changed files with 1,025 additions and 342 deletions.
78 changes: 78 additions & 0 deletions .github/workflows/bindings.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Bindings

on:
push:
branches:
- dev
pull_request:
merge_group:

permissions:
contents: read

jobs:
generate_bindings:
name: Generate bindings
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Install go1.21
uses: actions/setup-go@v5
with:
go-version: "1.21"

- name: Add Ethereum PPA
run: sudo add-apt-repository -y ppa:ethereum/ethereum

- name: Install Abigen
run: sudo apt-get update && sudo apt-get install ethereum

- name: Show abigen version
run: abigen --version

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: v0.3.0

- name: Run make bindings
run: make bindings

check_bindings:
name: Check bindings are up-to-date
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
submodules: recursive

# This step is needed to know if the contracts were changed.
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
contracts:
- 'contracts/lib/**'
- 'contracts/script/**'
- 'contracts/src/**'
bindings:
- 'contracts/bindings/**'
# This step runs only if some contract changed.
# It checks whether the bindings directory have changed.
# If there are no changes, then the bindings are outdated
# and therefore this step will fail.
- name: Check the bindings are up-to-date
if: steps.filter.outputs.contracts == 'true'
run: |
BINDINGS_UPDATED=${{ steps.filter.outputs.bindings }}
if [[ "$BINDINGS_UPDATED" == "false" ]]; then
echo "The bindings are outdated";
exit 1
fi
58 changes: 58 additions & 0 deletions .github/workflows/check-anvil-state.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Check anvil state
on:
push:
branches:
- dev
pull_request:
merge_group:

jobs:
generate-anvil-state:
name: generate anvil state
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: stable

- name: Generate anvil state
run: make deploy-contracts-to-anvil-and-save-state

check-anvil-state:
name: Check anvil dump is up-to-date
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

# This step is needed to know if the contracts were changed.
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
contracts:
- 'contracts/lib/**'
- 'contracts/script/**'
- 'contracts/src/**'
anvil_state:
- 'contracts/anvil/contracts-deployed-anvil-state.json'
# This step runs only if some contract changed.
# It checks whether the anvil state has changed.
# If there are no changes, then the anvil state is outdated
# and therefore this step will fail.
- name: Check the anvil state is up-to-date
if: steps.filter.outputs.contracts == 'true'
run: |
ANVIL_STATE_UPDATED=${{ steps.filter.outputs.anvil_state }}
if [[ "$ANVIL_STATE_UPDATED" == "false" ]]; then
echo "The anvil state is outdated";
exit 1
fi
40 changes: 40 additions & 0 deletions .github/workflows/contracts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Contracts CI

on:
push:
branches: [main]
pull_request:
branches: [ '**' ]

env:
FOUNDRY_PROFILE: ci

jobs:
check:
strategy:
fail-fast: true

name: Foundry project
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./contracts

steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: stable

- name: Show Forge version
run: forge --version

- name: Run Forge fmt
run: forge fmt --check

- name: Run Forge build
run: forge build
26 changes: 25 additions & 1 deletion chainio/clients/avsregistry/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ type Config struct {
OperatorStateRetrieverAddress common.Address
}

// The ChainReader provides methods to call the
// AVS registry contract's view functions.
type ChainReader struct {
logger logging.Logger
blsApkRegistryAddr common.Address
Expand All @@ -40,6 +42,7 @@ type ChainReader struct {
ethClient eth.HttpBackend
}

// Creates a new instance of the ChainReader.
func NewChainReader(
registryCoordinatorAddr common.Address,
blsApkRegistryAddr common.Address,
Expand Down Expand Up @@ -84,13 +87,16 @@ func NewReaderFromConfig(
), nil
}

// Returns the total quorum count read from the RegistryCoordinator
func (r *ChainReader) GetQuorumCount(opts *bind.CallOpts) (uint8, error) {
if r.registryCoordinator == nil {
return 0, errors.New("RegistryCoordinator contract not provided")
}
return r.registryCoordinator.QuorumCount(opts)
}

// Returns, for each quorum in `quorumNumbers`, a vector of the operators registered for
// that quorum at the current block, containing each operator's `operatorId` and `stake`.
func (r *ChainReader) GetOperatorsStakeInQuorumsAtCurrentBlock(
opts *bind.CallOpts,
quorumNumbers types.QuorumNums,
Expand Down Expand Up @@ -130,14 +136,15 @@ func (r *ChainReader) GetOperatorsStakeInQuorumsAtBlock(
return operatorStakes, nil
}

// Returns, for each quorum in `quorumNumbers`, a vector of the addresses of the
// operators registered for that quorum at the current block.
func (r *ChainReader) GetOperatorAddrsInQuorumsAtCurrentBlock(
opts *bind.CallOpts,
quorumNumbers types.QuorumNums,
) ([][]common.Address, error) {
if r.operatorStateRetriever == nil {
return nil, errors.New("OperatorStateRetriever contract not provided")
}

if opts.Context == nil {
opts.Context = context.Background()
}
Expand Down Expand Up @@ -169,6 +176,10 @@ func (r *ChainReader) GetOperatorAddrsInQuorumsAtCurrentBlock(

}

// Returns a tuple containing
// - An array with the quorum IDs in which the given operator is registered at the given block
// - An array that contains, for each quorum, an array with the address, id and stake
// of each operator registered in that quorum.
func (r *ChainReader) GetOperatorsStakeInQuorumsOfOperatorAtBlock(
opts *bind.CallOpts,
operatorId types.OperatorId,
Expand Down Expand Up @@ -261,6 +272,8 @@ func (r *ChainReader) GetOperatorStakeInQuorumsOfOperatorAtCurrentBlock(
return quorumStakes, nil
}

// Returns a struct containing the indices of the quorum members that signed,
// and the ones that didn't.
func (r *ChainReader) GetCheckSignaturesIndices(
opts *bind.CallOpts,
referenceBlockNumber uint32,
Expand Down Expand Up @@ -293,6 +306,7 @@ func (r *ChainReader) GetCheckSignaturesIndices(
return checkSignatureIndices, nil
}

// Given an operator address, returns its ID.
func (r *ChainReader) GetOperatorId(
opts *bind.CallOpts,
operatorAddress common.Address,
Expand All @@ -311,6 +325,7 @@ func (r *ChainReader) GetOperatorId(
return operatorId, nil
}

// Given an operator ID, returns its address.
func (r *ChainReader) GetOperatorFromId(
opts *bind.CallOpts,
operatorId types.OperatorId,
Expand All @@ -329,6 +344,8 @@ func (r *ChainReader) GetOperatorFromId(
return operatorAddress, nil
}

// Returns an array of booleans, where the boolean at index i represents
// whether the operator is registered for the quorum i.
func (r *ChainReader) QueryRegistrationDetail(
opts *bind.CallOpts,
operatorAddress common.Address,
Expand Down Expand Up @@ -358,6 +375,7 @@ func (r *ChainReader) QueryRegistrationDetail(
return quorums, nil
}

// Returns true if the operator is registered, false otherwise.
func (r *ChainReader) IsOperatorRegistered(
opts *bind.CallOpts,
operatorAddress common.Address,
Expand All @@ -376,6 +394,9 @@ func (r *ChainReader) IsOperatorRegistered(
return registeredWithAvs, nil
}

// Queries existing operators for a particular block range.
// Returns two arrays. The first one contains the addresses
// of the operators, and the second contains their corresponding public keys.
func (r *ChainReader) QueryExistingRegisteredOperatorPubKeys(
ctx context.Context,
startBlock *big.Int,
Expand Down Expand Up @@ -475,6 +496,9 @@ func (r *ChainReader) QueryExistingRegisteredOperatorPubKeys(
return operatorAddresses, operatorPubkeys, nil
}

// Queries existing operator sockets for a particular block range.
// Returns a mapping containing operator IDs as keys and their
// corresponding sockets as values.
func (r *ChainReader) QueryExistingRegisteredOperatorSockets(
ctx context.Context,
startBlock *big.Int,
Expand Down
76 changes: 76 additions & 0 deletions chainio/clients/avsregistry/subscriber_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package avsregistry_test

import (
"context"
"testing"
"time"

"github.com/Layr-Labs/eigensdk-go/crypto/bls"
"github.com/Layr-Labs/eigensdk-go/testutils"
"github.com/Layr-Labs/eigensdk-go/testutils/testclients"
"github.com/Layr-Labs/eigensdk-go/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestSubscriberAvsRegistry(t *testing.T) {
client, _ := testclients.BuildTestClients(t)
chainSubscriber := client.AvsRegistryChainSubscriber
chainWriter := client.AvsRegistryChainWriter

t.Run("subscribe to new pubkey registrations", func(t *testing.T) {
pubKeyRegistrationsC, event, err := chainSubscriber.SubscribeToNewPubkeyRegistrations()
require.NoError(t, err)
defer event.Unsubscribe()

// Emit a NewPubkeyRegistration event creating a new operator
keypair, err := bls.NewKeyPairFromString("0x01")
require.NoError(t, err)

ecdsaPrivateKey, err := crypto.HexToECDSA(testutils.ANVIL_FIRST_PRIVATE_KEY)
require.NoError(t, err)

quorumNumbers := types.QuorumNums{0}

receipt, err := chainWriter.RegisterOperator(
context.Background(),
ecdsaPrivateKey,
keypair,
quorumNumbers,
"",
true,
)
require.NoError(t, err)
require.NotNil(t, receipt)

select {
case newPubkeyRegistration := <-pubKeyRegistrationsC:
expectedOperator := crypto.PubkeyToAddress(ecdsaPrivateKey.PublicKey)
assert.Equal(t, expectedOperator, newPubkeyRegistration.Operator)
case <-time.After(10 * time.Second):
// Throw an error if the event is not received within 10 seconds, making the test fail
t.Fatal("Timed out waiting for NewPubkeyRegistration event")
}
})

t.Run("subscribe to operator socket updates", func(t *testing.T) {
socketC, event, err := chainSubscriber.SubscribeToOperatorSocketUpdates()
require.NoError(t, err)
defer event.Unsubscribe()

// Emit a SocketUpdate event
socketUpdate := "socket-update"
receipt, err := chainWriter.UpdateSocket(context.Background(), types.Socket(socketUpdate), true)
require.NoError(t, err)
require.NotNil(t, receipt)

select {
case operatorSocketUpdate := <-socketC:
assert.Equal(t, socketUpdate, operatorSocketUpdate.Socket)
case <-time.After(10 * time.Second):
// Throw an error if the event is not received within 10 seconds, making the test fail
t.Fatal("Timed out waiting for OperatorSocketUpdate event")
}
})
}
Loading

0 comments on commit 622f76d

Please sign in to comment.