Skip to content

Commit

Permalink
updated bindings to use m2-mainnet contracts and fixed all broken dep…
Browse files Browse the repository at this point in the history
…endencies (#91)

* updated bindings to use m2-mainnet contracts and fixed all broken dependencies

* fix linting error - missing error handling

* delete old pubkeycompendium mock

* removed all notions of pubkey compendium
also added builders for the avsregistry clients

* fixed compilation errors and ran go fmt

* fixed builder to return structs instead of interfaces

* fixed builder avs subscriber bug - was using http instead of ws client

* fixed buildall txmgr

* fixed bug - slasher no longer points to delegationManager so bindings creation logic was broken

* fixed avs registration function

* fix QueryExistingRegisteredOperatorPubkeys bug

* fix builder bug (was passing coordinator addr instead of apkreg addr)

* fix variable name keypair->privatekey

* update to updateStakes functions in avsregistry writer

* added quorumCount() function to avs reader

* added GetOperatorIdsInQuorumsAtCurrentBlock function to avs reader

* fix context bug in avs reader

* git pulled m2-mainnet for latest operatorStateRetriever changes and updated avs reader

* added comments explaining RegisterOperatorWithAVSRegistryCoordinator

* added GetOperatorsStakeInQuorumsAtCurrentBlock to avsregistry reader

* make mocks to fix tests

* remove "deleteme" debug log statement

* rename log->transactionLog in log output

* added comment explaining why we need to pass EcdsaPrivateKey in RegisterOperatorWithAVSRegistryCoordinator function

* remove all yaml names in BuildAllConfig struct - don't see why we would need to read this from config file

* remove TODO that was previously fixed

* added todo comment to update signFn and txmgr to be able to sign generic messages (not only txs)
  • Loading branch information
samlaf authored Jan 19, 2024
1 parent b5146b4 commit 95a7752
Show file tree
Hide file tree
Showing 57 changed files with 10,482 additions and 9,864 deletions.
294 changes: 257 additions & 37 deletions chainio/clients/avsregistry/reader.go

Large diffs are not rendered by default.

58 changes: 58 additions & 0 deletions chainio/clients/avsregistry/subscriber.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package avsregistry

import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/event"

"github.com/Layr-Labs/eigensdk-go/chainio/clients/eth"
blsapkreg "github.com/Layr-Labs/eigensdk-go/contracts/bindings/BLSApkRegistry"
"github.com/Layr-Labs/eigensdk-go/logging"
)

type AvsRegistrySubscriber interface {
SubscribeToNewPubkeyRegistrations() (chan *blsapkreg.ContractBLSApkRegistryNewPubkeyRegistration, event.Subscription, error)
}

type AvsRegistryChainSubscriber struct {
logger logging.Logger
blsApkRegistry blsapkreg.ContractBLSApkRegistryFilters
}

// forces EthSubscriber to implement the chainio.Subscriber interface
var _ AvsRegistrySubscriber = (*AvsRegistryChainSubscriber)(nil)

func NewAvsRegistryChainSubscriber(
blsApkRegistry blsapkreg.ContractBLSApkRegistryFilters,
logger logging.Logger,
) (*AvsRegistryChainSubscriber, error) {
return &AvsRegistryChainSubscriber{
logger: logger,
blsApkRegistry: blsApkRegistry,
}, nil
}

func BuildAvsRegistryChainSubscriber(
blsApkRegistryAddr common.Address,
ethWsClient eth.EthClient,
logger logging.Logger,
) (*AvsRegistryChainSubscriber, error) {
blsapkreg, err := blsapkreg.NewContractBLSApkRegistry(blsApkRegistryAddr, ethWsClient)
if err != nil {
logger.Error("Failed to create BLSApkRegistry contract", "err", err)
return nil, err
}
return NewAvsRegistryChainSubscriber(blsapkreg, logger)
}

func (s *AvsRegistryChainSubscriber) SubscribeToNewPubkeyRegistrations() (chan *blsapkreg.ContractBLSApkRegistryNewPubkeyRegistration, event.Subscription, error) {
newPubkeyRegistrationChan := make(chan *blsapkreg.ContractBLSApkRegistryNewPubkeyRegistration)
sub, err := s.blsApkRegistry.WatchNewPubkeyRegistration(
&bind.WatchOpts{}, newPubkeyRegistrationChan, nil,
)
if err != nil {
s.logger.Error("Failed to subscribe to NewPubkeyRegistration events", "err", err)
return nil, nil, err
}
return newPubkeyRegistrationChan, sub, nil
}
245 changes: 206 additions & 39 deletions chainio/clients/avsregistry/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,86 +2,229 @@ package avsregistry

import (
"context"
"crypto/ecdsa"
"errors"
"math/big"

"github.com/Layr-Labs/eigensdk-go/chainio/clients/elcontracts"
"github.com/Layr-Labs/eigensdk-go/chainio/clients/eth"
"github.com/Layr-Labs/eigensdk-go/chainio/txmgr"
"github.com/Layr-Labs/eigensdk-go/chainio/utils"
"github.com/Layr-Labs/eigensdk-go/crypto/bls"
"github.com/Layr-Labs/eigensdk-go/logging"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
gethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"

blsoperatorstateretriever "github.com/Layr-Labs/eigensdk-go/contracts/bindings/BLSOperatorStateRetriever"
blspubkeyregistry "github.com/Layr-Labs/eigensdk-go/contracts/bindings/BLSPubkeyRegistry"
blsregistrycoordinator "github.com/Layr-Labs/eigensdk-go/contracts/bindings/BLSRegistryCoordinatorWithIndices"
blsapkregistry "github.com/Layr-Labs/eigensdk-go/contracts/bindings/BLSApkRegistry"
opstateretriever "github.com/Layr-Labs/eigensdk-go/contracts/bindings/OperatorStateRetriever"
regcoord "github.com/Layr-Labs/eigensdk-go/contracts/bindings/RegistryCoordinator"
stakeregistry "github.com/Layr-Labs/eigensdk-go/contracts/bindings/StakeRegistry"
)

type AvsRegistryWriter interface {
// RegisterOperatorWithAVSRegistryCoordinator is used to register a single operator with the AVS's registry coordinator.
// - operatorEcdsaPrivateKey is the operator's ecdsa private key (used to sign a message to register operator in eigenlayer's delegation manager)
// - operatorToAvsRegistrationSigSalt is a random salt used to prevent replay attacks
// - operatorToAvsRegistrationSigExpiry is the expiry time of the signature
RegisterOperatorWithAVSRegistryCoordinator(
ctx context.Context,
operatorEcdsaPrivateKey *ecdsa.PrivateKey,
operatorToAvsRegistrationSigSalt [32]byte,
operatorToAvsRegistrationSigExpiry *big.Int,
blsKeyPair *bls.KeyPair,
quorumNumbers []byte,
pubkey blsregistrycoordinator.BN254G1Point,
socket string,
) (*types.Receipt, error)
) (*gethtypes.Receipt, error)

UpdateStakes(
// UpdateStakesOfEntireOperatorSetForQuorums is used by avs teams running https://github.com/Layr-Labs/avs-sync
// to updates the stake of their entire operator set.
// Because of high gas costs of this operation, it typically needs to be called for every quorum, or perhaps for a small grouping of quorums
// (highly dependent on number of operators per quorum)
UpdateStakesOfEntireOperatorSetForQuorums(
ctx context.Context,
operatorsPerQuorum [][]gethcommon.Address,
quorumNumbers []byte,
) (*gethtypes.Receipt, error)

// UpdateStakesOfOperatorSubsetForAllQuorums is meant to be used by single operators (or teams of operators, possibly running https://github.com/Layr-Labs/avs-sync)
// to update the stake of their own operator(s). This might be needed in the case that they received a lot of new stake delegations, and want this to be reflected
// in the AVS's registry coordinator.
UpdateStakesOfOperatorSubsetForAllQuorums(
ctx context.Context,
operators []gethcommon.Address,
) (*types.Receipt, error)
) (*gethtypes.Receipt, error)

DeregisterOperator(
ctx context.Context,
quorumNumbers []byte,
pubkey blsregistrycoordinator.BN254G1Point,
) (*types.Receipt, error)
pubkey regcoord.BN254G1Point,
) (*gethtypes.Receipt, error)
}

type AvsRegistryChainWriter struct {
registryCoordinator *blsregistrycoordinator.ContractBLSRegistryCoordinatorWithIndices
blsOperatorStateRetriever *blsoperatorstateretriever.ContractBLSOperatorStateRetriever
stakeRegistry *stakeregistry.ContractStakeRegistry
blsPubkeyRegistry *blspubkeyregistry.ContractBLSPubkeyRegistry
logger logging.Logger
ethClient eth.EthClient
txMgr txmgr.TxManager
serviceManagerAddr gethcommon.Address
registryCoordinator *regcoord.ContractRegistryCoordinator
operatorStateRetriever *opstateretriever.ContractOperatorStateRetriever
stakeRegistry *stakeregistry.ContractStakeRegistry
blsApkRegistry *blsapkregistry.ContractBLSApkRegistry
elReader elcontracts.ELReader
logger logging.Logger
ethClient eth.EthClient
txMgr txmgr.TxManager
}

var _ AvsRegistryWriter = (*AvsRegistryChainWriter)(nil)

func NewAvsRegistryWriter(
registryCoordinator *blsregistrycoordinator.ContractBLSRegistryCoordinatorWithIndices,
blsOperatorStateRetriever *blsoperatorstateretriever.ContractBLSOperatorStateRetriever,
func NewAvsRegistryChainWriter(
serviceManagerAddr gethcommon.Address,
registryCoordinator *regcoord.ContractRegistryCoordinator,
operatorStateRetriever *opstateretriever.ContractOperatorStateRetriever,
stakeRegistry *stakeregistry.ContractStakeRegistry,
blsPubkeyRegistry *blspubkeyregistry.ContractBLSPubkeyRegistry,
blsApkRegistry *blsapkregistry.ContractBLSApkRegistry,
elReader elcontracts.ELReader,
logger logging.Logger,
ethClient eth.EthClient,
txMgr txmgr.TxManager,
) (*AvsRegistryChainWriter, error) {
return &AvsRegistryChainWriter{
registryCoordinator: registryCoordinator,
blsOperatorStateRetriever: blsOperatorStateRetriever,
stakeRegistry: stakeRegistry,
blsPubkeyRegistry: blsPubkeyRegistry,
logger: logger,
ethClient: ethClient,
txMgr: txMgr,
serviceManagerAddr: serviceManagerAddr,
registryCoordinator: registryCoordinator,
operatorStateRetriever: operatorStateRetriever,
stakeRegistry: stakeRegistry,
blsApkRegistry: blsApkRegistry,
elReader: elReader,
logger: logger,
ethClient: ethClient,
txMgr: txMgr,
}, nil
}

func BuildAvsRegistryChainWriter(
registryCoordinatorAddr gethcommon.Address,
operatorStateRetrieverAddr gethcommon.Address,
logger logging.Logger,
ethClient eth.EthClient,
txMgr txmgr.TxManager,
) (*AvsRegistryChainWriter, error) {
registryCoordinator, err := regcoord.NewContractRegistryCoordinator(registryCoordinatorAddr, ethClient)
if err != nil {
return nil, err
}
operatorStateRetriever, err := opstateretriever.NewContractOperatorStateRetriever(
operatorStateRetrieverAddr,
ethClient,
)
if err != nil {
return nil, err
}
serviceManagerAddr, err := registryCoordinator.ServiceManager(&bind.CallOpts{})
if err != nil {
return nil, err
}
blsApkRegistryAddr, err := registryCoordinator.BlsApkRegistry(&bind.CallOpts{})
if err != nil {
return nil, err
}
blsApkRegistry, err := blsapkregistry.NewContractBLSApkRegistry(blsApkRegistryAddr, ethClient)
if err != nil {
return nil, err
}
stakeRegistryAddr, err := registryCoordinator.StakeRegistry(&bind.CallOpts{})
if err != nil {
return nil, err
}
stakeRegistry, err := stakeregistry.NewContractStakeRegistry(stakeRegistryAddr, ethClient)
if err != nil {
return nil, err
}
delegationManagerAddr, err := stakeRegistry.Delegation(&bind.CallOpts{})
if err != nil {
return nil, err
}
elReader, err := elcontracts.BuildELChainReader(delegationManagerAddr, ethClient, logger)
if err != nil {
return nil, err
}
return NewAvsRegistryChainWriter(
serviceManagerAddr,
registryCoordinator,
operatorStateRetriever,
stakeRegistry,
blsApkRegistry,
elReader,
logger,
ethClient,
txMgr,
)
}

// TODO(samlaf): clean up this function
func (w *AvsRegistryChainWriter) RegisterOperatorWithAVSRegistryCoordinator(
ctx context.Context,
// we need to pass the private key explicitly and can't use the signer because registering requires signing a message which isn't a transaction
// and the signer can only signs transactions
// see operatorSignature in https://github.com/Layr-Labs/eigenlayer-middleware/blob/m2-mainnet/docs/RegistryCoordinator.md#registeroperator
// TODO(madhur): check to see if we can make the signer and txmgr more flexible so we can use them (and remote signers) to sign non txs
operatorEcdsaPrivateKey *ecdsa.PrivateKey,
operatorToAvsRegistrationSigSalt [32]byte,
operatorToAvsRegistrationSigExpiry *big.Int,
blsKeyPair *bls.KeyPair,
quorumNumbers []byte,
pubkey blsregistrycoordinator.BN254G1Point,
socket string,
) (*types.Receipt, error) {
) (*gethtypes.Receipt, error) {
w.logger.Info("registering operator with the AVS's registry coordinator")
// params to register bls pubkey with bls apk registry
operatorAddr := crypto.PubkeyToAddress(operatorEcdsaPrivateKey.PublicKey)
g1HashedMsgToSign, err := w.registryCoordinator.PubkeyRegistrationMessageHash(&bind.CallOpts{}, operatorAddr)
if err != nil {
return nil, err
}
signedMsg := utils.ConvertToBN254G1Point(
blsKeyPair.SignHashedToCurveMessage(utils.ConvertBn254GethToGnark(g1HashedMsgToSign)).G1Point,
)
G1pubkeyBN254 := utils.ConvertToBN254G1Point(blsKeyPair.GetPubKeyG1())
G2pubkeyBN254 := utils.ConvertToBN254G2Point(blsKeyPair.GetPubKeyG2())
pubkeyRegParams := regcoord.IBLSApkRegistryPubkeyRegistrationParams{
PubkeyRegistrationSignature: signedMsg,
PubkeyG1: G1pubkeyBN254,
PubkeyG2: G2pubkeyBN254,
}

// params to register operator in delegation manager's operator-avs mapping
msgToSign, err := w.elReader.CalculateDelegationApprovalDigestHash(
&bind.CallOpts{}, operatorAddr, w.serviceManagerAddr, operatorToAvsRegistrationSigSalt, operatorToAvsRegistrationSigExpiry)
if err != nil {
return nil, err
}
operatorSignature, err := crypto.Sign(msgToSign[:], operatorEcdsaPrivateKey)
if err != nil {
return nil, err
}
// this is annoying, and not sure why its needed, but seems like some historical baggage
// see https://github.com/ethereum/go-ethereum/issues/28757#issuecomment-1874525854
// and https://twitter.com/pcaversaccio/status/1671488928262529031
operatorSignature[64] += 27
operatorSignatureWithSaltAndExpiry := regcoord.ISignatureUtilsSignatureWithSaltAndExpiry{
Signature: operatorSignature,
Salt: operatorToAvsRegistrationSigSalt,
Expiry: operatorToAvsRegistrationSigExpiry,
}

noSendTxOpts, err := w.txMgr.GetNoSendTxOpts()
if err != nil {
return nil, err
}
// TODO: this call will fail if max number of operators are already registered
// in that case, need to call churner to kick out another operator. See eigenDA's node/operator.go implementation
tx, err := w.registryCoordinator.RegisterOperatorWithCoordinator1(noSendTxOpts, quorumNumbers, pubkey, socket)
tx, err := w.registryCoordinator.RegisterOperator(
noSendTxOpts,
quorumNumbers,
socket,
pubkeyRegParams,
operatorSignatureWithSaltAndExpiry,
)
if err != nil {
return nil, err
}
Expand All @@ -94,16 +237,40 @@ func (w *AvsRegistryChainWriter) RegisterOperatorWithAVSRegistryCoordinator(
return receipt, nil
}

func (w *AvsRegistryChainWriter) UpdateStakes(
func (w *AvsRegistryChainWriter) UpdateStakesOfEntireOperatorSetForQuorums(
ctx context.Context,
operatorsPerQuorum [][]gethcommon.Address,
quorumNumbers []byte,
) (*gethtypes.Receipt, error) {
w.logger.Info("updating stakes for entire operator set", "quorumNumbers", quorumNumbers)
noSendTxOpts, err := w.txMgr.GetNoSendTxOpts()
if err != nil {
return nil, err
}
tx, err := w.registryCoordinator.UpdateOperatorsForQuorum(noSendTxOpts, operatorsPerQuorum, quorumNumbers)
if err != nil {
return nil, err
}
receipt, err := w.txMgr.Send(ctx, tx)
if err != nil {
return nil, errors.New("failed to send tx with err: " + err.Error())
}
w.logger.Infof("tx hash: %s", tx.Hash().String())
w.logger.Info("updated stakes for entire operator set", "quorumNumbers", quorumNumbers)
return receipt, nil

}

func (w *AvsRegistryChainWriter) UpdateStakesOfOperatorSubsetForAllQuorums(
ctx context.Context,
operators []gethcommon.Address,
) (*types.Receipt, error) {
w.logger.Info("updating stakes")
) (*gethtypes.Receipt, error) {
w.logger.Info("updating stakes of operator subset for all quorums", "operators", operators)
noSendTxOpts, err := w.txMgr.GetNoSendTxOpts()
if err != nil {
return nil, err
}
tx, err := w.stakeRegistry.UpdateStakes(noSendTxOpts, operators)
tx, err := w.registryCoordinator.UpdateOperators(noSendTxOpts, operators)
if err != nil {
return nil, err
}
Expand All @@ -112,22 +279,22 @@ func (w *AvsRegistryChainWriter) UpdateStakes(
return nil, errors.New("failed to send tx with err: " + err.Error())
}
w.logger.Infof("tx hash: %s", tx.Hash().String())
w.logger.Info("updated stakes")
w.logger.Info("updated stakes of operator subset for all quorums", "operators", operators)
return receipt, nil

}

func (w *AvsRegistryChainWriter) DeregisterOperator(
ctx context.Context,
quorumNumbers []byte,
pubkey blsregistrycoordinator.BN254G1Point,
) (*types.Receipt, error) {
pubkey regcoord.BN254G1Point,
) (*gethtypes.Receipt, error) {
w.logger.Info("deregistering operator with the AVS's registry coordinator")
noSendTxOpts, err := w.txMgr.GetNoSendTxOpts()
if err != nil {
return nil, err
}
tx, err := w.registryCoordinator.DeregisterOperatorWithCoordinator(noSendTxOpts, quorumNumbers, pubkey)
tx, err := w.registryCoordinator.DeregisterOperator(noSendTxOpts, quorumNumbers)
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 95a7752

Please sign in to comment.