From 143feaa265ad7fc8d5a2669527dc17cb5a90a875 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:19:36 +0000 Subject: [PATCH 01/50] feat(shared): module Create with ModuleOptions --- shared/modules/module.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared/modules/module.go b/shared/modules/module.go index 7e9ef989e..c6cf64c0c 100644 --- a/shared/modules/module.go +++ b/shared/modules/module.go @@ -20,9 +20,10 @@ type InterruptableModule interface { Stop() error } +type ModuleOption func(InitializableModule) type InitializableModule interface { GetModuleName() string - Create(bus Bus) (Module, error) + Create(bus Bus, options ...ModuleOption) (Module, error) } type KeyholderModule interface { From a04698440ba7e24e855eff5a89328a3f6f34ae2c Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:31:25 +0000 Subject: [PATCH 02/50] docs(shared): godoc for ModuleOption --- shared/modules/module.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/shared/modules/module.go b/shared/modules/module.go index c6cf64c0c..f390c5b66 100644 --- a/shared/modules/module.go +++ b/shared/modules/module.go @@ -20,6 +20,34 @@ type InterruptableModule interface { Stop() error } +// TODO(#509): improve the documentation for this and other interfaces/functions +// ModuleOption is a function that configures a module when it is created. +// It uses a widely used pattern in Go called functional options. +// See https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis +// for more information. +// +// It is used to provide optional parameters to the module constructor for all the cases +// where there is no configuration, which is often the case for sub-modules that are used +// and configured at runtime. +// +// It accepts an InitializableModule as a parameter, because in order to create a module with these options, +// at a minimum, the module must implement the InitializableModule interface. +// +// Example: +// +// func WithFoo(foo string) ModuleOption { +// return func(m InitializableModule) { +// m.(*MyModule).foo = foo +// } +// } +// +// func NewMyModule(options ...ModuleOption) (Module, error) { +// m := &MyModule{} +// for _, option := range options { +// option(m) +// } +// return m, nil +// } type ModuleOption func(InitializableModule) type InitializableModule interface { GetModuleName() string From 82505e420ed5ab75c5426a97559d753866dc641a Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:33:09 +0000 Subject: [PATCH 03/50] docs(shared): updated README --- shared/modules/doc/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shared/modules/doc/README.md b/shared/modules/doc/README.md index d7fdddea1..cec167a68 100644 --- a/shared/modules/doc/README.md +++ b/shared/modules/doc/README.md @@ -43,7 +43,10 @@ TODO(#235): Update once runtime configs are implemented #### Create the module -Module creation uses a typical constructor pattern signature `Create(bus modules.Bus) (modules.Module, error)` +Module creation uses a typical constructor pattern signature `Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error)` + +Where `options ...modules.ModuleOption` is an optional variadic argument that allows for the passing of options to the module. +This is useful to configure the module at creation time and it's usually used during prototyping and in "sub-modules" that don't have a specific configuration file and where adding it would add unnecessary complexity and overhead. If a module has a lot of `ModuleOption`s, at that point a configuration file might be advisable. Currently, module creation is not embedded or enforced in the interface to prevent the initializer from having to use clunky creation syntax -> `modPackage.new(module).Create(bus modules.Bus)` rather `modPackage.Create(bus modules.Bus)` From da9774b84952d7ffd7118ecdafa19de6120f4e68 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:33:57 +0000 Subject: [PATCH 04/50] feat(shared): base_modules --- .../base_modules/integratable_module.go | 25 +++++++++++++++++++ .../base_modules/interruptable_module.go | 19 ++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 shared/modules/base_modules/integratable_module.go create mode 100644 shared/modules/base_modules/interruptable_module.go diff --git a/shared/modules/base_modules/integratable_module.go b/shared/modules/base_modules/integratable_module.go new file mode 100644 index 000000000..4b24254c4 --- /dev/null +++ b/shared/modules/base_modules/integratable_module.go @@ -0,0 +1,25 @@ +package base_modules + +import "github.com/pokt-network/pocket/shared/modules" + +var _ modules.IntegratableModule = &IntegratableModule{} + +// IntegratableModule is a base struct that is meant to be embedded in module structs that implement the interface `modules.IntegratableModule`. +// +// It provides the basic logic for the `SetBus` and `GetBus` methods and allows the implementer to reduce boilerplate code keeping the code +// DRY (Don't Repeat Yourself) while preserving the ability to override the methods if needed. +type IntegratableModule struct { + bus modules.Bus +} + +func NewIntegratableModule(bus modules.Bus) *IntegratableModule { + return &IntegratableModule{bus: bus} +} + +func (m *IntegratableModule) GetBus() modules.Bus { + return m.bus +} + +func (m *IntegratableModule) SetBus(bus modules.Bus) { + m.bus = bus +} diff --git a/shared/modules/base_modules/interruptable_module.go b/shared/modules/base_modules/interruptable_module.go new file mode 100644 index 000000000..9ad46f793 --- /dev/null +++ b/shared/modules/base_modules/interruptable_module.go @@ -0,0 +1,19 @@ +package base_modules + +import "github.com/pokt-network/pocket/shared/modules" + +var _ modules.InterruptableModule = &InterruptableModule{} + +// InterruptableModule is a noop implementation of the InterruptableModule interface. +// +// It is useful for modules that do not need any particular logic to be executed when started or stopped. +// In these situations, just embed this struct into the module struct. +type InterruptableModule struct{} + +func (*InterruptableModule) Start() error { + return nil +} + +func (*InterruptableModule) Stop() error { + return nil +} From f784dabc0039ff8477ca3e396923578679976c31 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:35:38 +0000 Subject: [PATCH 05/50] fix(utility): logging error when ApplyTransaction fails --- utility/block.go | 1 + 1 file changed, 1 insertion(+) diff --git a/utility/block.go b/utility/block.go index c3d94cbaf..f5ff620af 100644 --- a/utility/block.go +++ b/utility/block.go @@ -57,6 +57,7 @@ func (u *utilityContext) CreateAndApplyProposalBlock(proposer []byte, maxTransac } txResult, err := u.applyTx(txIndex, tx) if err != nil { + u.logger.Err(err).Msg("Error in ApplyTransaction") // TODO(#327): Properly implement 'unhappy path' for save points if err := u.revertLastSavePoint(); err != nil { return "", nil, err From 049023ce706e5b96e4a8ceba5068d071ba695f70 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:36:40 +0000 Subject: [PATCH 06/50] refactor(utility): implementing base_modules and options --- utility/module.go | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/utility/module.go b/utility/module.go index 24c7d64d5..0bc28b1f5 100644 --- a/utility/module.go +++ b/utility/module.go @@ -5,6 +5,7 @@ import ( "github.com/pokt-network/pocket/runtime/configs" "github.com/pokt-network/pocket/shared/mempool" "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" "github.com/pokt-network/pocket/utility/types" ) @@ -14,23 +15,28 @@ var ( ) type utilityModule struct { - bus modules.Bus + base_modules.IntegratableModule + base_modules.InterruptableModule + config *configs.UtilityConfig logger modules.Logger mempool mempool.TXMempool } -func Create(bus modules.Bus) (modules.Module, error) { - return new(utilityModule).Create(bus) +func Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return new(utilityModule).Create(bus, options...) } -func (*utilityModule) Create(bus modules.Bus) (modules.Module, error) { +func (*utilityModule) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { m := &utilityModule{} - if err := bus.RegisterModule(m); err != nil { - return nil, err + + for _, option := range options { + option(m) } + bus.RegisterModule(m) + runtimeMgr := bus.GetRuntimeMgr() cfg := runtimeMgr.GetConfig() @@ -47,25 +53,10 @@ func (u *utilityModule) Start() error { return nil } -func (u *utilityModule) Stop() error { - return nil -} - func (u *utilityModule) GetModuleName() string { return modules.UtilityModuleName } -func (u *utilityModule) SetBus(bus modules.Bus) { - u.bus = bus -} - -func (u *utilityModule) GetBus() modules.Bus { - if u.bus == nil { - u.logger.Fatal().Msg("Bus is not initialized") - } - return u.bus -} - func (u *utilityModule) GetMempool() mempool.TXMempool { return u.mempool } From a18ecf5932908fb99ec559a2c865328bd150caf4 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:37:25 +0000 Subject: [PATCH 07/50] fix(utility): using logger in message_handler --- utility/message_handler.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/utility/message_handler.go b/utility/message_handler.go index 88387c34c..93d43c870 100644 --- a/utility/message_handler.go +++ b/utility/message_handler.go @@ -3,7 +3,6 @@ package utility import ( "encoding/hex" "fmt" - "log" "math/big" "github.com/pokt-network/pocket/shared/codec" @@ -32,9 +31,7 @@ func (u *utilityModule) HandleMessage(message *anypb.Any) error { } else if err := u.CheckTransaction(txGossipMsg.Tx); err != nil { return err } - - log.Println("MEMPOOL: Successfully added a new message to the mempool!") - + u.logger.Info().Str("source", "MEMPOOL").Msg("Successfully added a new message to the mempool!") default: return types.ErrUnknownMessageType(message.MessageName()) } From e01c75cc03860b39faa301178a0a0ded39a3fb8e Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:37:57 +0000 Subject: [PATCH 08/50] docs(utility): changelog --- utility/doc/CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utility/doc/CHANGELOG.md b/utility/doc/CHANGELOG.md index 036ea583e..2269a5270 100644 --- a/utility/doc/CHANGELOG.md +++ b/utility/doc/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.28] - 2023-02-15 + +- Module embeds `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness +- Logging error if `ApplyTransaction` fails (it was completely ignored before and it was really hard to understand what was going on) + ## [0.0.0.27] - 2023-02-14 - Added a `Validatable` type for basic validation From 142d53bc6a869e549d1b42f37c1da58fa5555587 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:39:29 +0000 Subject: [PATCH 09/50] refactor(telemetry): implementing base_modules and options --- telemetry/module.go | 18 +++++++++--------- telemetry/noop_module.go | 14 ++++++++------ telemetry/prometheus_module.go | 34 ++++++++++++---------------------- 3 files changed, 29 insertions(+), 37 deletions(-) diff --git a/telemetry/module.go b/telemetry/module.go index 6904ed40e..ba4f4f2aa 100644 --- a/telemetry/module.go +++ b/telemetry/module.go @@ -2,6 +2,7 @@ package telemetry import ( "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" ) var ( @@ -12,14 +13,17 @@ var ( } ) -type telemetryModule struct{} +type telemetryModule struct { + base_modules.IntegratableModule + base_modules.InterruptableModule +} -func Create(bus modules.Bus) (modules.Module, error) { - return new(telemetryModule).Create(bus) +func Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return new(telemetryModule).Create(bus, options...) } // TODO(pocket/issues/99): Add a switch statement and configuration variable when support for other telemetry modules is added. -func (*telemetryModule) Create(bus modules.Bus) (modules.Module, error) { +func (*telemetryModule) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { runtimeMgr := bus.GetRuntimeMgr() cfg := runtimeMgr.GetConfig() @@ -32,8 +36,4 @@ func (*telemetryModule) Create(bus modules.Bus) (modules.Module, error) { } } -func (t *telemetryModule) GetModuleName() string { return modules.TelemetryModuleName } -func (t *telemetryModule) SetBus(bus modules.Bus) {} -func (t *telemetryModule) GetBus() modules.Bus { return nil } -func (t *telemetryModule) Start() error { return nil } -func (t *telemetryModule) Stop() error { return nil } +func (t *telemetryModule) GetModuleName() string { return modules.TelemetryModuleName } diff --git a/telemetry/noop_module.go b/telemetry/noop_module.go index 6a1316935..e2fd75184 100644 --- a/telemetry/noop_module.go +++ b/telemetry/noop_module.go @@ -22,16 +22,18 @@ func NOOP(args ...any) { logger.Global.Debug().Msg("NOOP") } -func CreateNoopTelemetryModule(bus modules.Bus) (modules.Module, error) { - var m NoopTelemetryModule - return m.Create(bus) +func CreateNoopTelemetryModule(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return new(NoopTelemetryModule).Create(bus, options...) } -func (*NoopTelemetryModule) Create(bus modules.Bus) (modules.Module, error) { +func (*NoopTelemetryModule) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { m := &NoopTelemetryModule{} - if err := bus.RegisterModule(m); err != nil { - return nil, err + + for _, option := range options { + option(m) } + + bus.RegisterModule(m) return m, nil } diff --git a/telemetry/prometheus_module.go b/telemetry/prometheus_module.go index 1dd0191df..08dc017ae 100644 --- a/telemetry/prometheus_module.go +++ b/telemetry/prometheus_module.go @@ -8,6 +8,7 @@ import ( "github.com/pokt-network/pocket/logger" "github.com/pokt-network/pocket/runtime/configs" "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -23,7 +24,9 @@ var ( // DISCUSS(team): Should the warning logs in this module be handled differently? type PrometheusTelemetryModule struct { - bus modules.Bus + base_modules.IntegratableModule + base_modules.InterruptableModule + config *configs.TelemetryConfig logger modules.Logger @@ -33,17 +36,19 @@ type PrometheusTelemetryModule struct { gaugeVectors map[string]prometheus.GaugeVec } -func CreatePrometheusTelemetryModule(bus modules.Bus) (modules.Module, error) { - var m PrometheusTelemetryModule - return m.Create(bus) +func CreatePrometheusTelemetryModule(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return new(PrometheusTelemetryModule).Create(bus, options...) } -func (*PrometheusTelemetryModule) Create(bus modules.Bus) (modules.Module, error) { +func (*PrometheusTelemetryModule) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { m := &PrometheusTelemetryModule{} - if err := bus.RegisterModule(m); err != nil { - return nil, err + + for _, option := range options { + option(m) } + bus.RegisterModule(m) + runtimeMgr := bus.GetRuntimeMgr() cfg := runtimeMgr.GetConfig() telemetryCfg := cfg.Telemetry @@ -79,25 +84,10 @@ func (m *PrometheusTelemetryModule) Start() error { return nil } -func (m *PrometheusTelemetryModule) Stop() error { - return nil -} - -func (m *PrometheusTelemetryModule) SetBus(bus modules.Bus) { - m.bus = bus -} - func (m *PrometheusTelemetryModule) GetModuleName() string { return fmt.Sprintf("%s_prometheus", modules.TelemetryModuleName) } -func (m *PrometheusTelemetryModule) GetBus() modules.Bus { - if m.bus == nil { - m.logger.Fatal().Msg("PocketBus is not initialized") - } - return m.bus -} - // EventMetricsAgent interface implementation func (m *PrometheusTelemetryModule) GetEventMetricsAgent() modules.EventMetricsAgent { return modules.EventMetricsAgent(m) From 3c84eae78ed6e5b33a071f7f1baffefb3f22a38a Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:39:47 +0000 Subject: [PATCH 10/50] docs(telemetry): changelog --- telemetry/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/telemetry/CHANGELOG.md b/telemetry/CHANGELOG.md index 6b4dfe9b2..197e07dcc 100644 --- a/telemetry/CHANGELOG.md +++ b/telemetry/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.8] - 2023-02-10 + +- Modules embed `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness + ## [0.0.0.7] - 2023-02-07 - Added GITHUB_WIKI tags where it was missing From 4eed45a8bef3f841f1bf9a00997c98232a677d29 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:41:20 +0000 Subject: [PATCH 11/50] feat(shared): ModulesRegistry interface --- shared/modules/modules_registry_module.go | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 shared/modules/modules_registry_module.go diff --git a/shared/modules/modules_registry_module.go b/shared/modules/modules_registry_module.go new file mode 100644 index 000000000..67f2ef340 --- /dev/null +++ b/shared/modules/modules_registry_module.go @@ -0,0 +1,10 @@ +package modules + +//go:generate mockgen -source=$GOFILE -destination=./mocks/modules_registry_mock.go -aux_files=github.com/pokt-network/pocket/shared/modules=module.go + +type ModulesRegistry interface { + // RegisterModule registers a Module with the ModuleRegistry + RegisterModule(module Module) + // GetModule returns a Module by name or nil if not found in the ModuleRegistry + GetModule(moduleName string) (Module, error) +} From b094622a4cda4c0c3d8b3d9ac01161a4628f109f Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:42:09 +0000 Subject: [PATCH 12/50] refactor(shared): updated bus interface to use ModuleRegistry --- shared/modules/bus_module.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shared/modules/bus_module.go b/shared/modules/bus_module.go index d71e06e84..5ca749891 100644 --- a/shared/modules/bus_module.go +++ b/shared/modules/bus_module.go @@ -19,7 +19,9 @@ type Bus interface { GetBusEvent() *messaging.PocketEnvelope GetEventBus() EventsChannel - RegisterModule(module Module) error + // Dependency Injection / Service Discovery + GetModulesRegistry() ModulesRegistry + RegisterModule(module Module) // Pocket modules GetPersistenceModule() PersistenceModule From e6e8fe535f682fc66e2ee867d278e5c623d49af2 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:43:34 +0000 Subject: [PATCH 13/50] refactor(persistence): implementing base_modules and options --- persistence/module.go | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/persistence/module.go b/persistence/module.go index 887fa8594..3f5f5faf2 100644 --- a/persistence/module.go +++ b/persistence/module.go @@ -11,6 +11,7 @@ import ( "github.com/pokt-network/pocket/runtime/configs" "github.com/pokt-network/pocket/runtime/genesis" "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" ) var ( @@ -23,7 +24,8 @@ var ( // TODO: convert address and public key to string not bytes in all account and actor functions // TODO: remove address parameter from all pool operations type persistenceModule struct { - bus modules.Bus + base_modules.IntegratableModule + config *configs.PersistenceConfig genesisState *genesis.GenesisState @@ -37,18 +39,21 @@ type persistenceModule struct { writeContext *PostgresContext // only one write context is allowed at a time } -func Create(bus modules.Bus) (modules.Module, error) { - return new(persistenceModule).Create(bus) +func Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return new(persistenceModule).Create(bus, options...) } -func (*persistenceModule) Create(bus modules.Bus) (modules.Module, error) { +func (*persistenceModule) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { m := &persistenceModule{ writeContext: nil, } - if err := bus.RegisterModule(m); err != nil { - return nil, err + + for _, option := range options { + option(m) } + bus.RegisterModule(m) + runtimeMgr := bus.GetRuntimeMgr() persistenceCfg := runtimeMgr.GetConfig().Persistence @@ -117,17 +122,6 @@ func (m *persistenceModule) GetModuleName() string { return modules.PersistenceModuleName } -func (m *persistenceModule) SetBus(bus modules.Bus) { - m.bus = bus -} - -func (m *persistenceModule) GetBus() modules.Bus { - if m.bus == nil { - logger.Global.Fatal().Msg("PocketBus is not initialized") - } - return m.bus -} - func (m *persistenceModule) NewRWContext(height int64) (modules.PersistenceRWContext, error) { if m.writeContext != nil && m.writeContext.conn != nil && !m.writeContext.conn.IsClosed() { return nil, fmt.Errorf("write context already exists") From f8ed453cf79a25082d1997f27b3c3c0d2ccbbdc9 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:44:01 +0000 Subject: [PATCH 14/50] docs(persistence): changelog --- persistence/docs/CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/persistence/docs/CHANGELOG.md b/persistence/docs/CHANGELOG.md index 8f790c2a6..b13b7a898 100644 --- a/persistence/docs/CHANGELOG.md +++ b/persistence/docs/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.36] - 2023-02-15 + +- Module now embeds `base_modules.IntegratableModule` for DRYness + ## [0.0.0.35] - 2023-02-15 - Add a few `nolint` comments to fix the code on main @@ -32,7 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.0.0.30] - 2023-02-04 -- Changed log lines to utilize new logger module. +- Changed log lines to utilize new logger module ## [0.0.0.29] - 2023-01-31 From 2a2154230f8c0787c0142453a1549b6afdfa99c1 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:46:11 +0000 Subject: [PATCH 15/50] refactor(consensus): implementing base_modules and options --- consensus/module.go | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/consensus/module.go b/consensus/module.go index 4201a4a7e..885569504 100644 --- a/consensus/module.go +++ b/consensus/module.go @@ -17,6 +17,7 @@ import ( coreTypes "github.com/pokt-network/pocket/shared/core/types" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" "google.golang.org/protobuf/types/known/anypb" ) @@ -30,7 +31,8 @@ var ( ) type consensusModule struct { - bus modules.Bus + base_modules.IntegratableModule + privateKey cryptoPocket.Ed25519PrivateKey consCfg *configs.ConsensusConfig @@ -136,11 +138,11 @@ func (m *consensusModule) ClearLeaderMessagesPool() { m.clearMessagesPool() } -func Create(bus modules.Bus) (modules.Module, error) { - return new(consensusModule).Create(bus) +func Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return new(consensusModule).Create(bus, options...) } -func (*consensusModule) Create(bus modules.Bus) (modules.Module, error) { +func (*consensusModule) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { leaderElectionMod, err := leader_election.Create(bus) if err != nil { return nil, err @@ -179,10 +181,13 @@ func (*consensusModule) Create(bus modules.Bus) (modules.Module, error) { hotstuffMempool: make(map[typesCons.HotstuffStep]*hotstuffFIFOMempool), } - if err := bus.RegisterModule(m); err != nil { - return nil, err + + for _, option := range options { + option(m) } + bus.RegisterModule(m) + runtimeMgr := bus.GetRuntimeMgr() consensusCfg := runtimeMgr.GetConfig().Consensus @@ -259,15 +264,8 @@ func (m *consensusModule) GetModuleName() string { return modules.ConsensusModuleName } -func (m *consensusModule) GetBus() modules.Bus { - if m.bus == nil { - logger.Global.Fatal().Msg("PocketBus is not initialized") - } - return m.bus -} - func (m *consensusModule) SetBus(pocketBus modules.Bus) { - m.bus = pocketBus + m.IntegratableModule.SetBus(pocketBus) if m.paceMaker != nil { m.paceMaker.SetBus(pocketBus) } From e70b3081fbdcc0991df70a0fa45ab67af335ada8 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:47:08 +0000 Subject: [PATCH 16/50] refactor(logger): implementing base_modules and options --- logger/module.go | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/logger/module.go b/logger/module.go index 918b9ae75..2f7e26ebb 100644 --- a/logger/module.go +++ b/logger/module.go @@ -7,12 +7,16 @@ import ( "github.com/pokt-network/pocket/runtime/configs" "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" "github.com/rs/zerolog" ) var _ modules.Module = &loggerModule{} type loggerModule struct { + base_modules.IntegratableModule + base_modules.InterruptableModule + zerolog.Logger bus modules.Bus config *configs.LoggerConfig @@ -49,24 +53,27 @@ func init() { } } -func Create(bus modules.Bus) (modules.Module, error) { - return new(loggerModule).Create(bus) +func Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return new(loggerModule).Create(bus, options...) } func (*loggerModule) CreateLoggerForModule(moduleName string) modules.Logger { return Global.Logger.With().Str("module", moduleName).Logger() } -func (*loggerModule) Create(bus modules.Bus) (modules.Module, error) { +func (*loggerModule) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { runtimeMgr := bus.GetRuntimeMgr() cfg := runtimeMgr.GetConfig() m := &loggerModule{ config: cfg.Logger, } - if err := bus.RegisterModule(m); err != nil { - return nil, err + + for _, option := range options { + option(m) } + bus.RegisterModule(m) + Global.config = m.config Global.CreateLoggerForModule("global") @@ -95,25 +102,10 @@ func (m *loggerModule) Start() error { return nil } -func (m *loggerModule) Stop() error { - return nil -} - func (m *loggerModule) GetModuleName() string { return modules.LoggerModuleName } -func (m *loggerModule) SetBus(bus modules.Bus) { - m.bus = bus -} - -func (m *loggerModule) GetBus() modules.Bus { - if m.bus == nil { - m.Logger.Fatal().Msg("Bus is not initialized") - } - return m.bus -} - func (m *loggerModule) GetLogger() modules.Logger { return m.Logger } From 0d20adae5ecd40c3179c1c51749dd42e9594d198 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:47:23 +0000 Subject: [PATCH 17/50] docs(logger): changelog --- logger/docs/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/logger/docs/CHANGELOG.md b/logger/docs/CHANGELOG.md index abba623a7..fc8acb230 100644 --- a/logger/docs/CHANGELOG.md +++ b/logger/docs/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.7] - 2023-02-10 + +- Module embeds `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness + ## [0.0.0.6] - 2023-02-09 - `loggerModule` type-checking for `modules.Module` From 963212aa5e2f3c230acb6a8b994f8a732cab32af Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:48:57 +0000 Subject: [PATCH 18/50] refactor(rpc): implementing base_modules and options --- rpc/module.go | 39 +++++++++++++++------------------------ rpc/noop_module.go | 18 ++++++------------ rpc/server.go | 11 ++--------- 3 files changed, 23 insertions(+), 45 deletions(-) diff --git a/rpc/module.go b/rpc/module.go index c05b67b74..17537d70a 100644 --- a/rpc/module.go +++ b/rpc/module.go @@ -9,35 +9,41 @@ import ( "github.com/pokt-network/pocket/logger" "github.com/pokt-network/pocket/runtime/configs" "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" ) var _ modules.RPCModule = &rpcModule{} type rpcModule struct { - bus modules.Bus + base_modules.IntegratableModule + base_modules.InterruptableModule + logger modules.Logger config *configs.RPCConfig } -func Create(bus modules.Bus) (modules.Module, error) { - return new(rpcModule).Create(bus) +func Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return new(rpcModule).Create(bus, options...) } -func (*rpcModule) Create(bus modules.Bus) (modules.Module, error) { +func (*rpcModule) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { runtimeMgr := bus.GetRuntimeMgr() cfg := runtimeMgr.GetConfig() rpcCfg := cfg.RPC - rpcMod := modules.RPCModule(&rpcModule{ + m := modules.RPCModule(&rpcModule{ config: rpcCfg, }) if !rpcCfg.Enabled { - rpcMod = &noopRpcModule{} + m = &noopRpcModule{} } - if err := bus.RegisterModule(rpcMod); err != nil { - return nil, err + + for _, option := range options { + option(m) } - return rpcMod, nil + bus.RegisterModule(m) + + return m, nil } func (u *rpcModule) Start() error { @@ -46,21 +52,6 @@ func (u *rpcModule) Start() error { return nil } -func (u *rpcModule) Stop() error { - return nil -} - func (u *rpcModule) GetModuleName() string { return modules.RPCModuleName } - -func (u *rpcModule) SetBus(bus modules.Bus) { - u.bus = bus -} - -func (u *rpcModule) GetBus() modules.Bus { - if u.bus == nil { - u.logger.Fatal().Msg("Bus is not initialized") - } - return u.bus -} diff --git a/rpc/noop_module.go b/rpc/noop_module.go index daad5b40c..1c7401b80 100644 --- a/rpc/noop_module.go +++ b/rpc/noop_module.go @@ -4,31 +4,25 @@ import ( "log" "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" ) var _ modules.RPCModule = &noopRpcModule{} -type noopRpcModule struct{} +type noopRpcModule struct { + base_modules.IntegratableModule + base_modules.InterruptableModule +} func (m *noopRpcModule) GetModuleName() string { return "noop_rpc_module" } -func (m *noopRpcModule) Create(bus modules.Bus) (modules.Module, error) { +func (m *noopRpcModule) Create(bus modules.Bus, _ ...modules.ModuleOption) (modules.Module, error) { return &rpcModule{}, nil } -func (m *noopRpcModule) SetBus(_ modules.Bus) {} - -func (m *noopRpcModule) GetBus() modules.Bus { - return nil -} - func (m *noopRpcModule) Start() error { log.Println("[WARN] RPC server: OFFLINE") return nil } - -func (m *noopRpcModule) Stop() error { - return nil -} diff --git a/rpc/server.go b/rpc/server.go index 087b3ea06..696c78a58 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -7,10 +7,11 @@ import ( "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" ) type rpcServer struct { - bus modules.Bus + base_modules.IntegratableModule logger modules.Logger } @@ -66,11 +67,3 @@ func (s *rpcServer) StartRPC(port string, timeout uint64, logger *modules.Logger s.logger.Fatal().Err(err).Msg("RPC server failed to start") } } - -func (s *rpcServer) SetBus(bus modules.Bus) { - s.bus = bus -} - -func (s *rpcServer) GetBus() modules.Bus { - return s.bus -} From 8871a3d3c13d8bb9c0c9777c6fca1f5f713575fe Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:49:19 +0000 Subject: [PATCH 19/50] docs(rpc): changelog --- rpc/doc/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rpc/doc/CHANGELOG.md b/rpc/doc/CHANGELOG.md index 869d12656..9eb2ed4ba 100644 --- a/rpc/doc/CHANGELOG.md +++ b/rpc/doc/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.11] - 2023-02-10 + +- Updated modules to embed `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness + ## [0.0.0.10] - 2023-02-07 - Added GITHUB_WIKI tags where it was missing From 8d50538f2c0f2c90164c3179e9dd3c8952ed4dcf Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 17:50:18 +0000 Subject: [PATCH 20/50] feat(runtime): ModulesRegistry implementation --- runtime/modules_registry.go | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 runtime/modules_registry.go diff --git a/runtime/modules_registry.go b/runtime/modules_registry.go new file mode 100644 index 000000000..85b9c2c75 --- /dev/null +++ b/runtime/modules_registry.go @@ -0,0 +1,35 @@ +package runtime + +import ( + "sync" + + "github.com/pokt-network/pocket/shared/modules" +) + +var _ modules.ModulesRegistry = &modulesRegistry{} + +type modulesRegistry struct { + m sync.Mutex + registry map[string]modules.Module +} + +func NewModulesRegistry() *modulesRegistry { + return &modulesRegistry{ + registry: make(map[string]modules.Module), + } +} + +func (m *modulesRegistry) RegisterModule(module modules.Module) { + m.m.Lock() + defer m.m.Unlock() + m.registry[module.GetModuleName()] = module +} + +func (m *modulesRegistry) GetModule(moduleName string) (modules.Module, error) { + m.m.Lock() + defer m.m.Unlock() + if mod, ok := m.registry[moduleName]; ok { + return mod, nil + } + return nil, ErrModuleNotRegistered(moduleName) +} From 5141f07a14a35419c7c4cff61994551cc66eb606 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:16:23 +0000 Subject: [PATCH 21/50] feat(p2p): implementing base_modules and options --- p2p/module.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/p2p/module.go b/p2p/module.go index c43a424b7..307d6a5aa 100644 --- a/p2p/module.go +++ b/p2p/module.go @@ -13,6 +13,7 @@ import ( cryptoPocket "github.com/pokt-network/pocket/shared/crypto" "github.com/pokt-network/pocket/shared/messaging" "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" "github.com/pokt-network/pocket/telemetry" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" @@ -21,7 +22,7 @@ import ( var _ modules.P2PModule = &p2pModule{} type p2pModule struct { - bus modules.Bus + base_modules.IntegratableModule listener typesP2P.Transport address cryptoPocket.Address @@ -34,8 +35,8 @@ type p2pModule struct { injectedCurrentHeightProvider providers.CurrentHeightProvider } -func Create(bus modules.Bus) (modules.Module, error) { - return new(p2pModule).Create(bus) +func Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return new(p2pModule).Create(bus, options...) } // TODO(#429): need to define a better pattern for dependency injection. Currently we are probably limiting ourselves by having a common constructor `Create(bus modules.Bus) (modules.Module, error)` for all modules. @@ -69,13 +70,16 @@ func CreateWithProviders(bus modules.Bus, addrBookProvider providers.AddrBookPro return m, nil } -func (*p2pModule) Create(bus modules.Bus) (modules.Module, error) { +func (*p2pModule) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { log.Println("Creating network module") m := &p2pModule{} - if err := bus.RegisterModule(m); err != nil { - return nil, err + + for _, option := range options { + option(m) } + bus.RegisterModule(m) + runtimeMgr := bus.GetRuntimeMgr() cfg := runtimeMgr.GetConfig() p2pCfg := cfg.P2P From 1d98c9f19b67800db1cab53ddf1736ab8c3e92ab Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:18:42 +0000 Subject: [PATCH 22/50] refactor(state_sync): implementing base_modules and options --- consensus/state_sync/module.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/consensus/state_sync/module.go b/consensus/state_sync/module.go index 74bcf353b..4e45b06dd 100644 --- a/consensus/state_sync/module.go +++ b/consensus/state_sync/module.go @@ -55,20 +55,21 @@ type stateSync struct { logPrefix string } -func CreateStateSync(bus modules.Bus) (modules.Module, error) { - var m stateSync - return m.Create(bus) +func CreateStateSync(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return new(stateSync).Create(bus, options...) } -func (*stateSync) Create(bus modules.Bus) (modules.Module, error) { +func (*stateSync) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { m := &stateSync{ logPrefix: DefaultLogPrefix, } - if err := bus.RegisterModule(m); err != nil { - return nil, err + for _, option := range options { + option(m) } + bus.RegisterModule(m) + // when node is starting, it is in sync mode, as it might need to bootstrap to the latest state m.currentMode = Sync m.serverMode = false From f5f977740749aef66cba2d6fbabacb848ef0347b Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:25:05 +0000 Subject: [PATCH 23/50] refactor(runtime): bus uses ModulesRegistry and logger --- runtime/bus.go | 80 ++++++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/runtime/bus.go b/runtime/bus.go index 3289ba9f2..014dbc585 100644 --- a/runtime/bus.go +++ b/runtime/bus.go @@ -4,6 +4,7 @@ import ( "log" "sync" + "github.com/pokt-network/pocket/logger" "github.com/pokt-network/pocket/runtime/defaults" "github.com/pokt-network/pocket/shared/messaging" "github.com/pokt-network/pocket/shared/modules" @@ -21,7 +22,7 @@ type bus struct { // Node events channel modules.EventsChannel - modulesMap map[string]modules.Module + modulesRegistry modules.ModulesRegistry runtimeMgr modules.RuntimeMgr } @@ -34,17 +35,20 @@ func (b *bus) Create(runtimeMgr modules.RuntimeMgr) (modules.Bus, error) { bus := &bus{ channel: make(modules.EventsChannel, defaults.DefaultBusBufferSize), - runtimeMgr: runtimeMgr, - modulesMap: make(map[string]modules.Module), + runtimeMgr: runtimeMgr, + modulesRegistry: NewModulesRegistry(), } return bus, nil } -func (m *bus) RegisterModule(module modules.Module) error { +func (m *bus) GetModulesRegistry() modules.ModulesRegistry { + return m.modulesRegistry +} + +func (m *bus) RegisterModule(module modules.Module) { module.SetBus(m) - m.modulesMap[module.GetModuleName()] = module - return nil + m.modulesRegistry.RegisterModule(module) } func (m *bus) PublishEventToBus(e *messaging.PocketEnvelope) { @@ -61,41 +65,41 @@ func (m *bus) GetEventBus() modules.EventsChannel { } func (m *bus) GetPersistenceModule() modules.PersistenceModule { - if mod, ok := m.modulesMap[modules.PersistenceModuleName]; ok { - return mod.(modules.PersistenceModule) + mod, err := m.modulesRegistry.GetModule(modules.PersistenceModuleName) + if err != nil { + logger.Global.Logger.Fatal().Err(err).Msg("failed to get module from modulesRegistry") } - log.Fatalf("%s", ErrModuleNotRegistered("persistence")) - return nil + return mod.(modules.PersistenceModule) } func (m *bus) GetP2PModule() modules.P2PModule { - if mod, ok := m.modulesMap[modules.P2PModuleName]; ok { - return mod.(modules.P2PModule) + mod, err := m.modulesRegistry.GetModule(modules.P2PModuleName) + if err != nil { + logger.Global.Logger.Fatal().Err(err).Msg("failed to get module from modulesRegistry") } - log.Fatalf("%s", ErrModuleNotRegistered("P2P")) - return nil + return mod.(modules.P2PModule) } func (m *bus) GetUtilityModule() modules.UtilityModule { - if mod, ok := m.modulesMap[modules.UtilityModuleName]; ok { - return mod.(modules.UtilityModule) + mod, err := m.modulesRegistry.GetModule(modules.UtilityModuleName) + if err != nil { + logger.Global.Logger.Fatal().Err(err).Msg("failed to get module from modulesRegistry") } - log.Fatalf("%s", ErrModuleNotRegistered(modules.UtilityModuleName)) - return nil + return mod.(modules.UtilityModule) } func (m *bus) GetConsensusModule() modules.ConsensusModule { - if mod, ok := m.modulesMap[modules.ConsensusModuleName]; ok { - return mod.(modules.ConsensusModule) + mod, err := m.modulesRegistry.GetModule(modules.ConsensusModuleName) + if err != nil { + logger.Global.Logger.Fatal().Err(err).Msg("failed to get module from modulesRegistry") } - log.Fatalf("%s", ErrModuleNotRegistered(modules.ConsensusModuleName)) - return nil + return mod.(modules.ConsensusModule) } func (m *bus) GetTelemetryModule() modules.TelemetryModule { for _, moduleName := range telemetry.ImplementationNames { - telemetryMod, ok := m.modulesMap[moduleName] - if ok { + telemetryMod, err := m.modulesRegistry.GetModule(moduleName) + if err == nil { return telemetryMod.(modules.TelemetryModule) } } @@ -107,26 +111,32 @@ func (m *bus) GetTelemetryModule() modules.TelemetryModule { if err != nil { log.Fatalf("failed to create noop telemetry module: %v", err) } - if err := m.RegisterModule(noopModule); err != nil { - log.Fatalf("[ERROR] Failed to register telemetry module: %v", err.Error()) - } + m.RegisterModule(noopModule) return noopModule.(modules.TelemetryModule) } func (m *bus) GetLoggerModule() modules.LoggerModule { - if mod, ok := m.modulesMap[modules.LoggerModuleName]; ok { - return mod.(modules.LoggerModule) + mod, err := m.modulesRegistry.GetModule(modules.LoggerModuleName) + if err != nil { + logger.Global.Logger.Fatal().Err(err).Msg("failed to get module from modulesRegistry") } - log.Fatalf("%s", ErrModuleNotRegistered(modules.LoggerModuleName)) - return nil + return mod.(modules.LoggerModule) } func (m *bus) GetRPCModule() modules.RPCModule { - if mod, ok := m.modulesMap[modules.RPCModuleName]; ok { - return mod.(modules.RPCModule) + mod, err := m.modulesRegistry.GetModule(modules.RPCModuleName) + if err != nil { + logger.Global.Logger.Fatal().Err(err).Msg("failed to get module from modulesRegistry") + } + return mod.(modules.RPCModule) +} + +func (m *bus) GetStateMachineModule() modules.StateMachineModule { + mod, err := m.modulesRegistry.GetModule(modules.StateMachineModuleName) + if err != nil { + logger.Global.Logger.Fatal().Err(err).Msg("failed to get module from modulesRegistry") } - log.Fatalf("%s", ErrModuleNotRegistered(modules.RPCModuleName)) - return nil + return mod.(modules.StateMachineModule) } func (m *bus) GetRuntimeMgr() modules.RuntimeMgr { From 4c5f50cbd19648c625df6076e381de07a397a6cc Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:25:55 +0000 Subject: [PATCH 24/50] fix(runtime): StateMachine doesn't exist yet :) --- runtime/bus.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/runtime/bus.go b/runtime/bus.go index 014dbc585..23c16aeff 100644 --- a/runtime/bus.go +++ b/runtime/bus.go @@ -131,14 +131,6 @@ func (m *bus) GetRPCModule() modules.RPCModule { return mod.(modules.RPCModule) } -func (m *bus) GetStateMachineModule() modules.StateMachineModule { - mod, err := m.modulesRegistry.GetModule(modules.StateMachineModuleName) - if err != nil { - logger.Global.Logger.Fatal().Err(err).Msg("failed to get module from modulesRegistry") - } - return mod.(modules.StateMachineModule) -} - func (m *bus) GetRuntimeMgr() modules.RuntimeMgr { return m.runtimeMgr } From 7023ca0c8328a7dae3b67aa93bbd60ebcbb2dc89 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:27:32 +0000 Subject: [PATCH 25/50] refactor(runtime): errors referring ModulesRegistry --- runtime/errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/errors.go b/runtime/errors.go index 7ec9e1cc8..6750fd52a 100644 --- a/runtime/errors.go +++ b/runtime/errors.go @@ -4,7 +4,7 @@ import ( "fmt" ) -const ModuleNotRegisteredError = "module %s not found, did you call bus.RegisterModule() ?" +const ModuleNotRegisteredError = "module %s not found, did you call ModulesRegistry.RegisterModule() ?" func ErrModuleNotRegistered(moduleName string) error { return fmt.Errorf(ModuleNotRegisteredError, moduleName) From 34f3d8726bdf07605005808005a96eb5517e5b63 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:28:48 +0000 Subject: [PATCH 26/50] refactor(runtime): runtimeManager implements base IntegratableModule --- runtime/manager.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/runtime/manager.go b/runtime/manager.go index f08a52212..2dce03d22 100644 --- a/runtime/manager.go +++ b/runtime/manager.go @@ -16,12 +16,15 @@ import ( "github.com/pokt-network/pocket/runtime/genesis" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" "github.com/spf13/viper" ) var _ modules.RuntimeMgr = &Manager{} type Manager struct { + base_modules.IntegratableModule + config *configs.Config genesisState *genesis.GenesisState @@ -39,7 +42,7 @@ func NewManager(config *configs.Config, gen *genesis.GenesisState, options ...fu mgr.config = config mgr.genesisState = gen mgr.clock = clock.New() - mgr.bus = bus + mgr.SetBus(bus) for _, o := range options { o(mgr) @@ -77,10 +80,6 @@ func (m *Manager) GetGenesis() *genesis.GenesisState { return m.genesisState } -func (b *Manager) GetBus() modules.Bus { - return b.bus -} - func (m *Manager) GetClock() clock.Clock { return m.clock } From 74d012fbb15f6e217d0d61e2b0656db85a994c2f Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:29:36 +0000 Subject: [PATCH 27/50] feat(state_machine): KISS FSM implementation --- Makefile | 5 ++ state_machine/docs/CHANGELOG.md | 17 +++++ state_machine/docs/README.md | 64 +++++++++++++++++ state_machine/docs/state-machine.diagram.md | 14 ++++ state_machine/fsm.go | 67 ++++++++++++++++++ state_machine/module.go | 78 +++++++++++++++++++++ state_machine/visualizer/main.go | 23 ++++++ 7 files changed, 268 insertions(+) create mode 100644 state_machine/docs/CHANGELOG.md create mode 100644 state_machine/docs/README.md create mode 100644 state_machine/docs/state-machine.diagram.md create mode 100644 state_machine/fsm.go create mode 100644 state_machine/module.go create mode 100644 state_machine/visualizer/main.go diff --git a/Makefile b/Makefile index b78e88a68..16504dde3 100644 --- a/Makefile +++ b/Makefile @@ -304,6 +304,11 @@ generate_cli_commands_docs: ## (Re)generates the CLI commands docs (this is mean cd app/client/cli/docgen && go run . echo "CLI commands docs generated in ${cli_docs_dir}" +.PHONY: generate_node_state_machine_diagram +generate_node_state_machine_diagram: ## (Re)generates the Node State Machine diagram + go run ./state_machine/visualizer/main.go + echo "Node State Machine diagram generated in state_machine/docs/state-machine.diagram.md" + .PHONY: test_all test_all: ## Run all go unit tests go test -p 1 -count=1 ./... diff --git a/state_machine/docs/CHANGELOG.md b/state_machine/docs/CHANGELOG.md new file mode 100644 index 000000000..efab941aa --- /dev/null +++ b/state_machine/docs/CHANGELOG.md @@ -0,0 +1,17 @@ +# Changelog + +All notable changes to this module will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.0.0.1] - 2023-02-10 + +- Introduced this `CHANGELOG.md` and `README.md` +- Added `StateMachineModule` implementation with a POC of the finite state machine that will be used to manage the node lifecycle +- Added `StateMachine` diagram generator (linked in README.md) +- Integrated the `StateMachine` with the `bus` to propagate `StateMachineTransitionEvent` events whenever they occur + + diff --git a/state_machine/docs/README.md b/state_machine/docs/README.md new file mode 100644 index 000000000..5a2239b03 --- /dev/null +++ b/state_machine/docs/README.md @@ -0,0 +1,64 @@ +# State Machine Module + +> ⚠️ Work in progress ⚠️ - At the time of writing this document, the architecture is still being defined. +> +> This is pretty much a POC at the moment. + +This document outlines the purpose of this module, its components and how they all interact with the other modules. + +## Contents +- [Overview](#overview) +- [Code Structure](#code-structure) +- [High Level Architecture](#high-level-architecture) + - [FSM primer](#fsm-primer) +- [Current State Machine Definition](#current-state-machine-definition) + +## Overview + +The `StateMachine` module implements a FSM (Finite State Machine) that is responsible for managing the node lifecycle since its internal behaviour can be different depending on certain conditions that are used to determine the current state. + +In a nutshell: The FSM guarantees that the node is always in one specific state and verifies state transition (i.e. edges) to/from valid states (i.e. vertices). + +## Code Structure + +```bash +├── docs +│ ├── CHANGELOG.md # Changelog +│ ├── README.md # You are here +│ └── state-machine.diagram.md # State machine diagram (generated by visualizer/main.go) +├── fsm.go # Finite State Machine definition (events, states, transitions) +├── module.go # Implementation of the StateMachine module +└── visualizer + └── main.go # State machine diagram generator +``` + +## High Level Architecture + +High-level implementation details: + +- The [github.com/looplab/fsm](https://github.com/looplab/fsm) library is used to implement the FSM +- Pocket builds a wrapper around `looplab/fsm` to integrate with the other modules +- The `StateMachineModule` can be accessed via the `bus` from any other `IntegratableModule` +- State machine transitions emit `StateMachineTransitionEvent` events that subscribed pocket modules can listen to +- The `node` has a central [event handler](../../shared/node.go) for events that fan-out event handling to the relevant modules during state transitions + +### FSM primer + +The FSM has a declarative definition of an initial state and a set of transitions that have an `Event`, `Source` states and a single `Destination` state. + +These are the main building blocks: + +- **Event**: An event is a string that represents an action that can trigger a transition. For example, the event `start` can be used to trigger a transition from the `stopped` state to the `starting` state. +- **State**: A state is a string that represents a state that the FSM can be in. For example, the state `stopped` can be used to represent a state where the node is not running. +- **Callback**: A callback is a function that is called when a transition occurs. For example, a callback can be used to log the transition or to perform some other action. (there are various types of callbacks that essentially drive the WHEN they are called and help building more complex behaviours like transition cancelling, etc. but we won't cover them here, please read the FSM library documentation for more details) + +## Current State Machine Definition + +A diagram of the current state machine definition can be found [here](state-machine.diagram.md) +If you make any changes to it, you can re-generate it via: + +```bash +make generate_node_state_machine_diagram +``` + + diff --git a/state_machine/docs/state-machine.diagram.md b/state_machine/docs/state-machine.diagram.md new file mode 100644 index 000000000..651f4b20b --- /dev/null +++ b/state_machine/docs/state-machine.diagram.md @@ -0,0 +1,14 @@ +# Node Finite State Machine + +The following diagram displays the various states and events that govern the functionality of the node. + +```mermaid +stateDiagram-v2 + [*] --> Stopped + Consensus_SyncMode --> Consensus_Synced: Consensus_IsCaughtUp + Consensus_Unsynched --> Consensus_SyncMode: Consensus_IsSyncing + P2P_Bootstrapped --> Consensus_Synced: Consensus_IsCaughtUp + P2P_Bootstrapped --> Consensus_Unsynched: Consensus_IsUnsynched + P2P_Bootstrapping --> P2P_Bootstrapped: P2P_IsBootstrapped + Stopped --> P2P_Bootstrapping: Start +``` \ No newline at end of file diff --git a/state_machine/fsm.go b/state_machine/fsm.go new file mode 100644 index 000000000..df6051eb4 --- /dev/null +++ b/state_machine/fsm.go @@ -0,0 +1,67 @@ +package state_machine + +import ( + "github.com/looplab/fsm" + + coreTypes "github.com/pokt-network/pocket/shared/core/types" +) + +// NewNodeFSM returns a KISS Finite State Machine that is meant to mimick the various "states" of the node. +// +// The current set of states and events captures a limited subset of state sync and P2P bootstrapping-related events. +// More states & events in any of the modules supported should be added and documented here. +func NewNodeFSM(callbacks *fsm.Callbacks, options ...func(*fsm.FSM)) *fsm.FSM { + var cb = fsm.Callbacks{} + if callbacks != nil { + cb = *callbacks + } + + stateMachine := fsm.NewFSM( + string(coreTypes.StateMachineState_Stopped), + fsm.Events{ + { + Name: string(coreTypes.StateMachineEvent_Start), + Src: []string{ + string(coreTypes.StateMachineState_Stopped), + }, + Dst: string(coreTypes.StateMachineState_P2P_Bootstrapping), + }, + { + Name: string(coreTypes.StateMachineEvent_P2P_IsBootstrapped), + Src: []string{ + string(coreTypes.StateMachineState_P2P_Bootstrapping), + }, + Dst: string(coreTypes.StateMachineState_P2P_Bootstrapped), + }, + { + Name: string(coreTypes.StateMachineEvent_Consensus_IsUnsynched), + Src: []string{ + string(coreTypes.StateMachineState_P2P_Bootstrapped), + }, + Dst: string(coreTypes.StateMachineState_Consensus_Unsynched), + }, + { + Name: string(coreTypes.StateMachineEvent_Consensus_IsSyncing), + Src: []string{ + string(coreTypes.StateMachineState_Consensus_Unsynched), + }, + Dst: string(coreTypes.StateMachineState_Consensus_SyncMode), + }, + { + Name: string(coreTypes.StateMachineEvent_Consensus_IsCaughtUp), + Src: []string{ + string(coreTypes.StateMachineState_P2P_Bootstrapped), + string(coreTypes.StateMachineState_Consensus_SyncMode), + }, + Dst: string(coreTypes.StateMachineState_Consensus_Synced), + }, + }, + cb, + ) + + for _, option := range options { + option(stateMachine) + } + + return stateMachine +} diff --git a/state_machine/module.go b/state_machine/module.go new file mode 100644 index 000000000..d8410b3f0 --- /dev/null +++ b/state_machine/module.go @@ -0,0 +1,78 @@ +package state_machine + +import ( + "context" + + "github.com/looplab/fsm" + "github.com/pokt-network/pocket/logger" + coreTypes "github.com/pokt-network/pocket/shared/core/types" + "github.com/pokt-network/pocket/shared/messaging" + "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" +) + +var _ modules.StateMachineModule = &stateMachineModule{} + +type stateMachineModule struct { + base_modules.IntegratableModule + base_modules.InterruptableModule + + *fsm.FSM + logger modules.Logger +} + +func Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return new(stateMachineModule).Create(bus, options...) +} + +func (*stateMachineModule) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + m := &stateMachineModule{ + logger: logger.Global.CreateLoggerForModule(modules.StateMachineModuleName), + } + + m.FSM = NewNodeFSM(&fsm.Callbacks{ + "enter_state": func(_ context.Context, e *fsm.Event) { + m.logger.Info(). + Str("event", e.Event). + Str("sourceState", e.Src). + Msgf("entering state %s", e.Dst) + + newStateMachineTransitionEvent, err := messaging.PackMessage(&messaging.StateMachineTransitionEvent{ + Event: e.Event, + PreviousState: e.Src, + NewState: e.Dst, + }) + if err != nil { + m.logger.Fatal().Err(err).Msg("failed to pack state machine transition event") + } + + bus.PublishEventToBus(newStateMachineTransitionEvent) + }, + }) + + for _, option := range options { + option(m) + } + + bus.RegisterModule(m) + + return m, nil +} + +func (m *stateMachineModule) GetModuleName() string { + return modules.StateMachineModuleName +} + +func (m *stateMachineModule) SendEvent(event coreTypes.StateMachineEvent, args ...any) error { + return m.Event(context.TODO(), string(event), args) +} + +// options + +func WithCustomStateMachine(stateMachine *fsm.FSM) modules.ModuleOption { + return func(m modules.InitializableModule) { + if m, ok := m.(*stateMachineModule); ok { + m.FSM = stateMachine + } + } +} diff --git a/state_machine/visualizer/main.go b/state_machine/visualizer/main.go new file mode 100644 index 000000000..78824db40 --- /dev/null +++ b/state_machine/visualizer/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "os" + + "github.com/looplab/fsm" + "github.com/pokt-network/pocket/state_machine" +) + +func main() { + stateMachine := state_machine.NewNodeFSM(nil) + + mermaidStateDiagram, err := fsm.VisualizeForMermaidWithGraphType(stateMachine, fsm.StateDiagram) + if err != nil { + panic(err) + } + + header := "# Node Finite State Machine\n\nThe following diagram displays the various states and events that govern the functionality of the node.\n\n```mermaid\n" + footer := "```" + if err := os.WriteFile("state_machine/docs/state-machine.diagram.md", []byte(header+mermaidStateDiagram+footer), 0o600); err != nil { + panic(err) + } +} From d697a7f1eb8e799ebb6f051bf831b377e0a4af98 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:31:26 +0000 Subject: [PATCH 28/50] feat(shared): state_machine integration with node --- shared/node.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/shared/node.go b/shared/node.go index 4af232ea9..4f6a2a238 100644 --- a/shared/node.go +++ b/shared/node.go @@ -6,9 +6,11 @@ import ( "github.com/pokt-network/pocket/p2p" "github.com/pokt-network/pocket/persistence" "github.com/pokt-network/pocket/rpc" + coreTypes "github.com/pokt-network/pocket/shared/core/types" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" "github.com/pokt-network/pocket/shared/messaging" "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/state_machine" "github.com/pokt-network/pocket/telemetry" "github.com/pokt-network/pocket/utility" ) @@ -26,12 +28,13 @@ func NewNodeWithP2PAddress(address cryptoPocket.Address) *Node { return &Node{p2pAddress: address} } -func CreateNode(bus modules.Bus) (modules.Module, error) { - return new(Node).Create(bus) +func CreateNode(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return new(Node).Create(bus, options...) } -func (m *Node) Create(bus modules.Bus) (modules.Module, error) { - for _, mod := range []func(modules.Bus) (modules.Module, error){ +func (m *Node) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + for _, mod := range []func(modules.Bus, ...modules.ModuleOption) (modules.Module, error){ + state_machine.Create, persistence.Create, utility.Create, consensus.Create, @@ -61,6 +64,10 @@ func (node *Node) Start() error { // IMPORTANT: Order of module startup here matters + if err := node.GetBus().GetStateMachineModule().Start(); err != nil { + return err + } + if err := node.GetBus().GetTelemetryModule().Start(); err != nil { return err } @@ -124,6 +131,9 @@ func (node *Node) handleEvent(message *messaging.PocketEnvelope) error { switch contentType { case messaging.NodeStartedEventType: logger.Global.Info().Msg("Received NodeStartedEvent") + if err := node.GetBus().GetStateMachineModule().SendEvent(coreTypes.StateMachineEvent_Start); err != nil { + return err + } case consensus.HotstuffMessageContentType: return node.GetBus().GetConsensusModule().HandleMessage(message.Content) case consensus.StateSyncMessageContentType: From 8e89219484478dfb93d06fd5970504ca718f1b2b Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:31:54 +0000 Subject: [PATCH 29/50] feat(shared): FSM states and events --- shared/core/types/events.go | 13 +++++++++++++ shared/core/types/states.go | 14 ++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 shared/core/types/events.go create mode 100644 shared/core/types/states.go diff --git a/shared/core/types/events.go b/shared/core/types/events.go new file mode 100644 index 000000000..9321f1eb8 --- /dev/null +++ b/shared/core/types/events.go @@ -0,0 +1,13 @@ +package types + +type StateMachineEvent string + +const ( + StateMachineEvent_Start StateMachineEvent = "Start" + + StateMachineEvent_P2P_IsBootstrapped StateMachineEvent = "P2P_IsBootstrapped" + + StateMachineEvent_Consensus_IsUnsynched StateMachineEvent = "Consensus_IsUnsynched" + StateMachineEvent_Consensus_IsSyncing StateMachineEvent = "Consensus_IsSyncing" + StateMachineEvent_Consensus_IsCaughtUp StateMachineEvent = "Consensus_IsCaughtUp" +) diff --git a/shared/core/types/states.go b/shared/core/types/states.go new file mode 100644 index 000000000..adc8be077 --- /dev/null +++ b/shared/core/types/states.go @@ -0,0 +1,14 @@ +package types + +type StateMachineState string + +const ( + StateMachineState_Stopped StateMachineState = "Stopped" + + StateMachineState_P2P_Bootstrapping StateMachineState = "P2P_Bootstrapping" + StateMachineState_P2P_Bootstrapped StateMachineState = "P2P_Bootstrapped" + + StateMachineState_Consensus_Unsynched StateMachineState = "Consensus_Unsynched" + StateMachineState_Consensus_SyncMode StateMachineState = "Consensus_SyncMode" + StateMachineState_Consensus_Synced StateMachineState = "Consensus_Synced" +) From c66a5c85398d6f11d0770b7b931d86cb7623e242 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:32:39 +0000 Subject: [PATCH 30/50] refactor(shared): messaging events --- shared/messaging/events.go | 4 +++- shared/messaging/proto/events.proto | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/shared/messaging/events.go b/shared/messaging/events.go index 1ccfdf0c0..ecaf6c0d1 100644 --- a/shared/messaging/events.go +++ b/shared/messaging/events.go @@ -1,5 +1,7 @@ package messaging const ( - NodeStartedEventType = "pocket.NodeStartedEvent" + NodeStartedEventType = "pocket.NodeStartedEvent" + ConsensusNewHeightEventType = "pocket.ConsensusNewHeightEvent" + StateMachineTransitionEventType = "pocket.StateMachineTransitionEvent" ) diff --git a/shared/messaging/proto/events.proto b/shared/messaging/proto/events.proto index 22356bcc7..13931be93 100644 --- a/shared/messaging/proto/events.proto +++ b/shared/messaging/proto/events.proto @@ -5,3 +5,13 @@ package pocket; option go_package = "github.com/pokt-network/pocket/shared/messaging"; message NodeStartedEvent {} + +message ConsensusNewHeightEvent { + uint64 height = 1; +} + +message StateMachineTransitionEvent { + string event = 1; + string previous_state = 2; + string new_state = 3; +} From eb4174b27906143ab1e7117273de8e14caa6a24a Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:33:53 +0000 Subject: [PATCH 31/50] refactor(shared): state_machine interface --- shared/modules/bus_module.go | 1 + shared/modules/state_machine_module.go | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 shared/modules/state_machine_module.go diff --git a/shared/modules/bus_module.go b/shared/modules/bus_module.go index 5ca749891..62f5f3b74 100644 --- a/shared/modules/bus_module.go +++ b/shared/modules/bus_module.go @@ -31,6 +31,7 @@ type Bus interface { GetTelemetryModule() TelemetryModule GetLoggerModule() LoggerModule GetRPCModule() RPCModule + GetStateMachineModule() StateMachineModule // Runtime GetRuntimeMgr() RuntimeMgr diff --git a/shared/modules/state_machine_module.go b/shared/modules/state_machine_module.go new file mode 100644 index 000000000..5e7de8fc6 --- /dev/null +++ b/shared/modules/state_machine_module.go @@ -0,0 +1,15 @@ +package modules + +//go:generate mockgen -source=$GOFILE -destination=./mocks/state_machine_module_mock.go -aux_files=github.com/pokt-network/pocket/shared/modules=module.go + +import ( + coreTypes "github.com/pokt-network/pocket/shared/core/types" +) + +const StateMachineModuleName = "state_machine" + +type StateMachineModule interface { + Module + + SendEvent(event coreTypes.StateMachineEvent, args ...any) error +} From 7b974a9073df2ebee77aa9112c4a726c92c13f7b Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:35:41 +0000 Subject: [PATCH 32/50] fix(runtime): removed bus from Manager, it's embedded --- runtime/manager.go | 1 - 1 file changed, 1 deletion(-) diff --git a/runtime/manager.go b/runtime/manager.go index 2dce03d22..e1e41e4f7 100644 --- a/runtime/manager.go +++ b/runtime/manager.go @@ -29,7 +29,6 @@ type Manager struct { genesisState *genesis.GenesisState clock clock.Clock - bus modules.Bus } func NewManager(config *configs.Config, gen *genesis.GenesisState, options ...func(*Manager)) *Manager { From 8a5de140b77b481639e9dfe1285e6e875fff1a1f Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:36:18 +0000 Subject: [PATCH 33/50] refactor(consensus): updated tests --- consensus/e2e_tests/utils_test.go | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/consensus/e2e_tests/utils_test.go b/consensus/e2e_tests/utils_test.go index 646689158..81c807d3c 100644 --- a/consensus/e2e_tests/utils_test.go +++ b/consensus/e2e_tests/utils_test.go @@ -100,10 +100,9 @@ func CreateTestConsensusPocketNode( ) *shared.Node { // persistence is a dependency of consensus, so we need to create it first persistenceMock := basePersistenceMock(t, eventsChannel, bus) - err := (bus).RegisterModule(persistenceMock) - require.NoError(t, err) + bus.RegisterModule(persistenceMock) - _, err = consensus.Create(bus) + _, err := consensus.Create(bus) require.NoError(t, err) runtimeMgr := (bus).GetRuntimeMgr() @@ -114,16 +113,17 @@ func CreateTestConsensusPocketNode( telemetryMock := baseTelemetryMock(t, eventsChannel) loggerMock := baseLoggerMock(t, eventsChannel) rpcMock := baseRpcMock(t, eventsChannel) + stateMachineMock := baseStateMachineMock(t, eventsChannel) for _, module := range []modules.Module{ + stateMachineMock, p2pMock, utilityMock, telemetryMock, loggerMock, rpcMock, } { - err = (bus).RegisterModule(module) - require.NoError(t, err) + bus.RegisterModule(module) } require.NoError(t, err) @@ -424,6 +424,8 @@ func baseP2PMock(t *testing.T, eventsChannel modules.EventsChannel) *mockModules AnyTimes() p2pMock.EXPECT().GetModuleName().Return(modules.P2PModuleName).AnyTimes() + p2pMock.EXPECT().HandleEvent(gomock.Any()).Return(nil).AnyTimes() + return p2pMock } @@ -494,6 +496,16 @@ func baseRpcMock(t *testing.T, _ modules.EventsChannel) *mockModules.MockRPCModu return rpcMock } +func baseStateMachineMock(t *testing.T, _ modules.EventsChannel) *mockModules.MockStateMachineModule { + ctrl := gomock.NewController(t) + stateMachineMock := mockModules.NewMockStateMachineModule(ctrl) + stateMachineMock.EXPECT().Start().Return(nil).AnyTimes() + stateMachineMock.EXPECT().SetBus(gomock.Any()).Return().AnyTimes() + stateMachineMock.EXPECT().GetModuleName().Return(modules.StateMachineModuleName).AnyTimes() + + return stateMachineMock +} + func baseTelemetryTimeSeriesAgentMock(t *testing.T) *mockModules.MockTimeSeriesAgent { ctrl := gomock.NewController(t) timeSeriesAgentMock := mockModules.NewMockTimeSeriesAgent(ctrl) From 3a71510a0e9bdfb17624deb2db6926c5ec962bfa Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:38:23 +0000 Subject: [PATCH 34/50] feat(consensus): publishing event on new height --- consensus/events.go | 14 ++++++++++++++ consensus/module.go | 1 + 2 files changed, 15 insertions(+) create mode 100644 consensus/events.go diff --git a/consensus/events.go b/consensus/events.go new file mode 100644 index 000000000..0e31f8d72 --- /dev/null +++ b/consensus/events.go @@ -0,0 +1,14 @@ +package consensus + +import ( + "github.com/pokt-network/pocket/shared/messaging" +) + +// publishNewHeightEvent publishes a new height event to the bus so that other interested IntegratableModules can react to it if necessary +func (m *consensusModule) publishNewHeightEvent(height uint64) { + newHeightEvent, err := messaging.PackMessage(&messaging.ConsensusNewHeightEvent{Height: height}) + if err != nil { + m.logger.Fatal().Err(err).Msg("Failed to pack consensus new height event") + } + m.GetBus().PublishEventToBus(newHeightEvent) +} diff --git a/consensus/module.go b/consensus/module.go index 885569504..dcb43f581 100644 --- a/consensus/module.go +++ b/consensus/module.go @@ -92,6 +92,7 @@ type ConsensusDebugModule interface { func (m *consensusModule) SetHeight(height uint64) { m.height = height + m.publishNewHeightEvent(height) } func (m *consensusModule) SetRound(round uint64) { From a2e334842b4565ec9617debf4fc12f12ab7d1a45 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:39:31 +0000 Subject: [PATCH 35/50] refactor(leader_election): implementing base_modules and options --- consensus/leader_election/module.go | 34 ++++++++--------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/consensus/leader_election/module.go b/consensus/leader_election/module.go index 8d856dd24..2004bad28 100644 --- a/consensus/leader_election/module.go +++ b/consensus/leader_election/module.go @@ -2,8 +2,8 @@ package leader_election import ( typesCons "github.com/pokt-network/pocket/consensus/types" - "github.com/pokt-network/pocket/logger" "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" ) type LeaderElectionModule interface { @@ -14,45 +14,29 @@ type LeaderElectionModule interface { var _ LeaderElectionModule = &leaderElectionModule{} type leaderElectionModule struct { - bus modules.Bus + base_modules.IntegratableModule + base_modules.InterruptableModule } func Create(bus modules.Bus) (modules.Module, error) { return new(leaderElectionModule).Create(bus) } -func (*leaderElectionModule) Create(bus modules.Bus) (modules.Module, error) { +func (*leaderElectionModule) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { m := &leaderElectionModule{} - if err := bus.RegisterModule(m); err != nil { - return nil, err - } - return m, nil -} -func (m *leaderElectionModule) Start() error { - // TODO(olshansky): Use persistence to create leader election module. - return nil -} + for _, option := range options { + option(m) + } -func (m *leaderElectionModule) Stop() error { - return nil + bus.RegisterModule(m) + return m, nil } func (m *leaderElectionModule) GetModuleName() string { return modules.LeaderElectionModuleName } -func (m *leaderElectionModule) SetBus(pocketBus modules.Bus) { - m.bus = pocketBus -} - -func (m *leaderElectionModule) GetBus() modules.Bus { - if m.bus == nil { - logger.Global.Fatal().Msg("PocketBus is not initialized") - } - return m.bus -} - func (m *leaderElectionModule) ElectNextLeader(message *typesCons.HotstuffMessage) (typesCons.NodeId, error) { nodeId, err := m.electNextLeaderDeterministicRoundRobin(message) if err != nil { From f006a1d21c59298a23fe0a5779b7e81d5a241b29 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:39:59 +0000 Subject: [PATCH 36/50] refactor(pacemaker): implementing base_modules and options --- consensus/pacemaker/module.go | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/consensus/pacemaker/module.go b/consensus/pacemaker/module.go index 46d91c1bb..a7676e562 100644 --- a/consensus/pacemaker/module.go +++ b/consensus/pacemaker/module.go @@ -11,6 +11,7 @@ import ( "github.com/pokt-network/pocket/runtime/configs" "github.com/pokt-network/pocket/shared/codec" "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" "google.golang.org/protobuf/types/known/anypb" ) @@ -44,7 +45,9 @@ type Pacemaker interface { } type pacemaker struct { - bus modules.Bus + base_modules.IntegratableModule + base_modules.InterruptableModule + pacemakerCfg *configs.PacemakerConfig stepCancelFunc context.CancelFunc @@ -56,20 +59,21 @@ type pacemaker struct { logPrefix string } -func CreatePacemaker(bus modules.Bus) (modules.Module, error) { - var m pacemaker - return m.Create(bus) +func CreatePacemaker(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return new(pacemaker).Create(bus, options...) } -func (*pacemaker) Create(bus modules.Bus) (modules.Module, error) { +func (*pacemaker) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { m := &pacemaker{ logPrefix: defaultLogPrefix, } - if err := bus.RegisterModule(m); err != nil { - return nil, err + for _, option := range options { + option(m) } + bus.RegisterModule(m) + runtimeMgr := bus.GetRuntimeMgr() cfg := runtimeMgr.GetConfig() @@ -88,25 +92,11 @@ func (m *pacemaker) Start() error { m.RestartTimer() return nil } -func (*pacemaker) Stop() error { - return nil -} func (*pacemaker) GetModuleName() string { return pacemakerModuleName } -func (m *pacemaker) SetBus(pocketBus modules.Bus) { - m.bus = pocketBus -} - -func (m *pacemaker) GetBus() modules.Bus { - if m.bus == nil { - log.Fatalf("PocketBus is not initialized") - } - return m.bus -} - func (m *pacemaker) SetLogPrefix(logPrefix string) { m.logPrefix = logPrefix } From 8cdc827c4699821b6e45632a02c51a9cf36e9672 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:40:48 +0000 Subject: [PATCH 37/50] feat(consensus): sending events via SetHeight --- consensus/debugging.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/consensus/debugging.go b/consensus/debugging.go index e6e5eec08..c921ae5ac 100644 --- a/consensus/debugging.go +++ b/consensus/debugging.go @@ -49,10 +49,12 @@ func (m *consensusModule) GetNodeState() typesCons.ConsensusNodeState { func (m *consensusModule) resetToGenesis(_ *messaging.DebugMessage) error { m.logger.Debug().Msg(typesCons.DebugResetToGenesis) - m.height = 0 + + m.SetHeight(0) m.ResetForNewHeight() m.clearLeader() m.clearMessagesPool() + m.GetBus().GetUtilityModule().GetMempool().Clear() if err := m.GetBus().GetPersistenceModule().HandleDebugMessage(&messaging.DebugMessage{ Action: messaging.DebugMessageAction_DEBUG_PERSISTENCE_RESET_TO_GENESIS, Message: nil, From 5514fc3aa59277958284f3ede4f44d4eccf28ee8 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:41:01 +0000 Subject: [PATCH 38/50] docs(consensus): changelog --- consensus/doc/CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/consensus/doc/CHANGELOG.md b/consensus/doc/CHANGELOG.md index 2e3e98095..e262328a0 100644 --- a/consensus/doc/CHANGELOG.md +++ b/consensus/doc/CHANGELOG.md @@ -7,12 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.29] - 2023-02-15 + +- Modules embed `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness +- Updated modules `Create` to accept generic options +- `resetToGenesis` clears the utility mempool as well +- Publishing `ConsensusNewHeightEvent` on new height + ## [0.0.0.28] - 2023-02-14 - Add a few `nolint` comments to fix the code on main ## [0.0.0.27] - 2023-02-09 - - Add `state_sync` submodule, with `state_sync` struct - Implement state sync server to advertise blocks and metadata - Create new `state_sync_handler.go` source file that handles `StateSyncMessage`s sent to the `Consensus` module From 72f96d98fd72d13f1d0125e7bfeafc5d79fb99c1 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:43:10 +0000 Subject: [PATCH 39/50] docs(shared): updated README --- shared/README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/shared/README.md b/shared/README.md index 58938f471..992ed5e50 100644 --- a/shared/README.md +++ b/shared/README.md @@ -18,11 +18,12 @@ ## Code Structure ```bash -shared # [to-be-refactored] All of this is bound to change -├── codec # App wide encoding (currently protobuf) -├── config # Utilities to load and verify Node configurations -├── crypto # Shared crypto utilities specific to Pocket -├── modules # Interfaces to the core Pocket modules +shared # [to-be-refactored] All of this is bound to change +├── codec # App wide encoding (currently protobuf) +├── config # Utilities to load and verify Node configurations +├── crypto # Shared crypto utilities specific to Pocket +├── modules # Interfaces to the core Pocket modules +| ├── base_modules # Base modules that are meant to be embed into the module structs in order to reduce boilerplate code | ├── module.go | ├── bus_module.go | ├── consensus_module.go @@ -30,10 +31,10 @@ shared # [to-be-refactored] All of this is bound to change | ├── utility_module.go | ├── persistence_module.go | ├── telemetry_module.go -| ├── types.go # Shared interfaces -├── tests # Cross-module and shared testing_artifacts (to be refactored to make testing more modular) -├── node.go # The main entrypoint to the Pocket Node -├── bus.go # Implementation of the Bus module +| ├── types.go # Shared interfaces +├── tests # Cross-module and shared testing_artifacts (to be refactored to make testing more modular) +├── node.go # The main entrypoint to the Pocket Node +├── bus.go # Implementation of the Bus module ``` ## High Level Architecture From 934fe002a47d703745f05fe6118f23dde1bf3e54 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 19:45:49 +0000 Subject: [PATCH 40/50] chore(go.mod): tidy --- go.mod | 1 + go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index a292ac7d7..35ec76c52 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( github.com/jackc/pgconn v1.13.0 github.com/jordanorelli/lexnum v0.0.0-20141216151731-460eeb125754 github.com/labstack/echo/v4 v4.9.1 + github.com/looplab/fsm v1.0.1 github.com/manifoldco/promptui v0.9.0 github.com/mitchellh/mapstructure v1.5.0 github.com/quasilyte/go-ruleguard/dsl v0.3.21 diff --git a/go.sum b/go.sum index ae3da1f69..c41006b56 100644 --- a/go.sum +++ b/go.sum @@ -341,6 +341,8 @@ github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/looplab/fsm v1.0.1 h1:OEW0ORrIx095N/6lgoGkFkotqH6s7vaFPsgjLAaF5QU= +github.com/looplab/fsm v1.0.1/go.mod h1:PmD3fFvQEIsjMEfvZdrCDZ6y8VwKTwWNjlpEr6IKPO4= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= From 9bf8b8161503c00b6137148d801dbd6ad574df65 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 20:18:05 +0000 Subject: [PATCH 41/50] fix(p2p): fixes from backporting legacy functionality --- p2p/event_handler.go | 10 ++++++++++ p2p/module.go | 18 +----------------- p2p/utils_test.go | 17 +++++++---------- runtime/bus.go | 8 ++++++++ shared/modules/p2p_module.go | 3 +++ 5 files changed, 29 insertions(+), 27 deletions(-) create mode 100644 p2p/event_handler.go diff --git a/p2p/event_handler.go b/p2p/event_handler.go new file mode 100644 index 000000000..4d920231f --- /dev/null +++ b/p2p/event_handler.go @@ -0,0 +1,10 @@ +package p2p + +import ( + "google.golang.org/protobuf/types/known/anypb" +) + +func (m *p2pModule) HandleEvent(event *anypb.Any) error { + // no-op (for now... PRs are already cooked) + return nil +} diff --git a/p2p/module.go b/p2p/module.go index 307d6a5aa..8a9985d9e 100644 --- a/p2p/module.go +++ b/p2p/module.go @@ -43,9 +43,7 @@ func Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, e func CreateWithProviders(bus modules.Bus, addrBookProvider providers.AddrBookProvider, currentHeightProvider providers.CurrentHeightProvider) (modules.Module, error) { log.Println("Creating network module") m := &p2pModule{} - if err := bus.RegisterModule(m); err != nil { - return nil, err - } + bus.RegisterModule(m) runtimeMgr := bus.GetRuntimeMgr() cfg := runtimeMgr.GetConfig() @@ -101,20 +99,6 @@ func (*p2pModule) Create(bus modules.Bus, options ...modules.ModuleOption) (modu return m, nil } -func (m *p2pModule) SetBus(bus modules.Bus) { - // INVESTIGATE: Can the code flow be modified to set the bus here? - // m.network.SetBus(m.GetBus()) - m.bus = bus -} - -func (m *p2pModule) GetBus() modules.Bus { - if m.bus == nil { - m.logger.Warn().Msg("PocketBus is not initialized") - return nil - } - return m.bus -} - func (m *p2pModule) GetModuleName() string { return modules.P2PModuleName } diff --git a/p2p/utils_test.go b/p2p/utils_test.go index 37fdc8dbb..dcab6c141 100644 --- a/p2p/utils_test.go +++ b/p2p/utils_test.go @@ -10,12 +10,11 @@ import ( "testing" "time" - types "github.com/pokt-network/pocket/runtime/configs/types" - "github.com/golang/mock/gomock" typesP2P "github.com/pokt-network/pocket/p2p/types" mocksP2P "github.com/pokt-network/pocket/p2p/types/mocks" "github.com/pokt-network/pocket/runtime/configs" + types "github.com/pokt-network/pocket/runtime/configs/types" "github.com/pokt-network/pocket/runtime/genesis" coreTypes "github.com/pokt-network/pocket/shared/core/types" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" @@ -150,10 +149,11 @@ func createMockBus(t *testing.T, runtimeMgr modules.RuntimeMgr) *mockModules.Moc ctrl := gomock.NewController(t) mockBus := mockModules.NewMockBus(ctrl) mockBus.EXPECT().GetRuntimeMgr().Return(runtimeMgr).AnyTimes() - mockBus.EXPECT().RegisterModule(gomock.Any()).DoAndReturn(func(m modules.Module) error { + mockBus.EXPECT().RegisterModule(gomock.Any()).DoAndReturn(func(m modules.Module) { m.SetBus(mockBus) - return nil }).AnyTimes() + mockModulesRegistry := mockModules.NewMockModulesRegistry(ctrl) + mockBus.EXPECT().GetModulesRegistry().Return(mockModulesRegistry).AnyTimes() mockBus.EXPECT().PublishEventToBus(gomock.Any()).AnyTimes() return mockBus } @@ -201,8 +201,7 @@ func prepareConsensusMock(t *testing.T, busMock *mockModules.MockBus) *mockModul consensusMock.EXPECT().GetBus().Return(busMock).AnyTimes() consensusMock.EXPECT().SetBus(busMock).AnyTimes() consensusMock.EXPECT().GetModuleName().Return(modules.ConsensusModuleName).AnyTimes() - err := busMock.RegisterModule(consensusMock) - require.NoError(t, err) + busMock.RegisterModule(consensusMock) return consensusMock } @@ -221,8 +220,7 @@ func preparePersistenceMock(t *testing.T, busMock *mockModules.MockBus, genesisS persistenceMock.EXPECT().GetBus().Return(busMock).AnyTimes() persistenceMock.EXPECT().SetBus(busMock).AnyTimes() persistenceMock.EXPECT().GetModuleName().Return(modules.PersistenceModuleName).AnyTimes() - err := busMock.RegisterModule(persistenceMock) - require.NoError(t, err) + busMock.RegisterModule(persistenceMock) return persistenceMock } @@ -241,8 +239,7 @@ func prepareTelemetryMock(t *testing.T, busMock *mockModules.MockBus, valId stri telemetryMock.EXPECT().GetModuleName().Return(modules.TelemetryModuleName).AnyTimes() telemetryMock.EXPECT().GetBus().Return(busMock).AnyTimes() telemetryMock.EXPECT().SetBus(busMock).AnyTimes() - err := busMock.RegisterModule(telemetryMock) - require.NoError(t, err) + busMock.RegisterModule(telemetryMock) return telemetryMock } diff --git a/runtime/bus.go b/runtime/bus.go index 23c16aeff..d69106589 100644 --- a/runtime/bus.go +++ b/runtime/bus.go @@ -134,3 +134,11 @@ func (m *bus) GetRPCModule() modules.RPCModule { func (m *bus) GetRuntimeMgr() modules.RuntimeMgr { return m.runtimeMgr } + +func (m *bus) GetStateMachineModule() modules.StateMachineModule { + mod, err := m.modulesRegistry.GetModule(modules.StateMachineModuleName) + if err != nil { + logger.Global.Logger.Fatal().Err(err).Msg("failed to get module from modulesRegistry") + } + return mod.(modules.StateMachineModule) +} diff --git a/shared/modules/p2p_module.go b/shared/modules/p2p_module.go index aea86dc2d..93ea6e63c 100644 --- a/shared/modules/p2p_module.go +++ b/shared/modules/p2p_module.go @@ -21,6 +21,9 @@ type P2PModule interface { // A direct asynchronous Send(addr cryptoPocket.Address, msg *anypb.Any) error + // HandleEvent is used to react to events that occur inside the application + HandleEvent(*anypb.Any) error + // CONSIDERATION: The P2P module currently does implement a synchronous "request-response" pattern // for core business logic between nodes. Rather, all communication is done // asynchronously via a "fire-and-forget" pattern using `Send` and `Broadcast`. From 724a326eaaeccea87a0292ad54b917380411c71c Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 20:42:37 +0000 Subject: [PATCH 42/50] docs(shared): changelogs --- consensus/doc/CHANGELOG.md | 2 +- logger/docs/CHANGELOG.md | 2 +- p2p/CHANGELOG.md | 5 +++++ persistence/docs/CHANGELOG.md | 2 +- rpc/doc/CHANGELOG.md | 2 +- runtime/docs/CHANGELOG.md | 6 ++++++ shared/CHANGELOG.md | 8 ++++++++ state_machine/docs/CHANGELOG.md | 2 +- telemetry/CHANGELOG.md | 2 +- utility/doc/CHANGELOG.md | 2 +- 10 files changed, 26 insertions(+), 7 deletions(-) diff --git a/consensus/doc/CHANGELOG.md b/consensus/doc/CHANGELOG.md index e262328a0..c7d36fe1e 100644 --- a/consensus/doc/CHANGELOG.md +++ b/consensus/doc/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.29] - 2023-02-15 +## [0.0.0.29] - 2023-02-16 - Modules embed `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness - Updated modules `Create` to accept generic options diff --git a/logger/docs/CHANGELOG.md b/logger/docs/CHANGELOG.md index fc8acb230..cf6ac600f 100644 --- a/logger/docs/CHANGELOG.md +++ b/logger/docs/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.7] - 2023-02-10 +## [0.0.0.7] - 2023-02-16 - Module embeds `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness diff --git a/p2p/CHANGELOG.md b/p2p/CHANGELOG.md index ac5eeeb3f..6ae189816 100644 --- a/p2p/CHANGELOG.md +++ b/p2p/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.26] - 2023-02-16 + +- Modules embed `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness +- Updated tests + ## [0.0.0.25] - 2023-02-09 - Updated logging initialization and passing to the network component instead of using the global logger diff --git a/persistence/docs/CHANGELOG.md b/persistence/docs/CHANGELOG.md index b13b7a898..cf50f6a6e 100644 --- a/persistence/docs/CHANGELOG.md +++ b/persistence/docs/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.36] - 2023-02-15 +## [0.0.0.36] - 2023-02-16 - Module now embeds `base_modules.IntegratableModule` for DRYness diff --git a/rpc/doc/CHANGELOG.md b/rpc/doc/CHANGELOG.md index 9eb2ed4ba..c76b9e037 100644 --- a/rpc/doc/CHANGELOG.md +++ b/rpc/doc/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.11] - 2023-02-10 +## [0.0.0.11] - 2023-02-16 - Updated modules to embed `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness diff --git a/runtime/docs/CHANGELOG.md b/runtime/docs/CHANGELOG.md index de6062661..d74644754 100644 --- a/runtime/docs/CHANGELOG.md +++ b/runtime/docs/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.19] - 2023-02-16 + +- Introduced `modules.ModulesRegistry` for better separation of concerns +- Added `StateMachineModule` accessors +- `Manager` embeds `base_modules.IntegratableModule` for DRYness + ## [0.0.0.18] - 2023-02-16 - Added `IsProcessRunningInsideKubernetes` and centralized `GetEnv` so that it can be used across the board diff --git a/shared/CHANGELOG.md b/shared/CHANGELOG.md index 35c3b664f..241debdce 100644 --- a/shared/CHANGELOG.md +++ b/shared/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.27] - 2023-02-16 + +- Added events `ConsensusNewHeightEvent` and `StateMachineTransitionEvent` +- Introduced `BaseInterruptableModule` and `IntegratableModule` to reduce repetition and boilerpate code (DRYness) +- Added `ModulesRegistry` and `StateMachineModule` accessors and interfaces +- Introduced generic `ModuleOption` pattern to fine tune modules behaviour +- Added `StateMachine` to the `node` initialization + ## [0.0.0.26] - 2023-02-16 - Added `FetchValidatorPrivateKeys` function since it is going to be used by the `debug-client` and also by the upcoming `cluster-manager` [#490](https://github.com/pokt-network/pocket/issues/490) diff --git a/state_machine/docs/CHANGELOG.md b/state_machine/docs/CHANGELOG.md index efab941aa..03ffc4cef 100644 --- a/state_machine/docs/CHANGELOG.md +++ b/state_machine/docs/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.1] - 2023-02-10 +## [0.0.0.1] - 2023-02-16 - Introduced this `CHANGELOG.md` and `README.md` - Added `StateMachineModule` implementation with a POC of the finite state machine that will be used to manage the node lifecycle diff --git a/telemetry/CHANGELOG.md b/telemetry/CHANGELOG.md index 197e07dcc..9f3de0d2e 100644 --- a/telemetry/CHANGELOG.md +++ b/telemetry/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.8] - 2023-02-10 +## [0.0.0.8] - 2023-02-16 - Modules embed `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness diff --git a/utility/doc/CHANGELOG.md b/utility/doc/CHANGELOG.md index 2269a5270..8d0ddd023 100644 --- a/utility/doc/CHANGELOG.md +++ b/utility/doc/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.28] - 2023-02-15 +## [0.0.0.28] - 2023-02-16 - Module embeds `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness - Logging error if `ApplyTransaction` fails (it was completely ignored before and it was really hard to understand what was going on) From c0cdeacfab2efb39ffcc79159aae3160631ecc1a Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 21:10:17 +0000 Subject: [PATCH 43/50] feat(consensus): improved test resiliency --- consensus/e2e_tests/utils_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/consensus/e2e_tests/utils_test.go b/consensus/e2e_tests/utils_test.go index 81c807d3c..2ac1f04b9 100644 --- a/consensus/e2e_tests/utils_test.go +++ b/consensus/e2e_tests/utils_test.go @@ -533,6 +533,13 @@ func baseLoggerMock(t *testing.T, _ modules.EventsChannel) *mockModules.MockLogg func logTime(t *testing.T, clck *clock.Mock) { t.Helper() + defer func() { + // this is to recover from a panic that could happen if the goroutine tries to log after the test has finished + // cause of the panic: https://github.com/golang/go/blob/135c470b2277e1c9514ba8a5478408fea0dee8a2/src/testing/testing.go#L1003 + // + // spotted for the first time in our CI: https://github.com/pokt-network/pocket/actions/runs/4198025819/jobs/7281103860#step:8:1118 + recover() + }() t.Logf("[⌚ CLOCK ⌚] the time is: %v ms from UNIX Epoch [%v]", clck.Now().UTC().UnixMilli(), clck.Now().UTC()) } From e5c93f7386b3fdd9e461aa5f6167e9a21808db24 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Thu, 16 Feb 2023 21:53:30 +0000 Subject: [PATCH 44/50] chore(consensus): lint --- consensus/e2e_tests/utils_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/consensus/e2e_tests/utils_test.go b/consensus/e2e_tests/utils_test.go index 2ac1f04b9..306935992 100644 --- a/consensus/e2e_tests/utils_test.go +++ b/consensus/e2e_tests/utils_test.go @@ -538,6 +538,7 @@ func logTime(t *testing.T, clck *clock.Mock) { // cause of the panic: https://github.com/golang/go/blob/135c470b2277e1c9514ba8a5478408fea0dee8a2/src/testing/testing.go#L1003 // // spotted for the first time in our CI: https://github.com/pokt-network/pocket/actions/runs/4198025819/jobs/7281103860#step:8:1118 + //nolint:errcheck // ignoring completely recover() }() t.Logf("[⌚ CLOCK ⌚] the time is: %v ms from UNIX Epoch [%v]", clck.Now().UTC().UnixMilli(), clck.Now().UTC()) From 7381c8b4431816e7b9dec9363a38c4220f984e06 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Fri, 17 Feb 2023 09:31:29 +0000 Subject: [PATCH 45/50] Update state_machine/docs/README.md Co-authored-by: Daniel Olshansky --- state_machine/docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state_machine/docs/README.md b/state_machine/docs/README.md index 5a2239b03..200623949 100644 --- a/state_machine/docs/README.md +++ b/state_machine/docs/README.md @@ -50,7 +50,7 @@ These are the main building blocks: - **Event**: An event is a string that represents an action that can trigger a transition. For example, the event `start` can be used to trigger a transition from the `stopped` state to the `starting` state. - **State**: A state is a string that represents a state that the FSM can be in. For example, the state `stopped` can be used to represent a state where the node is not running. -- **Callback**: A callback is a function that is called when a transition occurs. For example, a callback can be used to log the transition or to perform some other action. (there are various types of callbacks that essentially drive the WHEN they are called and help building more complex behaviours like transition cancelling, etc. but we won't cover them here, please read the FSM library documentation for more details) +- **Callback**: A callback is a function that is called when a transition occurs. For example, a callback can be used to log the transition or to perform some other action. Various types of callbacks essentially drive behaviour **WHEN** they are called and help build more complex behaviours like transition cancelling, etc. See the core FSM library documentation for more details. ## Current State Machine Definition From 51e971ef5d289dd8d0b392644bc5776fe5052639 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Fri, 17 Feb 2023 09:31:44 +0000 Subject: [PATCH 46/50] Update consensus/e2e_tests/utils_test.go Co-authored-by: Daniel Olshansky --- consensus/e2e_tests/utils_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/consensus/e2e_tests/utils_test.go b/consensus/e2e_tests/utils_test.go index 306935992..f99600a9c 100644 --- a/consensus/e2e_tests/utils_test.go +++ b/consensus/e2e_tests/utils_test.go @@ -423,7 +423,6 @@ func baseP2PMock(t *testing.T, eventsChannel modules.EventsChannel) *mockModules }). AnyTimes() p2pMock.EXPECT().GetModuleName().Return(modules.P2PModuleName).AnyTimes() - p2pMock.EXPECT().HandleEvent(gomock.Any()).Return(nil).AnyTimes() return p2pMock From 43d31cde395e88081977cf7a59e351508e504320 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Fri, 17 Feb 2023 09:47:00 +0000 Subject: [PATCH 47/50] refactor(runtime): improved module getters via generics --- runtime/bus.go | 66 +++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 39 deletions(-) diff --git a/runtime/bus.go b/runtime/bus.go index d69106589..cea228733 100644 --- a/runtime/bus.go +++ b/runtime/bus.go @@ -1,7 +1,6 @@ package runtime import ( - "log" "sync" "github.com/pokt-network/pocket/logger" @@ -64,36 +63,24 @@ func (m *bus) GetEventBus() modules.EventsChannel { return m.channel } +func (m *bus) GetRuntimeMgr() modules.RuntimeMgr { + return m.runtimeMgr +} + func (m *bus) GetPersistenceModule() modules.PersistenceModule { - mod, err := m.modulesRegistry.GetModule(modules.PersistenceModuleName) - if err != nil { - logger.Global.Logger.Fatal().Err(err).Msg("failed to get module from modulesRegistry") - } - return mod.(modules.PersistenceModule) + return getModuleFromRegistry[modules.PersistenceModule](m, modules.PersistenceModuleName) } func (m *bus) GetP2PModule() modules.P2PModule { - mod, err := m.modulesRegistry.GetModule(modules.P2PModuleName) - if err != nil { - logger.Global.Logger.Fatal().Err(err).Msg("failed to get module from modulesRegistry") - } - return mod.(modules.P2PModule) + return getModuleFromRegistry[modules.P2PModule](m, modules.P2PModuleName) } func (m *bus) GetUtilityModule() modules.UtilityModule { - mod, err := m.modulesRegistry.GetModule(modules.UtilityModuleName) - if err != nil { - logger.Global.Logger.Fatal().Err(err).Msg("failed to get module from modulesRegistry") - } - return mod.(modules.UtilityModule) + return getModuleFromRegistry[modules.UtilityModule](m, modules.UtilityModuleName) } func (m *bus) GetConsensusModule() modules.ConsensusModule { - mod, err := m.modulesRegistry.GetModule(modules.ConsensusModuleName) - if err != nil { - logger.Global.Logger.Fatal().Err(err).Msg("failed to get module from modulesRegistry") - } - return mod.(modules.ConsensusModule) + return getModuleFromRegistry[modules.ConsensusModule](m, modules.ConsensusModuleName) } func (m *bus) GetTelemetryModule() modules.TelemetryModule { @@ -104,41 +91,42 @@ func (m *bus) GetTelemetryModule() modules.TelemetryModule { } } telemetryWarnOnce.Do(func() { - log.Printf("[WARNING] telemetry module not found, creating a default noop telemetry module instead") + logger.Global.Logger.Warn(). + Str("module", modules.TelemetryModuleName). + Msg("module not found, creating a default noop module instead") }) // this should happen only if called from the client noopModule, err := telemetry.CreateNoopTelemetryModule(m) if err != nil { - log.Fatalf("failed to create noop telemetry module: %v", err) + logger.Global.Logger.Fatal(). + Err(err). + Str("module", modules.TelemetryModuleName). + Msg("failed to create noop telemetry module") } m.RegisterModule(noopModule) return noopModule.(modules.TelemetryModule) } func (m *bus) GetLoggerModule() modules.LoggerModule { - mod, err := m.modulesRegistry.GetModule(modules.LoggerModuleName) - if err != nil { - logger.Global.Logger.Fatal().Err(err).Msg("failed to get module from modulesRegistry") - } - return mod.(modules.LoggerModule) + return getModuleFromRegistry[modules.LoggerModule](m, modules.LoggerModuleName) } func (m *bus) GetRPCModule() modules.RPCModule { - mod, err := m.modulesRegistry.GetModule(modules.RPCModuleName) - if err != nil { - logger.Global.Logger.Fatal().Err(err).Msg("failed to get module from modulesRegistry") - } - return mod.(modules.RPCModule) + return getModuleFromRegistry[modules.RPCModule](m, modules.RPCModuleName) } -func (m *bus) GetRuntimeMgr() modules.RuntimeMgr { - return m.runtimeMgr +func (m *bus) GetStateMachineModule() modules.StateMachineModule { + return getModuleFromRegistry[modules.StateMachineModule](m, modules.StateMachineModuleName) } -func (m *bus) GetStateMachineModule() modules.StateMachineModule { - mod, err := m.modulesRegistry.GetModule(modules.StateMachineModuleName) +// getModuleFromRegistry is a helper function to get a module from the registry that handles errors and casting via generics +func getModuleFromRegistry[T modules.Module](m *bus, moduleName string) T { + mod, err := m.modulesRegistry.GetModule(moduleName) if err != nil { - logger.Global.Logger.Fatal().Err(err).Msg("failed to get module from modulesRegistry") + logger.Global.Logger.Fatal(). + Err(err). + Str("module", moduleName). + Msg("failed to get module from modulesRegistry") } - return mod.(modules.StateMachineModule) + return mod.(T) } From 61bdd35b077d754aa84fdfc93b65d96f7b525e37 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Fri, 17 Feb 2023 09:49:35 +0000 Subject: [PATCH 48/50] chore(shared): renamed fsm states and events files --- shared/core/types/{events.go => fsm_events.go} | 0 shared/core/types/{states.go => fsm_states.go} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename shared/core/types/{events.go => fsm_events.go} (100%) rename shared/core/types/{states.go => fsm_states.go} (100%) diff --git a/shared/core/types/events.go b/shared/core/types/fsm_events.go similarity index 100% rename from shared/core/types/events.go rename to shared/core/types/fsm_events.go diff --git a/shared/core/types/states.go b/shared/core/types/fsm_states.go similarity index 100% rename from shared/core/types/states.go rename to shared/core/types/fsm_states.go From 65ac7ced8eec56e4dca53379bb1622b29738463d Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Fri, 17 Feb 2023 09:52:07 +0000 Subject: [PATCH 49/50] Update shared/modules/doc/README.md Co-authored-by: Daniel Olshansky --- shared/modules/doc/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared/modules/doc/README.md b/shared/modules/doc/README.md index cec167a68..6483dfc8f 100644 --- a/shared/modules/doc/README.md +++ b/shared/modules/doc/README.md @@ -43,6 +43,8 @@ TODO(#235): Update once runtime configs are implemented #### Create the module +TODO(#509): Add more detail and examples to this documentation. + Module creation uses a typical constructor pattern signature `Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error)` Where `options ...modules.ModuleOption` is an optional variadic argument that allows for the passing of options to the module. From 9fe0dc61b5fae8078cc0f2850ecd05aefd7a7443 Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Fri, 17 Feb 2023 09:55:20 +0000 Subject: [PATCH 50/50] docs(shared): changelogs dates --- app/client/doc/CHANGELOG.md | 2 +- build/docs/CHANGELOG.md | 2 +- consensus/doc/CHANGELOG.md | 2 +- logger/docs/CHANGELOG.md | 2 +- p2p/CHANGELOG.md | 2 +- persistence/docs/CHANGELOG.md | 2 +- rpc/doc/CHANGELOG.md | 2 +- runtime/docs/CHANGELOG.md | 2 +- shared/CHANGELOG.md | 2 +- state_machine/docs/CHANGELOG.md | 2 +- telemetry/CHANGELOG.md | 2 +- utility/doc/CHANGELOG.md | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/client/doc/CHANGELOG.md b/app/client/doc/CHANGELOG.md index 983f0e91b..698b73929 100644 --- a/app/client/doc/CHANGELOG.md +++ b/app/client/doc/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.14] - 2023-02-16 +## [0.0.0.14] - 2023-02-17 - Introduced logical switch to handle parsing of the debug private keys from a local file OR from Kubernetes secret (PR #517) - Bugfix for `Stake` command. Address erroneously sent instead of the PublicKey. (PR #518) diff --git a/build/docs/CHANGELOG.md b/build/docs/CHANGELOG.md index aa13f5e16..20a0fc54c 100644 --- a/build/docs/CHANGELOG.md +++ b/build/docs/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.15] - 2023-02-16 +## [0.0.0.15] - 2023-02-17 - Added manifests to handle `Roles`, `RoleBindings` and `ServiceAccounts` and referenced them in the `Tiltfile` - Updated `cli-client.yaml` to bind the `debug-client-account` `ServiceAccount` that has permissions to read the private keys from the `Secret` diff --git a/consensus/doc/CHANGELOG.md b/consensus/doc/CHANGELOG.md index c7d36fe1e..3bc5b40e6 100644 --- a/consensus/doc/CHANGELOG.md +++ b/consensus/doc/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.29] - 2023-02-16 +## [0.0.0.29] - 2023-02-17 - Modules embed `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness - Updated modules `Create` to accept generic options diff --git a/logger/docs/CHANGELOG.md b/logger/docs/CHANGELOG.md index cf6ac600f..7e3a49617 100644 --- a/logger/docs/CHANGELOG.md +++ b/logger/docs/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.7] - 2023-02-16 +## [0.0.0.7] - 2023-02-17 - Module embeds `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness diff --git a/p2p/CHANGELOG.md b/p2p/CHANGELOG.md index 6ae189816..7ac5febf4 100644 --- a/p2p/CHANGELOG.md +++ b/p2p/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.26] - 2023-02-16 +## [0.0.0.26] - 2023-02-17 - Modules embed `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness - Updated tests diff --git a/persistence/docs/CHANGELOG.md b/persistence/docs/CHANGELOG.md index cf50f6a6e..378cf3b85 100644 --- a/persistence/docs/CHANGELOG.md +++ b/persistence/docs/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.36] - 2023-02-16 +## [0.0.0.36] - 2023-02-17 - Module now embeds `base_modules.IntegratableModule` for DRYness diff --git a/rpc/doc/CHANGELOG.md b/rpc/doc/CHANGELOG.md index c76b9e037..9c186294b 100644 --- a/rpc/doc/CHANGELOG.md +++ b/rpc/doc/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.11] - 2023-02-16 +## [0.0.0.11] - 2023-02-17 - Updated modules to embed `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness diff --git a/runtime/docs/CHANGELOG.md b/runtime/docs/CHANGELOG.md index d74644754..8dbb058e7 100644 --- a/runtime/docs/CHANGELOG.md +++ b/runtime/docs/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.19] - 2023-02-16 +## [0.0.0.19] - 2023-02-17 - Introduced `modules.ModulesRegistry` for better separation of concerns - Added `StateMachineModule` accessors diff --git a/shared/CHANGELOG.md b/shared/CHANGELOG.md index 241debdce..0718222bc 100644 --- a/shared/CHANGELOG.md +++ b/shared/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.27] - 2023-02-16 +## [0.0.0.27] - 2023-02-17 - Added events `ConsensusNewHeightEvent` and `StateMachineTransitionEvent` - Introduced `BaseInterruptableModule` and `IntegratableModule` to reduce repetition and boilerpate code (DRYness) diff --git a/state_machine/docs/CHANGELOG.md b/state_machine/docs/CHANGELOG.md index 03ffc4cef..94b74f826 100644 --- a/state_machine/docs/CHANGELOG.md +++ b/state_machine/docs/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.1] - 2023-02-16 +## [0.0.0.1] - 2023-02-17 - Introduced this `CHANGELOG.md` and `README.md` - Added `StateMachineModule` implementation with a POC of the finite state machine that will be used to manage the node lifecycle diff --git a/telemetry/CHANGELOG.md b/telemetry/CHANGELOG.md index 9f3de0d2e..b3c005fc8 100644 --- a/telemetry/CHANGELOG.md +++ b/telemetry/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.8] - 2023-02-16 +## [0.0.0.8] - 2023-02-17 - Modules embed `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness diff --git a/utility/doc/CHANGELOG.md b/utility/doc/CHANGELOG.md index 8d0ddd023..4483fc792 100644 --- a/utility/doc/CHANGELOG.md +++ b/utility/doc/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.28] - 2023-02-16 +## [0.0.0.28] - 2023-02-17 - Module embeds `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness - Logging error if `ApplyTransaction` fails (it was completely ignored before and it was really hard to understand what was going on)