Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Core] KISS 1 - Finite State Machine [Merge me first] - (Issue: #499) #520

Merged
merged 51 commits into from
Feb 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
143feaa
feat(shared): module Create with ModuleOptions
deblasis Feb 16, 2023
a046984
docs(shared): godoc for ModuleOption
deblasis Feb 16, 2023
82505e4
docs(shared): updated README
deblasis Feb 16, 2023
da9774b
feat(shared): base_modules
deblasis Feb 16, 2023
f784dab
fix(utility): logging error when ApplyTransaction fails
deblasis Feb 16, 2023
049023c
refactor(utility): implementing base_modules and options
deblasis Feb 16, 2023
a18ecf5
fix(utility): using logger in message_handler
deblasis Feb 16, 2023
e01c75c
docs(utility): changelog
deblasis Feb 16, 2023
142d53b
refactor(telemetry): implementing base_modules and options
deblasis Feb 16, 2023
3c84eae
docs(telemetry): changelog
deblasis Feb 16, 2023
4eed45a
feat(shared): ModulesRegistry interface
deblasis Feb 16, 2023
b094622
refactor(shared): updated bus interface to use ModuleRegistry
deblasis Feb 16, 2023
e6e8fe5
refactor(persistence): implementing base_modules and options
deblasis Feb 16, 2023
f8ed453
docs(persistence): changelog
deblasis Feb 16, 2023
2a21542
refactor(consensus): implementing base_modules and options
deblasis Feb 16, 2023
e70b308
refactor(logger): implementing base_modules and options
deblasis Feb 16, 2023
0d20ada
docs(logger): changelog
deblasis Feb 16, 2023
963212a
refactor(rpc): implementing base_modules and options
deblasis Feb 16, 2023
8871a3d
docs(rpc): changelog
deblasis Feb 16, 2023
8d50538
feat(runtime): ModulesRegistry implementation
deblasis Feb 16, 2023
5141f07
feat(p2p): implementing base_modules and options
deblasis Feb 16, 2023
1d98c9f
refactor(state_sync): implementing base_modules and options
deblasis Feb 16, 2023
f5f9777
refactor(runtime): bus uses ModulesRegistry and logger
deblasis Feb 16, 2023
4c5f50c
fix(runtime): StateMachine doesn't exist yet :)
deblasis Feb 16, 2023
7023ca0
refactor(runtime): errors referring ModulesRegistry
deblasis Feb 16, 2023
34f3d87
refactor(runtime): runtimeManager implements base IntegratableModule
deblasis Feb 16, 2023
74d012f
feat(state_machine): KISS FSM implementation
deblasis Feb 16, 2023
d697a7f
feat(shared): state_machine integration with node
deblasis Feb 16, 2023
8e89219
feat(shared): FSM states and events
deblasis Feb 16, 2023
c66a5c8
refactor(shared): messaging events
deblasis Feb 16, 2023
eb4174b
refactor(shared): state_machine interface
deblasis Feb 16, 2023
7b974a9
fix(runtime): removed bus from Manager, it's embedded
deblasis Feb 16, 2023
8a5de14
refactor(consensus): updated tests
deblasis Feb 16, 2023
3a71510
feat(consensus): publishing event on new height
deblasis Feb 16, 2023
a2e3348
refactor(leader_election): implementing base_modules and options
deblasis Feb 16, 2023
f006a1d
refactor(pacemaker): implementing base_modules and options
deblasis Feb 16, 2023
8cdc827
feat(consensus): sending events via SetHeight
deblasis Feb 16, 2023
5514fc3
docs(consensus): changelog
deblasis Feb 16, 2023
72f96d9
docs(shared): updated README
deblasis Feb 16, 2023
934fe00
chore(go.mod): tidy
deblasis Feb 16, 2023
9bf8b81
fix(p2p): fixes from backporting legacy functionality
deblasis Feb 16, 2023
724a326
docs(shared): changelogs
deblasis Feb 16, 2023
c0cdeac
feat(consensus): improved test resiliency
deblasis Feb 16, 2023
e5c93f7
chore(consensus): lint
deblasis Feb 16, 2023
7381c8b
Update state_machine/docs/README.md
deblasis Feb 17, 2023
51e971e
Update consensus/e2e_tests/utils_test.go
deblasis Feb 17, 2023
43d31cd
refactor(runtime): improved module getters via generics
deblasis Feb 17, 2023
61bdd35
chore(shared): renamed fsm states and events files
deblasis Feb 17, 2023
65ac7ce
Update shared/modules/doc/README.md
deblasis Feb 17, 2023
8c5ad05
Merge branch 'issue/499-fsm' of github.com:pokt-network/pocket into i…
deblasis Feb 17, 2023
9fe0dc6
docs(shared): changelogs dates
deblasis Feb 17, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 ./...
Expand Down
2 changes: 1 addition & 1 deletion app/client/doc/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion build/docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
4 changes: 3 additions & 1 deletion consensus/debugging.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
8 changes: 7 additions & 1 deletion consensus/doc/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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-17

- 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
Expand Down
29 changes: 24 additions & 5 deletions consensus/e2e_tests/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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)
Expand Down Expand Up @@ -423,6 +423,7 @@ 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
}
Expand Down Expand Up @@ -494,6 +495,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)
Expand Down Expand Up @@ -521,6 +532,14 @@ func baseLoggerMock(t *testing.T, _ modules.EventsChannel) *mockModules.MockLogg

func logTime(t *testing.T, clck *clock.Mock) {
t.Helper()
defer func() {
deblasis marked this conversation as resolved.
Show resolved Hide resolved
// 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
//nolint:errcheck // ignoring completely
recover()
}()
t.Logf("[⌚ CLOCK ⌚] the time is: %v ms from UNIX Epoch [%v]", clck.Now().UTC().UnixMilli(), clck.Now().UTC())
}

Expand Down
14 changes: 14 additions & 0 deletions consensus/events.go
Original file line number Diff line number Diff line change
@@ -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)
}
34 changes: 9 additions & 25 deletions consensus/leader_election/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
27 changes: 13 additions & 14 deletions consensus/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -30,7 +31,8 @@ var (
)

type consensusModule struct {
bus modules.Bus
base_modules.IntegratableModule

privateKey cryptoPocket.Ed25519PrivateKey

consCfg *configs.ConsensusConfig
Expand Down Expand Up @@ -90,6 +92,7 @@ type ConsensusDebugModule interface {

func (m *consensusModule) SetHeight(height uint64) {
m.height = height
m.publishNewHeightEvent(height)
}

func (m *consensusModule) SetRound(round uint64) {
Expand Down Expand Up @@ -136,11 +139,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
Expand Down Expand Up @@ -179,10 +182,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
Expand Down Expand Up @@ -259,15 +265,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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're embedding IntegradbleModule, you should be able to use pocketBus directly

Screenshot 2023-02-16 at 7 53 32 PM

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your example is not representative of the scenario.
In here we are overloading something that's handled already in the embedded struct.

If I did what you are suggesting I guess we would have this 🤔:
image

Let's play dumb and try it out...
Actually the behaviour is even weirder:

overloading.mp4

nothing happens!

If I try to "walk my way into the stack"... it stops there, suggesting that my solution seems to be the right approach.

overloading2.mp4

If you wanna play along:
https://go.dev/play/p/s8ncxTVMMp6

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I understand what I was missing and why you're solution works.

However, now I'm trying to understand:

  1. We're not calling the parent's foo function (bey default)
  2. We're not entering an infinite recursion

I can understand why (1) is not happening, but without researching, this makes me feel that the playground abstracts (2) away for us.

Screenshot 2023-02-17 at 10 47 53 AM

if m.paceMaker != nil {
m.paceMaker.SetBus(pocketBus)
}
Expand Down
32 changes: 11 additions & 21 deletions consensus/pacemaker/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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

Expand All @@ -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()

Expand All @@ -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
}
Expand Down
13 changes: 7 additions & 6 deletions consensus/state_sync/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading