Skip to content

Commit

Permalink
Add read only builder (#326)
Browse files Browse the repository at this point in the history
  • Loading branch information
juanbono authored Aug 16, 2024
1 parent 4654b5c commit e5c3fb8
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 18 deletions.
42 changes: 42 additions & 0 deletions chainio/clients/avsregistry/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,48 @@ import (
"github.com/Layr-Labs/eigensdk-go/logging"
)

// Build an AVS registry client with the given configuration,
// HTTP and WS clients, and logger, but without a private key.
//
// This is useful for read-only operations.
func BuildReadClients(
config Config,
client eth.HttpBackend,
wsClient eth.WsBackend,
logger logging.Logger,
) (*ChainReader, *ChainSubscriber, *ContractBindings, error) {
avsBindings, err := NewBindingsFromConfig(
config,
client,
logger,
)

if err != nil {
return nil, nil, nil, err
}

chainReader := NewChainReader(
avsBindings.RegistryCoordinatorAddr,
avsBindings.BlsApkRegistryAddr,
avsBindings.RegistryCoordinator,
avsBindings.OperatorStateRetriever,
avsBindings.StakeRegistry,
logger,
client,
)

chainSubscriber, err := NewSubscriberFromConfig(
config,
wsClient,
logger,
)
if err != nil {
return nil, nil, nil, err
}

return chainReader, chainSubscriber, avsBindings, nil
}

func BuildClients(
config Config,
client eth.HttpBackend,
Expand Down
110 changes: 92 additions & 18 deletions chainio/clients/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,28 +29,99 @@ type BuildAllConfig struct {
PromMetricsIpPortAddress string
}

// Clients is a struct that holds all the clients that are needed to interact with the AVS and EL contracts.
// TODO: this is confusing right now because clients are not instrumented clients, but
// we return metrics and prometheus reg, so user has to build instrumented clients at the call
// site if they need them. We should probably separate into two separate constructors, one
// for non-instrumented clients that doesn't return metrics/reg, and another instrumented-constructor
// that returns instrumented clients and the metrics/reg.
type Clients struct {
// ReadClients is a struct that holds only the read clients for interacting with the AVS and EL contracts.
type ReadClients struct {
AvsRegistryChainReader *avsregistry.ChainReader
AvsRegistryChainSubscriber *avsregistry.ChainSubscriber
AvsRegistryChainWriter *avsregistry.ChainWriter
ElChainReader *elcontracts.ChainReader
ElChainWriter *elcontracts.ChainWriter
EthHttpClient eth.HttpBackend
EthWsClient eth.WsBackend
Wallet wallet.Wallet
TxManager txmgr.TxManager
AvsRegistryContractBindings *avsregistry.ContractBindings
EigenlayerContractBindings *elcontracts.ContractBindings
Metrics *metrics.EigenMetrics // exposes main avs node spec metrics that need to be incremented by avs code and used to start the metrics server
PrometheusRegistry *prometheus.Registry // Used if avs teams need to register avs-specific metrics
PrometheusRegistry *prometheus.Registry
}

// Clients is a struct that holds all the clients that are needed to interact with the AVS and EL contracts.
type Clients struct {
ReadClients
Wallet wallet.Wallet
TxManager txmgr.TxManager
ElChainWriter *elcontracts.ChainWriter
AvsRegistryChainWriter *avsregistry.ChainWriter
}

// BuildReadClients creates all the read clients needed to interact with the AVS and EL contracts.
func BuildReadClients(
config BuildAllConfig,
logger logging.Logger,
) (*ReadClients, error) {
config.validate(logger)

// Create the metrics server
promReg := prometheus.NewRegistry()
eigenMetrics := metrics.NewEigenMetrics(config.AvsName, config.PromMetricsIpPortAddress, promReg, logger)

// creating two types of Eth clients: HTTP and WS
ethHttpClient, err := ethclient.Dial(config.EthHttpUrl)
if err != nil {
return nil, utils.WrapError("Failed to create Eth Http client", err)
}

ethWsClient, err := ethclient.Dial(config.EthWsUrl)
if err != nil {
return nil, utils.WrapError("Failed to create Eth WS client", err)
}

// creating AVS clients: Reader
avsRegistryChainReader, avsRegistryChainSubscriber, avsRegistryContractBindings, err := avsregistry.BuildReadClients(
avsregistry.Config{
RegistryCoordinatorAddress: gethcommon.HexToAddress(config.RegistryCoordinatorAddr),
OperatorStateRetrieverAddress: gethcommon.HexToAddress(config.OperatorStateRetrieverAddr),
},
ethHttpClient,
ethWsClient,
logger,
)
if err != nil {
return nil, utils.WrapError("Failed to create AVS Registry Reader and Writer", err)
}

// creating EL clients: Reader and EigenLayer Contract Bindings
elChainReader, elContractBindings, err := elcontracts.BuildReadClients(
elcontracts.Config{
DelegationManagerAddress: avsRegistryContractBindings.DelegationManagerAddr,
AvsDirectoryAddress: avsRegistryContractBindings.AvsDirectoryAddr,
},
ethHttpClient,
logger,
eigenMetrics,
)
if err != nil {
return nil, utils.WrapError("Failed to create EL Reader and Writer", err)
}

readClients := ReadClients{
ElChainReader: elChainReader,
AvsRegistryChainReader: avsRegistryChainReader,
AvsRegistryChainSubscriber: avsRegistryChainSubscriber,
EthHttpClient: ethHttpClient,
EthWsClient: ethWsClient,
EigenlayerContractBindings: elContractBindings,
AvsRegistryContractBindings: avsRegistryContractBindings,
Metrics: eigenMetrics,
PrometheusRegistry: promReg,
}
return &readClients, nil
}

// BuildAll creates all the clients needed to interact with the AVS and EL contracts. For both read and write
// operations.
// TODO: this is confusing right now because clients are not instrumented clients, but
// we return metrics and prometheus reg, so user has to build instrumented clients at the call
// site if they need them. We should probably separate into two separate constructors, one
// for non-instrumented clients that doesn't return metrics/reg, and another instrumented-constructor
// that returns instrumented clients and the metrics/reg.
func BuildAll(
config BuildAllConfig,
ecdsaPrivateKey *ecdsa.PrivateKey,
Expand Down Expand Up @@ -120,22 +191,25 @@ func BuildAll(
return nil, utils.WrapError("Failed to create EL Reader and Writer", err)
}

return &Clients{
readClients := ReadClients{
ElChainReader: elChainReader,
ElChainWriter: elChainWriter,
AvsRegistryChainReader: avsRegistryChainReader,
AvsRegistryChainSubscriber: avsRegistryChainSubscriber,
AvsRegistryChainWriter: avsRegistryChainWriter,
EthHttpClient: ethHttpClient,
EthWsClient: ethWsClient,
Wallet: pkWallet,
TxManager: txMgr,
EigenlayerContractBindings: elContractBindings,
AvsRegistryContractBindings: avsRegistryContractBindings,
Metrics: eigenMetrics,
PrometheusRegistry: promReg,
}, nil
}

return &Clients{
ReadClients: readClients,
ElChainWriter: elChainWriter,
AvsRegistryChainWriter: avsRegistryChainWriter,
Wallet: pkWallet,
TxManager: txMgr,
}, nil
}

// Very basic validation that makes sure all fields are nonempty
Expand Down
30 changes: 30 additions & 0 deletions chainio/clients/elcontracts/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,36 @@ import (
"github.com/Layr-Labs/eigensdk-go/metrics"
)

// Returns a tuple of reader clients with the given:
// configuration, HTTP client, logger and metrics.
func BuildReadClients(
config Config,
client eth.HttpBackend,
logger logging.Logger,
eigenMetrics *metrics.EigenMetrics,
) (*ChainReader, *ContractBindings, error) {
elContractBindings, err := NewBindingsFromConfig(
config,
client,
logger,
)
if err != nil {
return nil, nil, err
}

elChainReader := NewChainReader(
elContractBindings.Slasher,
elContractBindings.DelegationManager,
elContractBindings.StrategyManager,
elContractBindings.AvsDirectory,
elContractBindings.RewardsCoordinator,
logger,
client,
)

return elChainReader, elContractBindings, nil
}

func BuildClients(
config Config,
client eth.HttpBackend,
Expand Down

0 comments on commit e5c3fb8

Please sign in to comment.