Skip to content

Commit

Permalink
feat(engineclient): Depinject (berachain#1087)
Browse files Browse the repository at this point in the history
* bet

* bet

* bet

* x

* bet

* logger

* bet

* bet

* bet

* bet
  • Loading branch information
Devon Bear authored May 16, 2024
1 parent 288b346 commit 0fe1a78
Show file tree
Hide file tree
Showing 18 changed files with 245 additions and 119 deletions.
2 changes: 1 addition & 1 deletion beacond/app/app_config.go → beacond/cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

package app
package main

import (
runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1"
Expand Down
5 changes: 2 additions & 3 deletions beacond/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ import (
"log/slog"
"os"

"github.com/berachain/beacon-kit/beacond/app"
nodebuilder "github.com/berachain/beacon-kit/mod/node-builder"
"github.com/berachain/beacon-kit/mod/node-builder/pkg/app"
"go.uber.org/automaxprocs/maxprocs"
)

Expand All @@ -45,8 +45,7 @@ func run() error {
nb := nodebuilder.NewNodeBuilder[app.BeaconApp]().
WithAppName("beacond").
WithAppDescription("beacond is a beacon node for any beacon-kit chain").
WithAppCreator(app.NewBeaconKitAppWithDefaultBaseAppOptions).
WithDepInjectConfig(app.Config())
WithDepInjectConfig(Config())

return nb.RunNode()
}
Expand Down
10 changes: 5 additions & 5 deletions beacond/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,15 @@ require (
cosmossdk.io/api v0.7.5
cosmossdk.io/core v0.12.1-0.20240516114011-e03476679912
cosmossdk.io/depinject v1.0.0-alpha.4.0.20240506202947-fbddf0a55044
cosmossdk.io/log v1.3.1
cosmossdk.io/x/auth v0.0.0-00010101000000-000000000000
cosmossdk.io/x/consensus v0.0.0-00010101000000-000000000000
github.com/berachain/beacon-kit/mod/consensus-types v0.0.0-20240508035017-2fb637ea5f0a
github.com/berachain/beacon-kit/mod/da v0.0.0-20240515154823-9321cabc0e88
github.com/berachain/beacon-kit/mod/node-builder v0.0.0-20240515154823-9321cabc0e88
github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240508035017-2fb637ea5f0a
github.com/berachain/beacon-kit/mod/primitives-engine v0.0.0-20240511193312-dee73d6774a7
github.com/berachain/beacon-kit/mod/runtime v0.0.0-00010101000000-000000000000
github.com/berachain/beacon-kit/mod/state-transition v0.0.0-20240513191314-ce000626be85
github.com/berachain/beacon-kit/mod/storage v0.0.0-20240515154823-9321cabc0e88
github.com/cometbft/cometbft v1.0.0-alpha.2.0.20240515102804-eff98c0b34fd
github.com/cometbft/cometbft/api v1.0.0-alpha.2.0.20240515102804-eff98c0b34fd
github.com/cosmos/cosmos-db v1.0.2
github.com/cosmos/cosmos-proto v1.0.0-beta.5
github.com/cosmos/cosmos-sdk v0.51.0
github.com/spf13/cast v1.6.0
Expand All @@ -59,6 +54,7 @@ require (
cosmossdk.io/client/v2 v2.0.0-20240412212305-037cf98f7eea // indirect
cosmossdk.io/collections v0.4.0 // indirect
cosmossdk.io/errors v1.0.1 // indirect
cosmossdk.io/log v1.3.1 // indirect
cosmossdk.io/math v1.3.0 // indirect
cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc // indirect
cosmossdk.io/store/v2 v2.0.0-20240515130459-16437119e0d8 // indirect
Expand All @@ -83,6 +79,7 @@ require (
github.com/berachain/beacon-kit/mod/log v0.0.0-20240508035017-2fb637ea5f0a // indirect
github.com/berachain/beacon-kit/mod/p2p v0.0.0-00010101000000-000000000000 // indirect
github.com/berachain/beacon-kit/mod/payload v0.0.0-00010101000000-000000000000 // indirect
github.com/berachain/beacon-kit/mod/runtime v0.0.0-00010101000000-000000000000 // indirect
github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.3 // indirect
Expand All @@ -94,10 +91,13 @@ require (
github.com/cockroachdb/pebble v1.1.0 // indirect
github.com/cockroachdb/redact v1.1.5 // indirect
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
github.com/cometbft/cometbft v1.0.0-alpha.2.0.20240515102804-eff98c0b34fd // indirect
github.com/cometbft/cometbft-db v0.12.0 // indirect
github.com/cometbft/cometbft/api v1.0.0-alpha.2.0.20240515102804-eff98c0b34fd // indirect
github.com/consensys/bavard v0.1.13 // indirect
github.com/consensys/gnark-crypto v0.12.1 // indirect
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/cosmos-db v1.0.2 // indirect
github.com/cosmos/crypto v0.0.0-20240312084433-de8f9c76030d // indirect
github.com/cosmos/go-bip39 v1.0.0 // indirect
github.com/cosmos/gogogateway v1.2.0 // indirect
Expand Down
126 changes: 81 additions & 45 deletions mod/execution/pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,39 +27,53 @@ package client

import (
"context"
"math/big"
"net/http"
"strings"
"sync"
"time"

"github.com/berachain/beacon-kit/mod/errors"
"github.com/berachain/beacon-kit/mod/execution/pkg/client/cache"
eth "github.com/berachain/beacon-kit/mod/execution/pkg/client/ethclient"
"github.com/berachain/beacon-kit/mod/execution/pkg/client/ethclient"
"github.com/berachain/beacon-kit/mod/log"
engineprimitives "github.com/berachain/beacon-kit/mod/primitives-engine"
"github.com/berachain/beacon-kit/mod/primitives/pkg/net/jwt"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
)

// EngineClient is a struct that holds a pointer to an Eth1Client.
type EngineClient[
ExecutionPayloadDenebT engineprimitives.ExecutionPayload,
] struct {
*eth.Eth1Client[ExecutionPayloadDenebT]
// Eth1Client is a struct that holds the Ethereum 1 client and
// its configuration.
*ethclient.Eth1Client[ExecutionPayloadDenebT]

cfg *Config
capabilities map[string]struct{}
logger log.Logger[any]
jwtSecret *jwt.Secret
// cfg is the supplied configuration for the engine client.
cfg *Config

// logger is the logger for the engine client.
logger log.Logger[any]

// engineCache is an all-in-one cache for data
// that are retrieved by the EngineClient.
engineCache *cache.EngineCache

// jwtSecret is the JWT secret for the execution client.
jwtSecret *jwt.Secret

// capabilities is a map of capabilities that the execution client has.
capabilities map[string]struct{}

// statusErrCond is a condition variable for the status error.
statusErrCond *sync.Cond
statusErrMu *sync.RWMutex
statusErr error

// statusErrMu is a mutex for the status error.
statusErrMu *sync.RWMutex

// statusErr is the status error of the engine client.
statusErr error
}

// New creates a new engine client EngineClient.
Expand All @@ -70,30 +84,47 @@ func New[ExecutionPayloadDenebT engineprimitives.ExecutionPayload](
logger log.Logger[any],
jwtSecret *jwt.Secret,
) *EngineClient[ExecutionPayloadDenebT] {
ec := &EngineClient[ExecutionPayloadDenebT]{
cfg: cfg,
logger: logger,
jwtSecret: jwtSecret,
Eth1Client: new(eth.Eth1Client[ExecutionPayloadDenebT]),
capabilities: make(map[string]struct{}),
statusErrMu: new(sync.RWMutex),
statusErrMu := new(sync.RWMutex)
return &EngineClient[ExecutionPayloadDenebT]{
cfg: cfg,
logger: logger,
jwtSecret: jwtSecret,
Eth1Client: new(ethclient.Eth1Client[ExecutionPayloadDenebT]),
capabilities: make(map[string]struct{}),
statusErrMu: statusErrMu,
statusErrCond: sync.NewCond(statusErrMu),
engineCache: cache.NewEngineCacheWithDefaultConfig(),
}
ec.statusErrCond = sync.NewCond(ec.statusErrMu)

// If the engine cache is not set, we create a new one.
if ec.engineCache == nil {
ec.engineCache = cache.NewEngineCacheWithDefaultConfig()
}

return ec
}

// Start starts the engine client.
func (s *EngineClient[ExecutionPayloadDenebT]) Start(ctx context.Context) {
func (s *EngineClient[ExecutionPayloadDenebT]) Start(
ctx context.Context,
) error {
var (
err error
chainID *big.Int
)

// TODO: This is not required for IPC connections.
if true /* http || https */ {
// If we are in a JWT mode, we will start the JWT refresh loop.
defer func() {
if s.jwtSecret == nil {
s.logger.Warn(
"JWT secret not provided for http(s) connection" +
" - please verify your configuration settings",
)
return
}
go s.jwtRefreshLoop(ctx)
}()
}

for {
s.logger.Info("waiting for execution client to start 🍺🕔",
"dial-url", s.cfg.RPCDialURL)
if err := s.setupExecutionClientConnection(ctx); err != nil {
if err = s.setupExecutionClientConnection(ctx); err != nil {
s.statusErrMu.Lock()
s.statusErr = err
s.statusErrMu.Unlock()
Expand All @@ -104,10 +135,10 @@ func (s *EngineClient[ExecutionPayloadDenebT]) Start(ctx context.Context) {
}

// Get the chain ID from the execution client.
chainID, err := s.ChainID(ctx)
chainID, err = s.ChainID(ctx)
if err != nil {
s.logger.Error("failed to get chain ID", "err", err)
return
return err
}

// Log the chain ID.
Expand All @@ -124,11 +155,10 @@ func (s *EngineClient[ExecutionPayloadDenebT]) Start(ctx context.Context) {
// Exchange capabilities with the execution client.
if _, err = s.ExchangeCapabilities(ctx); err != nil {
s.logger.Error("failed to exchange capabilities", "err", err)
return err
}

// If we reached this point, the execution client is connected so we can
// start the jwt refresh loop.
go s.jwtRefreshLoop(ctx)
return nil
}

// Status verifies the chain ID via JSON-RPC. By proxy
Expand Down Expand Up @@ -226,6 +256,7 @@ func (s *EngineClient[ExecutionPayloadDenebT]) VerifyChainID(
func (s *EngineClient[ExecutionPayloadDenebT]) jwtRefreshLoop(
ctx context.Context,
) {
s.logger.Info("starting JWT refresh loop 🔄")
ticker := time.NewTicker(s.cfg.RPCJWTRefreshInterval)
defer ticker.Stop()
for {
Expand Down Expand Up @@ -277,37 +308,42 @@ func (s *EngineClient[ExecutionPayloadDenebT]) dialExecutionRPCClient(
) error {
var (
client *rpc.Client
err error
)

// Build an http.Header with the JWT token attached.
header, err := s.buildJWTHeader()
if err != nil {
return err
}

// Dial the execution client based on the URL scheme.
switch s.cfg.RPCDialURL.Scheme {
case "http", "https":
// Build an http.Header with the JWT token attached.
header, err := s.buildJWTHeader()
if err != nil {
return err
}

client, err = rpc.DialOptions(
ctx, s.cfg.RPCDialURL.String(), rpc.WithHeaders(header),
)
if err != nil {
return err
}
case "", "ipc":
var err error
client, err = rpc.DialIPC(ctx, s.cfg.RPCDialURL.String())
if err != nil {
return err
}
default:
return errors.Newf(
"no known transport for URL scheme %q",
s.cfg.RPCDialURL.Scheme,
)
}

// Check for an error when dialing the execution client.
if err != nil {
return err
}

s.Client = ethclient.NewClient(client)
return nil
// Refresh the execution client with the new client.
var err error
s.Eth1Client, err = ethclient.NewFromRPCClient[ExecutionPayloadDenebT](
client,
)
return err
}

// buildJWTHeader builds an http.Header that has the JWT token
Expand Down
7 changes: 7 additions & 0 deletions mod/execution/pkg/client/ethclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ func NewEth1Client[
return c, nil
}

// NewFromRPCClient creates a new Ethereum 1 client from an RPC client.
func NewFromRPCClient[
ExecutionPayloadDenebT engineprimitives.ExecutionPayload,
](rpcClient *rpc.Client) (*Eth1Client[ExecutionPayloadDenebT], error) {
return NewEth1Client[ExecutionPayloadDenebT](ethclient.NewClient(rpcClient))
}

// NewPayloadV3 calls the engine_newPayloadV3 method via JSON-RPC.
func (s *Eth1Client[ExecutionPayloadDenebT]) NewPayloadV3(
ctx context.Context,
Expand Down
7 changes: 6 additions & 1 deletion mod/execution/pkg/engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,12 @@ func (ee *Engine[
]) Start(
ctx context.Context,
) {
go ee.ec.Start(ctx)
go func() {
// TODO: handle better
if err := ee.ec.Start(ctx); err != nil {
panic(err)
}
}()
}

// Status returns error if the service is not considered healthy.
Expand Down
8 changes: 4 additions & 4 deletions mod/node-api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
package main

import (
server "github.com/berachain/beacon-kit/mod/node-api/server"
handlers "github.com/berachain/beacon-kit/mod/node-api/server/handlers"
echo "github.com/labstack/echo/v4"
middleware "github.com/labstack/echo/v4/middleware"
"github.com/berachain/beacon-kit/mod/node-api/server"
"github.com/berachain/beacon-kit/mod/node-api/server/handlers"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)

func NewServer(corsConfig middleware.CORSConfig,
Expand Down
4 changes: 1 addition & 3 deletions mod/node-builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ type AppInfo[T servertypes.Application] struct {
Name string
// Description is a short description of the application.
Description string
// Creator is a function that creates the application.
Creator servertypes.AppCreator[T]
// DepInjectConfig is the configuration for the application.
DepInjectConfig depinject.Config
}
Expand Down Expand Up @@ -170,7 +168,7 @@ func (nb *NodeBuilder[T]) BuildRootCmd() error {
cmdlib.DefaultRootCommandSetup(
nb.rootCmd,
mm,
nb.appInfo.Creator,
nb.AppCreator,
)

return autoCliOpts.EnhanceRootCommand(nb.rootCmd)
Expand Down
Loading

0 comments on commit 0fe1a78

Please sign in to comment.