diff --git a/mod/async/go.mod b/mod/async/go.mod index 52f1b5068b..9df86a9b41 100644 --- a/mod/async/go.mod +++ b/mod/async/go.mod @@ -1,3 +1,22 @@ module github.com/berachain/beacon-kit/mod/async go 1.22.5 + +require ( + github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0 + github.com/berachain/beacon-kit/mod/log v0.0.0-20240807213340-5779c7a563cd +) + +require ( + github.com/cockroachdb/errors v1.11.3 // indirect + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/redact v1.1.5 // indirect + github.com/getsentry/sentry-go v0.28.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect +) diff --git a/mod/async/go.sum b/mod/async/go.sum new file mode 100644 index 0000000000..6ff86e4669 --- /dev/null +++ b/mod/async/go.sum @@ -0,0 +1,72 @@ +github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0 h1:kCSrkb/uVXfMKJPKjf0c7nlJkwn5cNwMxtzRW4zNq2A= +github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0/go.mod h1:og0jtHZosPDTyhge9tMBlRItoZ4Iv3aZFM9n4QDpcdo= +github.com/berachain/beacon-kit/mod/log v0.0.0-20240807213340-5779c7a563cd h1:DYSjsq80Omqqlt+z2VcYsSxjZpLqCDRz7CvUDBrLDJE= +github.com/berachain/beacon-kit/mod/log v0.0.0-20240807213340-5779c7a563cd/go.mod h1:BilVBmqKhC4GXYCaIs8QnKaR14kpn3YmF5uYBdayF9I= +github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= +github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/getsentry/sentry-go v0.28.1 h1:zzaSm/vHmGllRM6Tpx1492r0YDzauArdBfkJRtY6P5k= +github.com/getsentry/sentry-go v0.28.1/go.mod h1:1fQZ+7l7eeJ3wYi82q5Hg8GqAPgefRq+FP/QhafYVgg= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/mod/async/pkg/broker/broker.go b/mod/async/pkg/broker/broker.go deleted file mode 100644 index 0febf78961..0000000000 --- a/mod/async/pkg/broker/broker.go +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -// -// Copyright (C) 2024, Berachain Foundation. All rights reserved. -// Use of this software is governed by the Business Source License included -// in the LICENSE file of this repository and at www.mariadb.com/bsl11. -// -// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY -// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER -// VERSIONS OF THE LICENSED WORK. -// -// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF -// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF -// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). -// -// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON -// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, -// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND -// TITLE. - -package broker - -import ( - "context" - "time" -) - -// Broker broadcasts msgs to registered clients. -type Broker[T any] struct { - // name of the message broker. - name string - // clients is a map of registered clients. - clients map[chan T]struct{} - // msgs is the channel for publishing new messages. - msgs chan T - // timeout is the timeout for sending a msg to a client. - timeout time.Duration -} - -// New creates a new b. -func New[T any](name string) *Broker[T] { - return &Broker[T]{ - clients: make(map[chan T]struct{}), - msgs: make(chan T, defaultBufferSize), - timeout: defaultTimeout, - name: name, - } -} - -// Name returns the name of the msg broker. -func (b *Broker[T]) Name() string { - return b.name -} - -// Start starts the broker loop. -func (b *Broker[T]) Start(ctx context.Context) error { - go b.start(ctx) - return nil -} - -// start starts the broker loop. -func (b *Broker[T]) start(ctx context.Context) { - for { - select { - case <-ctx.Done(): - // close all leftover clients and break the broker loop - for client := range b.clients { - b.Unsubscribe(client) - } - return - case msg := <-b.msgs: - // broadcast published msg to all clients - for client := range b.clients { - // send msg to client (or discard msg after timeout) - select { - case client <- msg: - case <-time.After(b.timeout): - } - } - } - } -} - -// Publish publishes a msg to the b. -// Returns ErrTimeout on timeout. -func (b *Broker[T]) Publish(ctx context.Context, msg T) error { - select { - case b.msgs <- msg: - return nil - case <-ctx.Done(): - return ctx.Err() - } -} - -// Subscribe registers a new client to the broker and returns it to the caller. -// Returns ErrTimeout on timeout. -func (b *Broker[T]) Subscribe() (chan T, error) { - client := make(chan T) - b.clients[client] = struct{}{} - return client, nil -} - -// Unsubscribe removes a client from the b. -// Returns ErrTimeout on timeout. -func (b *Broker[T]) Unsubscribe(client chan T) { - // Remove the client from the broker - delete(b.clients, client) - // close the client channel - close(client) -} diff --git a/mod/async/pkg/dispatcher/dispatcher.go b/mod/async/pkg/dispatcher/dispatcher.go new file mode 100644 index 0000000000..c68502064b --- /dev/null +++ b/mod/async/pkg/dispatcher/dispatcher.go @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package dispatcher + +import ( + "context" + + "github.com/berachain/beacon-kit/mod/async/pkg/types" + "github.com/berachain/beacon-kit/mod/log" +) + +// Dispatcher faciliates asynchronous communication between components, +// typically services. It acts as an API facade to the underlying event and +// message servers. + +// Ensure Dispatcher implements DispatcherI. +var _ types.Dispatcher = (*Dispatcher)(nil) + +type Dispatcher struct { + eventServer EventServer + msgServer MessageServer + logger log.Logger[any] +} + +// NewDispatcher creates a new dispatcher. +func NewDispatcher( + eventServer EventServer, + msgServer MessageServer, + logger log.Logger[any], +) *Dispatcher { + eventServer.SetLogger(logger) + msgServer.SetLogger(logger) + return &Dispatcher{ + eventServer: eventServer, + msgServer: msgServer, + logger: logger, + } +} + +// Start starts the dispatcher. +func (d *Dispatcher) Start(ctx context.Context) error { + d.eventServer.Start(ctx) + return nil +} + +// PublishEvent dispatches the given event to the event server. +// It will error if the type is inconsistent with the publisher +// registered for the given eventID. +func (d *Dispatcher) PublishEvent(event types.BaseMessage) error { + return d.eventServer.Publish(event) +} + +// SendRequest dispatches the given request to the message server. +// It will error if the and types are inconsistent with the +// route registered for the given messageID. +func (d *Dispatcher) SendRequest(req types.BaseMessage, future any) error { + return d.msgServer.Request(req, future) +} + +// SendResponse dispatches the given response to the message server. +// It will error if the type is inconsistent with the route registered +// for the given messageID. +func (d *Dispatcher) SendResponse(resp types.BaseMessage) error { + return d.msgServer.Respond(resp) +} + +// ============================== Events =================================== + +// RegisterPublishers registers the given publisher with the given eventID. +// Any subsequent events with dispatched to this Dispatcher must be +// consistent with the type expected by . +func (d *Dispatcher) RegisterPublishers( + publishers ...types.Publisher, +) error { + var err error + for _, publisher := range publishers { + d.logger.Info("Publisher registered", "eventID", publisher.EventID()) + err = d.eventServer.RegisterPublisher(publisher.EventID(), publisher) + if err != nil { + return err + } + } + return nil +} + +// Subscribe subscribes the given channel to the event with the given . +// It will error if the channel type does not match the event type corresponding +// to the . +func (d *Dispatcher) Subscribe(eventID types.MessageID, ch any) error { + return d.eventServer.Subscribe(eventID, ch) +} + +// ================================ Messages ================================ + +// RegisterMsgRecipient registers the given channel to the message with the +// given . +func (d *Dispatcher) RegisterMsgReceiver( + messageID types.MessageID, ch any, +) error { + d.logger.Info("Message receiver registered", "messageID", messageID) + return d.msgServer.RegisterReceiver(messageID, ch) +} + +// RegisterRoutes registers the given route with the given messageID. +// Any subsequent messages with sent to this Dispatcher must be +// consistent with the type expected by . +func (d *Dispatcher) RegisterRoutes( + routes ...types.MessageRoute, +) error { + var err error + for _, route := range routes { + d.logger.Info("Route registered", "messageID", route.MessageID()) + err = d.msgServer.RegisterRoute(route.MessageID(), route) + if err != nil { + return err + } + } + return nil +} + +func (d *Dispatcher) Name() string { + return "dispatcher" +} diff --git a/mod/async/pkg/dispatcher/types.go b/mod/async/pkg/dispatcher/types.go new file mode 100644 index 0000000000..d51c2b74f8 --- /dev/null +++ b/mod/async/pkg/dispatcher/types.go @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package dispatcher + +import ( + "context" + + "github.com/berachain/beacon-kit/mod/async/pkg/types" + "github.com/berachain/beacon-kit/mod/log" +) + +type MessageServer interface { + RegisterReceiver(mID types.MessageID, ch any) error + Request(req types.BaseMessage, future any) error + Respond(resp types.BaseMessage) error + RegisterRoute(mID types.MessageID, route types.MessageRoute) error + SetLogger(logger log.Logger[any]) +} + +type EventServer interface { + Start(ctx context.Context) + RegisterPublisher(mID types.EventID, publisher types.Publisher) error + Subscribe(mID types.EventID, ch any) error + Publish(event types.BaseMessage) error + SetLogger(logger log.Logger[any]) +} diff --git a/mod/async/pkg/broker/constants.go b/mod/async/pkg/messaging/assert.go similarity index 73% rename from mod/async/pkg/broker/constants.go rename to mod/async/pkg/messaging/assert.go index aa54901023..c00698966a 100644 --- a/mod/async/pkg/broker/constants.go +++ b/mod/async/pkg/messaging/assert.go @@ -18,15 +18,14 @@ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. -package broker +package messaging -import "time" - -const ( - // defaultTimeout specifies the default timeout when the broker - // tries to send a message to a client, a message is published to the - // broker, or a client subscribes or unsubscribes. - defaultTimeout = time.Second - // defaultBufferSize specifies the default size of the message buffer. - defaultBufferSize = 10 -) +// ensureType ensures that the provided entity is of type T. +// It returns a typed entity or an error if the type is not correct. +func ensureType[T any](e any) (T, error) { + typedE, ok := e.(T) + if !ok { + return *new(T), errIncompatibleAssignee(*new(T), e) + } + return typedE, nil +} diff --git a/mod/primitives/pkg/events/events.go b/mod/async/pkg/messaging/constants.go similarity index 58% rename from mod/primitives/pkg/events/events.go rename to mod/async/pkg/messaging/constants.go index 77f4fa17b3..79c7f10602 100644 --- a/mod/primitives/pkg/events/events.go +++ b/mod/async/pkg/messaging/constants.go @@ -18,19 +18,23 @@ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. -package events +package messaging +import "time" + +// TODO: make timeout configurable thorugh config/context const ( - NewSlot = "new-slot" - BeaconBlockBuilt = "beacon-block-built" - BeaconBlockReceived = "beacon-block-received" - BeaconBlockVerified = "beacon-block-verified" - BeaconBlockFinalizedRequest = "beacon-block-finalized-request" - BeaconBlockFinalized = "beacon-block-finalized" - ValidatorSetUpdated = "validator-set-updated" - BlobSidecarsBuilt = "blob-sidecars-built" - BlobSidecarsReceived = "blob-sidecars-received" - BlobSidecarsProcessRequest = "blob-sidecars-process-request" - BlobSidecarsProcessed = "blob-sidecars-processed" - GenesisDataProcessRequest = "genesis-data-process-request" + // defaultPublisherTimeout specifies the default timeout when the publisher + // tries to send a message to a client, a message is published to the + // publisher, or a client subscribes or unsubscribes. + defaultPublisherTimeout = time.Second + + // defaultMaxTimeout specifies the default max timeout for a message to be + // sent to a client, a message to be published, or a client to subscribe or + // unsubscribe. + // TODO: fr implementation + defaultMaxTimeout = 2 * time.Second + + // defaultBufferSize specifies the default size of the message buffer. + defaultBufferSize = 10 ) diff --git a/mod/async/pkg/messaging/errors.go b/mod/async/pkg/messaging/errors.go new file mode 100644 index 0000000000..ea60b379d2 --- /dev/null +++ b/mod/async/pkg/messaging/errors.go @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package messaging + +import ( + "time" + + "github.com/berachain/beacon-kit/mod/async/pkg/types" + "github.com/berachain/beacon-kit/mod/errors" +) + +// errTimeout is the error returned when a dispatch operation timed out. +// +//nolint:gochecknoglobals // errors +var ( + // errTimeout is the error returned when a dispatch operation timed out. + errTimeout = func(messageID types.MessageID, timeout time.Duration) error { + return errors.Newf("message %s reached the max timeout of %s", + messageID, timeout) + } + + // errRouteAlreadySet is the error returned when the route is already set. + errRouteAlreadySet = errors.New("route already set") + + // errRegisteringNilChannel is the error returned when the channel to + // register is nil. + errRegisteringNilChannel = func(messageID types.MessageID) error { + return errors.Newf("cannot register nil channel for route: %s", + messageID) + } + + // errReceiverNotReady is the error returned when the receiver channel is + // full, closed, or not listening. + errReceiverNotReady = func(messageID types.MessageID) error { + return errors.Newf( + "receiver channel is full, closed, or not listening. Route: %s", + messageID, + ) + } + + errSendingNilResponse = func(messageID types.MessageID) error { + return errors.Newf("cannot send nil response for route: %s", + messageID) + } + + // errIncompatibleAssignee is the error returned when the assignee is not + // compatible with the assigner. + errIncompatibleAssignee = func( + assigner interface{}, assignee interface{}, + ) error { + return errors.Newf( + "incompatible assignee, expected: %T, received: %T", + assigner, + assignee, + ) + } +) diff --git a/mod/async/pkg/messaging/publisher.go b/mod/async/pkg/messaging/publisher.go new file mode 100644 index 0000000000..11b22fe821 --- /dev/null +++ b/mod/async/pkg/messaging/publisher.go @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package messaging + +import ( + "context" + "sync" + "time" + + "github.com/berachain/beacon-kit/mod/async/pkg/types" +) + +// Publisher is responsible for broadcasting all events corresponding to the +// to all registered client channels. +type Publisher[T any] struct { + eventID types.EventID + // clients is a map of subscribed clients. + clients map[chan T]struct{} + // msgs is the channel for publishing new messages. + msgs chan T + // timeout is the timeout for sending a msg to a client. + timeout time.Duration + // mu is the mutex for the clients map. + mu sync.Mutex +} + +// NewPublisher creates a new publisher publishing events of type T for the +// provided eventID. +func NewPublisher[T any](eventID string) *Publisher[T] { + return &Publisher[T]{ + eventID: types.EventID(eventID), + clients: make(map[chan T]struct{}), + msgs: make(chan T, defaultBufferSize), + timeout: defaultPublisherTimeout, + mu: sync.Mutex{}, + } +} + +// EventID returns the event ID that the publisher is responsible for. +func (p *Publisher[T]) EventID() types.EventID { + return p.eventID +} + +// Start starts the publisher loop. +func (p *Publisher[T]) Start(ctx context.Context) { + go p.start(ctx) +} + +// start starts the publisher loop. +func (p *Publisher[T]) start(ctx context.Context) { + for { + select { + case <-ctx.Done(): + // close all leftover clients and break the publisher loop + p.shutdown() + return + case msg := <-p.msgs: + // broadcast published msg to all clients + p.broadcast(msg) + } + } +} + +// Publish publishes a msg to all subscribers. +// Returns ErrTimeout on timeout. +func (p *Publisher[T]) Publish(msg types.BaseMessage) error { + typedMsg, err := ensureType[T](msg) + if err != nil { + return err + } + ctx := msg.Context() + select { + case p.msgs <- typedMsg: + return nil + case <-ctx.Done(): + return ctx.Err() + } +} + +// Subscribe registers the provided channel to the publisher, +// Returns ErrTimeout on timeout. +// TODO: see if its possible to accept a channel instead of any +func (p *Publisher[T]) Subscribe(ch any) error { + client, err := ensureType[chan T](ch) + if err != nil { + return err + } + p.mu.Lock() + defer p.mu.Unlock() + p.clients[client] = struct{}{} + return nil +} + +// Unsubscribe removes a client from the publisher. +// Returns an error if the provided channel is not of type chan T. +func (p *Publisher[T]) Unsubscribe(ch any) error { + client, err := ensureType[chan T](ch) + if err != nil { + return err + } + p.mu.Lock() + defer p.mu.Unlock() + delete(p.clients, client) + close(client) + return nil +} + +// broadcast broadcasts a msg to all clients. +func (p *Publisher[T]) broadcast(msg T) { + for client := range p.clients { + // send msg to client (or discard msg after timeout) + select { + case client <- msg: + case <-time.After(p.timeout): + } + } +} + +// shutdown closes all leftover clients. +func (p *Publisher[T]) shutdown() { + for client := range p.clients { + if err := p.Unsubscribe(client); err != nil { + panic(err) + } + } +} diff --git a/mod/async/pkg/messaging/route.go b/mod/async/pkg/messaging/route.go new file mode 100644 index 0000000000..c0bd32c869 --- /dev/null +++ b/mod/async/pkg/messaging/route.go @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package messaging + +import ( + "sync" + "time" + + "github.com/berachain/beacon-kit/mod/async/pkg/types" +) + +// Route represents a communication route to a single recipient. +// Invariant: there is exactly no more than one route for each messageID. +type Route[ReqT any, RespT any] struct { + // messageID is the ID of the message that the route is responsible for. + messageID types.MessageID + // recipientCh is the channel to send requests to. + recipientCh chan types.Message[ReqT] + // responseCh is the channel to send responses to. + responseCh chan types.Message[RespT] + // maxTimeout is the maximum duration to wait for a response + // before considering the request timed out and pruning the thread. + maxTimeout time.Duration + // mu is the mutex to synchronize access to the route. + mu sync.Mutex +} + +// NewRoute creates a new route. +func NewRoute[ReqT any, RespT any]( + messageID types.MessageID, +) *Route[ReqT, RespT] { + return &Route[ReqT, RespT]{ + messageID: messageID, + responseCh: make(chan types.Message[RespT]), + maxTimeout: defaultMaxTimeout, + mu: sync.Mutex{}, + } +} + +// MessageID returns the message ID that the route is responsible for. +func (r *Route[ReqT, RespT]) MessageID() types.MessageID { + return r.messageID +} + +// RegisterReceiver sets the recipient for the route. +func (r *Route[ReqT, RespT]) RegisterReceiver(ch any) error { + if r.recipientCh != nil { + return errRouteAlreadySet + } else if ch == nil { + return errRegisteringNilChannel(r.messageID) + } + typedCh, err := ensureType[chan types.Message[ReqT]](ch) + if err != nil { + return err + } + r.recipientCh = typedCh + return nil +} + +// SendRequestAsync accepts a future and sends a request to the recipient +// channel. Once the response is available, it will be written to the future. +func (r *Route[ReqT, RespT]) SendRequest( + req types.BaseMessage, future any, +) error { + if err := r.sendRequest(req); err != nil { + return err + } + typedFuture, err := ensureType[types.FutureI[RespT]](future) + if err != nil { + return err + } + go r.populateFuture(typedFuture) + return nil +} + +// SendResponse sends a response to the response channel. +func (r *Route[ReqT, RespT]) SendResponse(resp types.BaseMessage) error { + typedMsg, err := ensureType[types.Message[RespT]](resp) + if err != nil { + return err + } + if typedMsg == nil { + return errSendingNilResponse(r.messageID) + } + r.responseCh <- typedMsg + return nil +} + +// populateFuture sends a done signal to the future when the response is +// available. +func (r *Route[ReqT, RespT]) populateFuture(future types.FutureI[RespT]) { + select { + case resp := <-r.responseCh: + future.SetResult(resp.Data(), resp.Error()) + case <-time.After(r.maxTimeout): + future.SetResult(*new(RespT), errTimeout(r.messageID, r.maxTimeout)) + return + } +} + +// SendRequest sends a request to the recipient. +func (r *Route[ReqT, RespT]) sendRequest(req types.BaseMessage) error { + typedReq, err := ensureType[types.Message[ReqT]](req) + if err != nil { + return err + } + + select { + case r.recipientCh <- typedReq: + return nil + default: + // Channel is full or closed + return errReceiverNotReady(r.messageID) + } +} diff --git a/mod/async/pkg/server/errors.go b/mod/async/pkg/server/errors.go new file mode 100644 index 0000000000..6282dfb15d --- /dev/null +++ b/mod/async/pkg/server/errors.go @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package server + +import ( + "github.com/berachain/beacon-kit/mod/async/pkg/types" + "github.com/berachain/beacon-kit/mod/errors" +) + +//nolint:gochecknoglobals // errors +var ( + errPublisherNotFound = func(eventID types.EventID) error { + return errors.Newf("publisher not found for eventID: %s", eventID) + } + errRouteNotFound = errors.New("route not found") + errRouteAlreadyRegistered = func(messageID types.MessageID) error { + return errors.Newf("route already registered for messageID: %s", + messageID) + } + errPublisherAlreadyExists = func(eventID types.EventID) error { + return errors.Newf("publisher already exists for eventID: %s", eventID) + } +) diff --git a/mod/async/pkg/server/event.go b/mod/async/pkg/server/event.go new file mode 100644 index 0000000000..188ea6bcc3 --- /dev/null +++ b/mod/async/pkg/server/event.go @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package server + +import ( + "context" + + "github.com/berachain/beacon-kit/mod/async/pkg/types" + "github.com/berachain/beacon-kit/mod/log" +) + +// EventServer asyncronously dispatches events to subscribers. +type EventServer struct { + publishers map[types.MessageID]types.Publisher + logger log.Logger[any] +} + +// NewEventServer creates a new event server. +func NewEventServer() *EventServer { + return &EventServer{ + publishers: make(map[types.MessageID]types.Publisher), + } +} + +// Dispatch dispatches the given event to the publisher with the given eventID. +func (es *EventServer) Publish(event types.BaseMessage) error { + publisher, ok := es.publishers[event.ID()] + if !ok { + return errPublisherNotFound(event.ID()) + } + return publisher.Publish(event) +} + +// Subscribe subscribes the given channel to the publisher with the given +// eventID. It will error if the channel type does not match the event type +// corresponding to the publisher. +func (es *EventServer) Subscribe(eventID types.MessageID, ch any) error { + publisher, ok := es.publishers[eventID] + if !ok { + return errPublisherNotFound(eventID) + } + return publisher.Subscribe(ch) +} + +// Start starts the event server. +func (es *EventServer) Start(ctx context.Context) { + for _, publisher := range es.publishers { + go publisher.Start(ctx) + } +} + +// RegisterPublisher registers the given publisher with the given eventID. +// Any subsequent events with dispatched to this EventServer must be +// consistent with the type expected by . +func (es *EventServer) RegisterPublisher( + eventID types.MessageID, publisher types.Publisher, +) error { + if _, ok := es.publishers[eventID]; ok { + return errPublisherAlreadyExists(eventID) + } + es.publishers[eventID] = publisher + return nil +} + +// SetLogger sets the logger for the event server. +func (es *EventServer) SetLogger(logger log.Logger[any]) { + es.logger = logger +} diff --git a/mod/async/pkg/server/msg.go b/mod/async/pkg/server/msg.go new file mode 100644 index 0000000000..5b57b68e79 --- /dev/null +++ b/mod/async/pkg/server/msg.go @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package server + +import ( + "github.com/berachain/beacon-kit/mod/async/pkg/types" + "github.com/berachain/beacon-kit/mod/log" +) + +// MessageServer is a server for sending and receiving messages. +type MessageServer struct { + routes map[types.MessageID]types.MessageRoute + logger log.Logger[any] +} + +// NewMessageServer creates a new message server. +func NewMessageServer() *MessageServer { + return &MessageServer{ + routes: make(map[types.MessageID]types.MessageRoute), + } +} + +// Request sends a message to the server and awaits for a response. +// The response is written to the provided response pointer. +func (ms *MessageServer) Request(req types.BaseMessage, future any) error { + // send request and await response + route, ok := ms.routes[req.ID()] + if !ok { + return errRouteNotFound + } + return route.SendRequest(req, future) +} + +// Respond sends a response to the route that corresponds to the response's +// messageID. +func (ms *MessageServer) Respond(resp types.BaseMessage) error { + route, ok := ms.routes[resp.ID()] + if !ok { + return errRouteNotFound + } + return route.SendResponse(resp) +} + +// RegisterRoute registers the route with the given messageID. +// Any subsequent messages with sent to this MessageServer must be +// consistent with the type expected by . +func (ms *MessageServer) RegisterRoute( + messageID types.MessageID, route types.MessageRoute, +) error { + if ms.routes[messageID] != nil { + return errRouteAlreadyRegistered(messageID) + } + ms.routes[messageID] = route + return nil +} + +// SetRecipient sets the recipient for the route with the given messageID. +// Errors if the route with the given messageID is not found or the route +// already has a registered recipient. +func (ms *MessageServer) RegisterReceiver( + messageID types.MessageID, ch any, +) error { + route, ok := ms.routes[messageID] + if !ok { + return errRouteNotFound + } + return route.RegisterReceiver(ch) +} + +// SetLogger sets the logger for the message server. +func (ms *MessageServer) SetLogger(logger log.Logger[any]) { + ms.logger = logger +} diff --git a/mod/async/pkg/types/dispatcher.go b/mod/async/pkg/types/dispatcher.go new file mode 100644 index 0000000000..1769871e29 --- /dev/null +++ b/mod/async/pkg/types/dispatcher.go @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package types + +import "context" + +// Dispatcher is the full API for a dispatcher that facilitates the publishing +// of async events and the sending and receiving of async messages. +type Dispatcher interface { + EventDispatcher + MessageDispatcher + // Start starts the dispatcher. + Start(ctx context.Context) error + // RegisterPublishers registers publishers to the dispatcher. + RegisterPublishers(publishers ...Publisher) error + // RegisterRoutes registers message routes to the dispatcher. + RegisterRoutes(routes ...MessageRoute) error + // Name returns the name of the dispatcher. + Name() string +} + +// EventDispatcher is the API for a dispatcher that facilitates the publishing +// of async events. +type EventDispatcher interface { + // PublishEvent publishes an event to the dispatcher. + PublishEvent(event BaseMessage) error + // Subscribe subscribes to an event. + Subscribe(eventID EventID, ch any) error +} + +// MessageDispatcher is the API for a dispatcher that facilitates the sending +// and receiving of async messages. +type MessageDispatcher interface { + // SendRequest sends a request to the dispatcher. + SendRequest(req BaseMessage, future any) error + // SendResponse sends a response to the dispatcher. + SendResponse(resp BaseMessage) error + // RegisterMsgReceiver registers the given channel as the message receiver + // for the given message ID. + RegisterMsgReceiver(messageID MessageID, ch any) error +} + +// publisher is the interface that supports basic event publisher operations. +type Publisher interface { + // Start starts the event publisher. + Start(ctx context.Context) + // Publish publishes the given event to the event publisher. + Publish(event BaseMessage) error + // Subscribe subscribes the given channel to the event publisher. + Subscribe(ch any) error + // Unsubscribe unsubscribes the given channel from the event publisher. + Unsubscribe(ch any) error + // EventID returns the event ID that the publisher is responsible for. + EventID() EventID +} + +// messageRoute is the interface that supports basic message route operations. +type MessageRoute interface { + // RegisterRecipient sets the recipient for the route. + RegisterReceiver(ch any) error + // SendRequest sends a request to the recipient. + SendRequest(msg BaseMessage, future any) error + // SendResponse sends a response to the recipient. + SendResponse(msg BaseMessage) error + // MessageID returns the message ID that the route is responsible for. + MessageID() MessageID +} diff --git a/mod/async/pkg/broker/errors.go b/mod/async/pkg/types/errors.go similarity index 87% rename from mod/async/pkg/broker/errors.go rename to mod/async/pkg/types/errors.go index f0d88700fe..4fc6b7dfb0 100644 --- a/mod/async/pkg/broker/errors.go +++ b/mod/async/pkg/types/errors.go @@ -18,11 +18,10 @@ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. -package broker +package types -import ( - "errors" -) +import "errors" -// ErrTimeout is the error returned when a broker operation timed out. -var ErrTimeout = errors.New("timeout") +var ( + errTimeout = errors.New("future timed out") +) diff --git a/mod/async/pkg/types/event.go b/mod/async/pkg/types/event.go deleted file mode 100644 index 51238cec51..0000000000 --- a/mod/async/pkg/types/event.go +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -// -// Copyright (C) 2024, Berachain Foundation. All rights reserved. -// Use of this software is governed by the Business Source License included -// in the LICENSE file of this repository and at www.mariadb.com/bsl11. -// -// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY -// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER -// VERSIONS OF THE LICENSED WORK. -// -// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF -// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF -// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). -// -// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON -// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, -// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND -// TITLE. - -package types - -import ( - "context" - "errors" -) - -// EventID represents the type of an event. -type EventID string - -// Event represents a generic event in the beacon chain. -type Event[DataT any] struct { - // ctx is the context associated with the event. - ctx context.Context - // eventType is the name of the event. - eventType EventID - // event is the actual beacon event. - data DataT - // error is the error associated with the event. - err error -} - -// NewEvent creates a new Event with the given context and beacon event. -func NewEvent[ - DataT any, -]( - ctx context.Context, eventType EventID, data DataT, errs ...error, -) *Event[DataT] { - return &Event[DataT]{ - ctx: ctx, - eventType: eventType, - data: data, - err: errors.Join(errs...), - } -} - -// Type returns the type of the event. -func (e Event[DataT]) Type() EventID { - return e.eventType -} - -// Context returns the context associated with the event. -func (e Event[DataT]) Context() context.Context { - return e.ctx -} - -// Data returns the data associated with the event. -func (e Event[DataT]) Data() DataT { - return e.data -} - -// Error returns the error associated with the event. -func (e Event[DataT]) Error() error { - return e.err -} - -// Is returns true if the event has the given type. -func (e Event[DataT]) Is(eventType EventID) bool { - return e.eventType == eventType -} diff --git a/mod/async/pkg/types/future.go b/mod/async/pkg/types/future.go new file mode 100644 index 0000000000..cc2f34d0ed --- /dev/null +++ b/mod/async/pkg/types/future.go @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package types + +import ( + "sync" + "time" +) + +// FutureI is the interface that the future implements. +type FutureI[T any] interface { + // Resolve returns the result of the future, blocking until it's available + // or the context is done. + Resolve() (result T, err error) + // ResolveWithTimeout returns the result of the future, blocking until it's + // available or the timeout is reached. + ResolveWithTimeout(timeout time.Duration) (result T, err error) + // SetResult is called by the router to set the result of the future. + SetResult(result T, err error) + // IsDone returns true if the future has completed (successfully or with an + // error). + IsDone() bool +} + +// Future represents a value that will be available at some point in the future. +type Future[T any] struct { + result T + err error + done chan struct{} + once sync.Once +} + +// NewFuture creates a new Future and starts the given function in a goroutine. +func NewFuture[T any]() *Future[T] { + f := &Future[T]{ + done: make(chan struct{}), + } + return f +} + +// Resolve returns the result of the future, blocking until it's available or +// the context is done. +func (f *Future[T]) Resolve() (T, error) { + <-f.done + return f.result, f.err +} + +// SetResult sets the result of the future. +func (f *Future[T]) SetResult(result T, err error) { + f.result = result + f.err = err + f.once.Do(func() { close(f.done) }) +} + +// GetWithTimeout returns the result of the future, blocking until it's +// available or the timeout is reached. +func (f *Future[T]) ResolveWithTimeout(timeout time.Duration) (T, error) { + select { + case <-f.done: + return f.result, f.err + case <-time.After(timeout): + var zero T + return zero, errTimeout + } +} + +// IsDone returns true if the future has completed (successfully or with an +// error). +func (f *Future[T]) IsDone() bool { + select { + case <-f.done: + return true + default: + return false + } +} diff --git a/mod/async/pkg/types/message.go b/mod/async/pkg/types/message.go new file mode 100644 index 0000000000..8342794704 --- /dev/null +++ b/mod/async/pkg/types/message.go @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package types + +import ( + "context" + "errors" +) + +// MessageID represents the type of a message. +type MessageID string + +// EventID is a type alias for a MessageID. +type EventID = MessageID + +// BaseMessage defines the minimal interface that the dispatcher expects from a +// message. +type BaseMessage interface { + ID() MessageID + Context() context.Context +} + +// DataMessage defines the interface that the underlying route expects from a +// message with data. +type Message[DataT any] interface { + BaseMessage + Data() DataT + Error() error + Is(messageType MessageID) bool +} + +// NewEvent creates a new Event with the given context and beacon event. +func NewMessage[ + DataT any, +]( + ctx context.Context, messageType MessageID, data DataT, errs ...error, +) Message[DataT] { + return &message[DataT]{ + ctx: ctx, + id: messageType, + data: data, + err: errors.Join(errs...), + } +} + +// Event acts as a type alias for a Message that is meant to be broadcasted +// to all subscribers. +type Event[DataT any] struct{ Message[DataT] } + +// NewEvent creates a new Event with the given context and beacon event. +func NewEvent[ + DataT any, +]( + ctx context.Context, messageType EventID, data DataT, errs ...error, +) *Event[DataT] { + return &Event[DataT]{ + Message: NewMessage(ctx, messageType, data, errs...), + } +} + +// A Message is a hard type implementation of the Message and Event interfaces. +type message[DataT any] struct { + // ctx is the context associated with the event. + ctx context.Context + // id is the name of the event. + id MessageID + // event is the actual beacon event. + data DataT + // err is the error associated with the event. + err error +} + +// ID returns the ID of the event. +func (m *message[DataT]) ID() MessageID { + return m.id +} + +// Context returns the context associated with the event. +func (m *message[DataT]) Context() context.Context { + return m.ctx +} + +// Data returns the data associated with the event. +func (m *message[DataT]) Data() DataT { + return m.data +} + +// Error returns the error associated with the event. +func (m *message[DataT]) Error() error { + return m.err +} + +// Is returns true if the event has the given type. +func (m *message[DataT]) Is(messageType MessageID) bool { + return m.id == messageType +} diff --git a/mod/beacon/block_store/service.go b/mod/beacon/block_store/service.go index 50d41408ac..d87a0d169f 100644 --- a/mod/beacon/block_store/service.go +++ b/mod/beacon/block_store/service.go @@ -25,7 +25,7 @@ import ( asynctypes "github.com/berachain/beacon-kit/mod/async/pkg/types" "github.com/berachain/beacon-kit/mod/log" - "github.com/berachain/beacon-kit/mod/primitives/pkg/events" + "github.com/berachain/beacon-kit/mod/primitives/pkg/messages" ) // NewService creates a new block service. @@ -35,14 +35,16 @@ func NewService[ ]( config Config, logger log.Logger[any], - blkBroker EventFeed[*asynctypes.Event[BeaconBlockT]], + dispatcher asynctypes.EventDispatcher, store BlockStoreT, ) *Service[BeaconBlockT, BlockStoreT] { return &Service[BeaconBlockT, BlockStoreT]{ - config: config, - logger: logger, - blkBroker: blkBroker, - store: store, + config: config, + logger: logger, + dispatcher: dispatcher, + store: store, + // finalizedBlkEvents is a channel for receiving finalized block events. + finalizedBlkEvents: make(chan *asynctypes.Event[BeaconBlockT]), } } @@ -54,10 +56,13 @@ type Service[ // config is the configuration for the block service. config Config // logger is used for logging information and errors. - logger log.Logger[any] - blkBroker EventFeed[*asynctypes.Event[BeaconBlockT]] - + logger log.Logger[any] + // dispatcher is the dispatcher for the service. + dispatcher asynctypes.EventDispatcher + // store is the block store for the service. store BlockStoreT + // finalizedBlkEvents is a channel for receiving finalized block events. + finalizedBlkEvents chan *asynctypes.Event[BeaconBlockT] } // Name returns the name of the service. @@ -66,37 +71,37 @@ func (s *Service[_, _]) Name() string { } // Start starts the block service. -func (s *Service[_, _]) Start(ctx context.Context) error { +func (s *Service[BeaconBlockT, _]) Start(ctx context.Context) error { if !s.config.Enabled { s.logger.Warn("block service is disabled, skipping storing blocks") return nil } - subBlkCh, err := s.blkBroker.Subscribe() - if err != nil { + + // subscribe a channel to the finalized block events. + if err := s.dispatcher.Subscribe( + messages.BeaconBlockFinalizedEvent, s.finalizedBlkEvents, + ); err != nil { s.logger.Error("failed to subscribe to block events", "error", err) return err } - go s.listenAndStore(ctx, subBlkCh) + go s.listenAndStore(ctx) return nil } // listenAndStore listens for blocks and stores them in the KVStore. func (s *Service[BeaconBlockT, _]) listenAndStore( ctx context.Context, - subBlkCh <-chan *asynctypes.Event[BeaconBlockT], ) { for { select { case <-ctx.Done(): return - case msg := <-subBlkCh: - if msg.Is(events.BeaconBlockFinalized) { - slot := msg.Data().GetSlot() - if err := s.store.Set(msg.Data()); err != nil { - s.logger.Error( - "failed to store block", "slot", slot, "error", err, - ) - } + case msg := <-s.finalizedBlkEvents: + slot := msg.Data().GetSlot() + if err := s.store.Set(msg.Data()); err != nil { + s.logger.Error( + "failed to store block", "slot", slot, "error", err, + ) } } } diff --git a/mod/beacon/block_store/types.go b/mod/beacon/block_store/types.go index 0521765c4d..1a96d09d43 100644 --- a/mod/beacon/block_store/types.go +++ b/mod/beacon/block_store/types.go @@ -41,9 +41,9 @@ type BlockStore[BeaconBlockT BeaconBlock] interface { // Event is an interface for block events. type Event[BeaconBlockT BeaconBlock] interface { - // Type returns the type of the event. - Type() asynctypes.EventID - // Is returns true if the event is of the given type. + // ID returns the id of the event. + ID() asynctypes.EventID + // Is returns true if the event is of the given id. Is(asynctypes.EventID) bool // Data returns the data of the event. Data() BeaconBlockT diff --git a/mod/beacon/blockchain/execution_engine.go b/mod/beacon/blockchain/execution_engine.go index 49a9f7b988..56e7d34a5d 100644 --- a/mod/beacon/blockchain/execution_engine.go +++ b/mod/beacon/blockchain/execution_engine.go @@ -44,7 +44,7 @@ func (s *Service[ return } - if !s.shouldBuildOptimisticPayloads() && s.lb.Enabled() { + if !s.shouldBuildOptimisticPayloads() && s.localBuilder.Enabled() { s.sendNextFCUWithAttributes(ctx, st, blk, lph) } else { s.sendNextFCUWithoutAttributes(ctx, blk, lph) @@ -53,6 +53,8 @@ func (s *Service[ // sendNextFCUWithAttributes sends a forkchoice update to the execution // client with attributes. +// +//nolint:lll // it's fine func (s *Service[ _, BeaconBlockT, _, _, BeaconStateT, _, _, ExecutionPayloadHeaderT, _, _, _, @@ -63,7 +65,7 @@ func (s *Service[ lph ExecutionPayloadHeaderT, ) { stCopy := st.Copy() - if _, err := s.sp.ProcessSlots(stCopy, blk.GetSlot()+1); err != nil { + if _, err := s.stateProcessor.ProcessSlots(stCopy, blk.GetSlot()+1); err != nil { s.logger.Error( "failed to process slots in non-optimistic payload", "error", err, @@ -72,7 +74,7 @@ func (s *Service[ } prevBlockRoot := blk.HashTreeRoot() - if _, err := s.lb.RequestPayloadAsync( + if _, err := s.localBuilder.RequestPayloadAsync( ctx, stCopy, blk.GetSlot()+1, @@ -83,8 +85,7 @@ func (s *Service[ ); err != nil { s.logger.Error( "failed to send forkchoice update with attributes in non-optimistic payload", - "error", - err, + "error", err, ) } } @@ -99,7 +100,7 @@ func (s *Service[ blk BeaconBlockT, lph ExecutionPayloadHeaderT, ) { - if _, _, err := s.ee.NotifyForkchoiceUpdate( + if _, _, err := s.executionEngine.NotifyForkchoiceUpdate( ctx, // TODO: Switch to New(). engineprimitives. @@ -109,7 +110,7 @@ func (s *Service[ SafeBlockHash: lph.GetParentHash(), FinalizedBlockHash: lph.GetParentHash(), }, - s.cs.ActiveForkVersionForSlot(blk.GetSlot()), + s.chainSpec.ActiveForkVersionForSlot(blk.GetSlot()), ), ); err != nil { s.logger.Error( @@ -128,7 +129,7 @@ func (s *Service[ ]) calculateNextTimestamp(blk BeaconBlockT) uint64 { //#nosec:G701 // not an issue in practice. return max( - uint64(time.Now().Unix()+int64(s.cs.TargetSecondsPerEth1Block())), + uint64(time.Now().Unix()+int64(s.chainSpec.TargetSecondsPerEth1Block())), uint64(blk.GetBody().GetExecutionPayload().GetTimestamp()+1), ) } diff --git a/mod/beacon/blockchain/payload.go b/mod/beacon/blockchain/payload.go index ba000a8c3d..49d82e0209 100644 --- a/mod/beacon/blockchain/payload.go +++ b/mod/beacon/blockchain/payload.go @@ -46,7 +46,7 @@ func (s *Service[ // TODO: Verify if the slot number is correct here, I believe in current // form // it should be +1'd. Not a big deal until hardforks are in play though. - if err = s.lb.SendForceHeadFCU(ctx, st, slot+1); err != nil { + if err = s.localBuilder.SendForceHeadFCU(ctx, st, slot+1); err != nil { s.logger.Error( "failed to send force head FCU", "error", err, @@ -117,7 +117,7 @@ func (s *Service[ } // Submit a request for a new payload. - if _, err = s.lb.RequestPayloadAsync( + if _, err = s.localBuilder.RequestPayloadAsync( ctx, st, // We are rebuilding for the current slot. @@ -180,7 +180,7 @@ func (s *Service[ ) // We process the slot to update any RANDAO values. - if _, err := s.sp.ProcessSlots( + if _, err := s.stateProcessor.ProcessSlots( st, slot, ); err != nil { return err @@ -188,13 +188,13 @@ func (s *Service[ // We then trigger a request for the next payload. payload := blk.GetBody().GetExecutionPayload() - if _, err := s.lb.RequestPayloadAsync( + if _, err := s.localBuilder.RequestPayloadAsync( ctx, st, slot, // TODO: this is hood as fuck. max( //#nosec:G701 - uint64(time.Now().Unix()+int64(s.cs.TargetSecondsPerEth1Block())), + uint64(time.Now().Unix()+int64(s.chainSpec.TargetSecondsPerEth1Block())), uint64((payload.GetTimestamp()+1)), ), // The previous block root is simply the root of the block we just diff --git a/mod/beacon/blockchain/process.go b/mod/beacon/blockchain/process.go index 15fcbde193..1ad7f11609 100644 --- a/mod/beacon/blockchain/process.go +++ b/mod/beacon/blockchain/process.go @@ -25,7 +25,7 @@ import ( "time" asynctypes "github.com/berachain/beacon-kit/mod/async/pkg/types" - "github.com/berachain/beacon-kit/mod/primitives/pkg/events" + "github.com/berachain/beacon-kit/mod/primitives/pkg/messages" "github.com/berachain/beacon-kit/mod/primitives/pkg/transition" ) @@ -37,7 +37,7 @@ func (s *Service[ ctx context.Context, genesisData GenesisT, ) (transition.ValidatorUpdates, error) { - return s.sp.InitializePreminedBeaconStateFromEth1( + return s.stateProcessor.InitializePreminedBeaconStateFromEth1( s.sb.StateFromContext(ctx), genesisData.GetDeposits(), genesisData.GetExecutionPayloadHeader(), @@ -83,9 +83,9 @@ func (s *Service[ // TODO: this is hood as fuck. // We won't send a fcu if the block is bad, should be addressed // via ticker later. - if err = s.blkBroker.Publish(ctx, + if err = s.dispatcher.PublishEvent( asynctypes.NewEvent( - ctx, events.BeaconBlockFinalized, blk, + ctx, messages.BeaconBlockFinalizedEvent, blk, ), ); err != nil { return nil, err @@ -106,7 +106,7 @@ func (s *Service[ ) (transition.ValidatorUpdates, error) { startTime := time.Now() defer s.metrics.measureStateTransitionDuration(startTime) - valUpdates, err := s.sp.Transition( + valUpdates, err := s.stateProcessor.Transition( &transition.Context{ Context: ctx, OptimisticEngine: true, diff --git a/mod/beacon/blockchain/receive.go b/mod/beacon/blockchain/receive.go index 79d78c9775..49613326dd 100644 --- a/mod/beacon/blockchain/receive.go +++ b/mod/beacon/blockchain/receive.go @@ -118,7 +118,7 @@ func (s *Service[ ) error { startTime := time.Now() defer s.metrics.measureStateRootVerificationTime(startTime) - if _, err := s.sp.Transition( + if _, err := s.stateProcessor.Transition( // We run with a non-optimistic engine here to ensure // that the proposer does not try to push through a bad block. &transition.Context{ @@ -148,5 +148,5 @@ func (s *Service[ func (s *Service[ _, _, _, _, _, _, _, _, _, _, _, ]) shouldBuildOptimisticPayloads() bool { - return s.optimisticPayloadBuilds && s.lb.Enabled() + return s.optimisticPayloadBuilds && s.localBuilder.Enabled() } diff --git a/mod/beacon/blockchain/service.go b/mod/beacon/blockchain/service.go index ad500f51e1..2b7cfdece7 100644 --- a/mod/beacon/blockchain/service.go +++ b/mod/beacon/blockchain/service.go @@ -27,7 +27,7 @@ import ( asynctypes "github.com/berachain/beacon-kit/mod/async/pkg/types" "github.com/berachain/beacon-kit/mod/log" "github.com/berachain/beacon-kit/mod/primitives/pkg/common" - "github.com/berachain/beacon-kit/mod/primitives/pkg/events" + "github.com/berachain/beacon-kit/mod/primitives/pkg/messages" "github.com/berachain/beacon-kit/mod/primitives/pkg/transition" ) @@ -60,15 +60,17 @@ type Service[ ] // logger is used for logging messages in the service. logger log.Logger[any] - // cs holds the chain specifications. - cs common.ChainSpec - // ee is the execution engine responsible for processing execution payloads. - - ee ExecutionEngine[PayloadAttributesT] - // lb is a local builder for constructing new beacon states. - lb LocalBuilder[BeaconStateT] - // sp is the state processor for beacon blocks and states. - sp StateProcessor[ + // chainSpec holds the chain specifications. + chainSpec common.ChainSpec + // dispatcher is the dispatcher for the service. + dispatcher asynctypes.Dispatcher + // executionEngine is the execution engine responsible for processing + // execution payloads. + executionEngine ExecutionEngine[PayloadAttributesT] + // localBuilder is a local builder for constructing new beacon states. + localBuilder LocalBuilder[BeaconStateT] + // stateProcessor is the state processor for beacon blocks and states. + stateProcessor StateProcessor[ BeaconBlockT, BeaconStateT, *transition.Context, @@ -77,17 +79,19 @@ type Service[ ] // metrics is the metrics for the service. metrics *chainMetrics - // genesisBroker is the event feed for genesis data. - genesisBroker EventFeed[*asynctypes.Event[GenesisT]] - // blkBroker is the event feed for new blocks. - blkBroker EventFeed[*asynctypes.Event[BeaconBlockT]] - // validatorUpdateBroker is the event feed for validator updates. - validatorUpdateBroker EventFeed[*asynctypes.Event[transition.ValidatorUpdates]] // optimisticPayloadBuilds is a flag used when the optimistic payload // builder is enabled. optimisticPayloadBuilds bool // forceStartupSyncOnce is used to force a sync of the startup head. forceStartupSyncOnce *sync.Once + + // finalizeBlkReqs is a channel for receiving finalize beacon block + // requests. + finalizeBlkReqs chan asynctypes.Message[BeaconBlockT] + // verifyBlkReqs is a channel for receiving verify beacon block requests. + verifyBlkReqs chan asynctypes.Message[BeaconBlockT] + // processGenReqs is a channel for receiving process genesis data requests. + processGenReqs chan asynctypes.Message[GenesisT] } // NewService creates a new validator service. @@ -117,10 +121,11 @@ func NewService[ BeaconStateT, ], logger log.Logger[any], - cs common.ChainSpec, - ee ExecutionEngine[PayloadAttributesT], - lb LocalBuilder[BeaconStateT], - sp StateProcessor[ + chainSpec common.ChainSpec, + dispatcher asynctypes.Dispatcher, + executionEngine ExecutionEngine[PayloadAttributesT], + localBuilder LocalBuilder[BeaconStateT], + stateProcessor StateProcessor[ BeaconBlockT, BeaconStateT, *transition.Context, @@ -128,10 +133,6 @@ func NewService[ ExecutionPayloadHeaderT, ], ts TelemetrySink, - genesisBroker EventFeed[*asynctypes.Event[GenesisT]], - blkBroker EventFeed[*asynctypes.Event[BeaconBlockT]], - //nolint:lll // annoying formatter. - validatorUpdateBroker EventFeed[*asynctypes.Event[transition.ValidatorUpdates]], optimisticPayloadBuilds bool, ) *Service[ AvailabilityStoreT, BeaconBlockT, BeaconBlockBodyT, BeaconBlockHeaderT, @@ -145,16 +146,17 @@ func NewService[ ]{ sb: sb, logger: logger, - cs: cs, - ee: ee, - lb: lb, - sp: sp, + chainSpec: chainSpec, + dispatcher: dispatcher, + executionEngine: executionEngine, + localBuilder: localBuilder, + stateProcessor: stateProcessor, metrics: newChainMetrics(ts), - genesisBroker: genesisBroker, - blkBroker: blkBroker, - validatorUpdateBroker: validatorUpdateBroker, optimisticPayloadBuilds: optimisticPayloadBuilds, forceStartupSyncOnce: new(sync.Once), + finalizeBlkReqs: make(chan asynctypes.Message[BeaconBlockT]), + verifyBlkReqs: make(chan asynctypes.Message[BeaconBlockT]), + processGenReqs: make(chan asynctypes.Message[GenesisT]), } } @@ -165,83 +167,98 @@ func (s *Service[ return "blockchain" } +// Start sets up the service to listen for FinalizeBeaconBlock, +// VerifyBeaconBlock, and ProcessGenesisData requests, and handles them +// accordingly. func (s *Service[ - _, _, _, _, _, _, _, _, _, _, _, + _, BeaconBlockT, _, _, _, _, _, _, GenesisT, _, _, ]) Start(ctx context.Context) error { - subBlkCh, err := s.blkBroker.Subscribe() - if err != nil { + // register a channel as the receiver for FinalizeBeaconBlock: + if err := s.dispatcher.RegisterMsgReceiver( + messages.FinalizeBeaconBlock, s.finalizeBlkReqs, + ); err != nil { return err } - subGenCh, err := s.genesisBroker.Subscribe() - if err != nil { + // register a channel as the receiver for VerifyBeaconBlock: + if err := s.dispatcher.RegisterMsgReceiver( + messages.VerifyBeaconBlock, s.verifyBlkReqs, + ); err != nil { + return err + } + // register a channel as the receiver for ProcessGenesisData: + if err := s.dispatcher.RegisterMsgReceiver( + messages.ProcessGenesisData, s.processGenReqs, + ); err != nil { return err } - go s.start(ctx, subBlkCh, subGenCh) + + // start a goroutine to listen for requests and handle accordingly + go s.start(ctx) return nil } +// start starts the service. func (s *Service[ _, BeaconBlockT, _, _, _, _, _, _, GenesisT, _, _, -]) start( - ctx context.Context, - subBlkCh chan *asynctypes.Event[BeaconBlockT], - subGenCh chan *asynctypes.Event[GenesisT], -) { +]) start(ctx context.Context) { for { select { case <-ctx.Done(): return - case msg := <-subBlkCh: - switch msg.Type() { - case events.BeaconBlockReceived: - s.handleBeaconBlockReceived(msg) - case events.BeaconBlockFinalizedRequest: - s.handleBeaconBlockFinalization(msg) - } - case msg := <-subGenCh: - if msg.Type() == events.GenesisDataProcessRequest { - s.handleProcessGenesisDataRequest(msg) - } + case msg := <-s.finalizeBlkReqs: + s.handleFinalizeBeaconBlockRequest(msg) + case msg := <-s.verifyBlkReqs: + s.handleVerifyBeaconBlockRequest(msg) + case msg := <-s.processGenReqs: + s.handleProcessGenesisDataRequest(msg) } } } +/* -------------------------------------------------------------------------- */ +/* Message Handlers */ +/* -------------------------------------------------------------------------- */ + +// handleProcessGenesisDataRequest processes the given genesis data and +// dispatches a response. func (s *Service[ _, _, _, _, _, _, _, _, GenesisT, _, _, -]) handleProcessGenesisDataRequest(msg *asynctypes.Event[GenesisT]) { +]) handleProcessGenesisDataRequest(msg asynctypes.Message[GenesisT]) { + var ( + valUpdates transition.ValidatorUpdates + err error + ) if msg.Error() != nil { s.logger.Error("Error processing genesis data", "error", msg.Error()) return } // Process the genesis data. - valUpdates, err := s.ProcessGenesisData(msg.Context(), msg.Data()) + valUpdates, err = s.ProcessGenesisData(msg.Context(), msg.Data()) if err != nil { s.logger.Error("Failed to process genesis data", "error", err) } - // Publish the validator set updated event. - if err = s.validatorUpdateBroker.Publish( - msg.Context(), - asynctypes.NewEvent( + // dispatch a response containing the validator updates + if err = s.dispatcher.SendResponse( + asynctypes.NewMessage( msg.Context(), - events.ValidatorSetUpdated, + messages.ProcessGenesisData, valUpdates, - err, + nil, ), ); err != nil { s.logger.Error( - "Failed to publish validator set updated event", - "error", - err, + "Failed to dispatch response in process genesis data", + "error", err, ) } } func (s *Service[ _, BeaconBlockT, _, _, _, _, _, _, _, _, _, -]) handleBeaconBlockReceived( - msg *asynctypes.Event[BeaconBlockT], +]) handleVerifyBeaconBlockRequest( + msg asynctypes.Message[BeaconBlockT], ) { // If the block is nil, exit early. if msg.Error() != nil { @@ -249,50 +266,55 @@ func (s *Service[ return } - // Publish the verified block event. - if err := s.blkBroker.Publish( - msg.Context(), - asynctypes.NewEvent( + // dispatch a response with the error result from VerifyIncomingBlock + if err := s.dispatcher.SendResponse( + asynctypes.NewMessage( msg.Context(), - events.BeaconBlockVerified, + messages.VerifyBeaconBlock, msg.Data(), s.VerifyIncomingBlock(msg.Context(), msg.Data()), ), ); err != nil { - s.logger.Error("Failed to publish verified block", "error", err) + s.logger.Error( + "Failed to dispatch response in verify beacon block", + "error", err, + ) } } func (s *Service[ _, BeaconBlockT, _, _, _, _, _, _, _, _, _, -]) handleBeaconBlockFinalization( - msg *asynctypes.Event[BeaconBlockT], +]) handleFinalizeBeaconBlockRequest( + msg asynctypes.Message[BeaconBlockT], ) { + var ( + valUpdates transition.ValidatorUpdates + err error + ) // If there's an error in the event, log it and return if msg.Error() != nil { s.logger.Error("Error verifying beacon block", "error", msg.Error()) return } - // Process the verified block - valUpdates, err := s.ProcessBeaconBlock(msg.Context(), msg.Data()) + // process the verified block and get the validator updates + valUpdates, err = s.ProcessBeaconBlock(msg.Context(), msg.Data()) if err != nil { s.logger.Error("Failed to process verified beacon block", "error", err) } - // Publish the validator set updated event - if err = s.validatorUpdateBroker.Publish( - msg.Context(), - asynctypes.NewEvent( + // dispatch a response with the validator updates + if err = s.dispatcher.SendResponse( + asynctypes.NewMessage( msg.Context(), - events.ValidatorSetUpdated, + messages.FinalizeBeaconBlock, valUpdates, err, - )); err != nil { + ), + ); err != nil { s.logger.Error( - "Failed to publish validator set updated event", - "error", - err, + "Failed to dispatch response in finalize beacon block", + "error", err, ) } } diff --git a/mod/beacon/go.mod b/mod/beacon/go.mod index cf36a949ea..83704ae40e 100644 --- a/mod/beacon/go.mod +++ b/mod/beacon/go.mod @@ -2,10 +2,16 @@ module github.com/berachain/beacon-kit/mod/beacon go 1.22.5 +replace ( + github.com/berachain/beacon-kit/mod/async => ../async + github.com/berachain/beacon-kit/mod/engine-primitives => ../engine-primitives + github.com/berachain/beacon-kit/mod/primitives => ../primitives +) + require ( github.com/berachain/beacon-kit/mod/async v0.0.0-20240618214413-d5ec0e66b3dd github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240809202957-3e3f169ad720 - github.com/berachain/beacon-kit/mod/errors v0.0.0-20240618214413-d5ec0e66b3dd + github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0 github.com/berachain/beacon-kit/mod/log v0.0.0-20240809202957-3e3f169ad720 github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240808194557-e72e74f58197 golang.org/x/sync v0.8.0 diff --git a/mod/beacon/go.sum b/mod/beacon/go.sum index af16be4205..40895196cc 100644 --- a/mod/beacon/go.sum +++ b/mod/beacon/go.sum @@ -8,20 +8,14 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/berachain/beacon-kit/mod/async v0.0.0-20240618214413-d5ec0e66b3dd h1:YXZN5EGMFId+MlDU1HTo672c1+oAC2ubRzRJFriaNP4= -github.com/berachain/beacon-kit/mod/async v0.0.0-20240618214413-d5ec0e66b3dd/go.mod h1:ycwqumRG49gb8qg87cc6kVgPeiUDaFMajjLko54Ey+I= github.com/berachain/beacon-kit/mod/chain-spec v0.0.0-20240703145037-b5612ab256db h1:vGczI1vJ6s86tSDS4tsllzlWZUVZ42xZ710GoHMd4to= github.com/berachain/beacon-kit/mod/chain-spec v0.0.0-20240703145037-b5612ab256db/go.mod h1:rbvfJqTKUIckels2AlWy+XuG+UGnegoFQuHC+TUg+zA= -github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240809202957-3e3f169ad720 h1:rVltwwt4JAhpvqeRDZ8J07e9XM+jzfDCJEghPA4r5lg= -github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240809202957-3e3f169ad720/go.mod h1:kGxAesqTkt75+QYQ73O9I5PqAicSL9JGh5wypiWgb8I= -github.com/berachain/beacon-kit/mod/errors v0.0.0-20240618214413-d5ec0e66b3dd h1:jD/ggR959ZX+lqxsMzoRJzrGvFK7PI6UmgnRwOTh4S4= -github.com/berachain/beacon-kit/mod/errors v0.0.0-20240618214413-d5ec0e66b3dd/go.mod h1:iXa+Q+i0q+GCpLzkusulO57K5vlkDgM77jtfMr3QdFA= +github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0 h1:kCSrkb/uVXfMKJPKjf0c7nlJkwn5cNwMxtzRW4zNq2A= +github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0/go.mod h1:og0jtHZosPDTyhge9tMBlRItoZ4Iv3aZFM9n4QDpcdo= github.com/berachain/beacon-kit/mod/geth-primitives v0.0.0-20240806160829-cde2d1347e7e h1:0/FDBXtagMkpta/f4J2uAah2NM1G+0dqxngzMzrmbw4= github.com/berachain/beacon-kit/mod/geth-primitives v0.0.0-20240806160829-cde2d1347e7e/go.mod h1:7/SXz8S5VpFl2thcKuBdu1OId+SgI1o4N+S1FB92Zw8= github.com/berachain/beacon-kit/mod/log v0.0.0-20240809202957-3e3f169ad720 h1:qfFjDx7w3uU+zMw5HrghiKPZunxapgCiNHI1XqqtgmA= github.com/berachain/beacon-kit/mod/log v0.0.0-20240809202957-3e3f169ad720/go.mod h1:BilVBmqKhC4GXYCaIs8QnKaR14kpn3YmF5uYBdayF9I= -github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240808194557-e72e74f58197 h1:hk8N7Q1CCKMW/05pRu5rbfRnbTUou5TjULaeeRtbU+E= -github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240808194557-e72e74f58197/go.mod h1:7kNnd9rhYjyZJHuXs/ku5drL9EMM64ekJVR181fGmbM= github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/btcsuite/btcd/btcec/v2 v2.3.3 h1:6+iXlDKE8RMtKsvK0gshlXIuPbyWM/h84Ensb7o3sC0= diff --git a/mod/beacon/validator/block_builder.go b/mod/beacon/validator/block_builder.go index cc57349d9c..93b3e0c7cb 100644 --- a/mod/beacon/validator/block_builder.go +++ b/mod/beacon/validator/block_builder.go @@ -37,7 +37,7 @@ import ( // buildBlockAndSidecars builds a new beacon block. func (s *Service[ - AttestationDataT, BeaconBlockT, _, _, + AttestationDataT, BeaconBlockT, _, _, _, BlobSidecarsT, _, _, _, _, _, _, SlashingInfoT, SlotDataT, ]) buildBlockAndSidecars( ctx context.Context, @@ -134,7 +134,7 @@ func (s *Service[ // getEmptyBeaconBlockForSlot creates a new empty block. func (s *Service[ - _, BeaconBlockT, _, BeaconStateT, _, _, _, _, _, _, _, _, _, + _, BeaconBlockT, _, _, BeaconStateT, _, _, _, _, _, _, _, _, _, ]) getEmptyBeaconBlockForSlot( st BeaconStateT, requestedSlot math.Slot, ) (BeaconBlockT, error) { @@ -172,7 +172,7 @@ func (s *Service[ // buildRandaoReveal builds a randao reveal for the given slot. func (s *Service[ - _, _, _, BeaconStateT, _, _, _, _, _, _, ForkDataT, _, _, + _, _, _, _, BeaconStateT, _, _, _, _, _, _, ForkDataT, _, _, ]) buildRandaoReveal( st BeaconStateT, slot math.Slot, @@ -200,7 +200,7 @@ func (s *Service[ // retrieveExecutionPayload retrieves the execution payload for the block. func (s *Service[ - _, BeaconBlockT, _, BeaconStateT, _, _, _, _, + _, BeaconBlockT, _, _, BeaconStateT, _, _, _, _, ExecutionPayloadT, ExecutionPayloadHeaderT, _, _, _, ]) retrieveExecutionPayload( ctx context.Context, st BeaconStateT, blk BeaconBlockT, @@ -257,7 +257,7 @@ func (s *Service[ // BuildBlockBody assembles the block body with necessary components. func (s *Service[ - AttestationDataT, BeaconBlockT, _, BeaconStateT, _, + AttestationDataT, BeaconBlockT, _, _, BeaconStateT, _, _, _, Eth1DataT, ExecutionPayloadT, _, _, SlashingInfoT, SlotDataT, ]) buildBlockBody( _ context.Context, @@ -333,7 +333,7 @@ func (s *Service[ // computeAndSetStateRoot computes the state root of an outgoing block // and sets it in the block. func (s *Service[ - _, BeaconBlockT, _, BeaconStateT, _, _, _, _, _, _, _, _, _, + _, BeaconBlockT, _, _, BeaconStateT, _, _, _, _, _, _, _, _, _, ]) computeAndSetStateRoot( ctx context.Context, st BeaconStateT, @@ -354,7 +354,7 @@ func (s *Service[ // computeStateRoot computes the state root of an outgoing block. func (s *Service[ - _, BeaconBlockT, _, BeaconStateT, _, _, _, _, _, _, _, _, _, + _, BeaconBlockT, _, _, BeaconStateT, _, _, _, _, _, _, _, _, _, ]) computeStateRoot( ctx context.Context, st BeaconStateT, diff --git a/mod/beacon/validator/service.go b/mod/beacon/validator/service.go index 3d4f45b3cb..f4d6b4b8f4 100644 --- a/mod/beacon/validator/service.go +++ b/mod/beacon/validator/service.go @@ -27,7 +27,7 @@ import ( "github.com/berachain/beacon-kit/mod/log" "github.com/berachain/beacon-kit/mod/primitives/pkg/common" "github.com/berachain/beacon-kit/mod/primitives/pkg/crypto" - "github.com/berachain/beacon-kit/mod/primitives/pkg/events" + "github.com/berachain/beacon-kit/mod/primitives/pkg/messages" "github.com/berachain/beacon-kit/mod/primitives/pkg/transition" ) @@ -38,6 +38,9 @@ type Service[ AttestationDataT, BeaconBlockT, BeaconBlockBodyT, DepositT, Eth1DataT, ExecutionPayloadT, SlashingInfoT, ], + BeaconBlockBundleT BeaconBlockBundle[ + BeaconBlockBundleT, BeaconBlockT, BlobSidecarsT, + ], BeaconBlockBodyT BeaconBlockBody[ AttestationDataT, DepositT, Eth1DataT, ExecutionPayloadT, SlashingInfoT, ], @@ -52,6 +55,7 @@ type Service[ SlashingInfoT any, SlotDataT SlotData[AttestationDataT, SlashingInfoT], ] struct { + buildBlkBundleReqs chan asynctypes.Message[SlotDataT] // cfg is the validator config. cfg *Config // logger is a logger. @@ -69,6 +73,8 @@ type Service[ bsb StorageBackend[ BeaconStateT, DepositT, DepositStoreT, ExecutionPayloadHeaderT, ] + // dispatcher is the dispatcher. + dispatcher asynctypes.MessageDispatcher // stateProcessor is responsible for processing the state. stateProcessor StateProcessor[ BeaconBlockT, @@ -86,12 +92,6 @@ type Service[ remotePayloadBuilders []PayloadBuilder[BeaconStateT, ExecutionPayloadT] // metrics is a metrics collector. metrics *validatorMetrics - // blkBroker is a publisher for blocks. - blkBroker EventPublisher[*asynctypes.Event[BeaconBlockT]] - // sidecarBroker is a publisher for sidecars. - sidecarBroker EventPublisher[*asynctypes.Event[BlobSidecarsT]] - // newSlotSub is a feed for slots. - newSlotSub chan *asynctypes.Event[SlotDataT] } // NewService creates a new validator service. @@ -101,6 +101,9 @@ func NewService[ AttestationDataT, BeaconBlockT, BeaconBlockBodyT, DepositT, Eth1DataT, ExecutionPayloadT, SlashingInfoT, ], + BeaconBlockBundleT BeaconBlockBundle[ + BeaconBlockBundleT, BeaconBlockT, BlobSidecarsT, + ], BeaconBlockBodyT BeaconBlockBody[ AttestationDataT, DepositT, Eth1DataT, ExecutionPayloadT, SlashingInfoT, ], @@ -135,21 +138,22 @@ func NewService[ localPayloadBuilder PayloadBuilder[BeaconStateT, ExecutionPayloadT], remotePayloadBuilders []PayloadBuilder[BeaconStateT, ExecutionPayloadT], ts TelemetrySink, - blkBroker EventPublisher[*asynctypes.Event[BeaconBlockT]], - sidecarBroker EventPublisher[*asynctypes.Event[BlobSidecarsT]], - newSlotSub chan *asynctypes.Event[SlotDataT], + dispatcher asynctypes.MessageDispatcher, ) *Service[ - AttestationDataT, BeaconBlockT, BeaconBlockBodyT, BeaconStateT, - BlobSidecarsT, DepositT, DepositStoreT, Eth1DataT, ExecutionPayloadT, - ExecutionPayloadHeaderT, ForkDataT, SlashingInfoT, SlotDataT, + AttestationDataT, BeaconBlockT, BeaconBlockBundleT, BeaconBlockBodyT, + BeaconStateT, BlobSidecarsT, DepositT, DepositStoreT, Eth1DataT, + ExecutionPayloadT, ExecutionPayloadHeaderT, ForkDataT, SlashingInfoT, + SlotDataT, ] { return &Service[ - AttestationDataT, BeaconBlockT, BeaconBlockBodyT, BeaconStateT, - BlobSidecarsT, DepositT, DepositStoreT, Eth1DataT, ExecutionPayloadT, - ExecutionPayloadHeaderT, ForkDataT, SlashingInfoT, SlotDataT, + AttestationDataT, BeaconBlockT, BeaconBlockBundleT, BeaconBlockBodyT, + BeaconStateT, BlobSidecarsT, DepositT, DepositStoreT, Eth1DataT, + ExecutionPayloadT, ExecutionPayloadHeaderT, ForkDataT, SlashingInfoT, + SlotDataT, ]{ cfg: cfg, logger: logger, + buildBlkBundleReqs: make(chan asynctypes.Message[SlotDataT]), bsb: bsb, chainSpec: chainSpec, signer: signer, @@ -158,32 +162,39 @@ func NewService[ localPayloadBuilder: localPayloadBuilder, remotePayloadBuilders: remotePayloadBuilders, metrics: newValidatorMetrics(ts), - blkBroker: blkBroker, - sidecarBroker: sidecarBroker, - newSlotSub: newSlotSub, + dispatcher: dispatcher, } } // Name returns the name of the service. func (s *Service[ - _, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _, _, _, _, _, _, ]) Name() string { return "validator" } -// Start starts the service. +// Start starts the service registers this service with the +// BuildBeaconBlockAndSidecars route and begins listening for requests. func (s *Service[ - _, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _, _, _, _, _, SlotDataT, ]) Start( ctx context.Context, ) error { + // register the receiver channel for build block requests + if err := s.dispatcher.RegisterMsgReceiver( + messages.BuildBeaconBlockAndSidecars, s.buildBlkBundleReqs, + ); err != nil { + return err + } + + // start a goroutine to listen for requests and handle accordingly go s.start(ctx) return nil } // start starts the service. func (s *Service[ - _, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _, _, _, _, _, SlotDataT, ]) start( ctx context.Context, ) { @@ -191,43 +202,41 @@ func (s *Service[ select { case <-ctx.Done(): return - case req := <-s.newSlotSub: - if req.Type() == events.NewSlot { - s.handleNewSlot(req) - } + case req := <-s.buildBlkBundleReqs: + s.handleBuildBlockBundleRequest(req) } } } -// handleBlockRequest handles a block request. +// handleBuildBlockBundleRequest builds a block and sidecars for the requested +// slot data and dispatches a response containing the built block and sidecars. func (s *Service[ - _, _, _, _, _, _, _, _, _, _, _, _, SlotDataT, -]) handleNewSlot(msg *asynctypes.Event[SlotDataT]) { - blk, sidecars, err := s.buildBlockAndSidecars( - msg.Context(), msg.Data(), + _, BeaconBlockT, BeaconBlockBundleT, _, _, BlobSidecarsT, _, _, _, _, _, _, + _, SlotDataT, +]) handleBuildBlockBundleRequest(req asynctypes.Message[SlotDataT]) { + var ( + blk BeaconBlockT + sidecars BlobSidecarsT + blkData BeaconBlockBundleT + err error + ) + // build the block and sidecars for the requested slot data + blk, sidecars, err = s.buildBlockAndSidecars( + req.Context(), req.Data(), ) if err != nil { s.logger.Error("failed to build block", "err", err) } - // Publish our built block to the broker. - if blkErr := s.blkBroker.Publish( - msg.Context(), - asynctypes.NewEvent( - msg.Context(), events.BeaconBlockBuilt, blk, err, - )); blkErr != nil { - // Propagate the error from buildBlockAndSidecars - s.logger.Error("failed to publish block", "err", err) - } - - // Publish our built blobs to the broker. - if sidecarsErr := s.sidecarBroker.Publish( - msg.Context(), - asynctypes.NewEvent( - // Propagate the error from buildBlockAndSidecars - msg.Context(), events.BlobSidecarsBuilt, sidecars, err, - ), - ); sidecarsErr != nil { - s.logger.Error("failed to publish sidecars", "err", err) + // bundle the block and sidecars and dispatch the response + // blkData := *new(BeaconBlockBundleT) + blkData = blkData.New(blk, sidecars) + if err = s.dispatcher.SendResponse( + asynctypes.NewMessage( + req.Context(), + messages.BuildBeaconBlockAndSidecars, + blkData, + )); err != nil { + s.logger.Error("failed to respond", "err", err) } } diff --git a/mod/beacon/validator/types.go b/mod/beacon/validator/types.go index 9abc0a8344..11799d5095 100644 --- a/mod/beacon/validator/types.go +++ b/mod/beacon/validator/types.go @@ -65,6 +65,17 @@ type BeaconBlock[ GetBody() BeaconBlockBodyT } +// BeaconBlockBundle represents a block data interface. +type BeaconBlockBundle[ + T any, + BeaconBlockT any, + BlobSidecarsT any, +] interface { + New(BeaconBlockT, BlobSidecarsT) T + GetBeaconBlock() BeaconBlockT + GetSidecars() BlobSidecarsT +} + // BeaconBlockBody represents a beacon block body interface. type BeaconBlockBody[ AttestationDataT, DepositT, Eth1DataT, ExecutionPayloadT, SlashingInfoT any, diff --git a/mod/da/go.mod b/mod/da/go.mod index b6cb05ae3a..2ac6e60568 100644 --- a/mod/da/go.mod +++ b/mod/da/go.mod @@ -2,13 +2,18 @@ module github.com/berachain/beacon-kit/mod/da go 1.22.5 +replace ( + github.com/berachain/beacon-kit/mod/async => ../async + github.com/berachain/beacon-kit/mod/primitives => ../primitives +) + require ( - github.com/berachain/beacon-kit/mod/async v0.0.0-20240624003607-df94860f8eeb + github.com/berachain/beacon-kit/mod/async v0.0.0-20240807213340-5779c7a563cd github.com/berachain/beacon-kit/mod/chain-spec v0.0.0-20240705193247-d464364483df github.com/berachain/beacon-kit/mod/consensus-types v0.0.0-20240806160829-cde2d1347e7e github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240808194557-e72e74f58197 - github.com/berachain/beacon-kit/mod/errors v0.0.0-20240705193247-d464364483df - github.com/berachain/beacon-kit/mod/log v0.0.0-20240624033454-8f3451361f44 + github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0 + github.com/berachain/beacon-kit/mod/log v0.0.0-20240807213340-5779c7a563cd github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240808194557-e72e74f58197 github.com/crate-crypto/go-kzg-4844 v1.1.0 github.com/ethereum/c-kzg-4844 v1.0.3 diff --git a/mod/da/go.sum b/mod/da/go.sum index c79ea5a6e2..6c67a118dd 100644 --- a/mod/da/go.sum +++ b/mod/da/go.sum @@ -8,8 +8,6 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/berachain/beacon-kit/mod/async v0.0.0-20240624003607-df94860f8eeb h1:4N/wng6MC9Kz5O7diKcJI/k7gnP0o/5hPu+cYZIJpCc= -github.com/berachain/beacon-kit/mod/async v0.0.0-20240624003607-df94860f8eeb/go.mod h1:ycwqumRG49gb8qg87cc6kVgPeiUDaFMajjLko54Ey+I= github.com/berachain/beacon-kit/mod/chain-spec v0.0.0-20240705193247-d464364483df h1:mnD1LKqDQ0n+OFdDqOuvKaEiUKRJzsO4V0wyyn/gJYg= github.com/berachain/beacon-kit/mod/chain-spec v0.0.0-20240705193247-d464364483df/go.mod h1:bTFB4Rdvm7D/WdwPYkqQ+8T0XOMBv0pzXfp1E46BFX8= github.com/berachain/beacon-kit/mod/config v0.0.0-20240705193247-d464364483df h1:I0qrcOnLkWjruhCWJMY04Cc9KT78WaY4aXCIoUj9+V4= @@ -18,14 +16,12 @@ github.com/berachain/beacon-kit/mod/consensus-types v0.0.0-20240806160829-cde2d1 github.com/berachain/beacon-kit/mod/consensus-types v0.0.0-20240806160829-cde2d1347e7e/go.mod h1:ZU1bq1BMt6b0kPRAw+A3kP7FlSd5DSQNYePD5qL9zfQ= github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240808194557-e72e74f58197 h1:wVWkiiERY/7kaXvE/VNPPUtYp/l8ky6QSuKM3ThVMXU= github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240808194557-e72e74f58197/go.mod h1:LiOiqrJhhLH/GPo0XE5fel3EYyi7X6dwBOyTqZakTeQ= -github.com/berachain/beacon-kit/mod/errors v0.0.0-20240705193247-d464364483df h1:6MJllcmMFt6dtvftM5zmdl1WVDpqZkNy3hFXVZtNV0s= -github.com/berachain/beacon-kit/mod/errors v0.0.0-20240705193247-d464364483df/go.mod h1:yRD7rmnyaaqgq/6+eIVqvSkFJXuLXpBddUu59HUOrtc= +github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0 h1:kCSrkb/uVXfMKJPKjf0c7nlJkwn5cNwMxtzRW4zNq2A= +github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0/go.mod h1:og0jtHZosPDTyhge9tMBlRItoZ4Iv3aZFM9n4QDpcdo= github.com/berachain/beacon-kit/mod/geth-primitives v0.0.0-20240806160829-cde2d1347e7e h1:0/FDBXtagMkpta/f4J2uAah2NM1G+0dqxngzMzrmbw4= github.com/berachain/beacon-kit/mod/geth-primitives v0.0.0-20240806160829-cde2d1347e7e/go.mod h1:7/SXz8S5VpFl2thcKuBdu1OId+SgI1o4N+S1FB92Zw8= -github.com/berachain/beacon-kit/mod/log v0.0.0-20240624033454-8f3451361f44 h1:R4+mGOZDYA93rD4AUbYq4fSWmRsJhnlB/ww1ap09WOY= -github.com/berachain/beacon-kit/mod/log v0.0.0-20240624033454-8f3451361f44/go.mod h1:xP5KcG56VfbPgz2ZRHerxm90MkjXMSDaGZNOOO5yfH4= -github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240808194557-e72e74f58197 h1:hk8N7Q1CCKMW/05pRu5rbfRnbTUou5TjULaeeRtbU+E= -github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240808194557-e72e74f58197/go.mod h1:7kNnd9rhYjyZJHuXs/ku5drL9EMM64ekJVR181fGmbM= +github.com/berachain/beacon-kit/mod/log v0.0.0-20240807213340-5779c7a563cd h1:DYSjsq80Omqqlt+z2VcYsSxjZpLqCDRz7CvUDBrLDJE= +github.com/berachain/beacon-kit/mod/log v0.0.0-20240807213340-5779c7a563cd/go.mod h1:BilVBmqKhC4GXYCaIs8QnKaR14kpn3YmF5uYBdayF9I= github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/btcsuite/btcd/btcec/v2 v2.3.3 h1:6+iXlDKE8RMtKsvK0gshlXIuPbyWM/h84Ensb7o3sC0= diff --git a/mod/da/pkg/da/service.go b/mod/da/pkg/da/service.go index b3cb234c57..89f6330ae4 100644 --- a/mod/da/pkg/da/service.go +++ b/mod/da/pkg/da/service.go @@ -25,15 +25,14 @@ import ( asynctypes "github.com/berachain/beacon-kit/mod/async/pkg/types" "github.com/berachain/beacon-kit/mod/log" - "github.com/berachain/beacon-kit/mod/primitives/pkg/events" + "github.com/berachain/beacon-kit/mod/primitives/pkg/messages" ) type Service[ AvailabilityStoreT AvailabilityStore[BeaconBlockBodyT, BlobSidecarsT], BeaconBlockBodyT any, BlobSidecarsT BlobSidecar, - //nolint:lll // formatter. - EventPublisherSubscriberT EventPublisherSubscriber[*asynctypes.Event[BlobSidecarsT]], + ExecutionPayloadT any, ] struct { avs AvailabilityStoreT @@ -41,8 +40,10 @@ type Service[ AvailabilityStoreT, BeaconBlockBodyT, BlobSidecarsT, ExecutionPayloadT, ] - sidecarsBroker EventPublisherSubscriberT - logger log.Logger[any] + dispatcher asynctypes.MessageDispatcher + logger log.Logger[any] + processSidecarRequests chan asynctypes.Message[BlobSidecarsT] + verifySidecarRequests chan asynctypes.Message[BlobSidecarsT] } // NewService returns a new DA service. @@ -52,8 +53,7 @@ func NewService[ ], BeaconBlockBodyT any, BlobSidecarsT BlobSidecar, - //nolint:lll // formatter. - EventPublisherSubscriberT EventPublisherSubscriber[*asynctypes.Event[BlobSidecarsT]], + ExecutionPayloadT any, ]( avs AvailabilityStoreT, @@ -61,65 +61,82 @@ func NewService[ AvailabilityStoreT, BeaconBlockBodyT, BlobSidecarsT, ExecutionPayloadT, ], - sidecarsBroker EventPublisherSubscriberT, + dispatcher asynctypes.MessageDispatcher, logger log.Logger[any], ) *Service[ AvailabilityStoreT, BeaconBlockBodyT, - BlobSidecarsT, EventPublisherSubscriberT, ExecutionPayloadT, + BlobSidecarsT, ExecutionPayloadT, ] { return &Service[ AvailabilityStoreT, BeaconBlockBodyT, - BlobSidecarsT, EventPublisherSubscriberT, ExecutionPayloadT, + BlobSidecarsT, ExecutionPayloadT, ]{ - avs: avs, - bp: bp, - sidecarsBroker: sidecarsBroker, - logger: logger, + avs: avs, + bp: bp, + dispatcher: dispatcher, + logger: logger, + processSidecarRequests: make(chan asynctypes.Message[BlobSidecarsT]), + verifySidecarRequests: make(chan asynctypes.Message[BlobSidecarsT]), } } // Name returns the name of the service. -func (s *Service[_, _, _, _, _]) Name() string { +func (s *Service[_, _, _, _]) Name() string { return "da" } -// Start starts the service. -func (s *Service[_, _, _, _, _]) Start(ctx context.Context) error { - subSidecarsCh, err := s.sidecarsBroker.Subscribe() - if err != nil { +// Start registers this service as the recipient of ProcessSidecars and +// VerifySidecars messages, and begins listening for these requests. +func (s *Service[_, _, BlobSidecarsT, _]) Start(ctx context.Context) error { + var err error + // register as recipient of ProcessSidecars messages. + if err = s.dispatcher.RegisterMsgReceiver( + messages.ProcessSidecars, s.processSidecarRequests, + ); err != nil { + return err + } + + // register as recipient of VerifySidecars messages. + if err = s.dispatcher.RegisterMsgReceiver( + messages.VerifySidecars, s.verifySidecarRequests, + ); err != nil { return err } - go s.start(ctx, subSidecarsCh) + + // start a goroutine to listen for requests and handle accordingly + go s.start(ctx) return nil } -// start starts the service. -func (s *Service[_, _, BlobSidecarsT, _, _]) start( +// start starts listens for ProcessSidecars and VerifySidecars messages and +// handles them accordingly. +func (s *Service[_, _, BlobSidecarsT, _]) start( ctx context.Context, - sidecarsCh chan *asynctypes.Event[BlobSidecarsT], ) { for { select { case <-ctx.Done(): return - case msg := <-sidecarsCh: - switch msg.Type() { - case events.BlobSidecarsProcessRequest: - s.handleBlobSidecarsProcessRequest(msg) - case events.BlobSidecarsReceived: - s.handleBlobSidecarsReceived(msg) - } + case msg := <-s.processSidecarRequests: + s.handleBlobSidecarsProcessRequest(msg) + case msg := <-s.verifySidecarRequests: + s.handleSidecarsVerifyRequest(msg) } } } +/* -------------------------------------------------------------------------- */ +/* Message Handlers */ +/* -------------------------------------------------------------------------- */ + // handleBlobSidecarsProcessRequest handles the BlobSidecarsProcessRequest // event. // It processes the sidecars and publishes a BlobSidecarsProcessed event. -func (s *Service[_, _, BlobSidecarsT, _, _]) handleBlobSidecarsProcessRequest( - msg *asynctypes.Event[BlobSidecarsT], +func (s *Service[_, _, BlobSidecarsT, _]) handleBlobSidecarsProcessRequest( + msg asynctypes.Message[BlobSidecarsT], ) { - err := s.processSidecars(msg.Context(), msg.Data()) + var err error + err = s.processSidecars(msg.Context(), msg.Data()) if err != nil { s.logger.Error( "Failed to process blob sidecars", @@ -128,26 +145,27 @@ func (s *Service[_, _, BlobSidecarsT, _, _]) handleBlobSidecarsProcessRequest( ) } - if err = s.sidecarsBroker.Publish( - msg.Context(), - asynctypes.NewEvent( - msg.Context(), events.BlobSidecarsProcessed, msg.Data(), err, - )); err != nil { - s.logger.Error( - "Failed to publish blob sidecars processed event", - "error", - err, - ) + // dispatch a response to acknowledge the request. + if err = s.dispatcher.SendResponse( + asynctypes.NewMessage( + msg.Context(), + messages.ProcessSidecars, + msg.Data(), + nil, + ), + ); err != nil { + s.logger.Error("failed to respond", "err", err) } } -// handleBlobSidecarsReceived handles the BlobSidecarsReceived event. -// It receives the sidecars and publishes a BlobSidecarsProcessed event. -func (s *Service[_, _, BlobSidecarsT, _, _]) handleBlobSidecarsReceived( - msg *asynctypes.Event[BlobSidecarsT], +// handleSidecarsVerifyRequest handles the SidecarsVerifyRequest event. +// It verifies the sidecars and publishes a SidecarsVerified event. +func (s *Service[_, _, BlobSidecarsT, _]) handleSidecarsVerifyRequest( + msg asynctypes.Message[BlobSidecarsT], ) { - err := s.receiveSidecars(msg.Data()) - if err != nil { + var err error + // verify the sidecars. + if err = s.verifySidecars(msg.Data()); err != nil { s.logger.Error( "Failed to receive blob sidecars", "error", @@ -155,21 +173,25 @@ func (s *Service[_, _, BlobSidecarsT, _, _]) handleBlobSidecarsReceived( ) } - if err = s.sidecarsBroker.Publish( - msg.Context(), - asynctypes.NewEvent( - msg.Context(), events.BlobSidecarsProcessed, msg.Data(), err, - )); err != nil { - s.logger.Error( - "Failed to publish blob sidecars processed event", - "error", - err, - ) + // dispatch a response to acknowledge the request. + if err = s.dispatcher.SendResponse( + asynctypes.NewMessage( + msg.Context(), + messages.VerifySidecars, + msg.Data(), + nil, + ), + ); err != nil { + s.logger.Error("failed to respond", "err", err) } } +/* -------------------------------------------------------------------------- */ +/* helpers */ +/* -------------------------------------------------------------------------- */ + // ProcessSidecars processes the blob sidecars. -func (s *Service[_, _, BlobSidecarsT, _, _]) processSidecars( +func (s *Service[_, _, BlobSidecarsT, _]) processSidecars( _ context.Context, sidecars BlobSidecarsT, ) error { @@ -182,7 +204,7 @@ func (s *Service[_, _, BlobSidecarsT, _, _]) processSidecars( } // VerifyIncomingBlobs receives blobs from the network and processes them. -func (s *Service[_, _, BlobSidecarsT, _, _]) receiveSidecars( +func (s *Service[_, _, BlobSidecarsT, _]) verifySidecars( sidecars BlobSidecarsT, ) error { // If there are no blobs to verify, return early. diff --git a/mod/da/pkg/da/types.go b/mod/da/pkg/da/types.go index 75b0c7f866..1645f773e5 100644 --- a/mod/da/pkg/da/types.go +++ b/mod/da/pkg/da/types.go @@ -21,8 +21,6 @@ package da import ( - "context" - "github.com/berachain/beacon-kit/mod/primitives/pkg/math" ) @@ -62,14 +60,6 @@ type BlobSidecar interface { IsNil() bool } -// EventPublisher represents the event publisher interface. -type EventPublisherSubscriber[T any] interface { - // PublishEvent publishes an event. - Publish(context.Context, T) error - // Subscribe subscribes to the event system. - Subscribe() (chan T, error) -} - // StorageBackend defines an interface for accessing various storage components // required by the beacon node. type StorageBackend[ diff --git a/mod/da/pkg/types/bundle.go b/mod/da/pkg/types/bundle.go new file mode 100644 index 0000000000..1267376eee --- /dev/null +++ b/mod/da/pkg/types/bundle.go @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package types + +type BlockBundle[BeaconBlockT any, BlobSidecarsT any] struct { + Block BeaconBlockT + Sidecars BlobSidecarsT +} + +func (bb *BlockBundle[BeaconBlockT, BlobSidecarsT]) New( + block BeaconBlockT, + sidecars BlobSidecarsT, +) *BlockBundle[BeaconBlockT, BlobSidecarsT] { + return &BlockBundle[BeaconBlockT, BlobSidecarsT]{ + Block: block, + Sidecars: sidecars, + } +} + +func (bb *BlockBundle[BeaconBlockT, _]) GetBeaconBlock() BeaconBlockT { + return bb.Block +} + +func (bb *BlockBundle[_, BlobSidecarsT]) GetSidecars() BlobSidecarsT { + return bb.Sidecars +} diff --git a/mod/execution/go.mod b/mod/execution/go.mod index e9879a6e20..76ba2aaf7c 100644 --- a/mod/execution/go.mod +++ b/mod/execution/go.mod @@ -2,12 +2,14 @@ module github.com/berachain/beacon-kit/mod/execution go 1.22.5 +replace github.com/berachain/beacon-kit/mod/async => ../async + require ( github.com/berachain/beacon-kit/mod/async v0.0.0-20240624204855-d8809d5c8588 github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240808194557-e72e74f58197 - github.com/berachain/beacon-kit/mod/errors v0.0.0-20240618214413-d5ec0e66b3dd + github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0 github.com/berachain/beacon-kit/mod/geth-primitives v0.0.0-20240806160829-cde2d1347e7e - github.com/berachain/beacon-kit/mod/log v0.0.0-20240610210054-bfdc14c4013c + github.com/berachain/beacon-kit/mod/log v0.0.0-20240807213340-5779c7a563cd github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240808194557-e72e74f58197 github.com/ethereum/go-ethereum v1.14.7 github.com/goccy/go-json v0.10.3 diff --git a/mod/execution/go.sum b/mod/execution/go.sum index 75383e6c6f..14c26fa8a3 100644 --- a/mod/execution/go.sum +++ b/mod/execution/go.sum @@ -8,18 +8,16 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/berachain/beacon-kit/mod/async v0.0.0-20240624204855-d8809d5c8588 h1:i2IzAwiYKcYsA/tjQtiLH1tx80RoQ1CvfP9pBZ2JtTg= -github.com/berachain/beacon-kit/mod/async v0.0.0-20240624204855-d8809d5c8588/go.mod h1:tzZ5Oyg7BgCViZBkqDwHmfKPNI66xONwE5kWd1P2v7o= github.com/berachain/beacon-kit/mod/chain-spec v0.0.0-20240703145037-b5612ab256db h1:vGczI1vJ6s86tSDS4tsllzlWZUVZ42xZ710GoHMd4to= github.com/berachain/beacon-kit/mod/chain-spec v0.0.0-20240703145037-b5612ab256db/go.mod h1:rbvfJqTKUIckels2AlWy+XuG+UGnegoFQuHC+TUg+zA= github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240808194557-e72e74f58197 h1:wVWkiiERY/7kaXvE/VNPPUtYp/l8ky6QSuKM3ThVMXU= github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240808194557-e72e74f58197/go.mod h1:LiOiqrJhhLH/GPo0XE5fel3EYyi7X6dwBOyTqZakTeQ= -github.com/berachain/beacon-kit/mod/errors v0.0.0-20240618214413-d5ec0e66b3dd h1:jD/ggR959ZX+lqxsMzoRJzrGvFK7PI6UmgnRwOTh4S4= -github.com/berachain/beacon-kit/mod/errors v0.0.0-20240618214413-d5ec0e66b3dd/go.mod h1:iXa+Q+i0q+GCpLzkusulO57K5vlkDgM77jtfMr3QdFA= +github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0 h1:kCSrkb/uVXfMKJPKjf0c7nlJkwn5cNwMxtzRW4zNq2A= +github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0/go.mod h1:og0jtHZosPDTyhge9tMBlRItoZ4Iv3aZFM9n4QDpcdo= github.com/berachain/beacon-kit/mod/geth-primitives v0.0.0-20240806160829-cde2d1347e7e h1:0/FDBXtagMkpta/f4J2uAah2NM1G+0dqxngzMzrmbw4= github.com/berachain/beacon-kit/mod/geth-primitives v0.0.0-20240806160829-cde2d1347e7e/go.mod h1:7/SXz8S5VpFl2thcKuBdu1OId+SgI1o4N+S1FB92Zw8= -github.com/berachain/beacon-kit/mod/log v0.0.0-20240610210054-bfdc14c4013c h1:7f9dLYGOCMoV7LxT6YRmVSWLTPbGTTcxDPLPLvHGrOk= -github.com/berachain/beacon-kit/mod/log v0.0.0-20240610210054-bfdc14c4013c/go.mod h1:nFybcw/ZhJ6Gu66dna301W2I7u61skm2HfHxQmdR68Q= +github.com/berachain/beacon-kit/mod/log v0.0.0-20240807213340-5779c7a563cd h1:DYSjsq80Omqqlt+z2VcYsSxjZpLqCDRz7CvUDBrLDJE= +github.com/berachain/beacon-kit/mod/log v0.0.0-20240807213340-5779c7a563cd/go.mod h1:BilVBmqKhC4GXYCaIs8QnKaR14kpn3YmF5uYBdayF9I= github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240808194557-e72e74f58197 h1:hk8N7Q1CCKMW/05pRu5rbfRnbTUou5TjULaeeRtbU+E= github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240808194557-e72e74f58197/go.mod h1:7kNnd9rhYjyZJHuXs/ku5drL9EMM64ekJVR181fGmbM= github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= diff --git a/mod/execution/pkg/deposit/service.go b/mod/execution/pkg/deposit/service.go index 95873ab2c7..5e8834c1b0 100644 --- a/mod/execution/pkg/deposit/service.go +++ b/mod/execution/pkg/deposit/service.go @@ -23,6 +23,7 @@ package deposit import ( "context" + asynctypes "github.com/berachain/beacon-kit/mod/async/pkg/types" "github.com/berachain/beacon-kit/mod/log" "github.com/berachain/beacon-kit/mod/primitives/pkg/math" ) @@ -46,8 +47,12 @@ type Service[ dc Contract[DepositT] // ds is the deposit store that stores deposits. ds Store[DepositT] - // feed is the block feed that provides block events. - feed chan BlockEventT + // dispatcher is the dispatcher for the service. + dispatcher asynctypes.EventDispatcher + // finalizedBlockEventID is the event ID for the finalized block event. + finalizedBlockEventID asynctypes.EventID + // finalizedBlockEvents is the channel that provides finalized block events. + finalizedBlockEvents chan BlockEventT // metrics is the metrics for the deposit service. metrics *metrics // failedBlocks is a map of blocks that failed to be processed to be @@ -73,7 +78,8 @@ func NewService[ telemetrySink TelemetrySink, ds Store[DepositT], dc Contract[DepositT], - feed chan BlockEventT, + finalizedBlockEventID asynctypes.EventID, + dispatcher asynctypes.EventDispatcher, ) *Service[ BeaconBlockT, BeaconBlockBodyT, BlockEventT, DepositT, ExecutionPayloadT, WithdrawalCredentialsT, @@ -83,13 +89,15 @@ func NewService[ ExecutionPayloadT, WithdrawalCredentialsT, ]{ - feed: feed, - logger: logger, - eth1FollowDistance: eth1FollowDistance, - metrics: newMetrics(telemetrySink), - dc: dc, - ds: ds, - failedBlocks: make(map[math.Slot]struct{}), + dc: dc, + dispatcher: dispatcher, + ds: ds, + eth1FollowDistance: eth1FollowDistance, + failedBlocks: make(map[math.Slot]struct{}), + finalizedBlockEventID: finalizedBlockEventID, + finalizedBlockEvents: make(chan BlockEventT), + logger: logger, + metrics: newMetrics(telemetrySink), } } @@ -97,6 +105,13 @@ func NewService[ func (s *Service[ _, _, _, _, _, _, ]) Start(ctx context.Context) error { + if err := s.dispatcher.Subscribe( + s.finalizedBlockEventID, s.finalizedBlockEvents, + ); err != nil { + s.logger.Error("failed to subscribe to event", "event", + s.finalizedBlockEventID, "err", err) + return err + } go s.depositFetcher(ctx) go s.depositCatchupFetcher(ctx) return nil diff --git a/mod/execution/pkg/deposit/sync.go b/mod/execution/pkg/deposit/sync.go index 39fcde2b2c..842d0b2d3a 100644 --- a/mod/execution/pkg/deposit/sync.go +++ b/mod/execution/pkg/deposit/sync.go @@ -24,7 +24,6 @@ import ( "context" "time" - "github.com/berachain/beacon-kit/mod/primitives/pkg/events" "github.com/berachain/beacon-kit/mod/primitives/pkg/math" ) @@ -39,12 +38,10 @@ func (s *Service[ select { case <-ctx.Done(): return - case msg := <-s.feed: - if msg.Is(events.BeaconBlockFinalized) { - blockNum := msg.Data(). - GetBody().GetExecutionPayload().GetNumber() - s.fetchAndStoreDeposits(ctx, blockNum-s.eth1FollowDistance) - } + case msg := <-s.finalizedBlockEvents: + blockNum := msg.Data(). + GetBody().GetExecutionPayload().GetNumber() + s.fetchAndStoreDeposits(ctx, blockNum-s.eth1FollowDistance) } } } diff --git a/mod/execution/pkg/deposit/types.go b/mod/execution/pkg/deposit/types.go index a94dda411c..99beea8e8b 100644 --- a/mod/execution/pkg/deposit/types.go +++ b/mod/execution/pkg/deposit/types.go @@ -53,7 +53,7 @@ type BlockEvent[ BeaconBlockT BeaconBlock[DepositT, BeaconBlockBodyT, ExecutionPayloadT], ExecutionPayloadT ExecutionPayload, ] interface { - Type() asynctypes.EventID + ID() asynctypes.EventID Is(asynctypes.EventID) bool Data() BeaconBlockT } diff --git a/mod/execution/pkg/engine/engine.go b/mod/execution/pkg/engine/engine.go index 0ca4e71711..8e5144e01f 100644 --- a/mod/execution/pkg/engine/engine.go +++ b/mod/execution/pkg/engine/engine.go @@ -24,8 +24,6 @@ import ( "bytes" "context" - broker "github.com/berachain/beacon-kit/mod/async/pkg/broker" - asynctypes "github.com/berachain/beacon-kit/mod/async/pkg/types" engineprimitives "github.com/berachain/beacon-kit/mod/engine-primitives/pkg/engine-primitives" engineerrors "github.com/berachain/beacon-kit/mod/engine-primitives/pkg/errors" "github.com/berachain/beacon-kit/mod/errors" @@ -33,7 +31,6 @@ import ( "github.com/berachain/beacon-kit/mod/log" "github.com/berachain/beacon-kit/mod/primitives/pkg/common" jsonrpc "github.com/berachain/beacon-kit/mod/primitives/pkg/net/json-rpc" - "github.com/berachain/beacon-kit/mod/primitives/pkg/service" ) // Engine is Beacon-Kit's implementation of the `ExecutionEngine` @@ -54,8 +51,6 @@ type Engine[ logger log.Logger[any] // metrics is the metrics for the engine. metrics *engineMetrics - // statusPublisher is the status publishder for the engine. - statusPublisher *broker.Broker[*asynctypes.Event[*service.StatusEvent]] } // New creates a new Engine. @@ -68,9 +63,8 @@ func New[ EncodeIndex(int, *bytes.Buffer) }, ]( - ec *client.EngineClient[ExecutionPayloadT, PayloadAttributesT], + engineClient *client.EngineClient[ExecutionPayloadT, PayloadAttributesT], logger log.Logger[any], - statusPublisher *broker.Broker[*asynctypes.Event[*service.StatusEvent]], telemtrySink TelemetrySink, ) *Engine[ ExecutionPayloadT, PayloadAttributesT, @@ -80,10 +74,9 @@ func New[ ExecutionPayloadT, PayloadAttributesT, PayloadIDT, WithdrawalsT, ]{ - ec: ec, - logger: logger, - metrics: newEngineMetrics(telemtrySink, logger), - statusPublisher: statusPublisher, + ec: engineClient, + logger: logger, + metrics: newEngineMetrics(telemtrySink, logger), } } diff --git a/mod/node-core/go.mod b/mod/node-core/go.mod index f325e7ca13..13fdaa05a8 100644 --- a/mod/node-core/go.mod +++ b/mod/node-core/go.mod @@ -6,6 +6,18 @@ replace ( // The following are required to build with the latest version of the cosmos-sdk main branch: cosmossdk.io/api => cosmossdk.io/api v0.7.3-0.20240806152830-8fb47b368cd4 cosmossdk.io/core/testing => cosmossdk.io/core/testing v0.0.0-20240806152830-8fb47b368cd4 + // required until merged onto main + github.com/berachain/beacon-kit/mod/async => ../async + github.com/berachain/beacon-kit/mod/beacon => ../beacon + github.com/berachain/beacon-kit/mod/da => ../da + github.com/berachain/beacon-kit/mod/execution => ../execution + github.com/berachain/beacon-kit/mod/node-api => ../node-api + github.com/berachain/beacon-kit/mod/node-api/engines => ../node-api/engines + github.com/berachain/beacon-kit/mod/payload => ../payload + github.com/berachain/beacon-kit/mod/primitives => ../primitives + github.com/berachain/beacon-kit/mod/runtime => ../runtime + github.com/berachain/beacon-kit/mod/state-transition => ../state-transition + github.com/berachain/beacon-kit/mod/storage => ../storage github.com/cosmos/cosmos-sdk => github.com/berachain/cosmos-sdk v0.46.0-beta2.0.20240808182639-7bdbf06a94f2 ) @@ -20,14 +32,14 @@ require ( github.com/berachain/beacon-kit/mod/consensus v0.0.0-20240809163303-a4ebb22fd018 github.com/berachain/beacon-kit/mod/consensus-types v0.0.0-20240809163303-a4ebb22fd018 github.com/berachain/beacon-kit/mod/da v0.0.0-20240705193247-d464364483df - github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240808194557-e72e74f58197 - github.com/berachain/beacon-kit/mod/errors v0.0.0-20240705193247-d464364483df + github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240809202957-3e3f169ad720 + github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0 github.com/berachain/beacon-kit/mod/execution v0.0.0-20240705193247-d464364483df - github.com/berachain/beacon-kit/mod/log v0.0.0-20240705193247-d464364483df + github.com/berachain/beacon-kit/mod/log v0.0.0-20240809202957-3e3f169ad720 github.com/berachain/beacon-kit/mod/node-api v0.0.0-20240806160829-cde2d1347e7e github.com/berachain/beacon-kit/mod/node-api/engines v0.0.0-20240806160829-cde2d1347e7e github.com/berachain/beacon-kit/mod/payload v0.0.0-20240705193247-d464364483df - github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240808194557-e72e74f58197 + github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240809203305-99679c55701d github.com/berachain/beacon-kit/mod/runtime v0.0.0-20240809202957-3e3f169ad720 github.com/berachain/beacon-kit/mod/state-transition v0.0.0-20240717225334-64ec6650da31 github.com/berachain/beacon-kit/mod/storage v0.0.0-20240806160829-cde2d1347e7e @@ -95,7 +107,7 @@ require ( github.com/DataDog/zstd v1.5.6 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/berachain/beacon-kit/mod/async v0.0.0-20240705193247-d464364483df + github.com/berachain/beacon-kit/mod/async v0.0.0-20240809203305-99679c55701d github.com/berachain/beacon-kit/mod/p2p v0.0.0-20240618214413-d5ec0e66b3dd // indirect github.com/bgentry/speakeasy v0.2.0 // indirect github.com/bits-and-blooms/bitset v1.13.0 // indirect diff --git a/mod/node-core/go.sum b/mod/node-core/go.sum index 8211b81760..8a19a93dfb 100644 --- a/mod/node-core/go.sum +++ b/mod/node-core/go.sum @@ -72,10 +72,6 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/berachain/beacon-kit/mod/async v0.0.0-20240705193247-d464364483df h1:f44S4M0BLiTLeX+lGvAkt1+tAM8ri+q2XsPQOl962FE= -github.com/berachain/beacon-kit/mod/async v0.0.0-20240705193247-d464364483df/go.mod h1:MNNFLsraZnkZZpm1Cl42Mxnwwql+BWHinn+r6+DrASQ= -github.com/berachain/beacon-kit/mod/beacon v0.0.0-20240718074353-1a991cfeed63 h1:OYw3r0MV8Wt7NipYbQ0bi5yed9ffudYsevAvbhp275Y= -github.com/berachain/beacon-kit/mod/beacon v0.0.0-20240718074353-1a991cfeed63/go.mod h1:dJ4i7uEGjc6KwMrSDexeXdkFqzEOXXOelWLq8KjcNqo= github.com/berachain/beacon-kit/mod/chain-spec v0.0.0-20240705193247-d464364483df h1:mnD1LKqDQ0n+OFdDqOuvKaEiUKRJzsO4V0wyyn/gJYg= github.com/berachain/beacon-kit/mod/chain-spec v0.0.0-20240705193247-d464364483df/go.mod h1:bTFB4Rdvm7D/WdwPYkqQ+8T0XOMBv0pzXfp1E46BFX8= github.com/berachain/beacon-kit/mod/cli v0.0.0-20240806160829-cde2d1347e7e h1:sPD08g07FrZWrDnKDgWXn0P311WRFP+sd6kgBZiqz8k= @@ -86,34 +82,16 @@ github.com/berachain/beacon-kit/mod/consensus v0.0.0-20240809163303-a4ebb22fd018 github.com/berachain/beacon-kit/mod/consensus v0.0.0-20240809163303-a4ebb22fd018/go.mod h1:AabKi0yGSwa1FW9fZnuQXJi6OUcUzIWa4o4e8zm/5RM= github.com/berachain/beacon-kit/mod/consensus-types v0.0.0-20240809163303-a4ebb22fd018 h1:VN+glgL0JqQXf/N/8toDa9EnehltgBD4DbsHx65Macc= github.com/berachain/beacon-kit/mod/consensus-types v0.0.0-20240809163303-a4ebb22fd018/go.mod h1:A3Ohrylv4Dx2sf8EKJImC7ii091dUaWEAMp/AK5N6+s= -github.com/berachain/beacon-kit/mod/da v0.0.0-20240705193247-d464364483df h1:yZtRZBkhDJ2xMlMLx5DdUFtrtH9iWyPNl4HSW2uJyb8= -github.com/berachain/beacon-kit/mod/da v0.0.0-20240705193247-d464364483df/go.mod h1:iGTR+iYsqpj79WLX1RUVbV7hDs0rQtr+Iqa/VkAF4x8= -github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240808194557-e72e74f58197 h1:wVWkiiERY/7kaXvE/VNPPUtYp/l8ky6QSuKM3ThVMXU= -github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240808194557-e72e74f58197/go.mod h1:LiOiqrJhhLH/GPo0XE5fel3EYyi7X6dwBOyTqZakTeQ= -github.com/berachain/beacon-kit/mod/errors v0.0.0-20240705193247-d464364483df h1:6MJllcmMFt6dtvftM5zmdl1WVDpqZkNy3hFXVZtNV0s= -github.com/berachain/beacon-kit/mod/errors v0.0.0-20240705193247-d464364483df/go.mod h1:yRD7rmnyaaqgq/6+eIVqvSkFJXuLXpBddUu59HUOrtc= -github.com/berachain/beacon-kit/mod/execution v0.0.0-20240705193247-d464364483df h1:H6BHipSq4spa06PGLp8osdJ8LTwz7POQa015RruWJfw= -github.com/berachain/beacon-kit/mod/execution v0.0.0-20240705193247-d464364483df/go.mod h1:RwyZdP3Th3Qxgr/tdmEt0Zev92Ue30/CwEvvwksP76c= +github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240809202957-3e3f169ad720 h1:rVltwwt4JAhpvqeRDZ8J07e9XM+jzfDCJEghPA4r5lg= +github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240809202957-3e3f169ad720/go.mod h1:kGxAesqTkt75+QYQ73O9I5PqAicSL9JGh5wypiWgb8I= +github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0 h1:kCSrkb/uVXfMKJPKjf0c7nlJkwn5cNwMxtzRW4zNq2A= +github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0/go.mod h1:og0jtHZosPDTyhge9tMBlRItoZ4Iv3aZFM9n4QDpcdo= github.com/berachain/beacon-kit/mod/geth-primitives v0.0.0-20240806160829-cde2d1347e7e h1:0/FDBXtagMkpta/f4J2uAah2NM1G+0dqxngzMzrmbw4= github.com/berachain/beacon-kit/mod/geth-primitives v0.0.0-20240806160829-cde2d1347e7e/go.mod h1:7/SXz8S5VpFl2thcKuBdu1OId+SgI1o4N+S1FB92Zw8= -github.com/berachain/beacon-kit/mod/log v0.0.0-20240705193247-d464364483df h1:SnzeY9SCmKyEx0iGC/C/8E39ozpl/g5yI7lFXpmbMBI= -github.com/berachain/beacon-kit/mod/log v0.0.0-20240705193247-d464364483df/go.mod h1:mJ0ZlK+izcPWcveHAtM4+W0a+8jhu5Y4DMPL2Takacg= -github.com/berachain/beacon-kit/mod/node-api v0.0.0-20240806160829-cde2d1347e7e h1:fzW/jTq01yOTdrEoi0cucTqadvbZLROr9dGFtXfjBl8= -github.com/berachain/beacon-kit/mod/node-api v0.0.0-20240806160829-cde2d1347e7e/go.mod h1:wgOdrP96dMsXDXHItO4tRLuf8IaHP14RY4MbUPFAc4s= -github.com/berachain/beacon-kit/mod/node-api/engines v0.0.0-20240806160829-cde2d1347e7e h1:RJSPVKiuK4h2IJEIsJDX2JGbqY3ZdKGzvaEN8Dx7kYc= -github.com/berachain/beacon-kit/mod/node-api/engines v0.0.0-20240806160829-cde2d1347e7e/go.mod h1:lj5dEWEjUn4Mj9/qVrCKrfGqE7FCObk39VfqXs3Eo/E= +github.com/berachain/beacon-kit/mod/log v0.0.0-20240809202957-3e3f169ad720 h1:qfFjDx7w3uU+zMw5HrghiKPZunxapgCiNHI1XqqtgmA= +github.com/berachain/beacon-kit/mod/log v0.0.0-20240809202957-3e3f169ad720/go.mod h1:BilVBmqKhC4GXYCaIs8QnKaR14kpn3YmF5uYBdayF9I= github.com/berachain/beacon-kit/mod/p2p v0.0.0-20240618214413-d5ec0e66b3dd h1:QHAukFEWl62kscPjRvpqfxCPvd3RSg8cD4mw8qIBhU4= github.com/berachain/beacon-kit/mod/p2p v0.0.0-20240618214413-d5ec0e66b3dd/go.mod h1:ft214cxJaqrRPOuAjpYwgA9AOElJnHrDZZEQ0jZPWwQ= -github.com/berachain/beacon-kit/mod/payload v0.0.0-20240705193247-d464364483df h1:fLL+7ZZcbVOmE3XE0o+ZGS8zyPLjki7LrZAsXpcG4Sc= -github.com/berachain/beacon-kit/mod/payload v0.0.0-20240705193247-d464364483df/go.mod h1:wbSa9W1CDDzR9AptQfYf/16bWqktaIQIZdJsuKWeqC8= -github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240808194557-e72e74f58197 h1:hk8N7Q1CCKMW/05pRu5rbfRnbTUou5TjULaeeRtbU+E= -github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240808194557-e72e74f58197/go.mod h1:7kNnd9rhYjyZJHuXs/ku5drL9EMM64ekJVR181fGmbM= -github.com/berachain/beacon-kit/mod/runtime v0.0.0-20240809202957-3e3f169ad720 h1:dSBzTgN/h5WYNVs7Pbo6ZEkHecFUm0miGd8w+XT3BVA= -github.com/berachain/beacon-kit/mod/runtime v0.0.0-20240809202957-3e3f169ad720/go.mod h1:DwPFy0Q9D9zFaeXOrBcGRC1vHmbk4SH1ujT5xFXASd4= -github.com/berachain/beacon-kit/mod/state-transition v0.0.0-20240717225334-64ec6650da31 h1:1bJbJcoksyXfYMiga8YxPnkVKqT1lKwym/8kZnEPz58= -github.com/berachain/beacon-kit/mod/state-transition v0.0.0-20240717225334-64ec6650da31/go.mod h1:sIzib45R7B9Q99yvsYUcj2xJZPBpe3J9JbcBDMZNp7E= -github.com/berachain/beacon-kit/mod/storage v0.0.0-20240806160829-cde2d1347e7e h1:eIHdeGNL87GlWxFqAgsuUZpA/EBGvaOWXFMDuXSJgjU= -github.com/berachain/beacon-kit/mod/storage v0.0.0-20240806160829-cde2d1347e7e/go.mod h1:1Hti34fIHtniBapeikvYF3KyA038+6If8BRkRKqWUy4= github.com/berachain/cosmos-sdk v0.46.0-beta2.0.20240808182639-7bdbf06a94f2 h1:4qwOPga+dKeDelSJ6pseasQq6fcjd7iXhah0y7enuco= github.com/berachain/cosmos-sdk v0.46.0-beta2.0.20240808182639-7bdbf06a94f2/go.mod h1:DUyJJMMuFJ9OZAhnFMLA0KTFGoVw61p8wnqtV3Wgx3c= github.com/bgentry/speakeasy v0.2.0 h1:tgObeVOf8WAvtuAX6DhJ4xks4CFNwPDZiqzGqIHE51E= diff --git a/mod/node-core/pkg/components/availability_store.go b/mod/node-core/pkg/components/availability_store.go index da3b6b6624..cef82d0981 100644 --- a/mod/node-core/pkg/components/availability_store.go +++ b/mod/node-core/pkg/components/availability_store.go @@ -29,6 +29,7 @@ import ( dastore "github.com/berachain/beacon-kit/mod/da/pkg/store" "github.com/berachain/beacon-kit/mod/log" "github.com/berachain/beacon-kit/mod/primitives/pkg/common" + "github.com/berachain/beacon-kit/mod/primitives/pkg/messages" "github.com/berachain/beacon-kit/mod/storage/pkg/filedb" "github.com/berachain/beacon-kit/mod/storage/pkg/manager" "github.com/berachain/beacon-kit/mod/storage/pkg/pruner" @@ -73,8 +74,8 @@ func ProvideAvailibilityStore( type AvailabilityPrunerInput struct { depinject.In AvailabilityStore *AvailabilityStore - BlockBroker *BlockBroker ChainSpec common.ChainSpec + Dispatcher *Dispatcher Logger log.AdvancedLogger[any, sdklog.Logger] } @@ -89,25 +90,28 @@ func ProvideAvailabilityPruner( return nil, errors.New("availability store does not have a range db") } - subCh, err := in.BlockBroker.Subscribe() - if err != nil { - in.Logger.Error("failed to subscribe to block feed", "err", err) + var finalizedBlkCh = make(chan *FinalizedBlockEvent) + if err := in.Dispatcher.Subscribe( + messages.BeaconBlockFinalizedEvent, finalizedBlkCh, + ); err != nil { + in.Logger.Error("failed to subscribe to event", "event", + messages.BeaconBlockFinalizedEvent, "err", err) return nil, err } // build the availability pruner if IndexDB is available. return pruner.NewPruner[ *BeaconBlock, - *BlockEvent, + *FinalizedBlockEvent, *IndexDB, ]( in.Logger.With("service", manager.AvailabilityPrunerName), rangeDB, manager.AvailabilityPrunerName, - subCh, + finalizedBlkCh, dastore.BuildPruneRangeFn[ *BeaconBlock, - *BlockEvent, + *FinalizedBlockEvent, ](in.ChainSpec), ), nil } diff --git a/mod/node-core/pkg/components/blobs.go b/mod/node-core/pkg/components/blobs.go index 1b64f8f373..d0e397b4e8 100644 --- a/mod/node-core/pkg/components/blobs.go +++ b/mod/node-core/pkg/components/blobs.go @@ -101,8 +101,8 @@ type DAServiceIn struct { depinject.In AvailabilityStore *AvailabilityStore - SidecarsBroker *SidecarsBroker BlobProcessor *BlobProcessor + Dispatcher *Dispatcher Logger log.Logger } @@ -113,12 +113,11 @@ func ProvideDAService(in DAServiceIn) *DAService { *AvailabilityStore, *BeaconBlockBody, *BlobSidecars, - *SidecarsBroker, *ExecutionPayload, ]( in.AvailabilityStore, in.BlobProcessor, - in.SidecarsBroker, + in.Dispatcher, in.Logger.With("service", "da"), ) } diff --git a/mod/node-core/pkg/components/block_store.go b/mod/node-core/pkg/components/block_store.go index 663a82bd31..b448551d0a 100644 --- a/mod/node-core/pkg/components/block_store.go +++ b/mod/node-core/pkg/components/block_store.go @@ -24,11 +24,13 @@ import ( "cosmossdk.io/depinject" sdklog "cosmossdk.io/log" storev2 "cosmossdk.io/store/v2/db" + "github.com/berachain/beacon-kit/mod/async/pkg/dispatcher" blockservice "github.com/berachain/beacon-kit/mod/beacon/block_store" "github.com/berachain/beacon-kit/mod/config" "github.com/berachain/beacon-kit/mod/log" "github.com/berachain/beacon-kit/mod/node-core/pkg/components/storage" "github.com/berachain/beacon-kit/mod/primitives/pkg/common" + "github.com/berachain/beacon-kit/mod/primitives/pkg/messages" "github.com/berachain/beacon-kit/mod/storage/pkg/block" "github.com/berachain/beacon-kit/mod/storage/pkg/manager" "github.com/berachain/beacon-kit/mod/storage/pkg/pruner" @@ -67,35 +69,37 @@ func ProvideBlockStore( // BlockPrunerInput is the input for the block pruner. type BlockPrunerInput struct { depinject.In - - BlockBroker *BlockBroker - BlockStore *BlockStore - Config *config.Config - Logger log.AdvancedLogger[any, sdklog.Logger] + BlockStore *BlockStore + Config *config.Config + Dispatcher *dispatcher.Dispatcher + Logger log.AdvancedLogger[any, sdklog.Logger] } // ProvideBlockPruner provides a block pruner for the depinject framework. func ProvideBlockPruner( in BlockPrunerInput, ) (BlockPruner, error) { - subCh, err := in.BlockBroker.Subscribe() - if err != nil { - in.Logger.Error("failed to subscribe to block feed", "err", err) + var finalizedBlkCh = make(chan *FinalizedBlockEvent) + if err := in.Dispatcher.Subscribe( + messages.BeaconBlockFinalizedEvent, finalizedBlkCh, + ); err != nil { + in.Logger.Error("failed to subscribe to event", "event", + messages.BeaconBlockFinalizedEvent, "err", err) return nil, err } return pruner.NewPruner[ *BeaconBlock, - *BlockEvent, + *FinalizedBlockEvent, *BlockStore, ]( in.Logger.With("service", manager.BlockPrunerName), in.BlockStore, manager.BlockPrunerName, - subCh, + finalizedBlkCh, blockservice.BuildPruneRangeFn[ *BeaconBlock, - *BlockEvent, + *FinalizedBlockEvent, ](in.Config.BlockStoreService), ), nil } diff --git a/mod/node-core/pkg/components/block_store_service.go b/mod/node-core/pkg/components/block_store_service.go index 7d04e79ff3..8ab0d0c47f 100644 --- a/mod/node-core/pkg/components/block_store_service.go +++ b/mod/node-core/pkg/components/block_store_service.go @@ -31,10 +31,10 @@ import ( type BlockServiceInput struct { depinject.In - BlockBroker *BlockBroker - BlockStore *BlockStore - Config *config.Config - Logger log.Logger[any] + BlockStore *BlockStore + Config *config.Config + Dispatcher *Dispatcher + Logger log.Logger[any] } // ProvideBlockStoreService provides the block service. @@ -42,7 +42,7 @@ func ProvideBlockStoreService(in BlockServiceInput) *BlockStoreService { return blockstore.NewService( in.Config.BlockStoreService, in.Logger, - in.BlockBroker, + in.Dispatcher, in.BlockStore, ) } diff --git a/mod/node-core/pkg/components/brokers.go b/mod/node-core/pkg/components/brokers.go deleted file mode 100644 index 0cc9d84d2c..0000000000 --- a/mod/node-core/pkg/components/brokers.go +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -// -// Copyright (C) 2024, Berachain Foundation. All rights reserved. -// Use of this software is governed by the Business Source License included -// in the LICENSE file of this repository and at www.mariadb.com/bsl11. -// -// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY -// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER -// VERSIONS OF THE LICENSED WORK. -// -// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF -// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF -// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). -// -// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON -// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, -// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND -// TITLE. - -package components - -import ( - "github.com/berachain/beacon-kit/mod/async/pkg/broker" -) - -// ProvideBlobBroker provides a blob feed for the depinject framework. -func ProvideBlobBroker() *SidecarsBroker { - return broker.New[*SidecarEvent]( - "blob-broker", - ) -} - -// ProvideBlockBroker provides a block feed for the depinject framework. -func ProvideBlockBroker() *BlockBroker { - return broker.New[*BlockEvent]( - "blk-broker", - ) -} - -// ProvideGenesisBroker provides a genesis feed for the depinject framework. -func ProvideGenesisBroker() *GenesisBroker { - return broker.New[*GenesisEvent]( - "genesis-broker", - ) -} - -// ProvideSlotBroker provides a slot feed for the depinject framework. -func ProvideSlotBroker() *SlotBroker { - return broker.New[*SlotEvent]( - "slot-broker", - ) -} - -// ProvideStatusBroker provides a status feed. -func ProvideStatusBroker() *StatusBroker { - return broker.New[*StatusEvent]( - "status-broker", - ) -} - -// ProvideValidatorUpdateBroker provides a validator updates feed. -func ProvideValidatorUpdateBroker() *ValidatorUpdateBroker { - return broker.New[*ValidatorUpdateEvent]( - "validator-updates-broker", - ) -} - -// DefaultBrokerProviders returns a slice of the default broker providers. -func DefaultBrokerProviders() []interface{} { - return []interface{}{ - ProvideBlobBroker, - ProvideBlockBroker, - ProvideGenesisBroker, - ProvideSlotBroker, - ProvideStatusBroker, - ProvideValidatorUpdateBroker, - } -} diff --git a/mod/node-core/pkg/components/chain_service.go b/mod/node-core/pkg/components/chain_service.go index 3de0cbe7b4..97c6b4e6f7 100644 --- a/mod/node-core/pkg/components/chain_service.go +++ b/mod/node-core/pkg/components/chain_service.go @@ -35,20 +35,18 @@ import ( type ChainServiceInput struct { depinject.In - BlockBroker *BlockBroker - ChainSpec common.ChainSpec - Cfg *config.Config - DepositService *DepositService - EngineClient *EngineClient - ExecutionEngine *ExecutionEngine - GenesisBrocker *GenesisBroker - LocalBuilder *LocalBuilder - Logger log.AdvancedLogger[any, sdklog.Logger] - Signer crypto.BLSSigner - StateProcessor *StateProcessor - StorageBackend *StorageBackend - TelemetrySink *metrics.TelemetrySink - ValidatorUpdateBroker *ValidatorUpdateBroker + ChainSpec common.ChainSpec + Cfg *config.Config + DepositService *DepositService + Dispatcher *Dispatcher + EngineClient *EngineClient + ExecutionEngine *ExecutionEngine + LocalBuilder *LocalBuilder + Logger log.AdvancedLogger[any, sdklog.Logger] + Signer crypto.BLSSigner + StateProcessor *StateProcessor + StorageBackend *StorageBackend + TelemetrySink *metrics.TelemetrySink } // ProvideChainService is a depinject provider for the blockchain service. @@ -71,13 +69,11 @@ func ProvideChainService( in.StorageBackend, in.Logger.With("service", "blockchain"), in.ChainSpec, + in.Dispatcher, in.ExecutionEngine, in.LocalBuilder, in.StateProcessor, in.TelemetrySink, - in.GenesisBrocker, - in.BlockBroker, - in.ValidatorUpdateBroker, // If optimistic is enabled, we want to skip post finalization FCUs. in.Cfg.Validator.EnableOptimisticPayloadBuilds, ) diff --git a/mod/node-core/pkg/components/defaults.go b/mod/node-core/pkg/components/defaults.go index c6d20d0634..e0e9d91adb 100644 --- a/mod/node-core/pkg/components/defaults.go +++ b/mod/node-core/pkg/components/defaults.go @@ -62,6 +62,6 @@ func DefaultComponentsWithStandardTypes() []any { } components = append(components, DefaultNodeAPIComponents()...) components = append(components, DefaultNodeAPIHandlers()...) - components = append(components, DefaultBrokerProviders()...) + components = append(components, DefaultDispatcherComponents()...) return components } diff --git a/mod/node-core/pkg/components/deposit_service.go b/mod/node-core/pkg/components/deposit_service.go index c1ad506765..1c3b723bc2 100644 --- a/mod/node-core/pkg/components/deposit_service.go +++ b/mod/node-core/pkg/components/deposit_service.go @@ -21,8 +21,6 @@ package components import ( - "errors" - "cosmossdk.io/depinject" sdklog "cosmossdk.io/log" "github.com/berachain/beacon-kit/mod/execution/pkg/deposit" @@ -30,15 +28,16 @@ import ( "github.com/berachain/beacon-kit/mod/node-core/pkg/components/metrics" "github.com/berachain/beacon-kit/mod/primitives/pkg/common" "github.com/berachain/beacon-kit/mod/primitives/pkg/math" + "github.com/berachain/beacon-kit/mod/primitives/pkg/messages" ) // DepositServiceIn is the input for the deposit service. type DepositServiceIn struct { depinject.In BeaconDepositContract *DepositContract - BlockBroker *BlockBroker ChainSpec common.ChainSpec DepositStore *DepositStore + Dispatcher *Dispatcher EngineClient *EngineClient Logger log.AdvancedLogger[any, sdklog.Logger] TelemetrySink *metrics.TelemetrySink @@ -47,17 +46,11 @@ type DepositServiceIn struct { // ProvideDepositService provides the deposit service to the depinject // framework. func ProvideDepositService(in DepositServiceIn) (*DepositService, error) { - blkSub, err := in.BlockBroker.Subscribe() - if err != nil { - in.Logger.Error("failed to subscribe to block feed", "err", err) - return nil, errors.New("failed to subscribe to block feed") - } - // Build the deposit service. return deposit.NewService[ *BeaconBlockBody, *BeaconBlock, - *BlockEvent, + *FinalizedBlockEvent, *DepositStore, *ExecutionPayload, ]( @@ -66,6 +59,7 @@ func ProvideDepositService(in DepositServiceIn) (*DepositService, error) { in.TelemetrySink, in.DepositStore, in.BeaconDepositContract, - blkSub, + messages.BeaconBlockFinalizedEvent, + in.Dispatcher, ), nil } diff --git a/mod/node-core/pkg/components/deposit_store.go b/mod/node-core/pkg/components/deposit_store.go index 10f3676a86..d9a275d96b 100644 --- a/mod/node-core/pkg/components/deposit_store.go +++ b/mod/node-core/pkg/components/deposit_store.go @@ -27,6 +27,7 @@ import ( "github.com/berachain/beacon-kit/mod/execution/pkg/deposit" "github.com/berachain/beacon-kit/mod/node-core/pkg/components/storage" "github.com/berachain/beacon-kit/mod/primitives/pkg/common" + "github.com/berachain/beacon-kit/mod/primitives/pkg/messages" depositstore "github.com/berachain/beacon-kit/mod/storage/pkg/deposit" "github.com/berachain/beacon-kit/mod/storage/pkg/manager" "github.com/berachain/beacon-kit/mod/storage/pkg/pruner" @@ -59,9 +60,9 @@ func ProvideDepositStore( // DepositPrunerInput is the input for the deposit pruner. type DepositPrunerInput struct { depinject.In - BlockBroker *BlockBroker ChainSpec common.ChainSpec DepositStore *DepositStore + Dispatcher *Dispatcher Logger log.Logger } @@ -69,25 +70,28 @@ type DepositPrunerInput struct { func ProvideDepositPruner( in DepositPrunerInput, ) (DepositPruner, error) { - subCh, err := in.BlockBroker.Subscribe() - if err != nil { - in.Logger.Error("failed to subscribe to block feed", "err", err) + var finalizedBlkCh = make(chan *FinalizedBlockEvent) + if err := in.Dispatcher.Subscribe( + messages.BeaconBlockFinalizedEvent, finalizedBlkCh, + ); err != nil { + in.Logger.Error("failed to subscribe to event", "event", + messages.BeaconBlockFinalizedEvent, "err", err) return nil, err } return pruner.NewPruner[ *BeaconBlock, - *BlockEvent, + *FinalizedBlockEvent, *DepositStore, ]( in.Logger.With("service", manager.DepositPrunerName), in.DepositStore, manager.DepositPrunerName, - subCh, + finalizedBlkCh, deposit.BuildPruneRangeFn[ *BeaconBlockBody, *BeaconBlock, - *BlockEvent, + *FinalizedBlockEvent, *Deposit, *ExecutionPayload, WithdrawalCredentials, diff --git a/mod/node-core/pkg/components/dispatcher.go b/mod/node-core/pkg/components/dispatcher.go new file mode 100644 index 0000000000..d47ca87be2 --- /dev/null +++ b/mod/node-core/pkg/components/dispatcher.go @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package components + +import ( + "cosmossdk.io/depinject" + sdklog "cosmossdk.io/log" + "github.com/berachain/beacon-kit/mod/async/pkg/dispatcher" + asynctypes "github.com/berachain/beacon-kit/mod/async/pkg/types" + "github.com/berachain/beacon-kit/mod/log" +) + +// DispatcherInput is the input for the Dispatcher. +type DispatcherInput struct { + depinject.In + EventServer *EventServer + MessageServer *MessageServer + Logger log.AdvancedLogger[any, sdklog.Logger] + Publishers []asynctypes.Publisher + Routes []asynctypes.MessageRoute +} + +// ProvideDispatcher provides a new Dispatcher. +func ProvideDispatcher( + in DispatcherInput, +) (*Dispatcher, error) { + d := dispatcher.NewDispatcher( + in.EventServer, + in.MessageServer, + in.Logger.With("service", "dispatcher"), + ) + if err := d.RegisterPublishers(in.Publishers...); err != nil { + return nil, err + } + if err := d.RegisterRoutes(in.Routes...); err != nil { + return nil, err + } + return d, nil +} + +func DefaultDispatcherComponents() []any { + return []any{ + ProvideDispatcher, + ProvideMessageRoutes, + ProvidePublishers, + ProvideMessageServer, + ProvideEventServer, + } +} diff --git a/mod/node-core/pkg/components/engine.go b/mod/node-core/pkg/components/engine.go index ecbaac8137..89a6c27302 100644 --- a/mod/node-core/pkg/components/engine.go +++ b/mod/node-core/pkg/components/engine.go @@ -67,7 +67,6 @@ type ExecutionEngineInputs struct { depinject.In EngineClient *EngineClient Logger log.AdvancedLogger[any, sdklog.Logger] - StatusBroker *StatusBroker TelemetrySink *metrics.TelemetrySink } @@ -84,7 +83,6 @@ func ProvideExecutionEngine( ]( in.EngineClient, in.Logger.With("service", "execution-engine"), - in.StatusBroker, in.TelemetrySink, ) } diff --git a/mod/node-core/pkg/components/events.go b/mod/node-core/pkg/components/events.go new file mode 100644 index 0000000000..eef0b7942d --- /dev/null +++ b/mod/node-core/pkg/components/events.go @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package components + +import ( + "github.com/berachain/beacon-kit/mod/async/pkg/messaging" + "github.com/berachain/beacon-kit/mod/async/pkg/server" + asynctypes "github.com/berachain/beacon-kit/mod/async/pkg/types" + "github.com/berachain/beacon-kit/mod/primitives/pkg/messages" +) + +// ProvideEventServer provides an event server. +func ProvideEventServer() *EventServer { + return server.NewEventServer() +} + +// ProvidePublishers provides a publisher for beacon block +// finalized events. +func ProvidePublishers() []asynctypes.Publisher { + return []asynctypes.Publisher{ + messaging.NewPublisher[*FinalizedBlockEvent]( + messages.BeaconBlockFinalizedEvent, + ), + } +} diff --git a/mod/node-core/pkg/components/messages.go b/mod/node-core/pkg/components/messages.go new file mode 100644 index 0000000000..cb47de88ca --- /dev/null +++ b/mod/node-core/pkg/components/messages.go @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package components + +import ( + "github.com/berachain/beacon-kit/mod/async/pkg/messaging" + "github.com/berachain/beacon-kit/mod/async/pkg/server" + asynctypes "github.com/berachain/beacon-kit/mod/async/pkg/types" + "github.com/berachain/beacon-kit/mod/primitives/pkg/messages" + "github.com/berachain/beacon-kit/mod/primitives/pkg/transition" +) + +// ProvideMessageServer provides a message server. +func ProvideMessageServer() *server.MessageServer { + return server.NewMessageServer() +} + +// ProvideMessageRoutes provides all the message routes. +func ProvideMessageRoutes() []asynctypes.MessageRoute { + return []asynctypes.MessageRoute{ + messaging.NewRoute[*SlotData, *BeaconBlockBundle]( + messages.BuildBeaconBlockAndSidecars, + ), + messaging.NewRoute[*BeaconBlock, *BeaconBlock]( + messages.VerifyBeaconBlock, + ), + messaging.NewRoute[*BeaconBlock, transition.ValidatorUpdates]( + messages.FinalizeBeaconBlock, + ), + messaging.NewRoute[*Genesis, transition.ValidatorUpdates]( + messages.ProcessGenesisData, + ), + messaging.NewRoute[*BlobSidecars, *BlobSidecars]( + messages.VerifySidecars, + ), + messaging.NewRoute[*BlobSidecars, *BlobSidecars]( + messages.ProcessSidecars, + ), + } +} diff --git a/mod/node-core/pkg/components/middleware.go b/mod/node-core/pkg/components/middleware.go index 1a9879763f..7b2f1043b7 100644 --- a/mod/node-core/pkg/components/middleware.go +++ b/mod/node-core/pkg/components/middleware.go @@ -31,14 +31,10 @@ import ( // ABCIMiddlewareInput is the input for the validator middleware provider. type ABCIMiddlewareInput struct { depinject.In - BeaconBlockFeed *BlockBroker - ChainSpec common.ChainSpec - GenesisBroker *GenesisBroker - Logger log.Logger[any] - SidecarsFeed *SidecarsBroker - SlotBroker *SlotBroker - TelemetrySink *metrics.TelemetrySink - ValidatorUpdateBroker *ValidatorUpdateBroker + ChainSpec common.ChainSpec + Logger log.Logger[any] + TelemetrySink *metrics.TelemetrySink + Dispatcher *Dispatcher } // ProvideABCIMiddleware is a depinject provider for the validator @@ -46,21 +42,13 @@ type ABCIMiddlewareInput struct { func ProvideABCIMiddleware( in ABCIMiddlewareInput, ) (*ABCIMiddleware, error) { - validatorUpdatesSub, err := in.ValidatorUpdateBroker.Subscribe() - if err != nil { - return nil, err - } return middleware.NewABCIMiddleware[ - *AvailabilityStore, *BeaconBlock, *BlobSidecars, + *AvailabilityStore, *BeaconBlock, *BeaconBlockBundle, *BlobSidecars, *Deposit, *ExecutionPayload, *Genesis, *SlotData, ]( in.ChainSpec, in.Logger, in.TelemetrySink, - in.GenesisBroker, - in.BeaconBlockFeed, - in.SidecarsFeed, - in.SlotBroker, - validatorUpdatesSub, + in.Dispatcher, ), nil } diff --git a/mod/node-core/pkg/components/service_registry.go b/mod/node-core/pkg/components/service_registry.go index f48d5dc770..6d18cc689e 100644 --- a/mod/node-core/pkg/components/service_registry.go +++ b/mod/node-core/pkg/components/service_registry.go @@ -30,23 +30,18 @@ import ( // ServiceRegistryInput is the input for the service registry provider. type ServiceRegistryInput struct { depinject.In - ABCIService *ABCIMiddleware - BlockBroker *BlockBroker - BlockStoreService *BlockStoreService - ChainService *ChainService - DAService *DAService - DBManager *DBManager - DepositService *DepositService - EngineClient *EngineClient - GenesisBroker *GenesisBroker - Logger log.Logger - NodeAPIServer *NodeAPIServer - ReportingService *ReportingService - SidecarsBroker *SidecarsBroker - SlotBroker *SlotBroker - TelemetrySink *metrics.TelemetrySink - ValidatorService *ValidatorService - ValidatorUpdateBroker *ValidatorUpdateBroker + BlockStoreService *BlockStoreService + ChainService *ChainService + DAService *DAService + DBManager *DBManager + DepositService *DepositService + EngineClient *EngineClient + Logger log.Logger + NodeAPIServer *NodeAPIServer + ReportingService *ReportingService + TelemetrySink *metrics.TelemetrySink + ValidatorService *ValidatorService + Dispatcher *Dispatcher } // ProvideServiceRegistry is the depinject provider for the service registry. @@ -55,20 +50,15 @@ func ProvideServiceRegistry( ) *service.Registry { return service.NewRegistry( service.WithLogger(in.Logger), + service.WithService(in.Dispatcher), service.WithService(in.ValidatorService), service.WithService(in.BlockStoreService), service.WithService(in.ChainService), service.WithService(in.DAService), service.WithService(in.DepositService), - service.WithService(in.ABCIService), service.WithService(in.NodeAPIServer), service.WithService(in.ReportingService), service.WithService(in.DBManager), - service.WithService(in.GenesisBroker), - service.WithService(in.BlockBroker), - service.WithService(in.SlotBroker), - service.WithService(in.SidecarsBroker), - service.WithService(in.ValidatorUpdateBroker), service.WithService(in.EngineClient), ) } diff --git a/mod/node-core/pkg/components/types.go b/mod/node-core/pkg/components/types.go index 5739e72b9b..23bd301bf0 100644 --- a/mod/node-core/pkg/components/types.go +++ b/mod/node-core/pkg/components/types.go @@ -22,7 +22,9 @@ package components import ( "cosmossdk.io/core/appmodule/v2" - broker "github.com/berachain/beacon-kit/mod/async/pkg/broker" + "github.com/berachain/beacon-kit/mod/async/pkg/dispatcher" + "github.com/berachain/beacon-kit/mod/async/pkg/messaging" + asyncserver "github.com/berachain/beacon-kit/mod/async/pkg/server" asynctypes "github.com/berachain/beacon-kit/mod/async/pkg/types" blockstore "github.com/berachain/beacon-kit/mod/beacon/block_store" "github.com/berachain/beacon-kit/mod/beacon/blockchain" @@ -73,6 +75,7 @@ type ( ABCIMiddleware = middleware.ABCIMiddleware[ *AvailabilityStore, *BeaconBlock, + *BeaconBlockBundle, *BlobSidecars, *Deposit, *ExecutionPayload, @@ -95,6 +98,10 @@ type ( // BeaconBlock type aliases. BeaconBlock = types.BeaconBlock + BeaconBlockBundle = datypes.BlockBundle[ + *BeaconBlock, + *BlobSidecars, + ] BeaconBlockBody = types.BeaconBlockBody BeaconBlockHeader = types.BeaconBlockHeader @@ -194,7 +201,6 @@ type ( *AvailabilityStore, *BeaconBlockBody, *BlobSidecars, - *SidecarsBroker, *ExecutionPayload, ] @@ -214,7 +220,7 @@ type ( DepositService = deposit.Service[ *BeaconBlock, *BeaconBlockBody, - *BlockEvent, + *FinalizedBlockEvent, *Deposit, *ExecutionPayload, WithdrawalCredentials, @@ -396,6 +402,7 @@ type ( ValidatorService = validator.Service[ *AttestationData, *BeaconBlock, + *BeaconBlockBundle, *BeaconBlockBody, *BeaconState, *BlobSidecars, @@ -420,51 +427,68 @@ type ( ) /* -------------------------------------------------------------------------- */ -/* Events */ +/* Messages */ /* -------------------------------------------------------------------------- */ +// Events. type ( - // BlockEvent is a type alias for the block event. - BlockEvent = asynctypes.Event[*BeaconBlock] + // FinalizedBlockEvent is a type alias for the block event. + FinalizedBlockEvent = asynctypes.Event[*BeaconBlock] +) - // GenesisEvent is a type alias for the genesis event. - GenesisEvent = asynctypes.Event[*Genesis] +// Messages. +type ( + // BlockMessage is a type alias for the block message. + BlockMessage = asynctypes.Message[*BeaconBlock] - // SidecarEvent is a type alias for the sidecar event. - SidecarEvent = asynctypes.Event[*BlobSidecars] + // GenesisMessage is a type alias for the genesis message. + GenesisMessage = asynctypes.Message[*Genesis] - // SlotEvent is a type alias for the slot event. - SlotEvent = asynctypes.Event[*SlotData] + // SidecarMessage is a type alias for the sidecar message. + SidecarMessage = asynctypes.Message[*BlobSidecars] - // StatusEvent is a type alias for the status event. - StatusEvent = asynctypes.Event[*service.StatusEvent] + // SlotMessage is a type alias for the slot message. + SlotMessage = asynctypes.Message[*SlotData] - // ValidatorUpdateEvent is a type alias for the validator update event. - ValidatorUpdateEvent = asynctypes.Event[transition.ValidatorUpdates] + // StatusMessage is a type alias for the status message. + StatusMessage = asynctypes.Message[*service.StatusEvent] +) + +// Futures. +type ( + // BlockFuture is a type alias for a future containing a BeaconBlock. + BlockFuture = asynctypes.Future[*BeaconBlock] + // BlockBundleFuture is a type alias for a future containing a + // BeaconBlockBundle. + BlockBundleFuture = asynctypes.Future[*BeaconBlockBundle] + // SidecarFuture is a type alias for a future containing the BlobSidecars. + SidecarFuture = asynctypes.Future[*BlobSidecars] + // ValidatorUpdateFuture is a type alias for a future containing the + // ValidatorUpdates. + ValidatorUpdateFuture = asynctypes.Future[transition.ValidatorUpdates] ) /* -------------------------------------------------------------------------- */ -/* Brokers */ +/* Publishers */ /* -------------------------------------------------------------------------- */ type ( - // GenesisBroker is a type alias for the genesis feed. - GenesisBroker = broker.Broker[*GenesisEvent] - - // SidecarsBroker is a type alias for the blob feed. - SidecarsBroker = broker.Broker[*SidecarEvent] + BeaconBlockFinalizedPublisher = messaging.Publisher[*FinalizedBlockEvent] +) - // BlockBroker is a type alias for the block feed. - BlockBroker = broker.Broker[*BlockEvent] +/* -------------------------------------------------------------------------- */ +/* Dispatcher */ +/* -------------------------------------------------------------------------- */ - // SlotBroker is a type alias for the slot feed. - SlotBroker = broker.Broker[*SlotEvent] +type ( + // Dispatcher is a type alias for the dispatcher. + Dispatcher = dispatcher.Dispatcher - // StatusBroker is a type alias for the status feed. - StatusBroker = broker.Broker[*StatusEvent] + // EventServer is a type alias for the event server. + EventServer = asyncserver.EventServer - // ValidatorUpdateBroker is a type alias for the validator update feed. - ValidatorUpdateBroker = broker.Broker[*ValidatorUpdateEvent] + // MessageServer is a type alias for the messages server. + MessageServer = asyncserver.MessageServer ) /* -------------------------------------------------------------------------- */ diff --git a/mod/node-core/pkg/components/validator_service.go b/mod/node-core/pkg/components/validator_service.go index 891e0574b7..b89244996a 100644 --- a/mod/node-core/pkg/components/validator_service.go +++ b/mod/node-core/pkg/components/validator_service.go @@ -34,34 +34,28 @@ import ( // ValidatorServiceInput is the input for the validator service provider. type ValidatorServiceInput struct { depinject.In - BeaconBlockFeed *BlockBroker - BlobProcessor *BlobProcessor - Cfg *config.Config - ChainSpec common.ChainSpec - LocalBuilder *LocalBuilder - Logger log.AdvancedLogger[any, sdklog.Logger] - StateProcessor *StateProcessor - StorageBackend *StorageBackend - Signer crypto.BLSSigner - SidecarsFeed *SidecarsBroker - SidecarFactory *SidecarFactory - SlotBroker *SlotBroker - TelemetrySink *metrics.TelemetrySink + BlobProcessor *BlobProcessor + Cfg *config.Config + ChainSpec common.ChainSpec + Dispatcher *Dispatcher + LocalBuilder *LocalBuilder + Logger log.AdvancedLogger[any, sdklog.Logger] + StateProcessor *StateProcessor + StorageBackend *StorageBackend + Signer crypto.BLSSigner + SidecarFactory *SidecarFactory + TelemetrySink *metrics.TelemetrySink } // ProvideValidatorService is a depinject provider for the validator service. func ProvideValidatorService( in ValidatorServiceInput, ) (*ValidatorService, error) { - slotSubscription, err := in.SlotBroker.Subscribe() - if err != nil { - in.Logger.Error("failed to subscribe to slot feed", "err", err) - return nil, err - } // Build the builder service. return validator.NewService[ *AttestationData, *BeaconBlock, + *BeaconBlockBundle, *BeaconBlockBody, *BeaconState, *BlobSidecars, @@ -86,8 +80,6 @@ func ProvideValidatorService( in.LocalBuilder, }, in.TelemetrySink, - in.BeaconBlockFeed, - in.SidecarsFeed, - slotSubscription, + in.Dispatcher, ), nil } diff --git a/mod/primitives/pkg/messages/messages.go b/mod/primitives/pkg/messages/messages.go new file mode 100644 index 0000000000..9d3244995f --- /dev/null +++ b/mod/primitives/pkg/messages/messages.go @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package messages + +// messages. +const ( + BuildBeaconBlockAndSidecars = "build-beacon-block-and-sidecars" + VerifyBeaconBlock = "verify-beacon-block" + FinalizeBeaconBlock = "finalize-beacon-block" + ProcessGenesisData = "process-genesis-data" + VerifySidecars = "verify-sidecars" + ProcessSidecars = "process-sidecars" +) + +// events. +const ( + BeaconBlockFinalizedEvent = "beacon-block-finalized" +) diff --git a/mod/runtime/go.mod b/mod/runtime/go.mod index 80adaedc9e..9a62d73405 100644 --- a/mod/runtime/go.mod +++ b/mod/runtime/go.mod @@ -10,6 +10,9 @@ replace ( cosmossdk.io/x/auth => cosmossdk.io/x/auth v0.0.0-20240806152830-8fb47b368cd4 cosmossdk.io/x/consensus => cosmossdk.io/x/consensus v0.0.0-20240806152830-8fb47b368cd4 cosmossdk.io/x/staking => cosmossdk.io/x/staking v0.0.0-20240806152830-8fb47b368cd4 + // required until merged onto main + github.com/berachain/beacon-kit/mod/async => ../async + github.com/berachain/beacon-kit/mod/primitives => ../primitives github.com/cosmos/cosmos-sdk => github.com/berachain/cosmos-sdk v0.46.0-beta2.0.20240808182639-7bdbf06a94f2 ) @@ -18,8 +21,8 @@ require ( cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc github.com/berachain/beacon-kit/mod/consensus v0.0.0-20240809163303-a4ebb22fd018 github.com/berachain/beacon-kit/mod/consensus-types v0.0.0-20240809163303-a4ebb22fd018 - github.com/berachain/beacon-kit/mod/errors v0.0.0-20240705193247-d464364483df - github.com/berachain/beacon-kit/mod/log v0.0.0-20240610210054-bfdc14c4013c + github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0 + github.com/berachain/beacon-kit/mod/log v0.0.0-20240807213340-5779c7a563cd github.com/berachain/beacon-kit/mod/p2p v0.0.0-20240618214413-d5ec0e66b3dd github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240808194557-e72e74f58197 github.com/cometbft/cometbft v1.0.0-rc1.0.20240806094948-2c4293ef36c4 @@ -196,7 +199,7 @@ require ( golang.org/x/crypto v0.26.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/net v0.27.0 // indirect - golang.org/x/sync v0.8.0 + golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.23.0 // indirect golang.org/x/text v0.17.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d // indirect diff --git a/mod/runtime/go.sum b/mod/runtime/go.sum index 2b324d2556..08e3f5aa8c 100644 --- a/mod/runtime/go.sum +++ b/mod/runtime/go.sum @@ -61,8 +61,6 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/berachain/beacon-kit/mod/async v0.0.0-20240624011057-b0afb8163f14 h1:uGcy4mqiyDzjImZsrxjU3U5NKnXpi+2s1cO0cz1LGNY= -github.com/berachain/beacon-kit/mod/async v0.0.0-20240624011057-b0afb8163f14/go.mod h1:tzZ5Oyg7BgCViZBkqDwHmfKPNI66xONwE5kWd1P2v7o= github.com/berachain/beacon-kit/mod/chain-spec v0.0.0-20240705193247-d464364483df h1:mnD1LKqDQ0n+OFdDqOuvKaEiUKRJzsO4V0wyyn/gJYg= github.com/berachain/beacon-kit/mod/chain-spec v0.0.0-20240705193247-d464364483df/go.mod h1:bTFB4Rdvm7D/WdwPYkqQ+8T0XOMBv0pzXfp1E46BFX8= github.com/berachain/beacon-kit/mod/consensus v0.0.0-20240809163303-a4ebb22fd018 h1:LvqiLOa8L5CKacYyphFHv363Y07nH4DJObuik0qSJ8c= @@ -71,16 +69,14 @@ github.com/berachain/beacon-kit/mod/consensus-types v0.0.0-20240809163303-a4ebb2 github.com/berachain/beacon-kit/mod/consensus-types v0.0.0-20240809163303-a4ebb22fd018/go.mod h1:A3Ohrylv4Dx2sf8EKJImC7ii091dUaWEAMp/AK5N6+s= github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240808194557-e72e74f58197 h1:wVWkiiERY/7kaXvE/VNPPUtYp/l8ky6QSuKM3ThVMXU= github.com/berachain/beacon-kit/mod/engine-primitives v0.0.0-20240808194557-e72e74f58197/go.mod h1:LiOiqrJhhLH/GPo0XE5fel3EYyi7X6dwBOyTqZakTeQ= -github.com/berachain/beacon-kit/mod/errors v0.0.0-20240705193247-d464364483df h1:6MJllcmMFt6dtvftM5zmdl1WVDpqZkNy3hFXVZtNV0s= -github.com/berachain/beacon-kit/mod/errors v0.0.0-20240705193247-d464364483df/go.mod h1:yRD7rmnyaaqgq/6+eIVqvSkFJXuLXpBddUu59HUOrtc= +github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0 h1:kCSrkb/uVXfMKJPKjf0c7nlJkwn5cNwMxtzRW4zNq2A= +github.com/berachain/beacon-kit/mod/errors v0.0.0-20240806211103-d1105603bfc0/go.mod h1:og0jtHZosPDTyhge9tMBlRItoZ4Iv3aZFM9n4QDpcdo= github.com/berachain/beacon-kit/mod/geth-primitives v0.0.0-20240806160829-cde2d1347e7e h1:0/FDBXtagMkpta/f4J2uAah2NM1G+0dqxngzMzrmbw4= github.com/berachain/beacon-kit/mod/geth-primitives v0.0.0-20240806160829-cde2d1347e7e/go.mod h1:7/SXz8S5VpFl2thcKuBdu1OId+SgI1o4N+S1FB92Zw8= -github.com/berachain/beacon-kit/mod/log v0.0.0-20240610210054-bfdc14c4013c h1:7f9dLYGOCMoV7LxT6YRmVSWLTPbGTTcxDPLPLvHGrOk= -github.com/berachain/beacon-kit/mod/log v0.0.0-20240610210054-bfdc14c4013c/go.mod h1:nFybcw/ZhJ6Gu66dna301W2I7u61skm2HfHxQmdR68Q= +github.com/berachain/beacon-kit/mod/log v0.0.0-20240807213340-5779c7a563cd h1:DYSjsq80Omqqlt+z2VcYsSxjZpLqCDRz7CvUDBrLDJE= +github.com/berachain/beacon-kit/mod/log v0.0.0-20240807213340-5779c7a563cd/go.mod h1:BilVBmqKhC4GXYCaIs8QnKaR14kpn3YmF5uYBdayF9I= github.com/berachain/beacon-kit/mod/p2p v0.0.0-20240618214413-d5ec0e66b3dd h1:QHAukFEWl62kscPjRvpqfxCPvd3RSg8cD4mw8qIBhU4= github.com/berachain/beacon-kit/mod/p2p v0.0.0-20240618214413-d5ec0e66b3dd/go.mod h1:ft214cxJaqrRPOuAjpYwgA9AOElJnHrDZZEQ0jZPWwQ= -github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240808194557-e72e74f58197 h1:hk8N7Q1CCKMW/05pRu5rbfRnbTUou5TjULaeeRtbU+E= -github.com/berachain/beacon-kit/mod/primitives v0.0.0-20240808194557-e72e74f58197/go.mod h1:7kNnd9rhYjyZJHuXs/ku5drL9EMM64ekJVR181fGmbM= github.com/berachain/cosmos-sdk v0.46.0-beta2.0.20240808182639-7bdbf06a94f2 h1:4qwOPga+dKeDelSJ6pseasQq6fcjd7iXhah0y7enuco= github.com/berachain/cosmos-sdk v0.46.0-beta2.0.20240808182639-7bdbf06a94f2/go.mod h1:DUyJJMMuFJ9OZAhnFMLA0KTFGoVw61p8wnqtV3Wgx3c= github.com/bgentry/speakeasy v0.2.0 h1:tgObeVOf8WAvtuAX6DhJ4xks4CFNwPDZiqzGqIHE51E= diff --git a/mod/runtime/pkg/middleware/abci.go b/mod/runtime/pkg/middleware/abci.go index 10952fb8ff..2613639ea4 100644 --- a/mod/runtime/pkg/middleware/abci.go +++ b/mod/runtime/pkg/middleware/abci.go @@ -27,13 +27,12 @@ import ( asynctypes "github.com/berachain/beacon-kit/mod/async/pkg/types" "github.com/berachain/beacon-kit/mod/errors" "github.com/berachain/beacon-kit/mod/primitives/pkg/encoding/json" - "github.com/berachain/beacon-kit/mod/primitives/pkg/events" "github.com/berachain/beacon-kit/mod/primitives/pkg/math" + "github.com/berachain/beacon-kit/mod/primitives/pkg/messages" "github.com/berachain/beacon-kit/mod/primitives/pkg/transition" "github.com/berachain/beacon-kit/mod/runtime/pkg/encoding" cmtabci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/gogoproto/proto" - "golang.org/x/sync/errgroup" ) /* -------------------------------------------------------------------------- */ @@ -42,57 +41,29 @@ import ( // InitGenesis is called by the base app to initialize the state of the. func (h *ABCIMiddleware[ - _, _, _, _, _, GenesisT, _, + _, _, _, _, _, _, GenesisT, _, ]) InitGenesis( ctx context.Context, bz []byte, ) (transition.ValidatorUpdates, error) { - var ( - g errgroup.Group - valUpdates transition.ValidatorUpdates - genesisErr error - ) + var err error data := new(GenesisT) - if err := json.Unmarshal(bz, data); err != nil { - return nil, err - } - // Send a request to the chain service to process the genesis data. - if err := h.genesisBroker.Publish(ctx, asynctypes.NewEvent( - ctx, events.GenesisDataProcessRequest, *data, - )); err != nil { + if err = json.Unmarshal(bz, data); err != nil { + h.logger.Error("Failed to unmarshal genesis data", "error", err) return nil, err } - // Wait for the genesis data to be processed. - g.Go(func() error { - valUpdates, genesisErr = h.waitForGenesisData(ctx) - return genesisErr - }) - - if err := g.Wait(); err != nil { + // request for validator updates + valUpdates := asynctypes.NewFuture[transition.ValidatorUpdates]() + if err = h.dispatcher.SendRequest( + asynctypes.NewMessage( + ctx, messages.ProcessGenesisData, *data, + ), valUpdates, + ); err != nil { return nil, err } - return valUpdates, nil -} -// waitForGenesisData waits for the genesis data to be processed and returns -// the validator updates. -func (h *ABCIMiddleware[ - _, _, _, _, _, GenesisT, _, -]) waitForGenesisData(ctx context.Context) ( - transition.ValidatorUpdates, error) { - select { - case msg := <-h.valUpdateSub: - if msg.Type() != events.ValidatorSetUpdated { - return nil, errors.Wrapf( - ErrUnexpectedEvent, - "unexpected event type: %s", msg.Type(), - ) - } - return msg.Data(), msg.Error() - case <-ctx.Done(): - return nil, ctx.Err() - } + return valUpdates.Resolve() } /* -------------------------------------------------------------------------- */ @@ -101,75 +72,56 @@ func (h *ABCIMiddleware[ // prepareProposal is the internal handler for preparing proposals. func (h *ABCIMiddleware[ - _, _, _, _, _, _, SlotDataT, + _, BeaconBlockT, BeaconBlockBundleT, BlobSidecarsT, _, _, _, SlotDataT, ]) PrepareProposal( ctx context.Context, slotData SlotDataT, ) ([]byte, []byte, error) { - var ( - g errgroup.Group - startTime = time.Now() - beaconBlockErr, sidecarsErr error - beaconBlockBz, sidecarsBz []byte - ) + var err error + startTime := time.Now() defer h.metrics.measurePrepareProposalDuration(startTime) - // Send a request to the validator service to give us a beacon block - // and blob sidecards to pass to ABCI. - if err := h.slotBroker.Publish(ctx, asynctypes.NewEvent( - ctx, events.NewSlot, slotData, - )); err != nil { + // request a built beacon block for the given slot + beaconBlkBundleFuture := asynctypes.NewFuture[BeaconBlockBundleT]() + if err = h.dispatcher.SendRequest( + asynctypes.NewMessage( + ctx, messages.BuildBeaconBlockAndSidecars, slotData, + ), beaconBlkBundleFuture, + ); err != nil { return nil, nil, err } - // Wait for the beacon block to be built. - g.Go(func() error { - beaconBlockBz, beaconBlockErr = h.waitforBeaconBlk(ctx) - return beaconBlockErr - }) - - // Wait for the sidecars to be built. - g.Go(func() error { - sidecarsBz, sidecarsErr = h.waitForSidecars(ctx) - return sidecarsErr - }) + // resolve the beacon block bundle from the future + beaconBlkBundle, err := beaconBlkBundleFuture.Resolve() + if err != nil { + return nil, nil, err + } - // Wait for both processes to complete and then - // return the appropriate response. - return beaconBlockBz, sidecarsBz, g.Wait() + // gossip the built beacon block and blob sidecars + return h.handleBeaconBlockBundleResponse(ctx, beaconBlkBundle) } -// waitForSidecars waits for the sidecars to be built and returns them. +// handleBeaconBlockBundleResponse gossips the built beacon block and blob +// sidecars to the network. func (h *ABCIMiddleware[ - _, _, _, _, _, _, _, -]) waitForSidecars(ctx context.Context) ([]byte, error) { - select { - case <-ctx.Done(): - return nil, ctx.Err() - case msg := <-h.sidecarsCh: - if msg.Error() != nil { - return nil, msg.Error() - } - return h.blobGossiper.Publish(ctx, msg.Data()) + _, BeaconBlockT, BeaconBlockBundleT, BlobSidecarsT, _, _, _, _, +]) handleBeaconBlockBundleResponse( + ctx context.Context, + bbb BeaconBlockBundleT, +) ([]byte, []byte, error) { + // gossip beacon block + bbBz, bbErr := h.beaconBlockGossiper.Publish( + ctx, bbb.GetBeaconBlock(), + ) + if bbErr != nil { + return nil, nil, bbErr } -} - -// waitforBeaconBlk waits for the beacon block to be built and returns it. -func (h *ABCIMiddleware[ - _, _, _, _, _, _, _, -]) waitforBeaconBlk(ctx context.Context) ([]byte, error) { - select { - case <-ctx.Done(): - return nil, ctx.Err() - case beaconBlock := <-h.blkCh: - if beaconBlock.Error() != nil { - return nil, beaconBlock.Error() - } - return h.beaconBlockGossiper.Publish( - ctx, - beaconBlock.Data(), - ) + // gossip blob sidecars + scBz, scErr := h.blobGossiper.Publish(ctx, bbb.GetSidecars()) + if scErr != nil { + return nil, nil, scErr } + return bbBz, scBz, nil } /* -------------------------------------------------------------------------- */ @@ -179,7 +131,7 @@ func (h *ABCIMiddleware[ // ProcessProposal processes the proposal for the ABCI middleware. // It handles both the beacon block and blob sidecars concurrently. func (h *ABCIMiddleware[ - _, BeaconBlockT, BlobSidecarsT, _, _, _, _, + _, BeaconBlockT, _, BlobSidecarsT, _, _, _, _, ]) ProcessProposal( ctx context.Context, req proto.Message, @@ -188,7 +140,6 @@ func (h *ABCIMiddleware[ blk BeaconBlockT sidecars BlobSidecarsT err error - g, _ = errgroup.WithContext(ctx) startTime = time.Now() ) abciReq, ok := req.(*cmtabci.ProcessProposalRequest) @@ -203,95 +154,50 @@ func (h *ABCIMiddleware[ return h.createProcessProposalResponse(errors.WrapNonFatal(err)) } - // Begin processing the beacon block. - g.Go(func() error { - return h.verifyBeaconBlock(ctx, blk) - }) + // verify the beacon block + beaconBlockFuture := asynctypes.NewFuture[BeaconBlockT]() + if err = h.dispatcher.SendRequest( + asynctypes.NewMessage( + ctx, messages.VerifyBeaconBlock, blk, + ), beaconBlockFuture, + ); err != nil { + return h.createProcessProposalResponse(errors.WrapNonFatal(err)) + } // Request the blob sidecars. if sidecars, err = h.blobGossiper.Request(ctx, abciReq); err != nil { return h.createProcessProposalResponse(errors.WrapNonFatal(err)) } - // Begin processing the blob sidecars. - g.Go(func() error { - return h.verifyBlobSidecars(ctx, sidecars) - }) - - // Wait for both processes to complete and then - // return the appropriate response.s - return h.createProcessProposalResponse(g.Wait()) -} - -// verifyBeaconBlock handles the processing of the beacon block. -// It requests the block, publishes a received event, and waits for -// verification. -func (h *ABCIMiddleware[ - _, BeaconBlockT, BlobSidecarsT, _, _, _, _, -]) verifyBeaconBlock( - ctx context.Context, - blk BeaconBlockT, -) error { - // Publish the received event. - if err := h.blkBroker.Publish( - ctx, - asynctypes.NewEvent(ctx, events.BeaconBlockReceived, blk, nil), + // verify the blob sidecars + sidecarsFuture := asynctypes.NewFuture[BlobSidecarsT]() + if err = h.dispatcher.SendRequest( + asynctypes.NewMessage( + ctx, messages.VerifySidecars, sidecars, + ), sidecarsFuture, ); err != nil { - return err + return h.createProcessProposalResponse(errors.WrapNonFatal(err)) } - // Wait for a response. - select { - case <-ctx.Done(): - return ctx.Err() - case msg := <-h.blkCh: - if msg.Type() != events.BeaconBlockVerified { - return errors.Wrapf( - ErrUnexpectedEvent, "unexpected event type: %s", msg.Type(), - ) - } - return msg.Error() + // error if the beacon block or sidecars are invalid + _, err = beaconBlockFuture.Resolve() + if err != nil { + return h.createProcessProposalResponse(err) } -} -// processBlobSidecars handles the processing of blob sidecars. -// It requests the sidecars, publishes a received event, and waits for -// processing. -func (h *ABCIMiddleware[ - _, BeaconBlockT, BlobSidecarsT, _, _, _, _, -]) verifyBlobSidecars( - ctx context.Context, - sidecars BlobSidecarsT, -) error { - // Publish the received event. - if err := h.sidecarsBroker.Publish( - ctx, - asynctypes.NewEvent(ctx, events.BlobSidecarsReceived, sidecars), - ); err != nil { - return err + _, err = sidecarsFuture.Resolve() + if err != nil { + return h.createProcessProposalResponse(err) } - // Wait for a response. - select { - case <-ctx.Done(): - return ctx.Err() - case msg := <-h.sidecarsCh: - if msg.Type() != events.BlobSidecarsProcessed { - return errors.Wrapf( - ErrUnexpectedEvent, "unexpected event type: %s", msg.Type(), - ) - } - return msg.Error() - } + return h.createProcessProposalResponse(nil) } // createResponse generates the appropriate ProcessProposalResponse based on the // error. func (*ABCIMiddleware[ - _, BeaconBlockT, _, BlobSidecarsT, _, _, _, -]) createProcessProposalResponse( - err error, -) (proto.Message, error) { + _, BeaconBlockT, _, _, BlobSidecarsT, _, _, _, +]) createProcessProposalResponse(err error) (proto.Message, error) { status := cmtabci.PROCESS_PROPOSAL_STATUS_REJECT if !errors.IsFatal(err) { status = cmtabci.PROCESS_PROPOSAL_STATUS_ACCEPT @@ -306,15 +212,20 @@ func (*ABCIMiddleware[ // EndBlock returns the validator set updates from the beacon state. func (h *ABCIMiddleware[ - _, BeaconBlockT, BlobSidecarsT, _, _, _, _, + _, BeaconBlockT, _, BlobSidecarsT, _, _, _, _, ]) FinalizeBlock( ctx context.Context, req proto.Message, ) (transition.ValidatorUpdates, error) { + var ( + blk BeaconBlockT + blobs BlobSidecarsT + err error + ) abciReq, ok := req.(*cmtabci.FinalizeBlockRequest) if !ok { return nil, ErrInvalidFinalizeBlockRequestType } - blk, blobs, err := encoding. + blk, blobs, err = encoding. ExtractBlobsAndBlockFromRequest[BeaconBlockT, BlobSidecarsT]( abciReq, BeaconBlockTxIndex, @@ -328,68 +239,25 @@ func (h *ABCIMiddleware[ return nil, nil } - // Send the sidecars to the sidecars feed and wait for a response - if err = h.processSidecars(ctx, blobs); err != nil { + // process the sidecars. + sidecarsFuture := asynctypes.NewFuture[BlobSidecarsT]() + if err = h.dispatcher.SendRequest( + asynctypes.NewMessage( + ctx, messages.ProcessSidecars, blobs, + ), sidecarsFuture, + ); err != nil { return nil, err } - // Process the beacon block and return the validator updates. - return h.processBeaconBlock( - ctx, blk, - ) -} - -// processSidecars publishes the sidecars and waits for a response. -func (h *ABCIMiddleware[ - _, _, BlobSidecarsT, _, _, _, _, -]) processSidecars(ctx context.Context, blobs BlobSidecarsT) error { - // Publish the sidecars. - if err := h.sidecarsBroker.Publish(ctx, asynctypes.NewEvent( - ctx, events.BlobSidecarsProcessRequest, blobs, - )); err != nil { - return err - } - - // Wait for the sidecars to be processed. - select { - case <-ctx.Done(): - return ctx.Err() - case msg := <-h.sidecarsCh: - if msg.Type() != events.BlobSidecarsProcessed { - return errors.Wrapf( - ErrUnexpectedEvent, - "unexpected event type: %s", msg.Type(), - ) - } - return msg.Error() - } -} - -// processBeaconBlock processes the beacon block and returns validator updates. -func (h *ABCIMiddleware[ - _, BeaconBlockT, _, _, _, _, _, -]) processBeaconBlock( - ctx context.Context, blk BeaconBlockT, -) (transition.ValidatorUpdates, error) { - // Publish the verified block event. - if err := h.blkBroker.Publish( - ctx, asynctypes.NewEvent( - ctx, events.BeaconBlockFinalizedRequest, blk, - )); err != nil { + // finalize the beacon block. + valUpdatesFuture := asynctypes.NewFuture[transition.ValidatorUpdates]() + if err = h.dispatcher.SendRequest( + asynctypes.NewMessage( + ctx, messages.FinalizeBeaconBlock, blk, + ), valUpdatesFuture, + ); err != nil { return nil, err } - // Wait for the block to be processed. - select { - case msg := <-h.valUpdateSub: - if msg.Type() != events.ValidatorSetUpdated { - return nil, errors.Wrapf( - ErrUnexpectedEvent, - "unexpected event type: %s", msg.Type(), - ) - } - return msg.Data(), msg.Error() - case <-ctx.Done(): - return nil, ctx.Err() - } + return valUpdatesFuture.Resolve() } diff --git a/mod/runtime/pkg/middleware/middleware.go b/mod/runtime/pkg/middleware/middleware.go index 8a58e1bd57..59b0304e97 100644 --- a/mod/runtime/pkg/middleware/middleware.go +++ b/mod/runtime/pkg/middleware/middleware.go @@ -21,17 +21,13 @@ package middleware import ( - "context" "encoding/json" - "github.com/berachain/beacon-kit/mod/async/pkg/broker" asynctypes "github.com/berachain/beacon-kit/mod/async/pkg/types" "github.com/berachain/beacon-kit/mod/log" "github.com/berachain/beacon-kit/mod/p2p" "github.com/berachain/beacon-kit/mod/primitives/pkg/common" "github.com/berachain/beacon-kit/mod/primitives/pkg/constraints" - "github.com/berachain/beacon-kit/mod/primitives/pkg/events" - "github.com/berachain/beacon-kit/mod/primitives/pkg/transition" "github.com/berachain/beacon-kit/mod/runtime/pkg/encoding" rp2p "github.com/berachain/beacon-kit/mod/runtime/pkg/p2p" ) @@ -40,6 +36,7 @@ import ( type ABCIMiddleware[ AvailabilityStoreT any, BeaconBlockT BeaconBlock[BeaconBlockT], + BeaconBlockBundleT BeaconBlockBundle[BeaconBlockT, BlobSidecarsT], BlobSidecarsT interface { constraints.SSZMarshallable Empty() BlobSidecarsT @@ -67,36 +64,18 @@ type ABCIMiddleware[ encoding.ABCIRequest, BeaconBlockT, ] + dispatcher asynctypes.Dispatcher // metrics is the metrics emitter. metrics *ABCIMiddlewareMetrics // logger is the logger for the middleware. logger log.Logger[any] - - // Feeds - // - // genesisBroker is a feed for genesis data. - genesisBroker *broker.Broker[*asynctypes.Event[GenesisT]] - // blkBroker is a feed for blocks. - blkBroker *broker.Broker[*asynctypes.Event[BeaconBlockT]] - // sidecarsBroker is a feed for sidecars. - sidecarsBroker *broker.Broker[*asynctypes.Event[BlobSidecarsT]] - // slotBroker is a feed for slots. - slotBroker *broker.Broker[*asynctypes.Event[SlotDataT]] - - // Channels - // blkCh is used to communicate the beacon block to the EndBlock method. - blkCh chan *asynctypes.Event[BeaconBlockT] - // sidecarsCh is used to communicate the sidecars to the EndBlock method. - sidecarsCh chan *asynctypes.Event[BlobSidecarsT] - // valUpdateSub is the channel for listening for incoming validator set - // updates. - valUpdateSub chan *asynctypes.Event[transition.ValidatorUpdates] } // NewABCIMiddleware creates a new instance of the Handler struct. func NewABCIMiddleware[ AvailabilityStoreT any, BeaconBlockT BeaconBlock[BeaconBlockT], + BeaconBlockBundleT BeaconBlockBundle[BeaconBlockT, BlobSidecarsT], BlobSidecarsT interface { constraints.SSZMarshallable Empty() BlobSidecarsT @@ -109,17 +88,13 @@ func NewABCIMiddleware[ chainSpec common.ChainSpec, logger log.Logger[any], telemetrySink TelemetrySink, - genesisBroker *broker.Broker[*asynctypes.Event[GenesisT]], - blkBroker *broker.Broker[*asynctypes.Event[BeaconBlockT]], - sidecarsBroker *broker.Broker[*asynctypes.Event[BlobSidecarsT]], - slotBroker *broker.Broker[*asynctypes.Event[SlotDataT]], - valUpdateSub chan *asynctypes.Event[transition.ValidatorUpdates], + dispatcher asynctypes.Dispatcher, ) *ABCIMiddleware[ - AvailabilityStoreT, BeaconBlockT, BlobSidecarsT, DepositT, + AvailabilityStoreT, BeaconBlockT, BeaconBlockBundleT, BlobSidecarsT, DepositT, ExecutionPayloadT, GenesisT, SlotDataT, ] { return &ABCIMiddleware[ - AvailabilityStoreT, BeaconBlockT, BlobSidecarsT, DepositT, + AvailabilityStoreT, BeaconBlockT, BeaconBlockBundleT, BlobSidecarsT, DepositT, ExecutionPayloadT, GenesisT, SlotDataT, ]{ chainSpec: chainSpec, @@ -132,76 +107,16 @@ func NewABCIMiddleware[ ]( chainSpec, ), - logger: logger, - metrics: newABCIMiddlewareMetrics(telemetrySink), - genesisBroker: genesisBroker, - blkBroker: blkBroker, - sidecarsBroker: sidecarsBroker, - slotBroker: slotBroker, - blkCh: make( - chan *asynctypes.Event[BeaconBlockT], - 1, - ), - sidecarsCh: make( - chan *asynctypes.Event[BlobSidecarsT], - 1, - ), - valUpdateSub: valUpdateSub, + logger: logger, + metrics: newABCIMiddlewareMetrics(telemetrySink), + dispatcher: dispatcher, } } // Name returns the name of the middleware. func (am *ABCIMiddleware[ - AvailabilityStoreT, BeaconBlockT, BlobSidecarsT, DepositT, + AvailabilityStoreT, BeaconBlockT, BeaconBlockBundleT, BlobSidecarsT, DepositT, ExecutionPayloadT, GenesisT, SlotDataT, ]) Name() string { return "abci-middleware" } - -// Start the middleware. -func (am *ABCIMiddleware[ - _, _, _, _, _, _, _, -]) Start(ctx context.Context) error { - subBlkCh, err := am.blkBroker.Subscribe() - if err != nil { - return err - } - - subSidecarsCh, err := am.sidecarsBroker.Subscribe() - if err != nil { - return err - } - - go am.start(ctx, subBlkCh, subSidecarsCh) - return nil -} - -// start starts the middleware. -func (am *ABCIMiddleware[ - _, BeaconBlockT, BlobSidecarsT, _, _, _, _, -]) start( - ctx context.Context, - blkCh chan *asynctypes.Event[BeaconBlockT], - sidecarsCh chan *asynctypes.Event[BlobSidecarsT], -) { - for { - select { - case <-ctx.Done(): - return - case msg := <-blkCh: - switch msg.Type() { - case events.BeaconBlockBuilt: - fallthrough - case events.BeaconBlockVerified: - am.blkCh <- msg - } - case msg := <-sidecarsCh: - switch msg.Type() { - case events.BlobSidecarsBuilt: - fallthrough - case events.BlobSidecarsProcessed: - am.sidecarsCh <- msg - } - } - } -} diff --git a/mod/runtime/pkg/middleware/types.go b/mod/runtime/pkg/middleware/types.go index 77bb32831f..c8c2b080f7 100644 --- a/mod/runtime/pkg/middleware/types.go +++ b/mod/runtime/pkg/middleware/types.go @@ -39,6 +39,13 @@ type BeaconBlock[SelfT any] interface { NewFromSSZ([]byte, uint32) (SelfT, error) } +// BeaconBlockBundle is a bundle of a beacon block and its corresponding blob +// sidecars. +type BeaconBlockBundle[BeaconBlockT any, BlobSidecarsT any] interface { + GetBeaconBlock() BeaconBlockT + GetSidecars() BlobSidecarsT +} + // TelemetrySink is an interface for sending metrics to a telemetry backend. type TelemetrySink interface { // MeasureSince measures the time since the given time. diff --git a/mod/runtime/pkg/service/mocks/dispatcher.mock.go b/mod/runtime/pkg/service/mocks/dispatcher.mock.go new file mode 100644 index 0000000000..992d03e4f0 --- /dev/null +++ b/mod/runtime/pkg/service/mocks/dispatcher.mock.go @@ -0,0 +1,82 @@ +// Code generated by mockery v2.44.1. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// Dispatcher is an autogenerated mock type for the Dispatcher type +type Dispatcher struct { + mock.Mock +} + +type Dispatcher_Expecter struct { + mock *mock.Mock +} + +func (_m *Dispatcher) EXPECT() *Dispatcher_Expecter { + return &Dispatcher_Expecter{mock: &_m.Mock} +} + +// Start provides a mock function with given fields: ctx +func (_m *Dispatcher) Start(ctx context.Context) error { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for Start") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Dispatcher_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start' +type Dispatcher_Start_Call struct { + *mock.Call +} + +// Start is a helper method to define mock.On call +// - ctx context.Context +func (_e *Dispatcher_Expecter) Start(ctx interface{}) *Dispatcher_Start_Call { + return &Dispatcher_Start_Call{Call: _e.mock.On("Start", ctx)} +} + +func (_c *Dispatcher_Start_Call) Run(run func(ctx context.Context)) *Dispatcher_Start_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *Dispatcher_Start_Call) Return(_a0 error) *Dispatcher_Start_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Dispatcher_Start_Call) RunAndReturn(run func(context.Context) error) *Dispatcher_Start_Call { + _c.Call.Return(run) + return _c +} + +// NewDispatcher creates a new instance of Dispatcher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewDispatcher(t interface { + mock.TestingT + Cleanup(func()) +}) *Dispatcher { + mock := &Dispatcher{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mod/runtime/pkg/service/options.go b/mod/runtime/pkg/service/options.go index 481639b921..f6d43d6a83 100644 --- a/mod/runtime/pkg/service/options.go +++ b/mod/runtime/pkg/service/options.go @@ -20,7 +20,9 @@ package service -import "github.com/berachain/beacon-kit/mod/log" +import ( + "github.com/berachain/beacon-kit/mod/log" +) // RegistryOption is a functional option for the Registry. type RegistryOption func(*Registry) error diff --git a/mod/runtime/pkg/service/registry.go b/mod/runtime/pkg/service/registry.go index 358b400817..dff8fcd4b7 100644 --- a/mod/runtime/pkg/service/registry.go +++ b/mod/runtime/pkg/service/registry.go @@ -35,6 +35,10 @@ type Basic interface { Name() string } +type Dispatcher interface { + Start(ctx context.Context) error +} + // Registry provides a useful pattern for managing services. // It allows for ease of dependency management and ensures services // dependent on others use the same references in memory. @@ -48,7 +52,8 @@ type Registry struct { } // NewRegistry starts a registry instance for convenience. -func NewRegistry(opts ...RegistryOption) *Registry { +func NewRegistry( + opts ...RegistryOption) *Registry { r := &Registry{ services: make(map[string]Basic), } @@ -63,6 +68,7 @@ func NewRegistry(opts ...RegistryOption) *Registry { // StartAll initialized each service in order of registration. func (s *Registry) StartAll(ctx context.Context) error { + // start all services s.logger.Info("Starting services", "num", len(s.serviceTypes)) for _, typeName := range s.serviceTypes { s.logger.Info("Starting service", "type", typeName) diff --git a/mod/storage/pkg/pruner/mocks/block_event.mock.go b/mod/storage/pkg/pruner/mocks/block_event.mock.go index a08e70cc18..e69a1fea56 100644 --- a/mod/storage/pkg/pruner/mocks/block_event.mock.go +++ b/mod/storage/pkg/pruner/mocks/block_event.mock.go @@ -67,7 +67,7 @@ func (_c *BlockEvent_Data_Call[BeaconBlockT]) RunAndReturn(run func() BeaconBloc } // Is provides a mock function with given fields: _a0 -func (_m *BlockEvent[BeaconBlockT]) Is(_a0 types.EventID) bool { +func (_m *BlockEvent[BeaconBlockT]) Is(_a0 types.MessageID) bool { ret := _m.Called(_a0) if len(ret) == 0 { @@ -75,7 +75,7 @@ func (_m *BlockEvent[BeaconBlockT]) Is(_a0 types.EventID) bool { } var r0 bool - if rf, ok := ret.Get(0).(func(types.EventID) bool); ok { + if rf, ok := ret.Get(0).(func(types.MessageID) bool); ok { r0 = rf(_a0) } else { r0 = ret.Get(0).(bool) @@ -90,14 +90,14 @@ type BlockEvent_Is_Call[BeaconBlockT pruner.BeaconBlock] struct { } // Is is a helper method to define mock.On call -// - _a0 types.EventID +// - _a0 types.MessageID func (_e *BlockEvent_Expecter[BeaconBlockT]) Is(_a0 interface{}) *BlockEvent_Is_Call[BeaconBlockT] { return &BlockEvent_Is_Call[BeaconBlockT]{Call: _e.mock.On("Is", _a0)} } -func (_c *BlockEvent_Is_Call[BeaconBlockT]) Run(run func(_a0 types.EventID)) *BlockEvent_Is_Call[BeaconBlockT] { +func (_c *BlockEvent_Is_Call[BeaconBlockT]) Run(run func(_a0 types.MessageID)) *BlockEvent_Is_Call[BeaconBlockT] { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.EventID)) + run(args[0].(types.MessageID)) }) return _c } @@ -107,7 +107,7 @@ func (_c *BlockEvent_Is_Call[BeaconBlockT]) Return(_a0 bool) *BlockEvent_Is_Call return _c } -func (_c *BlockEvent_Is_Call[BeaconBlockT]) RunAndReturn(run func(types.EventID) bool) *BlockEvent_Is_Call[BeaconBlockT] { +func (_c *BlockEvent_Is_Call[BeaconBlockT]) RunAndReturn(run func(types.MessageID) bool) *BlockEvent_Is_Call[BeaconBlockT] { _c.Call.Return(run) return _c } diff --git a/mod/storage/pkg/pruner/pruner.go b/mod/storage/pkg/pruner/pruner.go index 0a7aa757fd..72dc6bc85c 100644 --- a/mod/storage/pkg/pruner/pruner.go +++ b/mod/storage/pkg/pruner/pruner.go @@ -30,7 +30,6 @@ import ( "context" "github.com/berachain/beacon-kit/mod/log" - "github.com/berachain/beacon-kit/mod/primitives/pkg/events" ) // Compile-time check to ensure pruner implements the Pruner interface. @@ -45,11 +44,11 @@ type pruner[ BlockEventT BlockEvent[BeaconBlockT], PrunableT Prunable, ] struct { - prunable Prunable - logger log.Logger[any] - name string - feed chan BlockEventT - pruneRangeFn func(BlockEventT) (uint64, uint64) + prunable Prunable + logger log.Logger[any] + name string + finalizedBlockCh chan BlockEventT + pruneRangeFn func(BlockEventT) (uint64, uint64) } // NewPruner creates a new Pruner. @@ -61,35 +60,35 @@ func NewPruner[ logger log.Logger[any], prunable Prunable, name string, - feed chan BlockEventT, + finalizedBlockCh chan BlockEventT, pruneRangeFn func(BlockEventT) (uint64, uint64), ) Pruner[PrunableT] { return &pruner[BeaconBlockT, BlockEventT, PrunableT]{ - logger: logger, - prunable: prunable, - name: name, - feed: feed, - pruneRangeFn: pruneRangeFn, + logger: logger, + prunable: prunable, + name: name, + finalizedBlockCh: finalizedBlockCh, + pruneRangeFn: pruneRangeFn, } } // Start starts the Pruner by listening for new indexes to prune. -func (p *pruner[_, _, _]) Start(ctx context.Context) { +func (p *pruner[_, BlockEventT, _]) Start(ctx context.Context) { go p.start(ctx) } // start listens for new indexes to prune. -func (p *pruner[_, _, _]) start(ctx context.Context) { +func (p *pruner[_, BlockEventT, _]) start( + ctx context.Context, +) { for { select { case <-ctx.Done(): return - case event := <-p.feed: - if event.Is(events.BeaconBlockFinalized) { - start, end := p.pruneRangeFn(event) - if err := p.prunable.Prune(start, end); err != nil { - p.logger.Error("‼️ error pruning index ‼️", "error", err) - } + case event := <-p.finalizedBlockCh: + start, end := p.pruneRangeFn(event) + if err := p.prunable.Prune(start, end); err != nil { + p.logger.Error("‼️ error pruning index ‼️", "error", err) } } }