diff --git a/Makefile b/Makefile index b625e1ca8..e6530081b 100644 --- a/Makefile +++ b/Makefile @@ -394,3 +394,25 @@ gen_genesis_and_config: ## Clear the genesis and config files for LocalNet clear_genesis_and_config: rm build/config/gen.*.json + +.PHONY: check_cross_module_imports +## Lists cross-module imports +check_cross_module_imports: + $(eval exclude_common=--exclude=Makefile --exclude-dir=shared --exclude-dir=app --exclude-dir=runtime) + echo "persistence:\n" + grep ${exclude_common} --exclude-dir=persistence -r "github.com/pokt-network/pocket/persistence" || echo "✅ OK!" + echo "-----------------------" + echo "utility:\n" + grep ${exclude_common} --exclude-dir=utility -r "github.com/pokt-network/pocket/utility" || echo "✅ OK!" + echo "-----------------------" + echo "consensus:\n" + grep ${exclude_common} --exclude-dir=consensus -r "github.com/pokt-network/pocket/consensus" || echo "✅ OK!" + echo "-----------------------" + echo "telemetry:\n" + grep ${exclude_common} --exclude-dir=telemetry -r "github.com/pokt-network/pocket/telemetry" || echo "✅ OK!" + echo "-----------------------" + echo "p2p:\n" + grep ${exclude_common} --exclude-dir=p2p -r "github.com/pokt-network/pocket/p2p" || echo "✅ OK!" + echo "-----------------------" + echo "runtime:\n" + grep ${exclude_common} --exclude-dir=runtime -r "github.com/pokt-network/pocket/runtime" || echo "✅ OK!" diff --git a/app/client/main.go b/app/client/main.go index 0fbf20a8e..eb305535d 100644 --- a/app/client/main.go +++ b/app/client/main.go @@ -6,6 +6,7 @@ import ( "log" "os" + "github.com/pokt-network/pocket/runtime" "github.com/pokt-network/pocket/shared/debug" "github.com/pokt-network/pocket/telemetry" @@ -47,24 +48,32 @@ var consensusMod modules.ConsensusModule func main() { var err error - consensusMod, err = consensus.Create(defaultConfigPath, defaultGenesisPath, true) // TECHDEBT: extra param required for injecting private key hack for debug client + + runtimeMgr := runtime.NewManagerFromFiles(defaultConfigPath, defaultGenesisPath, runtime.WithRandomPK()) + + consM, err := consensus.Create(runtimeMgr) if err != nil { log.Fatalf("[ERROR] Failed to create consensus module: %v", err.Error()) } - p2pMod, err = p2p.Create(defaultConfigPath, defaultGenesisPath, true) // TECHDEBT: extra param required for injecting private key hack for debug client + consensusMod = consM.(modules.ConsensusModule) + + p2pM, err := p2p.Create(runtimeMgr) if err != nil { log.Fatalf("[ERROR] Failed to create p2p module: %v", err.Error()) } + p2pMod = p2pM.(modules.P2PModule) + // This telemetry module instance is a NOOP because the 'enable_telemetry' flag in the `cfg` above is set to false. // Since this client mimics partial - networking only - functionality of a full node, some of the telemetry-related // code paths are executed. To avoid those messages interfering with the telemetry data collected, a non-nil telemetry // module that NOOPs (per the configs above) is injected. - telemetryMod, err := telemetry.Create(defaultConfigPath, defaultGenesisPath) + telemetryM, err := telemetry.Create(runtimeMgr) if err != nil { log.Fatalf("[ERROR] Failed to create NOOP telemetry module: " + err.Error()) } + telemetryMod := telemetryM.(modules.TelemetryModule) - _ = shared.CreateBusWithOptionalModules(nil, p2pMod, nil, consensusMod, telemetryMod) + _ = shared.CreateBusWithOptionalModules(runtimeMgr, nil, p2pMod, nil, consensusMod, telemetryMod) p2pMod.Start() diff --git a/build/config/main.go b/build/config/main.go index 77a46f023..c1848e17e 100644 --- a/build/config/main.go +++ b/build/config/main.go @@ -6,7 +6,7 @@ import ( "fmt" "io/ioutil" - "github.com/pokt-network/pocket/shared/test_artifacts" + "github.com/pokt-network/pocket/runtime/test_artifacts" ) // Utility to generate config and genesis files diff --git a/consensus/CHANGELOG.md b/consensus/CHANGELOG.md index f9e49f12a..03da52268 100644 --- a/consensus/CHANGELOG.md +++ b/consensus/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.6] - 2022-10-12 + +### [#235](https://github.com/pokt-network/pocket/pull/235) Config and genesis handling + +- Updated to use `RuntimeMgr` +- Made `ConsensusModule` struct unexported +- Updated tests and mocks +- Removed some cross-module dependencies + ## [0.0.0.5] - 2022-10-06 - Don't ignore the exit code of `m.Run()` in the unit tests diff --git a/consensus/block.go b/consensus/block.go index a70c6cecc..878cc1fe7 100644 --- a/consensus/block.go +++ b/consensus/block.go @@ -8,7 +8,7 @@ import ( "github.com/pokt-network/pocket/shared/codec" ) -func (m *ConsensusModule) commitBlock(block *typesCons.Block) error { +func (m *consensusModule) commitBlock(block *typesCons.Block) error { m.nodeLog(typesCons.CommittingBlock(m.Height, len(block.Transactions))) // Store the block in the KV store @@ -41,7 +41,7 @@ func (m *ConsensusModule) commitBlock(block *typesCons.Block) error { return nil } -func (m *ConsensusModule) storeBlock(block *typesCons.Block, blockProtoBytes []byte) error { +func (m *consensusModule) storeBlock(block *typesCons.Block, blockProtoBytes []byte) error { store := m.utilityContext.GetPersistenceContext() // Store in KV Store if err := store.StoreBlock(blockProtoBytes); err != nil { @@ -57,7 +57,7 @@ func (m *ConsensusModule) storeBlock(block *typesCons.Block, blockProtoBytes []b } // TODO: Add unit tests specific to block validation -func (m *ConsensusModule) validateBlockBasic(block *typesCons.Block) error { +func (m *consensusModule) validateBlockBasic(block *typesCons.Block) error { if block == nil && m.Step != NewRound { return typesCons.ErrNilBlock } @@ -66,8 +66,8 @@ func (m *ConsensusModule) validateBlockBasic(block *typesCons.Block) error { return typesCons.ErrBlockExists } - if block != nil && unsafe.Sizeof(*block) > uintptr(m.consGenesis.MaxBlockBytes) { - return typesCons.ErrInvalidBlockSize(uint64(unsafe.Sizeof(*block)), m.consGenesis.MaxBlockBytes) + if block != nil && unsafe.Sizeof(*block) > uintptr(m.consGenesis.GetMaxBlockBytes()) { + return typesCons.ErrInvalidBlockSize(uint64(unsafe.Sizeof(*block)), m.consGenesis.GetMaxBlockBytes()) } // If the current block being processed (i.e. voted on) by consensus is non nil, we need to make @@ -84,7 +84,7 @@ func (m *ConsensusModule) validateBlockBasic(block *typesCons.Block) error { } // Creates a new Utility context and clears/nullifies any previous contexts if they exist -func (m *ConsensusModule) refreshUtilityContext() error { +func (m *consensusModule) refreshUtilityContext() error { // Catch-all structure to release the previous utility context if it wasn't properly cleaned up. // Ideally, this should not be called. if m.utilityContext != nil { diff --git a/consensus/consensus_tests/hotstuff_test.go b/consensus/consensus_tests/hotstuff_test.go index 89c31d87c..8ac97b4e6 100644 --- a/consensus/consensus_tests/hotstuff_test.go +++ b/consensus/consensus_tests/hotstuff_test.go @@ -13,16 +13,16 @@ import ( ) func TestHotstuff4Nodes1BlockHappyPath(t *testing.T) { + clockMock := clock.NewMock() // Test configs numNodes := 4 - configs, genesisStates := GenerateNodeConfigs(t, numNodes) + runtimeMgrs := GenerateNodeRuntimeMgrs(t, numNodes, clockMock) - clockMock := clock.NewMock() go timeReminder(clockMock, 100*time.Millisecond) // Create & start test pocket nodes testChannel := make(modules.EventsChannel, 100) - pocketNodes := CreateTestConsensusPocketNodes(t, configs, genesisStates, clockMock, testChannel) + pocketNodes := CreateTestConsensusPocketNodes(t, runtimeMgrs, testChannel) StartAllTestPocketNodes(t, pocketNodes) // Debug message to start consensus by triggering first view change diff --git a/consensus/consensus_tests/pacemaker_test.go b/consensus/consensus_tests/pacemaker_test.go index 80bf64fc4..109ad2acf 100644 --- a/consensus/consensus_tests/pacemaker_test.go +++ b/consensus/consensus_tests/pacemaker_test.go @@ -24,15 +24,17 @@ func TestTinyPacemakerTimeouts(t *testing.T) { // Test configs numNodes := 4 paceMakerTimeoutMsec := uint64(50) // Set a very small pacemaker timeout - paceMakerTimeout := 50 * timePkg.Millisecond - configs, genesisStates := GenerateNodeConfigs(t, numNodes) - for _, config := range configs { - config.Consensus.GetPaceMakerConfig().SetTimeoutMsec(paceMakerTimeoutMsec) + paceMakerTimeout := 50 * time.Millisecond + runtimeMgrs := GenerateNodeRuntimeMgrs(t, numNodes, clockMock) + for _, runtimeConfig := range runtimeMgrs { + if consCfg, ok := runtimeConfig.GetConfig().GetConsensusConfig().(consensus.HasPacemakerConfig); ok { + consCfg.GetPacemakerConfig().SetTimeoutMsec(paceMakerTimeoutMsec) + } } // Create & start test pocket nodes testChannel := make(modules.EventsChannel, 100) - pocketNodes := CreateTestConsensusPocketNodes(t, configs, genesisStates, clockMock, testChannel) + pocketNodes := CreateTestConsensusPocketNodes(t, runtimeMgrs, testChannel) StartAllTestPocketNodes(t, pocketNodes) // Debug message to start consensus by triggering next view. @@ -123,15 +125,15 @@ func TestTinyPacemakerTimeouts(t *testing.T) { } func TestPacemakerCatchupSameStepDifferentRounds(t *testing.T) { + clockMock := clock.NewMock() numNodes := 4 - configs, genesisStates := GenerateNodeConfigs(t, numNodes) + runtimeConfigs := GenerateNodeRuntimeMgrs(t, numNodes, clockMock) - clockMock := clock.NewMock() timeReminder(clockMock, 100*time.Millisecond) // Create & start test pocket nodes testChannel := make(modules.EventsChannel, 100) - pocketNodes := CreateTestConsensusPocketNodes(t, configs, genesisStates, clockMock, testChannel) + pocketNodes := CreateTestConsensusPocketNodes(t, runtimeConfigs, testChannel) StartAllTestPocketNodes(t, pocketNodes) // Starting point @@ -143,13 +145,16 @@ func TestPacemakerCatchupSameStepDifferentRounds(t *testing.T) { leader := pocketNodes[leaderId] leaderRound := uint64(6) + consensusPK, err := leader.GetBus().GetConsensusModule().GetPrivateKey() + require.NoError(t, err) + // Placeholder block blockHeader := &typesCons.BlockHeader{ Height: int64(testHeight), Hash: hex.EncodeToString(appHash), NumTxs: 0, LastBlockHash: "", - ProposerAddress: leader.Address.Bytes(), + ProposerAddress: consensusPK.Address(), QuorumCertificate: nil, } block := &typesCons.Block{ diff --git a/consensus/consensus_tests/utils_test.go b/consensus/consensus_tests/utils_test.go index e3b3e0c0f..4b8b2539b 100644 --- a/consensus/consensus_tests/utils_test.go +++ b/consensus/consensus_tests/utils_test.go @@ -3,10 +3,8 @@ package consensus_tests import ( "context" "encoding/hex" - "encoding/json" "flag" "fmt" - "io/ioutil" "log" "os" "reflect" @@ -20,20 +18,19 @@ import ( "github.com/golang/mock/gomock" "github.com/pokt-network/pocket/consensus" typesCons "github.com/pokt-network/pocket/consensus/types" + "github.com/pokt-network/pocket/runtime" + "github.com/pokt-network/pocket/runtime/test_artifacts" "github.com/pokt-network/pocket/shared" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" "github.com/pokt-network/pocket/shared/debug" "github.com/pokt-network/pocket/shared/modules" modulesMock "github.com/pokt-network/pocket/shared/modules/mocks" - "github.com/pokt-network/pocket/shared/test_artifacts" "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/anypb" ) func TestMain(m *testing.M) { exitCode := m.Run() - os.Remove(testingConfigFilePath) - os.Remove(testingGenesisFilePath) os.Exit(exitCode) } @@ -64,65 +61,79 @@ type IdToNodeMapping map[typesCons.NodeId]*shared.Node /*** Node Generation Helpers ***/ -func GenerateNodeConfigs(_ *testing.T, validatorCount int) (configs []modules.Config, genesisState modules.GenesisState) { - var keys []string - genesisState, keys = test_artifacts.NewGenesisState(validatorCount, 1, 1, 1) - configs = test_artifacts.NewDefaultConfigs(keys) +func GenerateNodeRuntimeMgrs(_ *testing.T, validatorCount int, clockMgr clock.Clock) []runtime.Manager { + runtimeMgrs := make([]runtime.Manager, validatorCount) + var validatorKeys []string + genesisState, validatorKeys := test_artifacts.NewGenesisState(validatorCount, 1, 1, 1) + configs := test_artifacts.NewDefaultConfigs(validatorKeys) for i, config := range configs { - config.Consensus = &typesCons.ConsensusConfig{ - PrivateKey: config.Base.PrivateKey, + runtime.WithConsensusConfig(&typesCons.ConsensusConfig{ + PrivateKey: config.GetBaseConfig().GetPrivateKey(), MaxMempoolBytes: 500000000, PacemakerConfig: &typesCons.PacemakerConfig{ TimeoutMsec: 5000, Manual: false, DebugTimeBetweenStepsMsec: 0, }, - } - configs[i] = config + })(config) + runtimeMgrs[i] = *runtime.NewManager(config, genesisState, runtime.WithClock(clockMgr)) } - return + return runtimeMgrs } func CreateTestConsensusPocketNodes( t *testing.T, - configs []modules.Config, - genesisState modules.GenesisState, - clock clock.Clock, + runtimeMgrs []runtime.Manager, testChannel modules.EventsChannel, ) (pocketNodes IdToNodeMapping) { - pocketNodes = make(IdToNodeMapping, len(configs)) + pocketNodes = make(IdToNodeMapping, len(runtimeMgrs)) // TODO(design): The order here is important in order for NodeId to be set correctly below. // This logic will need to change once proper leader election is implemented. - sort.Slice(configs, func(i, j int) bool { - pk, err := cryptoPocket.NewPrivateKey(configs[i].Base.PrivateKey) + sort.Slice(runtimeMgrs, func(i, j int) bool { + pk, err := cryptoPocket.NewPrivateKey(runtimeMgrs[i].GetConfig().GetBaseConfig().GetPrivateKey()) require.NoError(t, err) - pk2, err := cryptoPocket.NewPrivateKey(configs[j].Base.PrivateKey) + pk2, err := cryptoPocket.NewPrivateKey(runtimeMgrs[j].GetConfig().GetBaseConfig().GetPrivateKey()) require.NoError(t, err) return pk.Address().String() < pk2.Address().String() }) - for i, cfg := range configs { - pocketNode := CreateTestConsensusPocketNode(t, cfg, genesisState, testChannel, clock) + for i, runtimeMgr := range runtimeMgrs { + pocketNode := CreateTestConsensusPocketNode(t, &runtimeMgr, testChannel) // TODO(olshansky): Figure this part out. pocketNodes[typesCons.NodeId(i+1)] = pocketNode } return } -const ( - testingGenesisFilePath = "genesis.json" - testingConfigFilePath = "config.json" -) +func CreateTestConsensusPocketNodesNew( + t *testing.T, + runtimeMgrs []runtime.Manager, + testChannel modules.EventsChannel, +) (pocketNodes IdToNodeMapping) { + pocketNodes = make(IdToNodeMapping, len(runtimeMgrs)) + // TODO(design): The order here is important in order for NodeId to be set correctly below. + // This logic will need to change once proper leader election is implemented. + sort.Slice(runtimeMgrs, func(i, j int) bool { + pk, err := cryptoPocket.NewPrivateKey(runtimeMgrs[i].GetConfig().GetBaseConfig().GetPrivateKey()) + require.NoError(t, err) + pk2, err := cryptoPocket.NewPrivateKey(runtimeMgrs[j].GetConfig().GetBaseConfig().GetPrivateKey()) + require.NoError(t, err) + return pk.Address().String() < pk2.Address().String() + }) + for i, runtimeMgr := range runtimeMgrs { + pocketNode := CreateTestConsensusPocketNode(t, &runtimeMgr, testChannel) + // TODO(olshansky): Figure this part out. + pocketNodes[typesCons.NodeId(i+1)] = pocketNode + } + return +} // Creates a pocket node where all the primary modules, exception for consensus, are mocked func CreateTestConsensusPocketNode( t *testing.T, - cfg modules.Config, - genesisState modules.GenesisState, + runtimeMgr *runtime.Manager, testChannel modules.EventsChannel, - clock clock.Clock, ) *shared.Node { - createTestingGenesisAndConfigFiles(t, cfg, genesisState) - consensusMod, err := consensus.Create(testingConfigFilePath, testingGenesisFilePath, false) + consensusMod, err := consensus.Create(runtimeMgr) require.NoError(t, err) // TODO(olshansky): At the moment we are using the same base mocks for all the tests, // but note that they will need to be customized on a per test basis. @@ -131,43 +142,19 @@ func CreateTestConsensusPocketNode( utilityMock := baseUtilityMock(t, testChannel) telemetryMock := baseTelemetryMock(t, testChannel) - bus, err := shared.CreateBus(persistenceMock, p2pMock, utilityMock, consensusMod, telemetryMock, clock) + bus, err := shared.CreateBus(runtimeMgr, persistenceMock, p2pMock, utilityMock, consensusMod.(modules.ConsensusModule), telemetryMock) require.NoError(t, err) - pk, err := cryptoPocket.NewPrivateKey(cfg.Base.PrivateKey) + pk, err := cryptoPocket.NewPrivateKey(runtimeMgr.GetConfig().GetBaseConfig().GetPrivateKey()) require.NoError(t, err) - pocketNode := &shared.Node{ - Address: pk.Address(), - } - pocketNode.SetClock(clock) + pocketNode := shared.NewNodeWithP2PAddress(pk.Address()) + pocketNode.SetBus(bus) return pocketNode } -func createTestingGenesisAndConfigFiles(t *testing.T, cfg modules.Config, genesisState modules.GenesisState) { - config, err := json.Marshal(cfg.Consensus) - require.NoError(t, err) - - genesis, err := json.Marshal(genesisState.ConsensusGenesisState) - require.NoError(t, err) - - genesisFile := make(map[string]json.RawMessage) - configFile := make(map[string]json.RawMessage) - consensusModName := new(consensus.ConsensusModule).GetModuleName() - genesisFile[test_artifacts.GetGenesisFileName(consensusModName)] = genesis - configFile[consensusModName] = config - - genesisFileBz, err := json.MarshalIndent(genesisFile, "", " ") - require.NoError(t, err) - - consensusFileBz, err := json.MarshalIndent(configFile, "", " ") - require.NoError(t, err) - require.NoError(t, ioutil.WriteFile(testingGenesisFilePath, genesisFileBz, 0777)) - require.NoError(t, ioutil.WriteFile(testingConfigFilePath, consensusFileBz, 0777)) -} - func StartAllTestPocketNodes(t *testing.T, pocketNodes IdToNodeMapping) { for _, pocketNode := range pocketNodes { go pocketNode.Start() diff --git a/consensus/debugging.go b/consensus/debugging.go index a73dad40e..1a3fe0f5c 100644 --- a/consensus/debugging.go +++ b/consensus/debugging.go @@ -7,7 +7,7 @@ import ( "github.com/pokt-network/pocket/shared/debug" ) -func (m *ConsensusModule) HandleDebugMessage(debugMessage *debug.DebugMessage) error { +func (m *consensusModule) HandleDebugMessage(debugMessage *debug.DebugMessage) error { switch debugMessage.Action { case debug.DebugMessageAction_DEBUG_CONSENSUS_RESET_TO_GENESIS: m.resetToGenesis(debugMessage) @@ -23,7 +23,7 @@ func (m *ConsensusModule) HandleDebugMessage(debugMessage *debug.DebugMessage) e return nil } -func (m *ConsensusModule) GetNodeState() typesCons.ConsensusNodeState { +func (m *consensusModule) GetNodeState() typesCons.ConsensusNodeState { m.m.RLock() defer m.m.RUnlock() leaderId := typesCons.NodeId(0) @@ -40,7 +40,7 @@ func (m *ConsensusModule) GetNodeState() typesCons.ConsensusNodeState { } } -func (m *ConsensusModule) resetToGenesis(_ *debug.DebugMessage) { +func (m *consensusModule) resetToGenesis(_ *debug.DebugMessage) { m.nodeLog(typesCons.DebugResetToGenesis) m.Height = 0 @@ -54,12 +54,12 @@ func (m *ConsensusModule) resetToGenesis(_ *debug.DebugMessage) { m.GetBus().GetPersistenceModule().Start() // reload genesis state } -func (m *ConsensusModule) printNodeState(_ *debug.DebugMessage) { +func (m *consensusModule) printNodeState(_ *debug.DebugMessage) { state := m.GetNodeState() m.nodeLog(typesCons.DebugNodeState(state)) } -func (m *ConsensusModule) triggerNextView(_ *debug.DebugMessage) { +func (m *consensusModule) triggerNextView(_ *debug.DebugMessage) { m.nodeLog(typesCons.DebugTriggerNextView) currentheight := m.Height @@ -75,7 +75,7 @@ func (m *ConsensusModule) triggerNextView(_ *debug.DebugMessage) { } } -func (m *ConsensusModule) togglePacemakerManualMode(_ *debug.DebugMessage) { +func (m *consensusModule) togglePacemakerManualMode(_ *debug.DebugMessage) { newMode := !m.paceMaker.IsManualMode() if newMode { m.nodeLog(typesCons.DebugTogglePacemakerManualMode("MANUAL")) diff --git a/consensus/helpers.go b/consensus/helpers.go index 364a9d26e..a04a53a5d 100644 --- a/consensus/helpers.go +++ b/consensus/helpers.go @@ -40,7 +40,7 @@ var ( // IMPROVE: Avoid having the `ConsensusModule` be a receiver of this; making it more functional. // TODO: Add unit tests for all quorumCert creation & validation logic... -func (m *ConsensusModule) getQuorumCertificate(height uint64, step typesCons.HotstuffStep, round uint64) (*typesCons.QuorumCertificate, error) { +func (m *consensusModule) getQuorumCertificate(height uint64, step typesCons.HotstuffStep, round uint64) (*typesCons.QuorumCertificate, error) { var pss []*typesCons.PartialSignature for _, msg := range m.messagePool[step] { if msg.GetPartialSignature() == nil { @@ -78,7 +78,7 @@ func (m *ConsensusModule) getQuorumCertificate(height uint64, step typesCons.Hot }, nil } -func (m *ConsensusModule) findHighQC(msgs []*typesCons.HotstuffMessage) (qc *typesCons.QuorumCertificate) { +func (m *consensusModule) findHighQC(msgs []*typesCons.HotstuffMessage) (qc *typesCons.QuorumCertificate) { for _, m := range msgs { if m.GetQuorumCertificate() == nil { continue @@ -111,11 +111,11 @@ func isSignatureValid(msg *typesCons.HotstuffMessage, pubKeyString string, signa return pubKey.Verify(bytesToVerify, signature) } -func (m *ConsensusModule) didReceiveEnoughMessageForStep(step typesCons.HotstuffStep) error { +func (m *consensusModule) didReceiveEnoughMessageForStep(step typesCons.HotstuffStep) error { return m.isOptimisticThresholdMet(len(m.messagePool[step])) } -func (m *ConsensusModule) isOptimisticThresholdMet(n int) error { +func (m *consensusModule) isOptimisticThresholdMet(n int) error { numValidators := len(m.validatorMap) if !(float64(n) > ByzantineThreshold*float64(numValidators)) { return typesCons.ErrByzantineThresholdCheck(n, ByzantineThreshold*float64(numValidators)) @@ -123,7 +123,7 @@ func (m *ConsensusModule) isOptimisticThresholdMet(n int) error { return nil } -func (m *ConsensusModule) resetForNewHeight() { +func (m *consensusModule) resetForNewHeight() { m.Round = 0 m.Block = nil m.highPrepareQC = nil @@ -140,7 +140,7 @@ func protoHash(m proto.Message) string { /*** P2P Helpers ***/ -func (m *ConsensusModule) sendToNode(msg *typesCons.HotstuffMessage) { +func (m *consensusModule) sendToNode(msg *typesCons.HotstuffMessage) { // TODO(olshansky): This can happen due to a race condition with the pacemaker. if m.LeaderId == nil { m.nodeLogError(typesCons.ErrNilLeaderId.Error(), nil) @@ -159,7 +159,7 @@ func (m *ConsensusModule) sendToNode(msg *typesCons.HotstuffMessage) { } } -func (m *ConsensusModule) broadcastToNodes(msg *typesCons.HotstuffMessage) { +func (m *consensusModule) broadcastToNodes(msg *typesCons.HotstuffMessage) { m.nodeLog(typesCons.BroadcastingMessage(msg)) anyConsensusMessage, err := codec.GetCodec().ToAny(msg) if err != nil { @@ -175,7 +175,7 @@ func (m *ConsensusModule) broadcastToNodes(msg *typesCons.HotstuffMessage) { /*** Persistence Helpers ***/ // TECHDEBT: Integrate this with the `persistence` module or a real mempool. -func (m *ConsensusModule) clearMessagesPool() { +func (m *consensusModule) clearMessagesPool() { for _, step := range HotstuffSteps { m.messagePool[step] = make([]*typesCons.HotstuffMessage, 0) } @@ -183,24 +183,24 @@ func (m *ConsensusModule) clearMessagesPool() { /*** Leader Election Helpers ***/ -func (m *ConsensusModule) isLeaderUnknown() bool { +func (m *consensusModule) isLeaderUnknown() bool { return m.LeaderId == nil } -func (m *ConsensusModule) isLeader() bool { +func (m *consensusModule) isLeader() bool { return m.LeaderId != nil && *m.LeaderId == m.nodeId } -func (m *ConsensusModule) isReplica() bool { +func (m *consensusModule) isReplica() bool { return !m.isLeader() } -func (m *ConsensusModule) clearLeader() { +func (m *consensusModule) clearLeader() { m.logPrefix = DefaultLogPrefix m.LeaderId = nil } -func (m *ConsensusModule) electNextLeader(message *typesCons.HotstuffMessage) error { +func (m *consensusModule) electNextLeader(message *typesCons.HotstuffMessage) error { leaderId, err := m.leaderElectionMod.ElectNextLeader(message) if err != nil || leaderId == 0 { m.nodeLogError(typesCons.ErrLeaderElection(message).Error(), err) @@ -224,15 +224,15 @@ func (m *ConsensusModule) electNextLeader(message *typesCons.HotstuffMessage) er /*** General Infrastructure Helpers ***/ // TODO(#164): Remove this once we have a proper logging system. -func (m *ConsensusModule) nodeLog(s string) { +func (m *consensusModule) nodeLog(s string) { log.Printf("[%s][%d] %s\n", m.logPrefix, m.nodeId, s) } // TODO(#164): Remove this once we have a proper logging system. -func (m *ConsensusModule) nodeLogError(s string, err error) { +func (m *consensusModule) nodeLogError(s string, err error) { log.Printf("[ERROR][%s][%d] %s: %v\n", m.logPrefix, m.nodeId, s, err) } -func (m *ConsensusModule) setLogPrefix(logPrefix string) { +func (m *consensusModule) setLogPrefix(logPrefix string) { m.logPrefix = logPrefix } diff --git a/consensus/hotstuff_handler.go b/consensus/hotstuff_handler.go index 274a1b45b..f1b580a0a 100644 --- a/consensus/hotstuff_handler.go +++ b/consensus/hotstuff_handler.go @@ -6,14 +6,14 @@ import ( // DISCUSS: Should these functions return an error? type HotstuffMessageHandler interface { - HandleNewRoundMessage(*ConsensusModule, *typesCons.HotstuffMessage) - HandlePrepareMessage(*ConsensusModule, *typesCons.HotstuffMessage) - HandlePrecommitMessage(*ConsensusModule, *typesCons.HotstuffMessage) - HandleCommitMessage(*ConsensusModule, *typesCons.HotstuffMessage) - HandleDecideMessage(*ConsensusModule, *typesCons.HotstuffMessage) + HandleNewRoundMessage(*consensusModule, *typesCons.HotstuffMessage) + HandlePrepareMessage(*consensusModule, *typesCons.HotstuffMessage) + HandlePrecommitMessage(*consensusModule, *typesCons.HotstuffMessage) + HandleCommitMessage(*consensusModule, *typesCons.HotstuffMessage) + HandleDecideMessage(*consensusModule, *typesCons.HotstuffMessage) } -func (m *ConsensusModule) handleHotstuffMessage(msg *typesCons.HotstuffMessage) error { +func (m *consensusModule) handleHotstuffMessage(msg *typesCons.HotstuffMessage) error { m.nodeLog(typesCons.DebugHandlingHotstuffMessage(msg)) step := msg.GetStep() @@ -42,12 +42,12 @@ func (m *ConsensusModule) handleHotstuffMessage(msg *typesCons.HotstuffMessage) return nil } -func (m *ConsensusModule) shouldElectNextLeader() bool { +func (m *consensusModule) shouldElectNextLeader() bool { // Execute leader election if there is no leader and we are in a new round return m.Step == NewRound && m.LeaderId == nil } -func (m *ConsensusModule) shouldLogHotstuffDiscardMessage(step typesCons.HotstuffStep) bool { +func (m *consensusModule) shouldLogHotstuffDiscardMessage(step typesCons.HotstuffStep) bool { // If a replica is not a leader for this round, but has already determined a leader, // and continues to receive NewRound messages, we avoid logging the "message discard" // because it creates unnecessary spam. diff --git a/consensus/hotstuff_leader.go b/consensus/hotstuff_leader.go index 54f41e0dd..19183830b 100644 --- a/consensus/hotstuff_leader.go +++ b/consensus/hotstuff_leader.go @@ -12,7 +12,7 @@ type HotstuffLeaderMessageHandler struct{} var ( LeaderMessageHandler HotstuffMessageHandler = &HotstuffLeaderMessageHandler{} - leaderHandlers = map[typesCons.HotstuffStep]func(*ConsensusModule, *typesCons.HotstuffMessage){ + leaderHandlers = map[typesCons.HotstuffStep]func(*consensusModule, *typesCons.HotstuffMessage){ NewRound: LeaderMessageHandler.HandleNewRoundMessage, Prepare: LeaderMessageHandler.HandlePrepareMessage, PreCommit: LeaderMessageHandler.HandlePrecommitMessage, @@ -23,7 +23,7 @@ var ( /*** Prepare Step ***/ -func (handler *HotstuffLeaderMessageHandler) HandleNewRoundMessage(m *ConsensusModule, msg *typesCons.HotstuffMessage) { +func (handler *HotstuffLeaderMessageHandler) HandleNewRoundMessage(m *consensusModule, msg *typesCons.HotstuffMessage) { defer m.paceMaker.RestartTimer() handler.emitTelemetryEvent(m, msg) @@ -93,7 +93,7 @@ func (handler *HotstuffLeaderMessageHandler) HandleNewRoundMessage(m *ConsensusM /*** PreCommit Step ***/ -func (handler *HotstuffLeaderMessageHandler) HandlePrepareMessage(m *ConsensusModule, msg *typesCons.HotstuffMessage) { +func (handler *HotstuffLeaderMessageHandler) HandlePrepareMessage(m *consensusModule, msg *typesCons.HotstuffMessage) { defer m.paceMaker.RestartTimer() handler.emitTelemetryEvent(m, msg) @@ -137,7 +137,7 @@ func (handler *HotstuffLeaderMessageHandler) HandlePrepareMessage(m *ConsensusMo /*** Commit Step ***/ -func (handler *HotstuffLeaderMessageHandler) HandlePrecommitMessage(m *ConsensusModule, msg *typesCons.HotstuffMessage) { +func (handler *HotstuffLeaderMessageHandler) HandlePrecommitMessage(m *consensusModule, msg *typesCons.HotstuffMessage) { defer m.paceMaker.RestartTimer() handler.emitTelemetryEvent(m, msg) @@ -181,7 +181,7 @@ func (handler *HotstuffLeaderMessageHandler) HandlePrecommitMessage(m *Consensus /*** Decide Step ***/ -func (handler *HotstuffLeaderMessageHandler) HandleCommitMessage(m *ConsensusModule, msg *typesCons.HotstuffMessage) { +func (handler *HotstuffLeaderMessageHandler) HandleCommitMessage(m *consensusModule, msg *typesCons.HotstuffMessage) { defer m.paceMaker.RestartTimer() handler.emitTelemetryEvent(m, msg) @@ -230,7 +230,7 @@ func (handler *HotstuffLeaderMessageHandler) HandleCommitMessage(m *ConsensusMod ) } -func (handler *HotstuffLeaderMessageHandler) HandleDecideMessage(m *ConsensusModule, msg *typesCons.HotstuffMessage) { +func (handler *HotstuffLeaderMessageHandler) HandleDecideMessage(m *consensusModule, msg *typesCons.HotstuffMessage) { defer m.paceMaker.RestartTimer() handler.emitTelemetryEvent(m, msg) @@ -241,7 +241,7 @@ func (handler *HotstuffLeaderMessageHandler) HandleDecideMessage(m *ConsensusMod } // anteHandle is the general handler called for every before every specific HotstuffLeaderMessageHandler handler -func (handler *HotstuffLeaderMessageHandler) anteHandle(m *ConsensusModule, msg *typesCons.HotstuffMessage) error { +func (handler *HotstuffLeaderMessageHandler) anteHandle(m *consensusModule, msg *typesCons.HotstuffMessage) error { // Basic block metadata validation if err := m.validateBlockBasic(msg.GetBlock()); err != nil { @@ -258,7 +258,7 @@ func (handler *HotstuffLeaderMessageHandler) anteHandle(m *ConsensusModule, msg return nil } -func (handler *HotstuffLeaderMessageHandler) emitTelemetryEvent(m *ConsensusModule, msg *typesCons.HotstuffMessage) { +func (handler *HotstuffLeaderMessageHandler) emitTelemetryEvent(m *consensusModule, msg *typesCons.HotstuffMessage) { m.GetBus(). GetTelemetryModule(). GetEventMetricsAgent(). @@ -271,7 +271,16 @@ func (handler *HotstuffLeaderMessageHandler) emitTelemetryEvent(m *ConsensusModu ) } -func (m *ConsensusModule) validatePartialSignature(msg *typesCons.HotstuffMessage) error { +// ValidateBasic general validation checks that apply to every HotstuffLeaderMessage +func (handler *HotstuffLeaderMessageHandler) validateBasic(m *consensusModule, msg *typesCons.HotstuffMessage) error { + // Discard messages with invalid partial signatures before storing it in the leader's consensus mempool + if err := m.validatePartialSignature(msg); err != nil { + return err + } + return nil +} + +func (m *consensusModule) validatePartialSignature(msg *typesCons.HotstuffMessage) error { if msg.GetStep() == NewRound { m.nodeLog(typesCons.ErrUnnecessaryPartialSigForNewRound.Error()) return nil @@ -309,7 +318,7 @@ func (m *ConsensusModule) validatePartialSignature(msg *typesCons.HotstuffMessag // It doesn't actually work because SizeOf returns the size of the map pointer, // and does not recursively determine the size of all the underlying elements // Add proper tests and implementation once the mempool is implemented. -func (m *ConsensusModule) tempIndexHotstuffMessage(msg *typesCons.HotstuffMessage) { +func (m *consensusModule) tempIndexHotstuffMessage(msg *typesCons.HotstuffMessage) { if m.consCfg.GetMaxMempoolBytes() < uint64(unsafe.Sizeof(m.messagePool)) { m.nodeLogError(typesCons.DisregardHotstuffMessage, typesCons.ErrConsensusMempoolFull) return @@ -322,7 +331,7 @@ func (m *ConsensusModule) tempIndexHotstuffMessage(msg *typesCons.HotstuffMessag // This is a helper function intended to be called by a leader/validator during a view change // to prepare a new block that is applied to the new underlying context. -func (m *ConsensusModule) prepareAndApplyBlock() (*typesCons.Block, error) { +func (m *consensusModule) prepareAndApplyBlock() (*typesCons.Block, error) { if m.isReplica() { return nil, typesCons.ErrReplicaPrepareBlock } @@ -364,7 +373,7 @@ func (m *ConsensusModule) prepareAndApplyBlock() (*typesCons.Block, error) { } // Return true if this node, the leader, should prepare a new block -func (m *ConsensusModule) shouldPrepareNewBlock(highPrepareQC *typesCons.QuorumCertificate) bool { +func (m *consensusModule) shouldPrepareNewBlock(highPrepareQC *typesCons.QuorumCertificate) bool { if highPrepareQC == nil { m.nodeLog("Preparing a new block - no highPrepareQC found") return true @@ -379,6 +388,6 @@ func (m *ConsensusModule) shouldPrepareNewBlock(highPrepareQC *typesCons.QuorumC } // The `highPrepareQC` is from the past so we can safely ignore it -func (m *ConsensusModule) isHighPrepareQCFromPast(highPrepareQC *typesCons.QuorumCertificate) bool { +func (m *consensusModule) isHighPrepareQCFromPast(highPrepareQC *typesCons.QuorumCertificate) bool { return highPrepareQC.Height < m.Height || highPrepareQC.Round < m.Round } diff --git a/consensus/hotstuff_replica.go b/consensus/hotstuff_replica.go index e55e85585..927956478 100644 --- a/consensus/hotstuff_replica.go +++ b/consensus/hotstuff_replica.go @@ -13,7 +13,7 @@ type HotstuffReplicaMessageHandler struct{} var ( ReplicaMessageHandler HotstuffMessageHandler = &HotstuffReplicaMessageHandler{} - replicaHandlers = map[typesCons.HotstuffStep]func(*ConsensusModule, *typesCons.HotstuffMessage){ + replicaHandlers = map[typesCons.HotstuffStep]func(*consensusModule, *typesCons.HotstuffMessage){ NewRound: ReplicaMessageHandler.HandleNewRoundMessage, Prepare: ReplicaMessageHandler.HandlePrepareMessage, PreCommit: ReplicaMessageHandler.HandlePrecommitMessage, @@ -24,7 +24,7 @@ var ( /*** NewRound Step ***/ -func (handler *HotstuffReplicaMessageHandler) HandleNewRoundMessage(m *ConsensusModule, msg *typesCons.HotstuffMessage) { +func (handler *HotstuffReplicaMessageHandler) HandleNewRoundMessage(m *consensusModule, msg *typesCons.HotstuffMessage) { defer m.paceMaker.RestartTimer() handler.emitTelemetryEvent(m, msg) @@ -44,7 +44,7 @@ func (handler *HotstuffReplicaMessageHandler) HandleNewRoundMessage(m *Consensus /*** Prepare Step ***/ -func (handler *HotstuffReplicaMessageHandler) HandlePrepareMessage(m *ConsensusModule, msg *typesCons.HotstuffMessage) { +func (handler *HotstuffReplicaMessageHandler) HandlePrepareMessage(m *consensusModule, msg *typesCons.HotstuffMessage) { defer m.paceMaker.RestartTimer() handler.emitTelemetryEvent(m, msg) @@ -79,7 +79,7 @@ func (handler *HotstuffReplicaMessageHandler) HandlePrepareMessage(m *ConsensusM /*** PreCommit Step ***/ -func (handler *HotstuffReplicaMessageHandler) HandlePrecommitMessage(m *ConsensusModule, msg *typesCons.HotstuffMessage) { +func (handler *HotstuffReplicaMessageHandler) HandlePrecommitMessage(m *consensusModule, msg *typesCons.HotstuffMessage) { defer m.paceMaker.RestartTimer() handler.emitTelemetryEvent(m, msg) @@ -108,7 +108,7 @@ func (handler *HotstuffReplicaMessageHandler) HandlePrecommitMessage(m *Consensu /*** Commit Step ***/ -func (handler *HotstuffReplicaMessageHandler) HandleCommitMessage(m *ConsensusModule, msg *typesCons.HotstuffMessage) { +func (handler *HotstuffReplicaMessageHandler) HandleCommitMessage(m *consensusModule, msg *typesCons.HotstuffMessage) { defer m.paceMaker.RestartTimer() handler.emitTelemetryEvent(m, msg) @@ -137,7 +137,7 @@ func (handler *HotstuffReplicaMessageHandler) HandleCommitMessage(m *ConsensusMo /*** Decide Step ***/ -func (handler *HotstuffReplicaMessageHandler) HandleDecideMessage(m *ConsensusModule, msg *typesCons.HotstuffMessage) { +func (handler *HotstuffReplicaMessageHandler) HandleDecideMessage(m *consensusModule, msg *typesCons.HotstuffMessage) { defer m.paceMaker.RestartTimer() handler.emitTelemetryEvent(m, msg) @@ -163,7 +163,7 @@ func (handler *HotstuffReplicaMessageHandler) HandleDecideMessage(m *ConsensusMo } // anteHandle is the handler called on every replica message before specific handler -func (handler *HotstuffReplicaMessageHandler) anteHandle(m *ConsensusModule, msg *typesCons.HotstuffMessage) error { +func (handler *HotstuffReplicaMessageHandler) anteHandle(m *consensusModule, msg *typesCons.HotstuffMessage) error { // Basic block metadata validation if err := m.validateBlockBasic(msg.GetBlock()); err != nil { return err @@ -172,7 +172,7 @@ func (handler *HotstuffReplicaMessageHandler) anteHandle(m *ConsensusModule, msg return nil } -func (handler *HotstuffReplicaMessageHandler) emitTelemetryEvent(m *ConsensusModule, msg *typesCons.HotstuffMessage) { +func (handler *HotstuffReplicaMessageHandler) emitTelemetryEvent(m *consensusModule, msg *typesCons.HotstuffMessage) { m.GetBus(). GetTelemetryModule(). GetEventMetricsAgent(). @@ -185,7 +185,7 @@ func (handler *HotstuffReplicaMessageHandler) emitTelemetryEvent(m *ConsensusMod ) } -func (m *ConsensusModule) validateProposal(msg *typesCons.HotstuffMessage) error { +func (m *consensusModule) validateProposal(msg *typesCons.HotstuffMessage) error { // Check if node should be accepting proposals if !(msg.GetType() == Propose && msg.GetStep() == Prepare) { return typesCons.ErrProposalNotValidInPrepare @@ -226,7 +226,7 @@ func (m *ConsensusModule) validateProposal(msg *typesCons.HotstuffMessage) error } // This helper applies the block metadata to the utility & persistence layers -func (m *ConsensusModule) applyBlock(block *typesCons.Block) error { +func (m *consensusModule) applyBlock(block *typesCons.Block) error { // TECHDEBT: Retrieve this from persistence lastByzValidators := make([][]byte, 0) @@ -244,7 +244,7 @@ func (m *ConsensusModule) applyBlock(block *typesCons.Block) error { return nil } -func (m *ConsensusModule) validateQuorumCertificate(qc *typesCons.QuorumCertificate) error { +func (m *consensusModule) validateQuorumCertificate(qc *typesCons.QuorumCertificate) error { if qc == nil { return typesCons.ErrNilQC } diff --git a/consensus/leader_election/module.go b/consensus/leader_election/module.go index a5e24dcf3..8341a162c 100644 --- a/consensus/leader_election/module.go +++ b/consensus/leader_election/module.go @@ -16,13 +16,17 @@ type LeaderElectionModule interface { ElectNextLeader(*typesCons.HotstuffMessage) (typesCons.NodeId, error) } -var _ leaderElectionModule = leaderElectionModule{} +var _ LeaderElectionModule = &leaderElectionModule{} type leaderElectionModule struct { bus modules.Bus } -func Create(_ *typesCons.ConsensusConfig, _ *typesCons.ConsensusGenesisState) (LeaderElectionModule, error) { +func Create(runtime modules.RuntimeMgr) (modules.Module, error) { + return new(leaderElectionModule).Create(runtime) +} + +func (*leaderElectionModule) Create(runtime modules.RuntimeMgr) (modules.Module, error) { return &leaderElectionModule{}, nil } @@ -35,14 +39,6 @@ func (m *leaderElectionModule) Stop() error { return nil } -func (m *leaderElectionModule) InitConfig(pathToConfigJSON string) (config modules.IConfig, err error) { - return // No-op -} - -func (m *leaderElectionModule) InitGenesis(pathToGenesisJSON string) (genesis modules.IGenesis, err error) { - return // No-op -} - func (m *leaderElectionModule) GetModuleName() string { return LeaderElectionModuleName } diff --git a/consensus/module.go b/consensus/module.go index d4c1eb371..aad862427 100644 --- a/consensus/module.go +++ b/consensus/module.go @@ -1,9 +1,7 @@ package consensus import ( - "encoding/json" "fmt" - "io/ioutil" "log" "sync" @@ -11,7 +9,6 @@ import ( typesCons "github.com/pokt-network/pocket/consensus/types" "github.com/pokt-network/pocket/shared/codec" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" - "github.com/pokt-network/pocket/shared/test_artifacts" "google.golang.org/protobuf/types/known/anypb" consensusTelemetry "github.com/pokt-network/pocket/consensus/telemetry" @@ -23,18 +20,19 @@ const ( ConsensusModuleName = "consensus" ) -var _ modules.ConsensusGenesisState = &typesCons.ConsensusGenesisState{} -var _ modules.PacemakerConfig = &typesCons.PacemakerConfig{} -var _ modules.ConsensusConfig = &typesCons.ConsensusConfig{} -var _ modules.ConsensusModule = &ConsensusModule{} +var ( + _ modules.ConsensusModule = &consensusModule{} + _ modules.ConsensusConfig = &typesCons.ConsensusConfig{} + _ modules.ConsensusGenesisState = &typesCons.ConsensusGenesisState{} +) // TODO(#256): Do not export the `ConsensusModule` struct or the fields inside of it. -type ConsensusModule struct { +type consensusModule struct { bus modules.Bus privateKey cryptoPocket.Ed25519PrivateKey - consCfg *typesCons.ConsensusConfig - consGenesis *typesCons.ConsensusGenesisState + consCfg modules.ConsensusConfig + consGenesis modules.ConsensusGenesisState // m is a mutex used to control synchronization when multiple goroutines are accessing the struct and its fields / properties. // @@ -75,48 +73,53 @@ type ConsensusModule struct { messagePool map[typesCons.HotstuffStep][]*typesCons.HotstuffMessage } -func Create(configPath, genesisPath string, useRandomPK bool) (modules.ConsensusModule, error) { - cm := new(ConsensusModule) - c, err := cm.InitConfig(configPath) - if err != nil { - return nil, err +func Create(runtimeMgr modules.RuntimeMgr) (modules.Module, error) { + return new(consensusModule).Create(runtimeMgr) +} + +func (*consensusModule) Create(runtimeMgr modules.RuntimeMgr) (modules.Module, error) { + var m *consensusModule + + cfg := runtimeMgr.GetConfig() + if err := m.ValidateConfig(cfg); err != nil { + return nil, fmt.Errorf("config validation failed: %w", err) } - g, err := cm.InitGenesis(genesisPath) - if err != nil { - return nil, err + consensusCfg := cfg.GetConsensusConfig() + + genesis := runtimeMgr.GetGenesis() + if err := m.ValidateGenesis(genesis); err != nil { + return nil, fmt.Errorf("genesis validation failed: %w", err) } - cfg := c.(*typesCons.ConsensusConfig) - genesis := g.(*typesCons.ConsensusGenesisState) - leaderElectionMod, err := leader_election.Create(cfg, genesis) + consensusGenesis := genesis.GetConsensusGenesisState() + + leaderElectionMod, err := leader_election.Create(runtimeMgr) if err != nil { return nil, err } // TODO(olshansky): Can we make this a submodule? - paceMaker, err := CreatePacemaker(cfg) + paceMakerMod, err := CreatePacemaker(runtimeMgr) if err != nil { return nil, err } - valMap := typesCons.ValidatorListToMap(genesis.Validators) - var privateKey cryptoPocket.PrivateKey - if useRandomPK { - privateKey, err = cryptoPocket.GeneratePrivateKey() - } else { - privateKey, err = cryptoPocket.NewPrivateKey(cfg.PrivateKey) - } + valMap := typesCons.ActorListToValidatorMap(consensusGenesis.GetVals()) + + privateKey, err := cryptoPocket.NewPrivateKey(consensusCfg.GetPrivateKey()) if err != nil { return nil, err } address := privateKey.Address().String() valIdMap, idValMap := typesCons.GetValAddrToIdMap(valMap) - m := &ConsensusModule{ + paceMaker := paceMakerMod.(Pacemaker) + + m = &consensusModule{ bus: nil, privateKey: privateKey.(cryptoPocket.Ed25519PrivateKey), - consCfg: cfg, - consGenesis: genesis, + consCfg: cfg.GetConsensusConfig(), + consGenesis: genesis.GetConsensusGenesisState(), Height: 0, Round: 0, @@ -136,7 +139,7 @@ func Create(configPath, genesisPath string, useRandomPK bool) (modules.Consensus utilityContext: nil, paceMaker: paceMaker, - leaderElectionMod: leaderElectionMod, + leaderElectionMod: leaderElectionMod.(leader_election.LeaderElectionModule), logPrefix: DefaultLogPrefix, messagePool: make(map[typesCons.HotstuffStep][]*typesCons.HotstuffMessage), @@ -148,40 +151,7 @@ func Create(configPath, genesisPath string, useRandomPK bool) (modules.Consensus return m, nil } -func (m *ConsensusModule) InitConfig(pathToConfigJSON string) (config modules.IConfig, err error) { - data, err := ioutil.ReadFile(pathToConfigJSON) - if err != nil { - return - } - // over arching configuration file - rawJSON := make(map[string]json.RawMessage) - if err = json.Unmarshal(data, &rawJSON); err != nil { - log.Fatalf("[ERROR] an error occurred unmarshalling the %s file: %v", pathToConfigJSON, err.Error()) - } - // consensus specific configuration file - config = new(typesCons.ConsensusConfig) - err = json.Unmarshal(rawJSON[m.GetModuleName()], config) - return -} - -func (m *ConsensusModule) InitGenesis(pathToGenesisJSON string) (genesis modules.IGenesis, err error) { - data, err := ioutil.ReadFile(pathToGenesisJSON) - if err != nil { - return - } - // over arching configuration file - rawJSON := make(map[string]json.RawMessage) - if err = json.Unmarshal(data, &rawJSON); err != nil { - log.Fatalf("[ERROR] an error occurred unmarshalling the %s file: %v", pathToGenesisJSON, err.Error()) - } - // consensus specific configuration file - genesis = new(typesCons.ConsensusGenesisState) - - err = json.Unmarshal(rawJSON[test_artifacts.GetGenesisFileName(m.GetModuleName())], genesis) - return -} - -func (m *ConsensusModule) Start() error { +func (m *consensusModule) Start() error { m.GetBus(). GetTelemetryModule(). GetTimeSeriesAgent(). @@ -205,28 +175,40 @@ func (m *ConsensusModule) Start() error { return nil } -func (m *ConsensusModule) Stop() error { +func (m *consensusModule) Stop() error { return nil } -func (m *ConsensusModule) GetModuleName() string { +func (m *consensusModule) GetModuleName() string { return ConsensusModuleName } -func (m *ConsensusModule) GetBus() modules.Bus { +func (m *consensusModule) GetBus() modules.Bus { if m.bus == nil { log.Fatalf("PocketBus is not initialized") } return m.bus } -func (m *ConsensusModule) SetBus(pocketBus modules.Bus) { +func (m *consensusModule) SetBus(pocketBus modules.Bus) { m.bus = pocketBus m.paceMaker.SetBus(pocketBus) m.leaderElectionMod.SetBus(pocketBus) } -func (m *ConsensusModule) HandleMessage(message *anypb.Any) error { +func (*consensusModule) ValidateConfig(cfg modules.Config) error { + return nil +} + +func (*consensusModule) ValidateGenesis(genesis modules.GenesisState) error { + return nil +} + +func (m *consensusModule) GetPrivateKey() (cryptoPocket.PrivateKey, error) { + return cryptoPocket.NewPrivateKey(m.consCfg.GetPrivateKey()) +} + +func (m *consensusModule) HandleMessage(message *anypb.Any) error { m.m.Lock() defer m.m.Unlock() switch message.MessageName() { @@ -251,25 +233,25 @@ func (m *ConsensusModule) HandleMessage(message *anypb.Any) error { return nil } -func (m *ConsensusModule) AppHash() string { +func (m *consensusModule) AppHash() string { return m.lastAppHash } -func (m *ConsensusModule) CurrentHeight() uint64 { +func (m *consensusModule) CurrentHeight() uint64 { return m.Height } -func (m *ConsensusModule) ValidatorMap() modules.ValidatorMap { // TODO: This needs to be dynamically updated during various operations and network changes. +func (m *consensusModule) ValidatorMap() modules.ValidatorMap { // TODO: This needs to be dynamically updated during various operations and network changes. return typesCons.ValidatorMapToModulesValidatorMap(m.validatorMap) } // TODO(#256): Currently only used for testing purposes -func (m *ConsensusModule) SetUtilityContext(utilityContext modules.UtilityContext) { +func (m *consensusModule) SetUtilityContext(utilityContext modules.UtilityContext) { m.utilityContext = utilityContext } // TODO: Populate the entire state from the persistence module: validator set, quorum cert, last block hash, etc... -func (m *ConsensusModule) loadPersistedState() error { +func (m *consensusModule) loadPersistedState() error { persistenceContext, err := m.GetBus().GetPersistenceModule().NewReadContext(-1) // Unknown height if err != nil { return nil @@ -293,3 +275,9 @@ func (m *ConsensusModule) loadPersistedState() error { m.nodeLog(fmt.Sprintf("Starting node at height %d", latestHeight)) return nil } + +// HasPacemakerConfig is used to determine if a ConsensusConfig includes a PacemakerConfig without having to cast to the struct +// (which would break mocks and/or pollute the codebase with mock types casts and checks) +type HasPacemakerConfig interface { + GetPacemakerConfig() *typesCons.PacemakerConfig +} diff --git a/consensus/pacemaker.go b/consensus/pacemaker.go index ba4202897..4f0651418 100644 --- a/consensus/pacemaker.go +++ b/consensus/pacemaker.go @@ -2,6 +2,7 @@ package consensus import ( "context" + "fmt" "log" timePkg "time" @@ -22,7 +23,7 @@ type Pacemaker interface { // TODO(olshansky): Rather than exposing the underlying `ConsensusModule` struct, // we could create a `ConsensusModuleDebug` interface that'll expose setters/getters // for the height/round/step/etc, and interface with the module that way. - SetConsensusModule(module *ConsensusModule) + SetConsensusModule(module *consensusModule) ValidateMessage(message *typesCons.HotstuffMessage) error RestartTimer() @@ -30,8 +31,12 @@ type Pacemaker interface { InterruptRound() } -var _ modules.Module = &paceMaker{} -var _ PacemakerDebug = &paceMaker{} +var ( + _ modules.Module = &paceMaker{} + _ modules.ConfigurableModule = &paceMaker{} + _ PacemakerDebug = &paceMaker{} + _ modules.PacemakerConfig = &typesCons.PacemakerConfig{} +) type paceMaker struct { bus modules.Bus @@ -40,9 +45,9 @@ type paceMaker struct { // due to it's dependency on the underlying implementation of `ConsensusModule`. Think // through a way to decouple these. This could be fixed with reflection but that's not // a great idea in production code. - consensusMod *ConsensusModule + consensusMod *consensusModule - pacemakerConfigs modules.PacemakerConfig + pacemakerCfg modules.PacemakerConfig stepCancelFunc context.CancelFunc @@ -50,26 +55,30 @@ type paceMaker struct { paceMakerDebug } -func (p *paceMaker) InitConfig(pathToConfigJSON string) (config modules.IConfig, err error) { - return // No-op +func CreatePacemaker(runtimeMgr modules.RuntimeMgr) (modules.Module, error) { + var m paceMaker + return m.Create(runtimeMgr) } -func (p *paceMaker) InitGenesis(pathToGenesisJSON string) (genesis modules.IGenesis, err error) { - return // No-op -} +func (m *paceMaker) Create(runtimeMgr modules.RuntimeMgr) (modules.Module, error) { + cfg := runtimeMgr.GetConfig() + if err := m.ValidateConfig(cfg); err != nil { + log.Fatalf("config validation failed: %v", err) + } + + pacemakerCfg := cfg.GetConsensusConfig().(HasPacemakerConfig).GetPacemakerConfig() -func CreatePacemaker(cfg *typesCons.ConsensusConfig) (m *paceMaker, err error) { return &paceMaker{ bus: nil, consensusMod: nil, - pacemakerConfigs: cfg.GetPaceMakerConfig(), + pacemakerCfg: pacemakerCfg, stepCancelFunc: nil, // Only set on restarts paceMakerDebug: paceMakerDebug{ - manualMode: cfg.GetPaceMakerConfig().GetManual(), - debugTimeBetweenStepsMsec: cfg.GetPaceMakerConfig().GetDebugTimeBetweenStepsMsec(), + manualMode: pacemakerCfg.GetManual(), + debugTimeBetweenStepsMsec: pacemakerCfg.GetDebugTimeBetweenStepsMsec(), quorumCertificate: nil, }, }, nil @@ -98,7 +107,14 @@ func (m *paceMaker) GetBus() modules.Bus { return m.bus } -func (m *paceMaker) SetConsensusModule(c *ConsensusModule) { +func (*paceMaker) ValidateConfig(cfg modules.Config) error { + if _, ok := cfg.GetConsensusConfig().(HasPacemakerConfig); !ok { + return fmt.Errorf("cannot cast to PacemakeredConsensus") + } + return nil +} + +func (m *paceMaker) SetConsensusModule(c *consensusModule) { m.consensusMod = c } @@ -161,7 +177,7 @@ func (p *paceMaker) RestartTimer() { stepTimeout := p.getStepTimeout(p.consensusMod.Round) - clock := p.bus.GetClock() + clock := p.bus.GetRuntimeMgr().GetClock() ctx, cancel := clock.WithTimeout(context.TODO(), stepTimeout) p.stepCancelFunc = cancel @@ -235,6 +251,6 @@ func (p *paceMaker) startNextView(qc *typesCons.QuorumCertificate, forceNextView // TODO(olshansky): Increase timeout using exponential backoff. func (p *paceMaker) getStepTimeout(round uint64) timePkg.Duration { - baseTimeout := timePkg.Duration(int64(timePkg.Millisecond) * int64(p.pacemakerConfigs.GetTimeoutMsec())) + baseTimeout := timePkg.Duration(int64(timePkg.Millisecond) * int64(p.pacemakerCfg.GetTimeoutMsec())) return baseTimeout } diff --git a/consensus/types/consensus_genesis.go b/consensus/types/consensus_genesis.go new file mode 100644 index 000000000..4ec59e476 --- /dev/null +++ b/consensus/types/consensus_genesis.go @@ -0,0 +1,19 @@ +package types + +import "github.com/pokt-network/pocket/shared/modules" + +var _ modules.ConsensusGenesisState = &ConsensusGenesisState{} + +func (x *ConsensusGenesisState) GetVals() []modules.Actor { + return ActorsToActorsInterface(x.GetValidators()) +} + +func ActorsToActorsInterface(vals []*Validator) (actorI []modules.Actor) { + actorI = make([]modules.Actor, len(vals)) + for i, actor := range vals { + actorI[i] = actor + } + return +} + +var _ modules.Actor = &Validator{} diff --git a/consensus/types/converters.go b/consensus/types/converters.go new file mode 100644 index 000000000..f11d42bc2 --- /dev/null +++ b/consensus/types/converters.go @@ -0,0 +1,22 @@ +package types + +import ( + "github.com/pokt-network/pocket/shared/modules" +) + +func actorToValidator(actor modules.Actor) *Validator { + return &Validator{ + Address: actor.GetAddress(), + PublicKey: actor.GetPublicKey(), + StakedAmount: actor.GetStakedAmount(), + GenericParam: actor.GetGenericParam(), + } +} + +func ToConsensusValidators(actors []modules.Actor) (vals []*Validator) { + vals = make([]*Validator, len(actors)) + for i, actor := range actors { + vals[i] = actorToValidator(actor) + } + return +} diff --git a/consensus/types/types.go b/consensus/types/types.go index 86b9a0624..a73637d6a 100644 --- a/consensus/types/types.go +++ b/consensus/types/types.go @@ -41,10 +41,6 @@ func GetValAddrToIdMap(validatorMap ValidatorMap) (ValAddrToIdMap, IdToValAddrMa return valToIdMap, idToValMap } -func (x *ConsensusConfig) GetPaceMakerConfig() modules.PacemakerConfig { - return x.GetPacemakerConfig() -} - func (x *PacemakerConfig) SetTimeoutMsec(u uint64) { x.TimeoutMsec = u } @@ -57,9 +53,9 @@ func ValidatorMapToModulesValidatorMap(validatorMap ValidatorMap) (vm modules.Va return } -func ValidatorListToMap(validators []*Validator) (m ValidatorMap) { - m = make(ValidatorMap, len(validators)) - for _, v := range validators { +func ActorListToValidatorMap(actors []modules.Actor) (m ValidatorMap) { + m = make(ValidatorMap, len(actors)) + for _, v := range actors { m[v.GetAddress()] = v } return diff --git a/go.mod b/go.mod index dfc0f9cb6..1d06da8d6 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,9 @@ require ( github.com/dgraph-io/badger/v3 v3.2103.2 github.com/jackc/pgconn v1.11.0 github.com/jordanorelli/lexnum v0.0.0-20141216151731-460eeb125754 + github.com/mitchellh/mapstructure v1.1.2 github.com/quasilyte/go-ruleguard/dsl v0.3.21 + github.com/spf13/viper v1.3.2 ) require ( @@ -70,7 +72,9 @@ require ( filippo.io/edwards25519 v1.0.0-rc.1 // indirect github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fsnotify/fsnotify v1.4.7 // indirect github.com/google/go-cmp v0.5.6 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect @@ -78,9 +82,16 @@ require ( github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect github.com/jackc/pgtype v1.10.0 // indirect github.com/kr/pretty v0.3.0 // indirect + github.com/magiconair/properties v1.8.0 // indirect + github.com/pelletier/go-toml v1.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/spf13/afero v1.1.2 // indirect + github.com/spf13/cast v1.3.0 // indirect + github.com/spf13/jwalterweatherman v1.0.0 // indirect + github.com/spf13/pflag v1.0.3 // indirect golang.org/x/sys v0.0.0-20220405210540-1e041c57c461 // indirect golang.org/x/text v0.3.7 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index fe5a248cd..cf1ce90f8 100644 --- a/go.sum +++ b/go.sum @@ -38,6 +38,7 @@ github.com/46bit/ristretto v0.1.0-with-arm-fix h1:jcjBpelxSNRlrGUo5jZnJNESgCsiJz github.com/46bit/ristretto v0.1.0-with-arm-fix/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= @@ -117,6 +118,7 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= @@ -207,6 +209,7 @@ github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQ github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -292,6 +295,7 @@ 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.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= @@ -303,6 +307,7 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -323,6 +328,7 @@ github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.m github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= @@ -381,11 +387,16 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -765,6 +776,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/p2p/CHANGELOG.md b/p2p/CHANGELOG.md index ae786bed2..72a1be716 100644 --- a/p2p/CHANGELOG.md +++ b/p2p/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.5] - 2022-10-12 + +### [#235](https://github.com/pokt-network/pocket/pull/235) Config and genesis handling + +- Updated to use `RuntimeMgr` +- Updated tests and mocks +- Removed some cross-module dependencies + ## [0.0.0.4] - 2022-10-06 - Don't ignore the exit code of `m.Run()` in the unit tests diff --git a/p2p/module.go b/p2p/module.go index 044549266..01c8447e2 100644 --- a/p2p/module.go +++ b/p2p/module.go @@ -5,8 +5,7 @@ package p2p // to be a "real" replacement for now. import ( - "encoding/json" - "io/ioutil" + "fmt" "log" "github.com/pokt-network/pocket/p2p/raintree" @@ -27,8 +26,8 @@ const ( ) type p2pModule struct { - bus modules.Bus - p2pConfig modules.P2PConfig // TODO (olshansky): to remove this since it'll be available via the bus + bus modules.Bus + p2pCfg modules.P2PConfig // TODO (olshansky): to remove this since it'll be available via the bus listener typesP2P.Transport address cryptoPocket.Address @@ -41,28 +40,30 @@ func (m *p2pModule) GetAddress() (cryptoPocket.Address, error) { return m.address, nil } -func Create(configPath, genesisPath string, useRandomPK bool) (m modules.P2PModule, err error) { +func Create(runtimeMgr modules.RuntimeMgr) (modules.Module, error) { + return new(p2pModule).Create(runtimeMgr) +} + +func (*p2pModule) Create(runtimeMgr modules.RuntimeMgr) (modules.Module, error) { log.Println("Creating network module") - c, err := new(p2pModule).InitConfig(configPath) - if err != nil { - return nil, err + var m *p2pModule + + cfg := runtimeMgr.GetConfig() + if err := m.ValidateConfig(cfg); err != nil { + return nil, fmt.Errorf("config validation failed: %w", err) } - cfg := c.(*typesP2P.P2PConfig) - l, err := CreateListener(cfg) + p2pCfg := cfg.GetP2PConfig() + + l, err := CreateListener(p2pCfg) if err != nil { return nil, err } - var privateKey cryptoPocket.PrivateKey - if useRandomPK { - privateKey, err = cryptoPocket.GeneratePrivateKey() - } else { - privateKey, err = cryptoPocket.NewPrivateKey(cfg.PrivateKey) - } + privateKey, err := cryptoPocket.NewPrivateKey(p2pCfg.GetPrivateKey()) if err != nil { return nil, err } m = &p2pModule{ - p2pConfig: cfg, + p2pCfg: p2pCfg, listener: l, address: privateKey.Address(), @@ -70,26 +71,6 @@ func Create(configPath, genesisPath string, useRandomPK bool) (m modules.P2PModu return m, nil } -func (m *p2pModule) InitConfig(pathToConfigJSON string) (config modules.IConfig, err error) { - data, err := ioutil.ReadFile(pathToConfigJSON) - if err != nil { - return - } - // over arching configuration file - rawJSON := make(map[string]json.RawMessage) - if err = json.Unmarshal(data, &rawJSON); err != nil { - log.Fatalf("[ERROR] an error occurred unmarshalling the %s file: %v", pathToConfigJSON, err.Error()) - } - // p2p specific configuration file - config = new(typesP2P.P2PConfig) - err = json.Unmarshal(rawJSON[m.GetModuleName()], config) - return -} - -func (m *p2pModule) InitGenesis(pathToGenesisJSON string) (genesis modules.IGenesis, err error) { - return // No-op -} - func (m *p2pModule) SetBus(bus modules.Bus) { // INVESTIGATE: Can the code flow be modified to set the bus here? // m.network.SetBus(m.GetBus()) @@ -119,12 +100,12 @@ func (m *p2pModule) Start() error { telemetry.P2P_NODE_STARTED_TIMESERIES_METRIC_DESCRIPTION, ) - addrBook, err := ValidatorMapToAddrBook(m.p2pConfig, m.bus.GetConsensusModule().ValidatorMap()) + addrBook, err := ValidatorMapToAddrBook(m.p2pCfg, m.bus.GetConsensusModule().ValidatorMap()) if err != nil { return err } - if m.p2pConfig.GetUseRainTree() { + if m.p2pCfg.GetUseRainTree() { m.network = raintree.NewRainTreeNetwork(m.address, addrBook) } else { m.network = stdnetwork.NewNetwork(addrBook) @@ -184,6 +165,10 @@ func (m *p2pModule) Send(addr cryptoPocket.Address, msg *anypb.Any, topic debug. return m.network.NetworkSend(data, addr) } +func (*p2pModule) ValidateConfig(cfg modules.Config) error { + return nil +} + func (m *p2pModule) handleNetworkMessage(networkMsgData []byte) { appMsgData, err := m.network.HandleNetworkData(networkMsgData) if err != nil { diff --git a/p2p/module_raintree_test.go b/p2p/module_raintree_test.go index 8d5ea23ff..6eac6b1b5 100644 --- a/p2p/module_raintree_test.go +++ b/p2p/module_raintree_test.go @@ -3,20 +3,18 @@ package p2p import ( "crypto/ed25519" "encoding/binary" - "encoding/json" "fmt" - "io/ioutil" "log" "os" "path/filepath" "sort" - "strconv" "sync" "testing" "time" + "github.com/pokt-network/pocket/runtime" "github.com/pokt-network/pocket/shared/debug" - "github.com/pokt-network/pocket/shared/test_artifacts" + "github.com/stretchr/testify/require" "github.com/golang/mock/gomock" typesP2P "github.com/pokt-network/pocket/p2p/types" @@ -24,7 +22,6 @@ import ( cryptoPocket "github.com/pokt-network/pocket/shared/crypto" "github.com/pokt-network/pocket/shared/modules" modulesMock "github.com/pokt-network/pocket/shared/modules/mocks" - "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/anypb" ) @@ -182,7 +179,7 @@ func TestRainTreeCompleteTwentySevenNodes(t *testing.T) { func testRainTreeCalls(t *testing.T, origNode string, testCommConfig TestRainTreeCommConfig, isOriginatorPinged bool) { // Network configurations numValidators := len(testCommConfig) - configs, genesisState := createConfigs(t, numValidators) + runtimeConfigs := createMockRuntimeMgrs(t, numValidators) // Test configurations var messageHandeledWaitGroup sync.WaitGroup @@ -193,7 +190,7 @@ func testRainTreeCalls(t *testing.T, origNode string, testCommConfig TestRainTre } // Network initialization - consensusMock := prepareConsensusMock(t, genesisState) + consensusMock := prepareConsensusMock(t, runtimeConfigs[0].GetGenesis()) telemetryMock := prepareTelemetryMock(t) connMocks := make(map[string]typesP2P.Transport) busMocks := make(map[string]modules.Bus) @@ -203,7 +200,7 @@ func testRainTreeCalls(t *testing.T, origNode string, testCommConfig TestRainTre } // Module injection - p2pModules := prepareP2PModules(t, configs) + p2pModules := prepareP2PModules(t, runtimeConfigs) for validatorId, p2pMod := range p2pModules { p2pMod.listener = connMocks[validatorId] p2pMod.SetBus(busMocks[validatorId]) @@ -242,9 +239,6 @@ const ( maxNumKeys = 42 // The number of keys generated for all the unit tests. Optimization to avoid regenerating every time. serviceUrlFormat = "val_%d" testChannelSize = 10000 - testingGenesisFilePath = "genesis" - testingConfigFilePath = "config" - jsonPosfix = ".json" ) // TODO(olshansky): Add configurations tests for dead and partially visible nodes @@ -300,7 +294,7 @@ func prepareConsensusMock(t *testing.T, genesisState modules.GenesisState) *modu ctrl := gomock.NewController(t) consensusMock := modulesMock.NewMockConsensusModule(ctrl) - validators := genesisState.PersistenceGenesisState.GetVals() + validators := genesisState.GetPersistenceGenesisState().GetVals() m := make(modules.ValidatorMap, len(validators)) for _, v := range validators { m[v.GetAddress()] = v @@ -367,85 +361,79 @@ func prepareConnMock(t *testing.T, expectedNumNetworkReads, expectedNumNetworkWr return connMock } -func prepareP2PModules(t *testing.T, configs []modules.Config) (p2pModules map[string]*p2pModule) { - p2pModules = make(map[string]*p2pModule, len(configs)) - for i, config := range configs { - createTestingGenesisAndConfigFiles(t, config, modules.GenesisState{}, i) - p2pMod, err := Create(testingConfigFilePath+strconv.Itoa(i)+jsonPosfix, testingGenesisFilePath+jsonPosfix, false) +// prepareP2PModules returns a map of configured p2pModules keyed by an incremental naming convention (eg: `val_1`, `val_2`, etc.) +func prepareP2PModules(t *testing.T, runtimeConfigs []modules.RuntimeMgr) (p2pModules map[string]*p2pModule) { + p2pModules = make(map[string]*p2pModule, len(runtimeConfigs)) + for i, runtimeConfig := range runtimeConfigs { + p2pMod, err := Create(runtimeConfig) require.NoError(t, err) p2pModules[validatorId(t, i+1)] = p2pMod.(*p2pModule) } return } -func createTestingGenesisAndConfigFiles(t *testing.T, cfg modules.Config, genesisState modules.GenesisState, n int) { - config, err := json.Marshal(cfg.P2P) - require.NoError(t, err) - - genesis, err := json.Marshal(genesisState.ConsensusGenesisState) - require.NoError(t, err) - - genesisFile := make(map[string]json.RawMessage) - configFile := make(map[string]json.RawMessage) - moduleName := new(p2pModule).GetModuleName() - - genesisFile[test_artifacts.GetGenesisFileName(moduleName)] = genesis - configFile[moduleName] = config - genesisFileBz, err := json.MarshalIndent(genesisFile, "", " ") - require.NoError(t, err) - - p2pFileBz, err := json.MarshalIndent(configFile, "", " ") - require.NoError(t, err) - require.NoError(t, ioutil.WriteFile(testingGenesisFilePath+jsonPosfix, genesisFileBz, 0777)) - require.NoError(t, ioutil.WriteFile(testingConfigFilePath+strconv.Itoa(n)+jsonPosfix, p2pFileBz, 0777)) -} - -func createConfigs(t *testing.T, numValidators int) (configs []modules.Config, genesisState modules.GenesisState) { - configs = make([]modules.Config, numValidators) +// createMockRuntimeMgrs creates `numValidators` instances of mocked `RuntimeMgr` that are essentially +// representing the runtime environments of the validators that we will use in our tests +func createMockRuntimeMgrs(t *testing.T, numValidators int) []modules.RuntimeMgr { + ctrl := gomock.NewController(t) + mockRuntimeMgrs := make([]modules.RuntimeMgr, numValidators) valKeys := make([]cryptoPocket.PrivateKey, numValidators) copy(valKeys[:], keys[:numValidators]) - genesisState = createGenesisState(t, valKeys) - for i := range configs { - configs[i] = modules.Config{ - Base: &modules.BaseConfig{ - RootDirectory: "", - PrivateKey: valKeys[i].String(), - }, - P2P: &typesP2P.P2PConfig{ - PrivateKey: valKeys[i].String(), - ConsensusPort: 8080, - UseRainTree: true, - IsEmptyConnectionType: true, - }, - } + mockGenesisState := createMockGenesisState(t, valKeys) + for i := range mockRuntimeMgrs { + mockConfig := modulesMock.NewMockConfig(ctrl) + mockConfig.EXPECT().GetBaseConfig().Return(&runtime.BaseConfig{ + RootDirectory: "", + PrivateKey: valKeys[i].String(), + }).AnyTimes() + mockConfig.EXPECT().GetP2PConfig().Return(&typesP2P.P2PConfig{ + PrivateKey: valKeys[i].String(), + ConsensusPort: 8080, + UseRainTree: true, + IsEmptyConnectionType: true, + }).AnyTimes() + + mockRuntimeMgr := modulesMock.NewMockRuntimeMgr(ctrl) + mockRuntimeMgr.EXPECT().GetConfig().Return(mockConfig).AnyTimes() + mockRuntimeMgr.EXPECT().GetGenesis().Return(mockGenesisState).AnyTimes() + mockRuntimeMgrs[i] = mockRuntimeMgr } - return + return mockRuntimeMgrs } func validatorId(_ *testing.T, i int) string { return fmt.Sprintf(serviceUrlFormat, i) } -func createGenesisState(t *testing.T, valKeys []cryptoPocket.PrivateKey) modules.GenesisState { +// createMockGenesisState configures and returns a mocked GenesisState +func createMockGenesisState(t *testing.T, valKeys []cryptoPocket.PrivateKey) modules.GenesisState { + ctrl := gomock.NewController(t) + validators := make([]modules.Actor, len(valKeys)) for i, valKey := range valKeys { addr := valKey.Address().String() - val := &test_artifacts.MockActor{ - Address: addr, - PublicKey: valKey.PublicKey().String(), - GenericParam: validatorId(t, i+1), - StakedAmount: "1000000000000000", - PausedHeight: 0, - UnstakingHeight: 0, - Output: addr, - } - validators[i] = val - } - return modules.GenesisState{ - PersistenceGenesisState: &test_artifacts.MockPersistenceGenesisState{ - Validators: validators, - }, + mockActor := modulesMock.NewMockActor(ctrl) + mockActor.EXPECT().GetAddress().Return(addr).AnyTimes() + mockActor.EXPECT().GetPublicKey().Return(valKey.PublicKey().String()).AnyTimes() + mockActor.EXPECT().GetGenericParam().Return(validatorId(t, i+1)).AnyTimes() + mockActor.EXPECT().GetStakedAmount().Return("1000000000000000").AnyTimes() + mockActor.EXPECT().GetPausedHeight().Return(int64(0)).AnyTimes() + mockActor.EXPECT().GetUnstakingHeight().Return(int64(0)).AnyTimes() + mockActor.EXPECT().GetOutput().Return(addr).AnyTimes() + validators[i] = mockActor } + + mockPersistenceGenesisState := modulesMock.NewMockPersistenceGenesisState(ctrl) + mockPersistenceGenesisState.EXPECT(). + GetVals(). + Return(validators).AnyTimes() + + mockGenesisState := modulesMock.NewMockGenesisState(ctrl) + mockGenesisState.EXPECT(). + GetPersistenceGenesisState(). + Return(mockPersistenceGenesisState).AnyTimes() + return mockGenesisState + } func TestMain(m *testing.M) { diff --git a/p2p/raintree/peers_manager_test.go b/p2p/raintree/peers_manager_test.go index 0fb3f29c4..4d37bbf71 100644 --- a/p2p/raintree/peers_manager_test.go +++ b/p2p/raintree/peers_manager_test.go @@ -116,7 +116,8 @@ func BenchmarkAddrBookUpdates(b *testing.B) { require.Equal(b, testCase.numExpectedLevels, int(peersManagerStateView.maxNumLevels)) for i := 0; i < numAddressessToBeAdded; i++ { - newAddr, _ := crypto.GenerateAddress() + newAddr, err := crypto.GenerateAddress() + require.NoError(b, err) network.AddPeerToAddrBook(&types.NetworkPeer{Address: newAddr}) } diff --git a/p2p/transport.go b/p2p/transport.go index 44ac1e238..cf836ea19 100644 --- a/p2p/transport.go +++ b/p2p/transport.go @@ -14,24 +14,24 @@ const ( ) func CreateListener(cfg modules.P2PConfig) (typesP2P.Transport, error) { - switch cfg.IsEmptyConnType() { // TECHDEBT kept in switch format because this should be an enum not a bool + switch cfg.GetIsEmptyConnectionType() { // TECHDEBT kept in switch format because this should be an enum not a bool case true: return createEmptyListener(cfg) case false: return createTCPListener(cfg) default: - return nil, fmt.Errorf("unsupported connection type for listener: %v", cfg.IsEmptyConnType()) + return nil, fmt.Errorf("unsupported connection type for listener: %v", cfg.GetIsEmptyConnectionType()) } } func CreateDialer(cfg modules.P2PConfig, url string) (typesP2P.Transport, error) { - switch cfg.IsEmptyConnType() { + switch cfg.GetIsEmptyConnectionType() { case true: return createEmptyDialer(cfg, url) case false: return createTCPDialer(cfg, url) default: - return nil, fmt.Errorf("unsupported connection type for dialer: %v", cfg.IsEmptyConnType()) + return nil, fmt.Errorf("unsupported connection type for dialer: %v", cfg.GetIsEmptyConnectionType()) } } diff --git a/persistence/debug.go b/persistence/debug.go index 5bfa942ad..51cf8939c 100644 --- a/persistence/debug.go +++ b/persistence/debug.go @@ -9,17 +9,14 @@ import ( "github.com/pokt-network/pocket/shared/debug" ) -func (m *PersistenceModule) HandleDebugMessage(debugMessage *debug.DebugMessage) error { +func (m *persistenceModule) HandleDebugMessage(debugMessage *debug.DebugMessage) error { switch debugMessage.Action { case debug.DebugMessageAction_DEBUG_SHOW_LATEST_BLOCK_IN_STORE: m.showLatestBlockInStore(debugMessage) case debug.DebugMessageAction_DEBUG_CLEAR_STATE: m.clearState(debugMessage) - g, err := m.InitGenesis(m.genesisPath) - if err != nil { - return err - } - m.populateGenesisState(g.(*types.PersistenceGenesisState)) + g := m.genesisState.(*types.PersistenceGenesisState) + m.populateGenesisState(g) default: log.Printf("Debug message not handled by persistence module: %s \n", debugMessage.Message) } @@ -27,7 +24,7 @@ func (m *PersistenceModule) HandleDebugMessage(debugMessage *debug.DebugMessage) } // TODO(olshansky): Create a shared interface `Block` to avoid the use of typesCons here. -func (m *PersistenceModule) showLatestBlockInStore(_ *debug.DebugMessage) { +func (m *persistenceModule) showLatestBlockInStore(_ *debug.DebugMessage) { // TODO: Add an iterator to the `kvstore` and use that instead height := m.GetBus().GetConsensusModule().CurrentHeight() - 1 // -1 because we want the latest committed height blockBytes, err := m.GetBlockStore().Get(heightToBytes(int64(height))) @@ -42,7 +39,7 @@ func (m *PersistenceModule) showLatestBlockInStore(_ *debug.DebugMessage) { log.Printf("Block at height %d with %d transactions: %+v \n", height, len(block.Transactions), block) } -func (m *PersistenceModule) clearState(_ *debug.DebugMessage) { +func (m *persistenceModule) clearState(_ *debug.DebugMessage) { context, err := m.NewRWContext(-1) defer context.Commit() if err != nil { diff --git a/persistence/docs/CHANGELOG.md b/persistence/docs/CHANGELOG.md index 39a682252..e3b94da43 100644 --- a/persistence/docs/CHANGELOG.md +++ b/persistence/docs/CHANGELOG.md @@ -6,6 +6,16 @@ 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.7] - 2022-10-12 + +### [#235](https://github.com/pokt-network/pocket/pull/235) Config and genesis handling + +- Updated to use `RuntimeMgr` +- Made `PersistenceModule` struct unexported +- Updated tests and mocks +- Removed some cross-module dependencies + ## [0.0.0.6] - 2022-09-30 - Removed no-op `DeleteActor` code diff --git a/persistence/genesis.go b/persistence/genesis.go index 463f88ff2..65d2fd197 100644 --- a/persistence/genesis.go +++ b/persistence/genesis.go @@ -12,7 +12,7 @@ import ( // TODO(andrew): generalize with the `actors interface` // WARNING: This function crashes the process if there is an error populating the genesis state. -func (m *PersistenceModule) populateGenesisState(state *types.PersistenceGenesisState) { +func (m *persistenceModule) populateGenesisState(state modules.PersistenceGenesisState) { log.Println("Populating genesis state...") // REFACTOR: This business logic should probably live in `types/genesis.go` @@ -155,7 +155,9 @@ func (m *PersistenceModule) populateGenesisState(state *types.PersistenceGenesis } // TODO(pocket/issues/149): All of the functions below following a structure similar to `GetAll` -// can easily be refactored and condensed into a single function using a generic type or a common +// +// can easily be refactored and condensed into a single function using a generic type or a common +// // interface. func (p PostgresContext) GetAllAccounts(height int64) (accs []modules.Account, err error) { ctx, tx, err := p.GetCtxAndTx() diff --git a/persistence/module.go b/persistence/module.go index da8df0c89..d6a08e763 100644 --- a/persistence/module.go +++ b/persistence/module.go @@ -2,9 +2,7 @@ package persistence import ( "context" - "encoding/json" "fmt" - "io/ioutil" "log" "github.com/pokt-network/pocket/persistence/types" @@ -12,23 +10,25 @@ import ( "github.com/jackc/pgx/v4" "github.com/pokt-network/pocket/persistence/kvstore" "github.com/pokt-network/pocket/shared/modules" - "github.com/pokt-network/pocket/shared/test_artifacts" ) -var _ modules.PersistenceModule = &PersistenceModule{} -var _ modules.PersistenceRWContext = &PostgresContext{} -var _ modules.PersistenceGenesisState = &types.PersistenceGenesisState{} -var _ modules.PersistenceConfig = &types.PersistenceConfig{} +var ( + _ modules.PersistenceModule = &persistenceModule{} + _ modules.PersistenceModule = &persistenceModule{} + + _ modules.PersistenceRWContext = &PostgresContext{} + _ modules.PersistenceGenesisState = &types.PersistenceGenesisState{} + _ modules.PersistenceConfig = &types.PersistenceConfig{} +) // 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 +type persistenceModule struct { + bus modules.Bus + config modules.PersistenceConfig + genesisState modules.PersistenceGenesisState - postgresURL string - nodeSchema string - genesisPath string - blockStore kvstore.KVStore // INVESTIGATE: We may need to create a custom `BlockStore` package in the future + blockStore kvstore.KVStore // INVESTIGATE: We may need to create a custom `BlockStore` package in the future // TECHDEBT: Need to implement context pooling (for writes), timeouts (for read & writes), etc... writeContext *PostgresContext // only one write context is allowed at a time @@ -38,19 +38,27 @@ const ( PersistenceModuleName = "persistence" ) -func Create(configPath, genesisPath string) (modules.PersistenceModule, error) { - m := new(PersistenceModule) - c, err := m.InitConfig(configPath) - if err != nil { - return nil, err +func Create(runtimeMgr modules.RuntimeMgr) (modules.Module, error) { + return new(persistenceModule).Create(runtimeMgr) +} + +func (*persistenceModule) Create(runtimeMgr modules.RuntimeMgr) (modules.Module, error) { + var m *persistenceModule + + cfg := runtimeMgr.GetConfig() + + if err := m.ValidateConfig(cfg); err != nil { + return nil, fmt.Errorf("config validation failed: %w", err) } - cfg := c.(*types.PersistenceConfig) - g, err := m.InitGenesis(genesisPath) - if err != nil { - return nil, err + persistenceCfg := cfg.GetPersistenceConfig() + + genesis := runtimeMgr.GetGenesis() + if err := m.ValidateGenesis(genesis); err != nil { + return nil, fmt.Errorf("genesis validation failed: %w", err) } - genesis := g.(*types.PersistenceGenesisState) - conn, err := connectToDatabase(cfg.GetPostgresUrl(), cfg.GetNodeSchema()) + persistenceGenesis := genesis.GetPersistenceGenesisState() + + conn, err := connectToDatabase(persistenceCfg.GetPostgresUrl(), persistenceCfg.GetNodeSchema()) if err != nil { return nil, err } @@ -59,98 +67,73 @@ func Create(configPath, genesisPath string) (modules.PersistenceModule, error) { } conn.Close(context.TODO()) - blockStore, err := initializeBlockStore(cfg.GetBlockStorePath()) + blockStore, err := initializeBlockStore(persistenceCfg.GetBlockStorePath()) if err != nil { return nil, err } - persistenceMod := &PersistenceModule{ + m = &persistenceModule{ bus: nil, - postgresURL: cfg.GetPostgresUrl(), - nodeSchema: cfg.GetNodeSchema(), - genesisPath: genesisPath, + config: persistenceCfg, + genesisState: persistenceGenesis, blockStore: blockStore, writeContext: nil, } // Determine if we should hydrate the genesis db or use the current state of the DB attached - if shouldHydrateGenesis, err := persistenceMod.shouldHydrateGenesisDb(); err != nil { + if shouldHydrateGenesis, err := m.shouldHydrateGenesisDb(); err != nil { return nil, err } else if shouldHydrateGenesis { // TECHDEBT: reconsider if this is the best place to call `populateGenesisState`. Note that // this forces the genesis state to be reloaded on every node startup until state sync is // implemented. // NOTE: `populateGenesisState` does not return an error but logs a fatal error if there's a problem - persistenceMod.populateGenesisState(genesis) + m.populateGenesisState(persistenceGenesis) } else { log.Println("Loading state from previous state...") } - return persistenceMod, nil -} - -func (m *PersistenceModule) InitConfig(pathToConfigJSON string) (config modules.IConfig, err error) { - data, err := ioutil.ReadFile(pathToConfigJSON) - if err != nil { - return - } - // over arching configuration file - rawJSON := make(map[string]json.RawMessage) - if err = json.Unmarshal(data, &rawJSON); err != nil { - log.Fatalf("[ERROR] an error occurred unmarshalling the %s file: %v", pathToConfigJSON, err.Error()) - } - // persistence specific configuration file - config = new(types.PersistenceConfig) - err = json.Unmarshal(rawJSON[m.GetModuleName()], config) - return -} - -func (m *PersistenceModule) InitGenesis(pathToGenesisJSON string) (genesis modules.IGenesis, err error) { - data, err := ioutil.ReadFile(pathToGenesisJSON) - if err != nil { - return - } - // over arching configuration file - rawJSON := make(map[string]json.RawMessage) - if err = json.Unmarshal(data, &rawJSON); err != nil { - log.Fatalf("[ERROR] an error occurred unmarshalling the %s file: %v", pathToGenesisJSON, err.Error()) - } - // persistence specific configuration file - genesis = new(types.PersistenceGenesisState) - err = json.Unmarshal(rawJSON[test_artifacts.GetGenesisFileName(m.GetModuleName())], genesis) - return + return m, nil } -func (m *PersistenceModule) Start() error { +func (m *persistenceModule) Start() error { log.Println("Starting persistence module...") return nil } -func (m *PersistenceModule) Stop() error { +func (m *persistenceModule) Stop() error { m.blockStore.Stop() return nil } -func (m *PersistenceModule) GetModuleName() string { +func (m *persistenceModule) GetModuleName() string { return PersistenceModuleName } -func (m *PersistenceModule) SetBus(bus modules.Bus) { +func (m *persistenceModule) SetBus(bus modules.Bus) { m.bus = bus } -func (m *PersistenceModule) GetBus() modules.Bus { +func (m *persistenceModule) GetBus() modules.Bus { if m.bus == nil { log.Fatalf("PocketBus is not initialized") } return m.bus } -func (m *PersistenceModule) NewRWContext(height int64) (modules.PersistenceRWContext, error) { +func (*persistenceModule) ValidateConfig(cfg modules.Config) error { + return nil +} + +func (*persistenceModule) ValidateGenesis(genesis modules.GenesisState) error { + return nil +} + +func (m *persistenceModule) NewRWContext(height int64) (modules.PersistenceRWContext, error) { if m.writeContext != nil && !m.writeContext.conn.IsClosed() { return nil, fmt.Errorf("write context already exists") } - conn, err := connectToDatabase(m.postgresURL, m.nodeSchema) + conn, err := connectToDatabase(m.config.GetPostgresUrl(), m.config.GetNodeSchema()) if err != nil { return nil, err } @@ -174,8 +157,8 @@ func (m *PersistenceModule) NewRWContext(height int64) (modules.PersistenceRWCon } -func (m *PersistenceModule) NewReadContext(height int64) (modules.PersistenceReadContext, error) { - conn, err := connectToDatabase(m.postgresURL, m.nodeSchema) +func (m *persistenceModule) NewReadContext(height int64) (modules.PersistenceReadContext, error) { + conn, err := connectToDatabase(m.config.GetPostgresUrl(), m.config.GetNodeSchema()) if err != nil { return nil, err } @@ -196,11 +179,11 @@ func (m *PersistenceModule) NewReadContext(height int64) (modules.PersistenceRea }, nil } -func (m *PersistenceModule) GetBlockStore() kvstore.KVStore { +func (m *persistenceModule) GetBlockStore() kvstore.KVStore { return m.blockStore } -func (m *PersistenceModule) NewWriteContext() modules.PersistenceRWContext { +func (m *persistenceModule) NewWriteContext() modules.PersistenceRWContext { return m.writeContext } @@ -213,7 +196,7 @@ func initializeBlockStore(blockStorePath string) (kvstore.KVStore, error) { // TODO(drewsky): Simplify and externalize the logic for whether genesis should be populated and // move the if logic out of this file. -func (m *PersistenceModule) shouldHydrateGenesisDb() (bool, error) { +func (m *persistenceModule) shouldHydrateGenesisDb() (bool, error) { checkContext, err := m.NewReadContext(-1) if err != nil { return false, err diff --git a/persistence/test/setup_test.go b/persistence/test/setup_test.go index cd3b80dc1..e685c6e67 100644 --- a/persistence/test/setup_test.go +++ b/persistence/test/setup_test.go @@ -2,9 +2,7 @@ package test import ( "encoding/hex" - "encoding/json" "fmt" - "io/ioutil" "log" "math/big" "math/rand" @@ -13,12 +11,11 @@ import ( "testing" "time" - "github.com/pokt-network/pocket/persistence/types" - "github.com/pokt-network/pocket/shared/test_artifacts" - "github.com/pokt-network/pocket/persistence" + "github.com/pokt-network/pocket/persistence/types" + "github.com/pokt-network/pocket/runtime" + "github.com/pokt-network/pocket/runtime/test_artifacts" "github.com/pokt-network/pocket/shared/modules" - sharedTest "github.com/pokt-network/pocket/shared/test_artifacts" "github.com/stretchr/testify/require" "golang.org/x/exp/slices" ) @@ -53,12 +50,10 @@ var testPersistenceMod modules.PersistenceModule // initialized in TestMain // See https://github.com/ory/dockertest as reference for the template of this code // Postgres example can be found here: https://github.com/ory/dockertest/blob/v3/examples/PostgreSQL.md func TestMain(m *testing.M) { - pool, resource, dbUrl := sharedTest.SetupPostgresDocker() + pool, resource, dbUrl := test_artifacts.SetupPostgresDocker() testPersistenceMod = newTestPersistenceModule(dbUrl) exitCode := m.Run() - os.Remove(testingConfigFilePath) - os.Remove(testingGenesisFilePath) - sharedTest.CleanupPostgresDocker(m, pool, resource) + test_artifacts.CleanupPostgresDocker(m, pool, resource) os.Exit(exitCode) } @@ -102,20 +97,19 @@ func NewFuzzTestPostgresContext(f *testing.F, height int64) *persistence.Postgre // TODO(andrew): Take in `t testing.T` as a parameter and error if there's an issue func newTestPersistenceModule(databaseUrl string) modules.PersistenceModule { - cfg := modules.Config{ - Persistence: &types.PersistenceConfig{ - PostgresUrl: databaseUrl, - NodeSchema: testSchema, - BlockStorePath: "", - }, - } + cfg := runtime.NewConfig(&runtime.BaseConfig{}, runtime.WithPersistenceConfig(&types.PersistenceConfig{ + PostgresUrl: databaseUrl, + NodeSchema: testSchema, + BlockStorePath: "", + })) genesisState, _ := test_artifacts.NewGenesisState(5, 1, 1, 1) - createTestingGenesisAndConfigFiles(cfg, genesisState) - persistenceMod, err := persistence.Create(testingConfigFilePath, testingGenesisFilePath) + runtimeCfg := runtime.NewManager(cfg, genesisState) + + persistenceMod, err := persistence.Create(runtimeCfg) if err != nil { log.Fatalf("Error creating persistence module: %s", err) } - return persistenceMod + return persistenceMod.(modules.PersistenceModule) } // IMPROVE(team): Extend this to more complex and variable test cases challenging & randomizing the state of persistence. @@ -288,43 +282,6 @@ func fuzzSingleProtocolActor( }) } -// TODO(olshansky): Make these functions & variables more functional to avoid having "unexpected" -// side effects and making it clearer to the reader. -const ( - testingGenesisFilePath = "genesis.json" - testingConfigFilePath = "config.json" -) - -func createTestingGenesisAndConfigFiles(cfg modules.Config, genesisState modules.GenesisState) { - config, err := json.Marshal(cfg.Persistence) - if err != nil { - log.Fatal(err) - } - genesis, err := json.Marshal(genesisState.PersistenceGenesisState) - if err != nil { - log.Fatal(err) - } - genesisFile := make(map[string]json.RawMessage) - configFile := make(map[string]json.RawMessage) - persistenceModuleName := new(persistence.PersistenceModule).GetModuleName() - genesisFile[test_artifacts.GetGenesisFileName(persistenceModuleName)] = genesis - configFile[persistenceModuleName] = config - genesisFileBz, err := json.MarshalIndent(genesisFile, "", " ") - if err != nil { - log.Fatal(err) - } - configFileBz, err := json.MarshalIndent(configFile, "", " ") - if err != nil { - log.Fatal(err) - } - if err := ioutil.WriteFile(testingGenesisFilePath, genesisFileBz, 0777); err != nil { - log.Fatal(err) - } - if err := ioutil.WriteFile(testingConfigFilePath, configFileBz, 0777); err != nil { - log.Fatal(err) - } -} - func getRandomChains() (chains []string) { setRandomSeed() diff --git a/persistence/types/converters.go b/persistence/types/converters.go new file mode 100644 index 000000000..ab5ccfdc2 --- /dev/null +++ b/persistence/types/converters.go @@ -0,0 +1,151 @@ +package types + +import ( + "github.com/pokt-network/pocket/shared/modules" +) + +func toPersistenceActor(actor modules.Actor) *Actor { + return &Actor{ + Address: actor.GetAddress(), + PublicKey: actor.GetPublicKey(), + StakedAmount: actor.GetStakedAmount(), + GenericParam: actor.GetGenericParam(), + } +} + +func ToPersistenceActors(actors []modules.Actor) []*Actor { + perActors := make([]*Actor, len(actors)) + for i, actor := range actors { + perActors[i] = toPersistenceActor(actor) + } + return perActors +} + +func toPersistenceAccount(account modules.Account) *Account { + return &Account{ + Address: account.GetAddress(), + Amount: account.GetAmount(), + } +} + +func ToPersistenceAccounts(accounts []modules.Account) []*Account { + perAccounts := make([]*Account, len(accounts)) + for i, account := range accounts { + perAccounts[i] = toPersistenceAccount(account) + } + return perAccounts +} + +func ToPersistenceParams(params modules.Params) *Params { + return &Params{ + BlocksPerSession: params.GetBlocksPerSession(), + AppMinimumStake: params.GetAppMinimumStake(), + AppMaxChains: params.GetAppMaxChains(), + AppBaselineStakeRate: params.GetAppBaselineStakeRate(), + AppStakingAdjustment: params.GetAppStakingAdjustment(), + AppUnstakingBlocks: params.GetAppUnstakingBlocks(), + AppMinimumPauseBlocks: params.GetAppMinimumPauseBlocks(), + AppMaxPauseBlocks: params.GetAppMaxPauseBlocks(), + ServiceNodeMinimumStake: params.GetServiceNodeMinimumStake(), + ServiceNodeMaxChains: params.GetServiceNodeMaxChains(), + ServiceNodeUnstakingBlocks: params.GetServiceNodeUnstakingBlocks(), + ServiceNodeMinimumPauseBlocks: params.GetServiceNodeMinimumPauseBlocks(), + ServiceNodeMaxPauseBlocks: params.GetServiceNodeMaxPauseBlocks(), + ServiceNodesPerSession: params.GetServiceNodesPerSession(), + FishermanMinimumStake: params.GetFishermanMinimumStake(), + FishermanMaxChains: params.GetFishermanMaxChains(), + FishermanUnstakingBlocks: params.GetFishermanUnstakingBlocks(), + FishermanMinimumPauseBlocks: params.GetFishermanMinimumPauseBlocks(), + FishermanMaxPauseBlocks: params.GetFishermanMaxPauseBlocks(), + ValidatorMinimumStake: params.GetValidatorMinimumStake(), + ValidatorUnstakingBlocks: params.GetValidatorUnstakingBlocks(), + ValidatorMinimumPauseBlocks: params.GetValidatorMinimumPauseBlocks(), + ValidatorMaxPauseBlocks: params.GetValidatorMaxPauseBlocks(), + ValidatorMaximumMissedBlocks: params.GetValidatorMaximumMissedBlocks(), + ValidatorMaxEvidenceAgeInBlocks: params.GetValidatorMaxEvidenceAgeInBlocks(), + ProposerPercentageOfFees: params.GetProposerPercentageOfFees(), + MissedBlocksBurnPercentage: params.GetMissedBlocksBurnPercentage(), + DoubleSignBurnPercentage: params.GetDoubleSignBurnPercentage(), + MessageDoubleSignFee: params.GetMessageDoubleSignFee(), + MessageSendFee: params.GetMessageSendFee(), + MessageStakeFishermanFee: params.GetMessageStakeFishermanFee(), + MessageEditStakeFishermanFee: params.GetMessageEditStakeFishermanFee(), + MessageUnstakeFishermanFee: params.GetMessageUnstakeFishermanFee(), + MessagePauseFishermanFee: params.GetMessagePauseFishermanFee(), + MessageUnpauseFishermanFee: params.GetMessageUnpauseFishermanFee(), + MessageFishermanPauseServiceNodeFee: params.GetMessageFishermanPauseServiceNodeFee(), + MessageTestScoreFee: params.GetMessageTestScoreFee(), + MessageProveTestScoreFee: params.GetMessageProveTestScoreFee(), + MessageStakeAppFee: params.GetMessageStakeAppFee(), + MessageEditStakeAppFee: params.GetMessageEditStakeAppFee(), + MessageUnstakeAppFee: params.GetMessageUnstakeAppFee(), + MessagePauseAppFee: params.GetMessagePauseAppFee(), + MessageUnpauseAppFee: params.GetMessageUnpauseAppFee(), + MessageStakeValidatorFee: params.GetMessageStakeValidatorFee(), + MessageEditStakeValidatorFee: params.GetMessageEditStakeValidatorFee(), + MessageUnstakeValidatorFee: params.GetMessageUnstakeValidatorFee(), + MessagePauseValidatorFee: params.GetMessagePauseValidatorFee(), + MessageUnpauseValidatorFee: params.GetMessageUnpauseValidatorFee(), + MessageStakeServiceNodeFee: params.GetMessageStakeServiceNodeFee(), + MessageEditStakeServiceNodeFee: params.GetMessageEditStakeServiceNodeFee(), + MessageUnstakeServiceNodeFee: params.GetMessageUnstakeServiceNodeFee(), + MessagePauseServiceNodeFee: params.GetMessagePauseServiceNodeFee(), + MessageUnpauseServiceNodeFee: params.GetMessageUnpauseServiceNodeFee(), + MessageChangeParameterFee: params.GetMessageChangeParameterFee(), + AclOwner: params.GetAclOwner(), + BlocksPerSessionOwner: params.GetBlocksPerSessionOwner(), + AppMinimumStakeOwner: params.GetAppMinimumStakeOwner(), + AppMaxChainsOwner: params.GetAppMaxChainsOwner(), + AppBaselineStakeRateOwner: params.GetAppBaselineStakeRateOwner(), + AppStakingAdjustmentOwner: params.GetAppStakingAdjustmentOwner(), + AppUnstakingBlocksOwner: params.GetAppUnstakingBlocksOwner(), + AppMinimumPauseBlocksOwner: params.GetAppMinimumPauseBlocksOwner(), + AppMaxPausedBlocksOwner: params.GetAppMaxPausedBlocksOwner(), + ServiceNodeMinimumStakeOwner: params.GetServiceNodeMinimumStakeOwner(), + ServiceNodeMaxChainsOwner: params.GetServiceNodeMaxChainsOwner(), + ServiceNodeUnstakingBlocksOwner: params.GetServiceNodeUnstakingBlocksOwner(), + ServiceNodeMinimumPauseBlocksOwner: params.GetServiceNodeMinimumPauseBlocksOwner(), + ServiceNodeMaxPausedBlocksOwner: params.GetServiceNodeMaxPausedBlocksOwner(), + ServiceNodesPerSessionOwner: params.GetServiceNodesPerSessionOwner(), + FishermanMinimumStakeOwner: params.GetFishermanMinimumStakeOwner(), + FishermanMaxChainsOwner: params.GetFishermanMaxChainsOwner(), + FishermanUnstakingBlocksOwner: params.GetFishermanUnstakingBlocksOwner(), + FishermanMinimumPauseBlocksOwner: params.GetFishermanMinimumPauseBlocksOwner(), + FishermanMaxPausedBlocksOwner: params.GetFishermanMaxPausedBlocksOwner(), + ValidatorMinimumStakeOwner: params.GetValidatorMinimumStakeOwner(), + ValidatorUnstakingBlocksOwner: params.GetValidatorUnstakingBlocksOwner(), + ValidatorMinimumPauseBlocksOwner: params.GetValidatorMinimumPauseBlocksOwner(), + ValidatorMaxPausedBlocksOwner: params.GetValidatorMaxPausedBlocksOwner(), + ValidatorMaximumMissedBlocksOwner: params.GetValidatorMaximumMissedBlocksOwner(), + ValidatorMaxEvidenceAgeInBlocksOwner: params.GetValidatorMaxEvidenceAgeInBlocksOwner(), + ProposerPercentageOfFeesOwner: params.GetProposerPercentageOfFeesOwner(), + MissedBlocksBurnPercentageOwner: params.GetMissedBlocksBurnPercentageOwner(), + DoubleSignBurnPercentageOwner: params.GetDoubleSignBurnPercentageOwner(), + MessageDoubleSignFeeOwner: params.GetMessageDoubleSignFeeOwner(), + MessageSendFeeOwner: params.GetMessageSendFeeOwner(), + MessageStakeFishermanFeeOwner: params.GetMessageStakeFishermanFeeOwner(), + MessageEditStakeFishermanFeeOwner: params.GetMessageEditStakeFishermanFeeOwner(), + MessageUnstakeFishermanFeeOwner: params.GetMessageUnstakeFishermanFeeOwner(), + MessagePauseFishermanFeeOwner: params.GetMessagePauseFishermanFeeOwner(), + MessageUnpauseFishermanFeeOwner: params.GetMessageUnpauseFishermanFeeOwner(), + MessageFishermanPauseServiceNodeFeeOwner: params.GetMessageFishermanPauseServiceNodeFeeOwner(), + MessageTestScoreFeeOwner: params.GetMessageTestScoreFeeOwner(), + MessageProveTestScoreFeeOwner: params.GetMessageProveTestScoreFeeOwner(), + MessageStakeAppFeeOwner: params.GetMessageStakeAppFeeOwner(), + MessageEditStakeAppFeeOwner: params.GetMessageEditStakeAppFeeOwner(), + MessageUnstakeAppFeeOwner: params.GetMessageUnstakeAppFeeOwner(), + MessagePauseAppFeeOwner: params.GetMessagePauseAppFeeOwner(), + MessageUnpauseAppFeeOwner: params.GetMessageUnpauseAppFeeOwner(), + MessageStakeValidatorFeeOwner: params.GetMessageStakeValidatorFeeOwner(), + MessageEditStakeValidatorFeeOwner: params.GetMessageEditStakeValidatorFeeOwner(), + MessageUnstakeValidatorFeeOwner: params.GetMessageUnstakeValidatorFeeOwner(), + MessagePauseValidatorFeeOwner: params.GetMessagePauseValidatorFeeOwner(), + MessageUnpauseValidatorFeeOwner: params.GetMessageUnpauseValidatorFeeOwner(), + MessageStakeServiceNodeFeeOwner: params.GetMessageStakeServiceNodeFeeOwner(), + MessageEditStakeServiceNodeFeeOwner: params.GetMessageEditStakeServiceNodeFeeOwner(), + MessageUnstakeServiceNodeFeeOwner: params.GetMessageUnstakeServiceNodeFeeOwner(), + MessagePauseServiceNodeFeeOwner: params.GetMessagePauseServiceNodeFeeOwner(), + MessageUnpauseServiceNodeFeeOwner: params.GetMessageUnpauseServiceNodeFeeOwner(), + MessageChangeParameterFeeOwner: params.GetMessageChangeParameterFeeOwner(), + } +} diff --git a/persistence/types/persistence_genesis.go b/persistence/types/persistence_genesis.go index 9154e2e08..9268f20c2 100644 --- a/persistence/types/persistence_genesis.go +++ b/persistence/types/persistence_genesis.go @@ -7,6 +7,8 @@ import ( "github.com/pokt-network/pocket/shared/modules" ) +var _ modules.PersistenceGenesisState = &PersistenceGenesisState{} + // TODO (Research) is there anyway to not have to name these protobuf files uniquely? // not a fan of _config/genesis.go would rather just config/genesis.go diff --git a/runtime/base_config.go b/runtime/base_config.go new file mode 100644 index 000000000..dede2a201 --- /dev/null +++ b/runtime/base_config.go @@ -0,0 +1,18 @@ +package runtime + +import "github.com/pokt-network/pocket/shared/modules" + +var _ modules.BaseConfig = &BaseConfig{} + +type BaseConfig struct { + RootDirectory string `json:"root_directory"` + PrivateKey string `json:"private_key"` // TODO (pocket/issues/150) better architecture for key management (keybase, keyfiles, etc.) +} + +func (c *BaseConfig) GetRootDirectory() string { + return c.RootDirectory +} + +func (c *BaseConfig) GetPrivateKey() string { + return c.PrivateKey +} diff --git a/runtime/config.go b/runtime/config.go new file mode 100644 index 000000000..5cddd4057 --- /dev/null +++ b/runtime/config.go @@ -0,0 +1,79 @@ +package runtime + +import ( + typesCons "github.com/pokt-network/pocket/consensus/types" + typesP2P "github.com/pokt-network/pocket/p2p/types" + typesPers "github.com/pokt-network/pocket/persistence/types" + "github.com/pokt-network/pocket/shared/modules" + typesTelemetry "github.com/pokt-network/pocket/telemetry" + typesUtil "github.com/pokt-network/pocket/utility/types" +) + +var _ modules.Config = &runtimeConfig{} + +type runtimeConfig struct { + Base *BaseConfig `json:"base"` + Consensus *typesCons.ConsensusConfig `json:"consensus"` + Utility *typesUtil.UtilityConfig `json:"utility"` + Persistence *typesPers.PersistenceConfig `json:"persistence"` + P2P *typesP2P.P2PConfig `json:"p2p"` + Telemetry *typesTelemetry.TelemetryConfig `json:"telemetry"` +} + +func NewConfig(base *BaseConfig, otherConfigs ...func(modules.Config)) *runtimeConfig { + rc := &runtimeConfig{ + Base: base, + } + for _, oc := range otherConfigs { + oc(rc) + } + return rc +} + +func WithConsensusConfig(consensusConfig modules.ConsensusConfig) func(modules.Config) { + return func(rc modules.Config) { + rc.(*runtimeConfig).Consensus = consensusConfig.(*typesCons.ConsensusConfig) + } +} + +func WithUtilityConfig(utilityConfig modules.UtilityConfig) func(modules.Config) { + return func(rc modules.Config) { + rc.(*runtimeConfig).Utility = utilityConfig.(*typesUtil.UtilityConfig) + } +} + +func WithPersistenceConfig(persistenceConfig modules.PersistenceConfig) func(modules.Config) { + return func(rc modules.Config) { + rc.(*runtimeConfig).Persistence = persistenceConfig.(*typesPers.PersistenceConfig) + } +} + +func WithP2PConfig(p2pConfig modules.P2PConfig) func(modules.Config) { + return func(rc modules.Config) { + rc.(*runtimeConfig).P2P = p2pConfig.(*typesP2P.P2PConfig) + } +} +func WithTelemetryConfig(telemetryConfig modules.TelemetryConfig) func(modules.Config) { + return func(rc modules.Config) { + rc.(*runtimeConfig).Telemetry = telemetryConfig.(*typesTelemetry.TelemetryConfig) + } +} + +func (c *runtimeConfig) GetBaseConfig() modules.BaseConfig { + return c.Base +} +func (c *runtimeConfig) GetConsensusConfig() modules.ConsensusConfig { + return c.Consensus +} +func (c *runtimeConfig) GetUtilityConfig() modules.UtilityConfig { + return c.Utility +} +func (c *runtimeConfig) GetPersistenceConfig() modules.PersistenceConfig { + return c.Persistence +} +func (c *runtimeConfig) GetP2PConfig() modules.P2PConfig { + return c.P2P +} +func (c *runtimeConfig) GetTelemetryConfig() modules.TelemetryConfig { + return c.Telemetry +} diff --git a/runtime/docs/CHANGELOG.md b/runtime/docs/CHANGELOG.md new file mode 100644 index 000000000..16725f07d --- /dev/null +++ b/runtime/docs/CHANGELOG.md @@ -0,0 +1,20 @@ +# 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] - 2022-09-30 + +### [#235](https://github.com/pokt-network/pocket/pull/235) Config and genesis handling + +- Abstracted config and genesis handling +- Mockable runtime +- Refactored all modules to use `RuntimeMgr` +- Updated `RuntimeMgr` to manage clock as well +- Modules now accept `interfaces` instead of paths. +- Unmarshalling is done in a new `runtime` package (runtime because what we do in there affects the runtime of the application) +- We are now able to accept configuration via environment variables (thanks to @okdas for inspiration and [sp13 for Viper]("github.com/spf13/viper")) diff --git a/runtime/docs/README.md b/runtime/docs/README.md new file mode 100644 index 000000000..cc6cac0cc --- /dev/null +++ b/runtime/docs/README.md @@ -0,0 +1,38 @@ +# RuntimeMgr + +This document outlines the purpose of this module, its components and how they all interact with the other modules. + +## Contents + +- [Overview](#overview) +- [Components](#components) + +### Overview + +The `RuntimeMgr`'s purpose is to abstract the runtime so that it's easier to test and reason about various configuration scenarios. + +It works like a black-box that takes the current environment/machine and therefore the configuration files, flags supplied to the binary, etc. and returns a structure that can be queried for settings that are relevant for the functioning of the modules and the system as a whole. + +### Components + +This module includes the following components: + +- **Config** + + As the name says, it includes, in the form of properties, module specific configurations. + + It also has a `Base` configuration that is supposed to contain more cross-functional settings that cannot really find place in module-specific "subconfigs" (as another way to define module-specific configurations). + +- **Genesis** + + The genesis represents the initial state of the blockchain. + + This allows the binary to start with a specific initial state. + + Similarly to `Config`, these are scoped by module as well and currently we have `Persistence` and `Consensus` specific `GenesisState`s + +- **Clock** + + Clock is a drop-in replacement for some of the features offered by the `time` package, it acts as an injectable clock implementation used to provide time manipulation while testing. + + By default, the **real** clock is used and while testing it's possible to override it by using the "option" `WithClock(...)` diff --git a/runtime/genesis.go b/runtime/genesis.go new file mode 100644 index 000000000..8627e0649 --- /dev/null +++ b/runtime/genesis.go @@ -0,0 +1,46 @@ +package runtime + +import ( + "encoding/json" + "os" + + consTypes "github.com/pokt-network/pocket/consensus/types" + persTypes "github.com/pokt-network/pocket/persistence/types" + "github.com/pokt-network/pocket/shared/modules" +) + +var _ modules.GenesisState = &runtimeGenesis{} + +type runtimeGenesis struct { + ConsensusGenesisState *consTypes.ConsensusGenesisState `json:"consensus_genesis_state"` + PersistenceGenesisState *persTypes.PersistenceGenesisState `json:"persistence_genesis_state"` +} + +func NewGenesis( + consensusGenesisState modules.ConsensusGenesisState, + persistenceGenesisState modules.PersistenceGenesisState, +) *runtimeGenesis { + return &runtimeGenesis{ + ConsensusGenesisState: consensusGenesisState.(*consTypes.ConsensusGenesisState), + PersistenceGenesisState: persistenceGenesisState.(*persTypes.PersistenceGenesisState), + } +} + +func (g *runtimeGenesis) GetPersistenceGenesisState() modules.PersistenceGenesisState { + return g.PersistenceGenesisState +} +func (g *runtimeGenesis) GetConsensusGenesisState() modules.ConsensusGenesisState { + return g.ConsensusGenesisState +} + +func parseGenesisJSON(genesisPath string) (g *runtimeGenesis, err error) { + data, err := os.ReadFile(genesisPath) + if err != nil { + return + } + + // general genesis file + g = new(runtimeGenesis) + err = json.Unmarshal(data, &g) + return +} diff --git a/runtime/manager.go b/runtime/manager.go new file mode 100644 index 000000000..1110de3c1 --- /dev/null +++ b/runtime/manager.go @@ -0,0 +1,179 @@ +package runtime + +import ( + "encoding/json" + "io" + "log" + "path" + "path/filepath" + "strings" + + "github.com/benbjohnson/clock" + "github.com/mitchellh/mapstructure" + typesCons "github.com/pokt-network/pocket/consensus/types" + typesP2P "github.com/pokt-network/pocket/p2p/types" + cryptoPocket "github.com/pokt-network/pocket/shared/crypto" + "github.com/pokt-network/pocket/shared/modules" + "github.com/spf13/viper" +) + +var _ modules.RuntimeMgr = &Manager{} + +type Manager struct { + config *runtimeConfig + genesis *runtimeGenesis + + clock clock.Clock +} + +func NewManagerFromFiles(configPath, genesisPath string, options ...func(*Manager)) *Manager { + mgr := &Manager{ + clock: clock.New(), + } + + cfg, genesis, err := mgr.init(configPath, genesisPath) + if err != nil { + log.Fatalf("[ERROR] Failed to initialize runtime builder: %v", err) + } + mgr.config = cfg + mgr.genesis = genesis + + for _, o := range options { + o(mgr) + } + + return mgr +} + +// NewManagerFromReaders returns a *Manager given io.Readers for the config and the genesis. +// +// Ideally useful when the user doesn't want to rely on the filesystem and instead intends plugging in different configuration management system. +// +// Note: currently unused, here as a reference +func NewManagerFromReaders(configReader, genesisReader io.Reader, options ...func(*Manager)) *Manager { + var cfg *runtimeConfig + parse(configReader, cfg) + + var genesis *runtimeGenesis + parse(genesisReader, genesis) + + mgr := &Manager{ + config: cfg, + genesis: genesis, + clock: clock.New(), + } + + for _, o := range options { + o(mgr) + } + + return mgr +} + +func NewManager(config modules.Config, genesis modules.GenesisState, options ...func(*Manager)) *Manager { + mgr := &Manager{ + config: config.(*runtimeConfig), + genesis: genesis.(*runtimeGenesis), + clock: clock.New(), + } + + for _, o := range options { + o(mgr) + } + + return mgr +} + +func (rc *Manager) init(configPath, genesisPath string) (config *runtimeConfig, genesis *runtimeGenesis, err error) { + dir, file := path.Split(configPath) + filename := strings.TrimSuffix(file, filepath.Ext(file)) + + viper.AddConfigPath(".") + viper.AddConfigPath(dir) + viper.SetConfigName(filename) + viper.SetConfigType("json") + + // The lines below allow for environment variables configuration (12 factor app) + // Eg: POCKET_CONSENSUS_PRIVATE_KEY=somekey would override `consensus.private_key` in config + viper.SetEnvPrefix("POCKET") + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + viper.AutomaticEnv() + + if err = viper.ReadInConfig(); err != nil { + return + } + + decoderConfig := func(dc *mapstructure.DecoderConfig) { + // This is to leverage the `json` struct tags without having to add `mapstructure` ones. + // Until we have complex use cases, this should work just fine. + dc.TagName = "json" + } + if err = viper.Unmarshal(&config, decoderConfig); err != nil { + return + } + + if config.Base == nil { + config.Base = &BaseConfig{} + } + + genesis, err = parseGenesisJSON(genesisPath) + return +} + +func (b *Manager) GetConfig() modules.Config { + return b.config +} + +func (b *Manager) GetGenesis() modules.GenesisState { + return b.genesis +} + +func (b *Manager) GetClock() clock.Clock { + return b.clock +} + +type supportedStructs interface { + *runtimeConfig | *runtimeGenesis +} + +func parse[T supportedStructs](reader io.Reader, target T) { + bz, err := io.ReadAll(reader) + if err != nil { + log.Fatalf("[ERROR] Failed to read from reader: %v", err) + + } + if err := json.Unmarshal(bz, &target); err != nil { + log.Fatalf("[ERROR] Failed to unmarshal: %v", err) + } +} + +// Manager option helpers + +func WithRandomPK() func(*Manager) { + privateKey, err := cryptoPocket.GeneratePrivateKey() + if err != nil { + log.Fatalf("unable to generate private key") + } + + return WithPK(privateKey.String()) +} + +func WithPK(pk string) func(*Manager) { + return func(b *Manager) { + if b.config.Consensus == nil { + b.config.Consensus = &typesCons.ConsensusConfig{} + } + b.config.Consensus.PrivateKey = pk + + if b.config.P2P == nil { + b.config.P2P = &typesP2P.P2PConfig{} + } + b.config.P2P.PrivateKey = pk + } +} + +func WithClock(clockMgr clock.Clock) func(*Manager) { + return func(b *Manager) { + b.clock = clockMgr + } +} diff --git a/shared/test_artifacts/generator.go b/runtime/test_artifacts/generator.go similarity index 58% rename from shared/test_artifacts/generator.go rename to runtime/test_artifacts/generator.go index d0f90899c..1b11e5cfa 100644 --- a/shared/test_artifacts/generator.go +++ b/runtime/test_artifacts/generator.go @@ -1,15 +1,21 @@ package test_artifacts +// TODO: Move `root/shared/test_artifacts` to `root/test/test_artifacts` +// Cross module imports are okay because this is only used for testing and not business logic import ( "fmt" "math/big" "strconv" - typesPersistence "github.com/pokt-network/pocket/persistence/types" + typesCons "github.com/pokt-network/pocket/consensus/types" + typesP2P "github.com/pokt-network/pocket/p2p/types" + typesPers "github.com/pokt-network/pocket/persistence/types" + "github.com/pokt-network/pocket/runtime" + "github.com/pokt-network/pocket/shared/crypto" "github.com/pokt-network/pocket/shared/modules" + typesTelemetry "github.com/pokt-network/pocket/telemetry" "github.com/pokt-network/pocket/utility/types" - - "github.com/pokt-network/pocket/shared/crypto" + typesUtil "github.com/pokt-network/pocket/utility/types" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -34,28 +40,31 @@ var ( // TODO (Team) this is meant to be a **temporary** replacement for the recently deprecated // 'genesis config' option. We need to implement a real suite soon! -func NewGenesisState(numValidators, numServiceNodes, numApplications, numFisherman int) (genesisState modules.GenesisState, validatorPrivateKeys []string) { - apps, appsPrivateKeys := NewActors(MockActorType_App, numApplications) - vals, validatorPrivateKeys := NewActors(MockActorType_Val, numValidators) - serviceNodes, snPrivateKeys := NewActors(MockActorType_Node, numServiceNodes) - fish, fishPrivateKeys := NewActors(MockActorType_Fish, numFisherman) - return modules.GenesisState{ - ConsensusGenesisState: &MockConsensusGenesisState{ +func NewGenesisState(numValidators, numServiceNodes, numApplications, numFisherman int) (modules.GenesisState, []string) { + apps, appsPrivateKeys := NewActors(types.ActorType_App, numApplications) + vals, validatorPrivateKeys := NewActors(types.ActorType_Validator, numValidators) + serviceNodes, snPrivateKeys := NewActors(types.ActorType_ServiceNode, numServiceNodes) + fish, fishPrivateKeys := NewActors(types.ActorType_Fisherman, numFisherman) + + genesisState := runtime.NewGenesis( + &typesCons.ConsensusGenesisState{ GenesisTime: timestamppb.Now(), ChainId: DefaultChainID, MaxBlockBytes: DefaultMaxBlockBytes, - Validators: vals, + Validators: typesCons.ToConsensusValidators(vals), }, - PersistenceGenesisState: &MockPersistenceGenesisState{ - Pools: NewPools(), - Accounts: NewAccounts(numValidators+numServiceNodes+numApplications+numFisherman, append(append(append(validatorPrivateKeys, snPrivateKeys...), fishPrivateKeys...), appsPrivateKeys...)...), // TODO(olshansky): clean this up - Applications: apps, - Validators: vals, - ServiceNodes: serviceNodes, - Fishermen: fish, - Params: DefaultParams(), + &typesPers.PersistenceGenesisState{ + Pools: typesPers.ToPersistenceAccounts(NewPools()), + Accounts: typesPers.ToPersistenceAccounts(NewAccounts(numValidators+numServiceNodes+numApplications+numFisherman, append(append(append(validatorPrivateKeys, snPrivateKeys...), fishPrivateKeys...), appsPrivateKeys...)...)), // TODO(olshansky): clean this up + Applications: typesPers.ToPersistenceActors(apps), + Validators: typesPers.ToPersistenceActors(vals), + ServiceNodes: typesPers.ToPersistenceActors(serviceNodes), + Fishermen: typesPers.ToPersistenceActors(fish), + Params: typesPers.ToPersistenceParams(DefaultParams()), }, - }, validatorPrivateKeys + ) + + return genesisState, validatorPrivateKeys } func NewDefaultConfigs(privateKeys []string) (configs []modules.Config) { @@ -66,53 +75,54 @@ func NewDefaultConfigs(privateKeys []string) (configs []modules.Config) { } func NewDefaultConfig(i int, pk string) modules.Config { - return modules.Config{ - Base: &modules.BaseConfig{ + return runtime.NewConfig( + &runtime.BaseConfig{ RootDirectory: "/go/src/github.com/pocket-network", PrivateKey: pk, }, - Consensus: &MockConsensusConfig{ - MaxMempoolBytes: 500000000, - PacemakerConfig: &MockPacemakerConfig{ - TimeoutMsec: 5000, - Manual: true, - DebugTimeBetweenStepsMsec: 1000, - }, - PrivateKey: pk, - }, - Utility: &MockUtilityConfig{ + runtime.WithConsensusConfig( + &typesCons.ConsensusConfig{ + MaxMempoolBytes: 500000000, + PacemakerConfig: &typesCons.PacemakerConfig{ + TimeoutMsec: 5000, + Manual: true, + DebugTimeBetweenStepsMsec: 1000, + }, + PrivateKey: pk, + }), + runtime.WithUtilityConfig(&typesUtil.UtilityConfig{ MaxMempoolTransactionBytes: 1024 * 1024 * 1024, // 1GB V0 defaults MaxMempoolTransactions: 9000, - }, - Persistence: &typesPersistence.PersistenceConfig{ + }), + runtime.WithPersistenceConfig(&typesPers.PersistenceConfig{ PostgresUrl: "postgres://postgres:postgres@pocket-db:5432/postgres", NodeSchema: "node" + strconv.Itoa(i+1), BlockStorePath: "/var/blockstore", - }, - P2P: &MockP2PConfig{ + }), + runtime.WithP2PConfig(&typesP2P.P2PConfig{ ConsensusPort: 8080, UseRainTree: true, IsEmptyConnectionType: false, PrivateKey: pk, - }, - Telemetry: &MockTelemetryConfig{ + }), + runtime.WithTelemetryConfig(&typesTelemetry.TelemetryConfig{ Enabled: true, Address: "0.0.0.0:9000", Endpoint: "/metrics", - }, - } + }), + ) } func NewPools() (pools []modules.Account) { // TODO (Team) in the real testing suite, we need to populate the pool amounts dependent on the actors - for _, name := range typesPersistence.PoolNames_name { - if name == typesPersistence.PoolNames_FeeCollector.String() { - pools = append(pools, &MockAcc{ + for _, name := range typesPers.PoolNames_name { + if name == typesPers.PoolNames_FeeCollector.String() { + pools = append(pools, &typesPers.Account{ Address: name, Amount: "0", }) continue } - pools = append(pools, &MockAcc{ + pools = append(pools, &typesPers.Account{ Address: name, Amount: DefaultAccountAmountString, }) @@ -127,7 +137,7 @@ func NewAccounts(n int, privateKeys ...string) (accounts []modules.Account) { pk, _ := crypto.NewPrivateKey(privateKeys[i]) addr = pk.Address().String() } - accounts = append(accounts, &MockAcc{ + accounts = append(accounts, &typesPers.Account{ Address: addr, Amount: DefaultAccountAmountString, }) @@ -135,10 +145,10 @@ func NewAccounts(n int, privateKeys ...string) (accounts []modules.Account) { return } -func NewActors(actorType MockActorType, n int) (actors []modules.Actor, privateKeys []string) { +func NewActors(actorType typesUtil.ActorType, n int) (actors []modules.Actor, privateKeys []string) { for i := 0; i < n; i++ { genericParam := fmt.Sprintf("node%d.consensus:8080", i+1) - if int32(actorType) == int32(MockActorType_App) { + if int32(actorType) == int32(types.ActorType_App) { genericParam = DefaultMaxRelaysString } actor, pk := NewDefaultActor(int32(actorType), genericParam) @@ -151,12 +161,12 @@ func NewActors(actorType MockActorType, n int) (actors []modules.Actor, privateK func NewDefaultActor(actorType int32, genericParam string) (actor modules.Actor, privateKey string) { privKey, pubKey, addr := GenerateNewKeysStrings() chains := DefaultChains - if actorType == int32(typesPersistence.ActorType_Val) { + if actorType == int32(typesPers.ActorType_Val) { chains = nil - } else if actorType == int32(MockActorType_App) { + } else if actorType == int32(types.ActorType_App) { genericParam = DefaultMaxRelaysString } - return &MockActor{ + return &typesPers.Actor{ Address: addr, PublicKey: pubKey, Chains: chains, @@ -165,7 +175,7 @@ func NewDefaultActor(actorType int32, genericParam string) (actor modules.Actor, PausedHeight: DefaultPauseHeight, UnstakingHeight: DefaultUnstakingHeight, Output: addr, - ActorType: MockActorType(actorType), + ActorType: typesPers.ActorType(actorType), }, privKey } diff --git a/shared/test_artifacts/genesis.go b/runtime/test_artifacts/genesis.go similarity index 100% rename from shared/test_artifacts/genesis.go rename to runtime/test_artifacts/genesis.go diff --git a/shared/test_artifacts/gov.go b/runtime/test_artifacts/gov.go similarity index 98% rename from shared/test_artifacts/gov.go rename to runtime/test_artifacts/gov.go index 84deeb1c0..febf92d25 100644 --- a/shared/test_artifacts/gov.go +++ b/runtime/test_artifacts/gov.go @@ -1,9 +1,11 @@ package test_artifacts import ( + "math/big" + + typesPers "github.com/pokt-network/pocket/persistence/types" "github.com/pokt-network/pocket/shared/modules" "github.com/pokt-network/pocket/utility/types" - "math/big" "github.com/pokt-network/pocket/shared/crypto" ) @@ -15,7 +17,7 @@ var ( ) func DefaultParams() modules.Params { - return &MockParams{ + return &typesPers.Params{ BlocksPerSession: 4, AppMinimumStake: types.BigIntToString(big.NewInt(15000000000)), AppMaxChains: 15, diff --git a/shared/test_artifacts/util.go b/runtime/test_artifacts/util.go similarity index 96% rename from shared/test_artifacts/util.go rename to runtime/test_artifacts/util.go index 8b47b2daf..ac7cfd8fb 100644 --- a/shared/test_artifacts/util.go +++ b/runtime/test_artifacts/util.go @@ -25,7 +25,8 @@ const ( ) // DISCUSS(team) both the persistence module and the utility module share this code which is less than ideal -// (see call to action in generator.go to try to remove the cross module testing code) +// +// (see call to action in generator.go to try to remove the cross module testing code) func SetupPostgresDocker() (*dockertest.Pool, *dockertest.Resource, string) { opts := dockertest.RunOptions{ Repository: "postgres", @@ -92,6 +93,7 @@ func CleanupPostgresDocker(_ *testing.M, pool *dockertest.Pool, resource *docker if err := pool.Purge(resource); err != nil { log.Fatalf("could not purge resource: %s", err) } + os.Exit(0) } // TODO(drewsky): Remove this in favor of a golang specific solution diff --git a/shared/CHANGELOG.md b/shared/CHANGELOG.md index 1e572e8a1..bab69fd3e 100644 --- a/shared/CHANGELOG.md +++ b/shared/CHANGELOG.md @@ -7,7 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.2] - 2022-10-12 + +### [#235](https://github.com/pokt-network/pocket/pull/235) Config and genesis handling + +- Updated to use `RuntimeMgr`, available via `GetRuntimeMgr()` +- Segregate interfaces (eg: `GenesisDependentModule`, `P2PAddressableModule`, etc) +- Updated tests and mocks + ## [0.0.1] - 2022-09-30 + - Used proper `TODO/INVESTIGATE/DISCUSS` convention across package - Moved TxIndexer Package to Utility to properly encapsulate - Add unit test for `SharedCodec()` diff --git a/shared/README.md b/shared/README.md index 8fdefaf6b..dbe312a6e 100644 --- a/shared/README.md +++ b/shared/README.md @@ -45,7 +45,8 @@ The key things to keep in mind are: - Receive asynchronous events from the **main events channel** - The **Persistence** module is the only module that communicates with the local database - The **P2P** module is the only one that communicates with the outside world -- **Clock** is a drop-in replacement for some of the features offered by the `time` package, it acts as an injectable clock implementation used to provide time manipulation while testing. +- **RuntimeMgr** abstracts the runtime and is injected in the modules (more details [here](../runtime/docs/README.md)) + ```mermaid @@ -54,11 +55,11 @@ flowchart TD subgraph Pocket's Application Specific Bus B("Bus") E("Main Events Channel") - Clock("Clock") B <-.-> E - B <-.-> Clock end subgraph Pocket's Core Modules + RMGR(RuntimeMgr) + RMGR .- P(Persistence) & C(Consensus) & U(Utility) & P2P(P2P) end P <--> B diff --git a/shared/bus.go b/shared/bus.go index 4c4498e7c..7a85e4c75 100644 --- a/shared/bus.go +++ b/shared/bus.go @@ -4,8 +4,6 @@ import ( "log" "github.com/pokt-network/pocket/shared/debug" - - "github.com/benbjohnson/clock" "github.com/pokt-network/pocket/shared/modules" ) @@ -24,7 +22,7 @@ type bus struct { consensus modules.ConsensusModule telemetry modules.TelemetryModule - clock clock.Clock + runtimeMgr modules.RuntimeMgr } const ( @@ -32,23 +30,23 @@ const ( ) func CreateBus( + runtimeMgr modules.RuntimeMgr, persistence modules.PersistenceModule, p2p modules.P2PModule, utility modules.UtilityModule, consensus modules.ConsensusModule, telemetry modules.TelemetryModule, - clock clock.Clock, ) (modules.Bus, error) { bus := &bus{ channel: make(modules.EventsChannel, DefaultPocketBusBufferSize), + runtimeMgr: runtimeMgr, + persistence: persistence, p2p: p2p, utility: utility, consensus: consensus, telemetry: telemetry, - - clock: clock, } modules := map[string]modules.Module{ @@ -82,6 +80,7 @@ func CreateBus( // Using `CreateBusWithOptionalModules`, we can create a bus with only pre2p and a NOOP telemetry module // so that we can the pre2p module without any issues. func CreateBusWithOptionalModules( + runtimeMgr modules.RuntimeMgr, persistence modules.PersistenceModule, p2p modules.P2PModule, utility modules.UtilityModule, @@ -89,7 +88,10 @@ func CreateBusWithOptionalModules( telemetry modules.TelemetryModule, ) modules.Bus { bus := &bus{ - channel: make(modules.EventsChannel, DefaultPocketBusBufferSize), + channel: make(modules.EventsChannel, DefaultPocketBusBufferSize), + + runtimeMgr: runtimeMgr, + persistence: persistence, p2p: p2p, utility: utility, @@ -145,6 +147,6 @@ func (m bus) GetTelemetryModule() modules.TelemetryModule { return m.telemetry } -func (m *bus) GetClock() clock.Clock { - return m.clock +func (m *bus) GetRuntimeMgr() modules.RuntimeMgr { + return m.runtimeMgr } diff --git a/shared/modules/bus_module.go b/shared/modules/bus_module.go index e2769a660..05140e0ed 100644 --- a/shared/modules/bus_module.go +++ b/shared/modules/bus_module.go @@ -3,9 +3,6 @@ package modules //go:generate mockgen -source=$GOFILE -destination=./mocks/bus_module_mock.go -aux_files=github.com/pokt-network/pocket/shared/modules=module.go import ( - "encoding/json" - - "github.com/benbjohnson/clock" "github.com/pokt-network/pocket/shared/debug" ) @@ -27,10 +24,6 @@ type Bus interface { GetConsensusModule() ConsensusModule GetTelemetryModule() TelemetryModule - // Configuration - GetConfig() map[string]json.RawMessage - GetGenesis() map[string]json.RawMessage - - // Time - GetClock() clock.Clock + // Runtime + GetRuntimeMgr() RuntimeMgr } diff --git a/shared/modules/consensus_module.go b/shared/modules/consensus_module.go index 8831e0f26..a08be408e 100644 --- a/shared/modules/consensus_module.go +++ b/shared/modules/consensus_module.go @@ -15,6 +15,9 @@ type ValidatorMap map[string]Actor // Make sure that you are not locking again within the same call to avoid deadlocks (for example when the methods below call each other in your implementation). type ConsensusModule interface { Module + ConfigurableModule + GenesisDependentModule + KeyholderModule // Consensus Engine Handlers HandleMessage(*anypb.Any) error diff --git a/shared/modules/module.go b/shared/modules/module.go index 49d8f261f..f666a61b3 100644 --- a/shared/modules/module.go +++ b/shared/modules/module.go @@ -1,5 +1,10 @@ package modules +import ( + "github.com/pokt-network/pocket/shared/crypto" + cryptoPocket "github.com/pokt-network/pocket/shared/crypto" +) + type Module interface { InitializableModule IntegratableModule @@ -18,6 +23,21 @@ type InterruptableModule interface { type InitializableModule interface { GetModuleName() string - InitConfig(pathToConfigJSON string) (IConfig, error) - InitGenesis(pathToGenesisJSON string) (IGenesis, error) + Create(runtime RuntimeMgr) (Module, error) +} + +type ConfigurableModule interface { + ValidateConfig(Config) error +} + +type GenesisDependentModule interface { + ValidateGenesis(GenesisState) error +} + +type KeyholderModule interface { + GetPrivateKey() (crypto.PrivateKey, error) +} + +type P2PAddressableModule interface { + GetP2PAddress() cryptoPocket.Address } diff --git a/shared/modules/p2p_module.go b/shared/modules/p2p_module.go index a927ca693..6c6eef045 100644 --- a/shared/modules/p2p_module.go +++ b/shared/modules/p2p_module.go @@ -10,6 +10,8 @@ import ( type P2PModule interface { Module + ConfigurableModule + Broadcast(msg *anypb.Any, topic debug.PocketTopic) error // TECHDEBT: get rid of topic Send(addr cryptoPocket.Address, msg *anypb.Any, topic debug.PocketTopic) error // TECHDEBT: get rid of topic GetAddress() (cryptoPocket.Address, error) diff --git a/shared/modules/persistence_module.go b/shared/modules/persistence_module.go index 0f74b1152..b53e6a630 100644 --- a/shared/modules/persistence_module.go +++ b/shared/modules/persistence_module.go @@ -9,6 +9,9 @@ import ( type PersistenceModule interface { Module + ConfigurableModule + GenesisDependentModule + NewRWContext(height int64) (PersistenceRWContext, error) NewReadContext(height int64) (PersistenceReadContext, error) GetBlockStore() kvstore.KVStore diff --git a/shared/modules/runtime_module.go b/shared/modules/runtime_module.go new file mode 100644 index 000000000..ef4ca8e9a --- /dev/null +++ b/shared/modules/runtime_module.go @@ -0,0 +1,11 @@ +package modules + +import "github.com/benbjohnson/clock" + +//go:generate mockgen -source=$GOFILE -destination=./mocks/runtime_module_mock.go -aux_files=github.com/pokt-network/pocket/shared/modules=module.go + +type RuntimeMgr interface { + GetConfig() Config + GetGenesis() GenesisState + GetClock() clock.Clock +} diff --git a/shared/modules/telemetry_module.go b/shared/modules/telemetry_module.go index 21e83efa3..fbe398ada 100644 --- a/shared/modules/telemetry_module.go +++ b/shared/modules/telemetry_module.go @@ -6,6 +6,7 @@ import "github.com/prometheus/client_golang/prometheus" type TelemetryModule interface { Module + ConfigurableModule GetTimeSeriesAgent() TimeSeriesAgent GetEventMetricsAgent() EventMetricsAgent diff --git a/shared/modules/types.go b/shared/modules/types.go index 5262a062d..7c9dc419b 100644 --- a/shared/modules/types.go +++ b/shared/modules/types.go @@ -1,5 +1,7 @@ package modules +//go:generate mockgen -source=$GOFILE -destination=./mocks/types_mock.go -aux_files=github.com/pokt-network/pocket/shared/modules=module.go + import ( "google.golang.org/protobuf/types/known/timestamppb" ) @@ -7,28 +9,28 @@ import ( // This file contains the minimum shared structures (GenesisState) and the many shared interfaces the modules implement // the main purpose of this structure is to ensure the ownership of the -type GenesisState struct { - PersistenceGenesisState PersistenceGenesisState `json:"persistence_genesis_state"` - ConsensusGenesisState ConsensusGenesisState `json:"consensus_genesis_state"` +type GenesisState interface { + GetPersistenceGenesisState() PersistenceGenesisState + GetConsensusGenesisState() ConsensusGenesisState } -type BaseConfig struct { - RootDirectory string `json:"root_directory"` - PrivateKey string `json:"private_key"` // TODO (#150) better architecture for key management (keybase, keyfiles, etc.) +type Config interface { + GetBaseConfig() BaseConfig + GetConsensusConfig() ConsensusConfig + GetUtilityConfig() UtilityConfig + GetPersistenceConfig() PersistenceConfig + GetP2PConfig() P2PConfig + GetTelemetryConfig() TelemetryConfig } -type Config struct { - Base *BaseConfig `json:"base"` - Consensus ConsensusConfig `json:"consensus"` - Utility UtilityConfig `json:"utility"` - Persistence PersistenceConfig `json:"persistence"` - P2P P2PConfig `json:"p2p"` - Telemetry TelemetryConfig `json:"telemetry"` +type BaseConfig interface { + GetRootDirectory() string + GetPrivateKey() string // TODO (pocket/issues/150) better architecture for key management (keybase, keyfiles, etc.) } type ConsensusConfig interface { GetMaxMempoolBytes() uint64 - GetPaceMakerConfig() PacemakerConfig + GetPrivateKey() string // TODO (pocket/issues/150) better architecture for key management (keybase, keyfiles, etc.) } type PacemakerConfig interface { @@ -45,9 +47,10 @@ type PersistenceConfig interface { } type P2PConfig interface { + GetPrivateKey() string GetConsensusPort() uint32 GetUseRainTree() bool - IsEmptyConnType() bool // TODO : make enum + GetIsEmptyConnectionType() bool // TODO : make enum } type TelemetryConfig interface { @@ -56,7 +59,10 @@ type TelemetryConfig interface { GetEndpoint() string } -type UtilityConfig interface{} +type UtilityConfig interface { + GetMaxMempoolTransactionBytes() uint64 + GetMaxMempoolTransactions() uint32 +} type PersistenceGenesisState interface { GetAccs() []Account @@ -72,6 +78,7 @@ type ConsensusGenesisState interface { GetGenesisTime() *timestamppb.Timestamp GetChainId() string GetMaxBlockBytes() uint64 + GetVals() []Actor } type Account interface { @@ -221,16 +228,3 @@ type Params interface { GetMessageUnpauseServiceNodeFeeOwner() string GetMessageChangeParameterFeeOwner() string } - -var _ IConfig = PacemakerConfig(nil) -var _ IConfig = PersistenceConfig(nil) -var _ IConfig = P2PConfig(nil) -var _ IConfig = TelemetryConfig(nil) -var _ IConfig = UtilityConfig(nil) - -var _ IGenesis = PersistenceGenesisState(nil) -var _ IGenesis = ConsensusGenesisState(nil) - -// TODO(#235): Remove these interfaces once the runtime config approach is implemented. -type IConfig interface{} -type IGenesis interface{} diff --git a/shared/modules/utility_module.go b/shared/modules/utility_module.go index edfbc94ee..45e1bb95b 100644 --- a/shared/modules/utility_module.go +++ b/shared/modules/utility_module.go @@ -4,6 +4,7 @@ package modules type UtilityModule interface { Module + ConfigurableModule NewContext(height int64) (UtilityContext, error) } diff --git a/shared/node.go b/shared/node.go index da73ca166..026a2c9f8 100644 --- a/shared/node.go +++ b/shared/node.go @@ -7,6 +7,7 @@ import ( "github.com/pokt-network/pocket/consensus" "github.com/pokt-network/pocket/p2p" "github.com/pokt-network/pocket/persistence" + "github.com/pokt-network/pocket/runtime" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" "github.com/pokt-network/pocket/shared/debug" "github.com/pokt-network/pocket/shared/modules" @@ -16,56 +17,67 @@ import ( "google.golang.org/protobuf/types/known/anypb" ) -var _ modules.Module = &Node{} - const ( MainModuleName = "main" ) type Node struct { - clock clock.Clock - bus modules.Bus - Address cryptoPocket.Address + bus modules.Bus + p2pAddress cryptoPocket.Address +} + +func NewNodeWithP2PAddress(address cryptoPocket.Address) *Node { + return &Node{p2pAddress: address} } -func Create(configPath, genesisPath string, clock clock.Clock) (n *Node, err error) { - persistenceMod, err := persistence.Create(configPath, genesisPath) +func Create(configPath, genesisPath string, clock clock.Clock) (modules.Module, error) { + return new(Node).Create(runtime.NewManagerFromFiles(configPath, genesisPath)) +} + +func (m *Node) Create(runtimeMgr modules.RuntimeMgr) (modules.Module, error) { + persistenceMod, err := persistence.Create(runtimeMgr) if err != nil { return nil, err } - p2pMod, err := p2p.Create(configPath, genesisPath, false) + p2pMod, err := p2p.Create(runtimeMgr) if err != nil { return nil, err } - utilityMod, err := utility.Create(configPath, genesisPath) + utilityMod, err := utility.Create(runtimeMgr) if err != nil { return nil, err } - consensusMod, err := consensus.Create(configPath, genesisPath, false) + consensusMod, err := consensus.Create(runtimeMgr) if err != nil { return nil, err } - telemetryMod, err := telemetry.Create(configPath, genesisPath) + telemetryMod, err := telemetry.Create(runtimeMgr) if err != nil { return nil, err } - bus, err := CreateBus(persistenceMod, p2pMod, utilityMod, consensusMod, telemetryMod, clock) + bus, err := CreateBus( + runtimeMgr, + persistenceMod.(modules.PersistenceModule), + p2pMod.(modules.P2PModule), + utilityMod.(modules.UtilityModule), + consensusMod.(modules.ConsensusModule), + telemetryMod.(modules.TelemetryModule), + ) if err != nil { return nil, err } - addr, err := p2pMod.GetAddress() + addr, err := p2pMod.(modules.P2PModule).GetAddress() if err != nil { return nil, err } return &Node{ - bus: bus, - Address: addr, - clock: clock, + bus: bus, + p2pAddress: addr, }, nil } @@ -167,18 +179,6 @@ func (node *Node) GetModuleName() string { return MainModuleName } -func (node *Node) InitConfig(pathToConfigJSON string) (modules.IConfig, error) { - return nil, nil -} - -func (node *Node) InitGenesis(pathToGenesisJSON string) (modules.IGenesis, error) { - return nil, nil -} - -func (m *Node) SetClock(clock clock.Clock) { - m.clock = clock -} - -func (m *Node) GetClock() clock.Clock { - return m.clock +func (node *Node) GetP2PAddress() cryptoPocket.Address { + return node.p2pAddress } diff --git a/shared/test_artifacts/mock.go b/shared/test_artifacts/mock.go deleted file mode 100644 index a52ad3404..000000000 --- a/shared/test_artifacts/mock.go +++ /dev/null @@ -1,912 +0,0 @@ -package test_artifacts - -import ( - "fmt" - "github.com/pokt-network/pocket/shared/modules" - "google.golang.org/protobuf/types/known/timestamppb" -) - -// This file contains *seemingly* necessary implementations of the shared interfaces in order to -// do things like: create a genesis file and perform testing where cross module implementations are needed -// (see call to action in generator.go to try to remove the cross module testing code) - -// TODO (Team) convert these to proper mocks -var _ modules.Actor = &MockActor{} -var _ modules.Account = &MockAcc{} - -type MockAcc struct { - Address string `json:"address"` - Amount string `json:"amount"` -} - -func (m *MockAcc) GetAddress() string { - return m.Address -} - -func (m *MockAcc) GetAmount() string { - return m.Amount -} - -type MockActor struct { - Address string `json:"address"` - PublicKey string `json:"public_key"` - Chains []string `json:"chains"` - GenericParam string `json:"generic_param"` - StakedAmount string `json:"staked_amount"` - PausedHeight int64 `json:"paused_height"` - UnstakingHeight int64 `json:"unstaking_height"` - Output string `json:"output"` - ActorType MockActorType `json:"actor_type"` -} - -const ( - MockActorType_App MockActorType = 0 - MockActorType_Node MockActorType = 1 - MockActorType_Fish MockActorType = 2 - MockActorType_Val MockActorType = 3 -) - -func (m *MockActor) GetAddress() string { - return m.Address -} - -func (m *MockActor) GetPublicKey() string { - return m.PublicKey -} - -func (m *MockActor) GetChains() []string { - return m.Chains -} - -func (m *MockActor) GetGenericParam() string { - return m.GenericParam -} - -func (m *MockActor) GetStakedAmount() string { - return m.StakedAmount -} - -func (m *MockActor) GetPausedHeight() int64 { - return m.PausedHeight -} - -func (m *MockActor) GetUnstakingHeight() int64 { - return m.UnstakingHeight -} - -func (m *MockActor) GetOutput() string { - return m.Output -} - -func (m *MockActor) GetActorTyp() modules.ActorType { - return m.ActorType -} - -type MockActorType int32 - -func (m MockActorType) String() string { - return fmt.Sprintf("%d", m) -} - -var _ modules.PersistenceGenesisState = &MockPersistenceGenesisState{} -var _ modules.ConsensusGenesisState = &MockConsensusGenesisState{} - -type MockConsensusGenesisState struct { - GenesisTime *timestamppb.Timestamp `json:"genesis_time"` - ChainId string `json:"chain_id"` - MaxBlockBytes uint64 `json:"max_block_bytes"` - Validators []modules.Actor `json:"validators"` -} - -func (m *MockConsensusGenesisState) GetGenesisTime() *timestamppb.Timestamp { - return m.GenesisTime -} - -func (m *MockConsensusGenesisState) GetChainId() string { - return m.ChainId -} - -func (m *MockConsensusGenesisState) GetMaxBlockBytes() uint64 { - return m.MaxBlockBytes -} - -type MockPersistenceGenesisState struct { - Accounts []modules.Account `json:"accounts"` - Pools []modules.Account `json:"pools"` - Validators []modules.Actor `json:"validators"` - Applications []modules.Actor `json:"applications"` - ServiceNodes []modules.Actor `json:"service_nodes"` - Fishermen []modules.Actor `json:"fishermen"` - Params modules.Params `json:"params"` -} - -func (m MockPersistenceGenesisState) GetAccs() []modules.Account { - return m.Accounts -} - -func (m MockPersistenceGenesisState) GetAccPools() []modules.Account { - return m.Pools -} - -func (m MockPersistenceGenesisState) GetApps() []modules.Actor { - return m.Applications -} - -func (m MockPersistenceGenesisState) GetVals() []modules.Actor { - return m.Validators -} - -func (m MockPersistenceGenesisState) GetFish() []modules.Actor { - return m.Fishermen -} - -func (m MockPersistenceGenesisState) GetNodes() []modules.Actor { - return m.ServiceNodes -} - -func (m MockPersistenceGenesisState) GetParameters() modules.Params { - return m.Params -} - -var _ modules.ConsensusConfig = &MockConsensusConfig{} -var _ modules.PacemakerConfig = &MockPacemakerConfig{} -var _ modules.PersistenceConfig = &MockPersistenceConfig{} - -type MockPersistenceConfig struct { - PostgresUrl string `json:"postgres_url"` - NodeSchema string `json:"node_schema"` - BlockStorePath string `json:"block_store_path"` -} - -func (m *MockPersistenceConfig) GetPostgresUrl() string { - return m.PostgresUrl -} - -func (m *MockPersistenceConfig) GetNodeSchema() string { - return m.NodeSchema -} - -func (m *MockPersistenceConfig) GetBlockStorePath() string { - return m.BlockStorePath -} - -type MockConsensusConfig struct { - MaxMempoolBytes uint64 `json:"max_mempool_bytes"` - PacemakerConfig *MockPacemakerConfig `json:"pacemaker_config"` - PrivateKey string `json:"private_key"` -} - -func (m *MockConsensusConfig) GetMaxMempoolBytes() uint64 { - return m.MaxMempoolBytes -} - -func (m *MockConsensusConfig) GetPaceMakerConfig() modules.PacemakerConfig { - return m.PacemakerConfig -} - -type MockPacemakerConfig struct { - TimeoutMsec uint64 `json:"timeout_msec"` - Manual bool `json:"manual"` - DebugTimeBetweenStepsMsec uint64 `json:"debug_time_between_steps_msec"` -} - -func (m *MockPacemakerConfig) SetTimeoutMsec(u uint64) { - m.TimeoutMsec = u -} - -func (m *MockPacemakerConfig) GetTimeoutMsec() uint64 { - return m.TimeoutMsec -} - -func (m *MockPacemakerConfig) GetManual() bool { - return m.Manual -} - -func (m *MockPacemakerConfig) GetDebugTimeBetweenStepsMsec() uint64 { - return m.DebugTimeBetweenStepsMsec -} - -var _ modules.P2PConfig = &MockP2PConfig{} - -type MockP2PConfig struct { - ConsensusPort uint32 `json:"consensus_port"` - UseRainTree bool `json:"use_rain_tree"` - IsEmptyConnectionType bool `json:"is_empty_connection_type"` - PrivateKey string `json:"private_key"` -} - -func (m *MockP2PConfig) GetConsensusPort() uint32 { - return m.ConsensusPort -} - -func (m *MockP2PConfig) GetUseRainTree() bool { - return m.UseRainTree -} - -func (m *MockP2PConfig) IsEmptyConnType() bool { - return m.IsEmptyConnectionType -} - -var _ modules.TelemetryConfig = &MockTelemetryConfig{} - -type MockTelemetryConfig struct { - Enabled bool `json:"enabled"` - Address string `json:"address"` - Endpoint string `json:"endpoint"` -} - -func (m *MockTelemetryConfig) GetEnabled() bool { - return m.Enabled -} - -func (m *MockTelemetryConfig) GetAddress() string { - return m.Address -} - -func (m *MockTelemetryConfig) GetEndpoint() string { - return m.Endpoint -} - -type MockUtilityConfig struct { - MaxMempoolTransactionBytes uint64 `json:"max_mempool_transaction_bytes"` - MaxMempoolTransactions uint32 `json:"max_mempool_transactions"` -} - -var _ modules.Params = &MockParams{} - -type MockParams struct { - //@gotags: pokt:"val_type=BIGINT" - BlocksPerSession int32 `protobuf:"varint,1,opt,name=blocks_per_session,json=blocksPerSession,proto3" json:"blocks_per_session,omitempty"` - //@gotags: pokt:"val_type=STRING" - AppMinimumStake string `protobuf:"bytes,2,opt,name=app_minimum_stake,json=appMinimumStake,proto3" json:"app_minimum_stake,omitempty"` - //@gotags: pokt:"val_type=SMALLINT" - AppMaxChains int32 `protobuf:"varint,3,opt,name=app_max_chains,json=appMaxChains,proto3" json:"app_max_chains,omitempty"` - //@gotags: pokt:"val_type=BIGINT" - AppBaselineStakeRate int32 `protobuf:"varint,4,opt,name=app_baseline_stake_rate,json=appBaselineStakeRate,proto3" json:"app_baseline_stake_rate,omitempty"` - //@gotags: pokt:"val_type=BIGINT" - AppStakingAdjustment int32 `protobuf:"varint,5,opt,name=app_staking_adjustment,json=appStakingAdjustment,proto3" json:"app_staking_adjustment,omitempty"` - //@gotags: pokt:"val_type=BIGINT" - AppUnstakingBlocks int32 `protobuf:"varint,6,opt,name=app_unstaking_blocks,json=appUnstakingBlocks,proto3" json:"app_unstaking_blocks,omitempty"` - //@gotags: pokt:"val_type=SMALLINT" - AppMinimumPauseBlocks int32 `protobuf:"varint,7,opt,name=app_minimum_pause_blocks,json=appMinimumPauseBlocks,proto3" json:"app_minimum_pause_blocks,omitempty"` - //@gotags: pokt:"val_type=BIGINT" - AppMaxPauseBlocks int32 `protobuf:"varint,8,opt,name=app_max_pause_blocks,json=appMaxPauseBlocks,proto3" json:"app_max_pause_blocks,omitempty"` - //@gotags: pokt:"val_type=STRING" - ServiceNodeMinimumStake string `protobuf:"bytes,9,opt,name=service_node_minimum_stake,json=serviceNodeMinimumStake,proto3" json:"service_node_minimum_stake,omitempty"` - //@gotags: pokt:"val_type=SMALLINT" - ServiceNodeMaxChains int32 `protobuf:"varint,10,opt,name=service_node_max_chains,json=serviceNodeMaxChains,proto3" json:"service_node_max_chains,omitempty"` - //@gotags: pokt:"val_type=BIGINT" - ServiceNodeUnstakingBlocks int32 `protobuf:"varint,11,opt,name=service_node_unstaking_blocks,json=serviceNodeUnstakingBlocks,proto3" json:"service_node_unstaking_blocks,omitempty"` - //@gotags: pokt:"val_type=SMALLINT" - ServiceNodeMinimumPauseBlocks int32 `protobuf:"varint,12,opt,name=service_node_minimum_pause_blocks,json=serviceNodeMinimumPauseBlocks,proto3" json:"service_node_minimum_pause_blocks,omitempty"` - //@gotags: pokt:"val_type=BIGINT" - ServiceNodeMaxPauseBlocks int32 `protobuf:"varint,13,opt,name=service_node_max_pause_blocks,json=serviceNodeMaxPauseBlocks,proto3" json:"service_node_max_pause_blocks,omitempty"` - //@gotags: pokt:"val_type=SMALLINT" - ServiceNodesPerSession int32 `protobuf:"varint,14,opt,name=service_nodes_per_session,json=serviceNodesPerSession,proto3" json:"service_nodes_per_session,omitempty"` - //@gotags: pokt:"val_type=STRING" - FishermanMinimumStake string `protobuf:"bytes,15,opt,name=fisherman_minimum_stake,json=fishermanMinimumStake,proto3" json:"fisherman_minimum_stake,omitempty"` - //@gotags: pokt:"val_type=SMALLINT" - FishermanMaxChains int32 `protobuf:"varint,16,opt,name=fisherman_max_chains,json=fishermanMaxChains,proto3" json:"fisherman_max_chains,omitempty"` - //@gotags: pokt:"val_type=BIGINT" - FishermanUnstakingBlocks int32 `protobuf:"varint,17,opt,name=fisherman_unstaking_blocks,json=fishermanUnstakingBlocks,proto3" json:"fisherman_unstaking_blocks,omitempty"` - //@gotags: pokt:"val_type=SMALLINT" - FishermanMinimumPauseBlocks int32 `protobuf:"varint,18,opt,name=fisherman_minimum_pause_blocks,json=fishermanMinimumPauseBlocks,proto3" json:"fisherman_minimum_pause_blocks,omitempty"` - //@gotags: pokt:"val_type=SMALLINT" - FishermanMaxPauseBlocks int32 `protobuf:"varint,19,opt,name=fisherman_max_pause_blocks,json=fishermanMaxPauseBlocks,proto3" json:"fisherman_max_pause_blocks,omitempty"` - //@gotags: pokt:"val_type=STRING" - ValidatorMinimumStake string `protobuf:"bytes,20,opt,name=validator_minimum_stake,json=validatorMinimumStake,proto3" json:"validator_minimum_stake,omitempty"` - //@gotags: pokt:"val_type=BIGINT" - ValidatorUnstakingBlocks int32 `protobuf:"varint,21,opt,name=validator_unstaking_blocks,json=validatorUnstakingBlocks,proto3" json:"validator_unstaking_blocks,omitempty"` - //@gotags: pokt:"val_type=SMALLINT" - ValidatorMinimumPauseBlocks int32 `protobuf:"varint,22,opt,name=validator_minimum_pause_blocks,json=validatorMinimumPauseBlocks,proto3" json:"validator_minimum_pause_blocks,omitempty"` - //@gotags: pokt:"val_type=SMALLINT" - ValidatorMaxPauseBlocks int32 `protobuf:"varint,23,opt,name=validator_max_pause_blocks,json=validatorMaxPauseBlocks,proto3" json:"validator_max_pause_blocks,omitempty"` - //@gotags: pokt:"val_type=SMALLINT" - ValidatorMaximumMissedBlocks int32 `protobuf:"varint,24,opt,name=validator_maximum_missed_blocks,json=validatorMaximumMissedBlocks,proto3" json:"validator_maximum_missed_blocks,omitempty"` - //@gotags: pokt:"val_type=SMALLINT" - ValidatorMaxEvidenceAgeInBlocks int32 `protobuf:"varint,25,opt,name=validator_max_evidence_age_in_blocks,json=validatorMaxEvidenceAgeInBlocks,proto3" json:"validator_max_evidence_age_in_blocks,omitempty"` - //@gotags: pokt:"val_type=SMALLINT" - ProposerPercentageOfFees int32 `protobuf:"varint,26,opt,name=proposer_percentage_of_fees,json=proposerPercentageOfFees,proto3" json:"proposer_percentage_of_fees,omitempty"` - //@gotags: pokt:"val_type=SMALLINT" - MissedBlocksBurnPercentage int32 `protobuf:"varint,27,opt,name=missed_blocks_burn_percentage,json=missedBlocksBurnPercentage,proto3" json:"missed_blocks_burn_percentage,omitempty"` - //@gotags: pokt:"val_type=SMALLINT" - DoubleSignBurnPercentage int32 `protobuf:"varint,28,opt,name=double_sign_burn_percentage,json=doubleSignBurnPercentage,proto3" json:"double_sign_burn_percentage,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageDoubleSignFee string `protobuf:"bytes,29,opt,name=message_double_sign_fee,json=messageDoubleSignFee,proto3" json:"message_double_sign_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageSendFee string `protobuf:"bytes,30,opt,name=message_send_fee,json=messageSendFee,proto3" json:"message_send_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageStakeFishermanFee string `protobuf:"bytes,31,opt,name=message_stake_fisherman_fee,json=messageStakeFishermanFee,proto3" json:"message_stake_fisherman_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageEditStakeFishermanFee string `protobuf:"bytes,32,opt,name=message_edit_stake_fisherman_fee,json=messageEditStakeFishermanFee,proto3" json:"message_edit_stake_fisherman_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageUnstakeFishermanFee string `protobuf:"bytes,33,opt,name=message_unstake_fisherman_fee,json=messageUnstakeFishermanFee,proto3" json:"message_unstake_fisherman_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessagePauseFishermanFee string `protobuf:"bytes,34,opt,name=message_pause_fisherman_fee,json=messagePauseFishermanFee,proto3" json:"message_pause_fisherman_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageUnpauseFishermanFee string `protobuf:"bytes,35,opt,name=message_unpause_fisherman_fee,json=messageUnpauseFishermanFee,proto3" json:"message_unpause_fisherman_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageFishermanPauseServiceNodeFee string `protobuf:"bytes,36,opt,name=message_fisherman_pause_service_node_fee,json=messageFishermanPauseServiceNodeFee,proto3" json:"message_fisherman_pause_service_node_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageTestScoreFee string `protobuf:"bytes,37,opt,name=message_test_score_fee,json=messageTestScoreFee,proto3" json:"message_test_score_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageProveTestScoreFee string `protobuf:"bytes,38,opt,name=message_prove_test_score_fee,json=messageProveTestScoreFee,proto3" json:"message_prove_test_score_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageStakeAppFee string `protobuf:"bytes,39,opt,name=message_stake_app_fee,json=messageStakeAppFee,proto3" json:"message_stake_app_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageEditStakeAppFee string `protobuf:"bytes,40,opt,name=message_edit_stake_app_fee,json=messageEditStakeAppFee,proto3" json:"message_edit_stake_app_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageUnstakeAppFee string `protobuf:"bytes,41,opt,name=message_unstake_app_fee,json=messageUnstakeAppFee,proto3" json:"message_unstake_app_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessagePauseAppFee string `protobuf:"bytes,42,opt,name=message_pause_app_fee,json=messagePauseAppFee,proto3" json:"message_pause_app_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageUnpauseAppFee string `protobuf:"bytes,43,opt,name=message_unpause_app_fee,json=messageUnpauseAppFee,proto3" json:"message_unpause_app_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageStakeValidatorFee string `protobuf:"bytes,44,opt,name=message_stake_validator_fee,json=messageStakeValidatorFee,proto3" json:"message_stake_validator_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageEditStakeValidatorFee string `protobuf:"bytes,45,opt,name=message_edit_stake_validator_fee,json=messageEditStakeValidatorFee,proto3" json:"message_edit_stake_validator_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageUnstakeValidatorFee string `protobuf:"bytes,46,opt,name=message_unstake_validator_fee,json=messageUnstakeValidatorFee,proto3" json:"message_unstake_validator_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessagePauseValidatorFee string `protobuf:"bytes,47,opt,name=message_pause_validator_fee,json=messagePauseValidatorFee,proto3" json:"message_pause_validator_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageUnpauseValidatorFee string `protobuf:"bytes,48,opt,name=message_unpause_validator_fee,json=messageUnpauseValidatorFee,proto3" json:"message_unpause_validator_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageStakeServiceNodeFee string `protobuf:"bytes,49,opt,name=message_stake_service_node_fee,json=messageStakeServiceNodeFee,proto3" json:"message_stake_service_node_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageEditStakeServiceNodeFee string `protobuf:"bytes,50,opt,name=message_edit_stake_service_node_fee,json=messageEditStakeServiceNodeFee,proto3" json:"message_edit_stake_service_node_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageUnstakeServiceNodeFee string `protobuf:"bytes,51,opt,name=message_unstake_service_node_fee,json=messageUnstakeServiceNodeFee,proto3" json:"message_unstake_service_node_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessagePauseServiceNodeFee string `protobuf:"bytes,52,opt,name=message_pause_service_node_fee,json=messagePauseServiceNodeFee,proto3" json:"message_pause_service_node_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageUnpauseServiceNodeFee string `protobuf:"bytes,53,opt,name=message_unpause_service_node_fee,json=messageUnpauseServiceNodeFee,proto3" json:"message_unpause_service_node_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageChangeParameterFee string `protobuf:"bytes,54,opt,name=message_change_parameter_fee,json=messageChangeParameterFee,proto3" json:"message_change_parameter_fee,omitempty"` - //@gotags: pokt:"val_type=STRING" - AclOwner string `protobuf:"bytes,55,opt,name=acl_owner,json=aclOwner,proto3" json:"acl_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - BlocksPerSessionOwner string `protobuf:"bytes,56,opt,name=blocks_per_session_owner,json=blocksPerSessionOwner,proto3" json:"blocks_per_session_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - AppMinimumStakeOwner string `protobuf:"bytes,57,opt,name=app_minimum_stake_owner,json=appMinimumStakeOwner,proto3" json:"app_minimum_stake_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - AppMaxChainsOwner string `protobuf:"bytes,58,opt,name=app_max_chains_owner,json=appMaxChainsOwner,proto3" json:"app_max_chains_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - AppBaselineStakeRateOwner string `protobuf:"bytes,59,opt,name=app_baseline_stake_rate_owner,json=appBaselineStakeRateOwner,proto3" json:"app_baseline_stake_rate_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - AppStakingAdjustmentOwner string `protobuf:"bytes,60,opt,name=app_staking_adjustment_owner,json=appStakingAdjustmentOwner,proto3" json:"app_staking_adjustment_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - AppUnstakingBlocksOwner string `protobuf:"bytes,61,opt,name=app_unstaking_blocks_owner,json=appUnstakingBlocksOwner,proto3" json:"app_unstaking_blocks_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - AppMinimumPauseBlocksOwner string `protobuf:"bytes,62,opt,name=app_minimum_pause_blocks_owner,json=appMinimumPauseBlocksOwner,proto3" json:"app_minimum_pause_blocks_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - AppMaxPausedBlocksOwner string `protobuf:"bytes,63,opt,name=app_max_paused_blocks_owner,json=appMaxPausedBlocksOwner,proto3" json:"app_max_paused_blocks_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - ServiceNodeMinimumStakeOwner string `protobuf:"bytes,64,opt,name=service_node_minimum_stake_owner,json=serviceNodeMinimumStakeOwner,proto3" json:"service_node_minimum_stake_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - ServiceNodeMaxChainsOwner string `protobuf:"bytes,65,opt,name=service_node_max_chains_owner,json=serviceNodeMaxChainsOwner,proto3" json:"service_node_max_chains_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - ServiceNodeUnstakingBlocksOwner string `protobuf:"bytes,66,opt,name=service_node_unstaking_blocks_owner,json=serviceNodeUnstakingBlocksOwner,proto3" json:"service_node_unstaking_blocks_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - ServiceNodeMinimumPauseBlocksOwner string `protobuf:"bytes,67,opt,name=service_node_minimum_pause_blocks_owner,json=serviceNodeMinimumPauseBlocksOwner,proto3" json:"service_node_minimum_pause_blocks_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - ServiceNodeMaxPausedBlocksOwner string `protobuf:"bytes,68,opt,name=service_node_max_paused_blocks_owner,json=serviceNodeMaxPausedBlocksOwner,proto3" json:"service_node_max_paused_blocks_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - ServiceNodesPerSessionOwner string `protobuf:"bytes,69,opt,name=service_nodes_per_session_owner,json=serviceNodesPerSessionOwner,proto3" json:"service_nodes_per_session_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - FishermanMinimumStakeOwner string `protobuf:"bytes,70,opt,name=fisherman_minimum_stake_owner,json=fishermanMinimumStakeOwner,proto3" json:"fisherman_minimum_stake_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - FishermanMaxChainsOwner string `protobuf:"bytes,71,opt,name=fisherman_max_chains_owner,json=fishermanMaxChainsOwner,proto3" json:"fisherman_max_chains_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - FishermanUnstakingBlocksOwner string `protobuf:"bytes,72,opt,name=fisherman_unstaking_blocks_owner,json=fishermanUnstakingBlocksOwner,proto3" json:"fisherman_unstaking_blocks_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - FishermanMinimumPauseBlocksOwner string `protobuf:"bytes,73,opt,name=fisherman_minimum_pause_blocks_owner,json=fishermanMinimumPauseBlocksOwner,proto3" json:"fisherman_minimum_pause_blocks_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - FishermanMaxPausedBlocksOwner string `protobuf:"bytes,74,opt,name=fisherman_max_paused_blocks_owner,json=fishermanMaxPausedBlocksOwner,proto3" json:"fisherman_max_paused_blocks_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - ValidatorMinimumStakeOwner string `protobuf:"bytes,75,opt,name=validator_minimum_stake_owner,json=validatorMinimumStakeOwner,proto3" json:"validator_minimum_stake_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - ValidatorUnstakingBlocksOwner string `protobuf:"bytes,76,opt,name=validator_unstaking_blocks_owner,json=validatorUnstakingBlocksOwner,proto3" json:"validator_unstaking_blocks_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - ValidatorMinimumPauseBlocksOwner string `protobuf:"bytes,77,opt,name=validator_minimum_pause_blocks_owner,json=validatorMinimumPauseBlocksOwner,proto3" json:"validator_minimum_pause_blocks_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - ValidatorMaxPausedBlocksOwner string `protobuf:"bytes,78,opt,name=validator_max_paused_blocks_owner,json=validatorMaxPausedBlocksOwner,proto3" json:"validator_max_paused_blocks_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - ValidatorMaximumMissedBlocksOwner string `protobuf:"bytes,79,opt,name=validator_maximum_missed_blocks_owner,json=validatorMaximumMissedBlocksOwner,proto3" json:"validator_maximum_missed_blocks_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - ValidatorMaxEvidenceAgeInBlocksOwner string `protobuf:"bytes,80,opt,name=validator_max_evidence_age_in_blocks_owner,json=validatorMaxEvidenceAgeInBlocksOwner,proto3" json:"validator_max_evidence_age_in_blocks_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - ProposerPercentageOfFeesOwner string `protobuf:"bytes,81,opt,name=proposer_percentage_of_fees_owner,json=proposerPercentageOfFeesOwner,proto3" json:"proposer_percentage_of_fees_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MissedBlocksBurnPercentageOwner string `protobuf:"bytes,82,opt,name=missed_blocks_burn_percentage_owner,json=missedBlocksBurnPercentageOwner,proto3" json:"missed_blocks_burn_percentage_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - DoubleSignBurnPercentageOwner string `protobuf:"bytes,83,opt,name=double_sign_burn_percentage_owner,json=doubleSignBurnPercentageOwner,proto3" json:"double_sign_burn_percentage_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageDoubleSignFeeOwner string `protobuf:"bytes,84,opt,name=message_double_sign_fee_owner,json=messageDoubleSignFeeOwner,proto3" json:"message_double_sign_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageSendFeeOwner string `protobuf:"bytes,85,opt,name=message_send_fee_owner,json=messageSendFeeOwner,proto3" json:"message_send_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageStakeFishermanFeeOwner string `protobuf:"bytes,86,opt,name=message_stake_fisherman_fee_owner,json=messageStakeFishermanFeeOwner,proto3" json:"message_stake_fisherman_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageEditStakeFishermanFeeOwner string `protobuf:"bytes,87,opt,name=message_edit_stake_fisherman_fee_owner,json=messageEditStakeFishermanFeeOwner,proto3" json:"message_edit_stake_fisherman_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageUnstakeFishermanFeeOwner string `protobuf:"bytes,88,opt,name=message_unstake_fisherman_fee_owner,json=messageUnstakeFishermanFeeOwner,proto3" json:"message_unstake_fisherman_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessagePauseFishermanFeeOwner string `protobuf:"bytes,89,opt,name=message_pause_fisherman_fee_owner,json=messagePauseFishermanFeeOwner,proto3" json:"message_pause_fisherman_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageUnpauseFishermanFeeOwner string `protobuf:"bytes,90,opt,name=message_unpause_fisherman_fee_owner,json=messageUnpauseFishermanFeeOwner,proto3" json:"message_unpause_fisherman_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageFishermanPauseServiceNodeFeeOwner string `protobuf:"bytes,91,opt,name=message_fisherman_pause_service_node_fee_owner,json=messageFishermanPauseServiceNodeFeeOwner,proto3" json:"message_fisherman_pause_service_node_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageTestScoreFeeOwner string `protobuf:"bytes,92,opt,name=message_test_score_fee_owner,json=messageTestScoreFeeOwner,proto3" json:"message_test_score_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageProveTestScoreFeeOwner string `protobuf:"bytes,93,opt,name=message_prove_test_score_fee_owner,json=messageProveTestScoreFeeOwner,proto3" json:"message_prove_test_score_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageStakeAppFeeOwner string `protobuf:"bytes,94,opt,name=message_stake_app_fee_owner,json=messageStakeAppFeeOwner,proto3" json:"message_stake_app_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageEditStakeAppFeeOwner string `protobuf:"bytes,95,opt,name=message_edit_stake_app_fee_owner,json=messageEditStakeAppFeeOwner,proto3" json:"message_edit_stake_app_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageUnstakeAppFeeOwner string `protobuf:"bytes,96,opt,name=message_unstake_app_fee_owner,json=messageUnstakeAppFeeOwner,proto3" json:"message_unstake_app_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessagePauseAppFeeOwner string `protobuf:"bytes,97,opt,name=message_pause_app_fee_owner,json=messagePauseAppFeeOwner,proto3" json:"message_pause_app_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageUnpauseAppFeeOwner string `protobuf:"bytes,98,opt,name=message_unpause_app_fee_owner,json=messageUnpauseAppFeeOwner,proto3" json:"message_unpause_app_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageStakeValidatorFeeOwner string `protobuf:"bytes,99,opt,name=message_stake_validator_fee_owner,json=messageStakeValidatorFeeOwner,proto3" json:"message_stake_validator_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageEditStakeValidatorFeeOwner string `protobuf:"bytes,100,opt,name=message_edit_stake_validator_fee_owner,json=messageEditStakeValidatorFeeOwner,proto3" json:"message_edit_stake_validator_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageUnstakeValidatorFeeOwner string `protobuf:"bytes,101,opt,name=message_unstake_validator_fee_owner,json=messageUnstakeValidatorFeeOwner,proto3" json:"message_unstake_validator_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessagePauseValidatorFeeOwner string `protobuf:"bytes,102,opt,name=message_pause_validator_fee_owner,json=messagePauseValidatorFeeOwner,proto3" json:"message_pause_validator_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageUnpauseValidatorFeeOwner string `protobuf:"bytes,103,opt,name=message_unpause_validator_fee_owner,json=messageUnpauseValidatorFeeOwner,proto3" json:"message_unpause_validator_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageStakeServiceNodeFeeOwner string `protobuf:"bytes,104,opt,name=message_stake_service_node_fee_owner,json=messageStakeServiceNodeFeeOwner,proto3" json:"message_stake_service_node_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageEditStakeServiceNodeFeeOwner string `protobuf:"bytes,105,opt,name=message_edit_stake_service_node_fee_owner,json=messageEditStakeServiceNodeFeeOwner,proto3" json:"message_edit_stake_service_node_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageUnstakeServiceNodeFeeOwner string `protobuf:"bytes,106,opt,name=message_unstake_service_node_fee_owner,json=messageUnstakeServiceNodeFeeOwner,proto3" json:"message_unstake_service_node_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessagePauseServiceNodeFeeOwner string `protobuf:"bytes,107,opt,name=message_pause_service_node_fee_owner,json=messagePauseServiceNodeFeeOwner,proto3" json:"message_pause_service_node_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageUnpauseServiceNodeFeeOwner string `protobuf:"bytes,108,opt,name=message_unpause_service_node_fee_owner,json=messageUnpauseServiceNodeFeeOwner,proto3" json:"message_unpause_service_node_fee_owner,omitempty"` - //@gotags: pokt:"val_type=STRING" - MessageChangeParameterFeeOwner string `protobuf:"bytes,109,opt,name=message_change_parameter_fee_owner,json=messageChangeParameterFeeOwner,proto3" json:"message_change_parameter_fee_owner,omitempty"` -} - -func (m *MockParams) GetBlocksPerSession() int32 { - return m.BlocksPerSession -} - -func (m *MockParams) GetAppMinimumStake() string { - return m.AppMinimumStake -} - -func (m *MockParams) GetAppMaxChains() int32 { - return m.AppMaxChains -} - -func (m *MockParams) GetAppBaselineStakeRate() int32 { - return m.AppBaselineStakeRate -} - -func (m *MockParams) GetAppStakingAdjustment() int32 { - return m.AppStakingAdjustment -} - -func (m *MockParams) GetAppUnstakingBlocks() int32 { - return m.AppUnstakingBlocks -} - -func (m *MockParams) GetAppMinimumPauseBlocks() int32 { - return m.AppMinimumPauseBlocks -} - -func (m *MockParams) GetAppMaxPauseBlocks() int32 { - return m.AppMaxPauseBlocks -} - -func (m *MockParams) GetServiceNodeMinimumStake() string { - return m.ServiceNodeMinimumStake -} - -func (m *MockParams) GetServiceNodeMaxChains() int32 { - return m.ServiceNodeMaxChains -} - -func (m *MockParams) GetServiceNodeUnstakingBlocks() int32 { - return m.ServiceNodeUnstakingBlocks -} - -func (m *MockParams) GetServiceNodeMinimumPauseBlocks() int32 { - return m.ServiceNodeMinimumPauseBlocks -} - -func (m *MockParams) GetServiceNodeMaxPauseBlocks() int32 { - return m.ServiceNodeMaxPauseBlocks -} - -func (m *MockParams) GetServiceNodesPerSession() int32 { - return m.ServiceNodesPerSession -} - -func (m *MockParams) GetFishermanMinimumStake() string { - return m.FishermanMinimumStake -} - -func (m *MockParams) GetFishermanMaxChains() int32 { - return m.FishermanMaxChains -} - -func (m *MockParams) GetFishermanUnstakingBlocks() int32 { - return m.FishermanUnstakingBlocks -} - -func (m *MockParams) GetFishermanMinimumPauseBlocks() int32 { - return m.FishermanMinimumPauseBlocks -} - -func (m *MockParams) GetFishermanMaxPauseBlocks() int32 { - return m.FishermanMaxPauseBlocks -} - -func (m *MockParams) GetValidatorMinimumStake() string { - return m.ValidatorMinimumStake -} - -func (m *MockParams) GetValidatorUnstakingBlocks() int32 { - return m.ValidatorUnstakingBlocks -} - -func (m *MockParams) GetValidatorMinimumPauseBlocks() int32 { - return m.ValidatorMinimumPauseBlocks -} - -func (m *MockParams) GetValidatorMaxPauseBlocks() int32 { - return m.ValidatorMaxPauseBlocks -} - -func (m *MockParams) GetValidatorMaximumMissedBlocks() int32 { - return m.ValidatorMaximumMissedBlocks -} - -func (m *MockParams) GetValidatorMaxEvidenceAgeInBlocks() int32 { - return m.ValidatorMaxEvidenceAgeInBlocks -} - -func (m *MockParams) GetProposerPercentageOfFees() int32 { - return m.ProposerPercentageOfFees -} - -func (m *MockParams) GetMissedBlocksBurnPercentage() int32 { - return m.MissedBlocksBurnPercentage -} - -func (m *MockParams) GetDoubleSignBurnPercentage() int32 { - return m.DoubleSignBurnPercentage -} - -func (m *MockParams) GetMessageDoubleSignFee() string { - return m.MessageDoubleSignFee -} - -func (m *MockParams) GetMessageSendFee() string { - return m.MessageSendFee -} - -func (m *MockParams) GetMessageStakeFishermanFee() string { - return m.MessageStakeFishermanFee -} - -func (m *MockParams) GetMessageEditStakeFishermanFee() string { - return m.MessageEditStakeFishermanFee -} - -func (m *MockParams) GetMessageUnstakeFishermanFee() string { - return m.MessageUnstakeFishermanFee -} - -func (m *MockParams) GetMessagePauseFishermanFee() string { - return m.MessagePauseFishermanFee -} - -func (m *MockParams) GetMessageUnpauseFishermanFee() string { - return m.MessageUnpauseFishermanFee -} - -func (m *MockParams) GetMessageFishermanPauseServiceNodeFee() string { - return m.MessageFishermanPauseServiceNodeFee -} - -func (m *MockParams) GetMessageTestScoreFee() string { - return m.MessageTestScoreFee -} - -func (m *MockParams) GetMessageProveTestScoreFee() string { - return m.MessageProveTestScoreFee -} - -func (m *MockParams) GetMessageStakeAppFee() string { - return m.MessageStakeAppFee -} - -func (m *MockParams) GetMessageEditStakeAppFee() string { - return m.MessageEditStakeAppFee -} - -func (m *MockParams) GetMessageUnstakeAppFee() string { - return m.MessageUnstakeAppFee -} - -func (m *MockParams) GetMessagePauseAppFee() string { - return m.MessagePauseAppFee -} - -func (m *MockParams) GetMessageUnpauseAppFee() string { - return m.MessageUnpauseAppFee -} - -func (m *MockParams) GetMessageStakeValidatorFee() string { - return m.MessageStakeValidatorFee -} - -func (m *MockParams) GetMessageEditStakeValidatorFee() string { - return m.MessageEditStakeValidatorFee -} - -func (m *MockParams) GetMessageUnstakeValidatorFee() string { - return m.MessageUnstakeValidatorFee -} - -func (m *MockParams) GetMessagePauseValidatorFee() string { - return m.MessagePauseValidatorFee -} - -func (m *MockParams) GetMessageUnpauseValidatorFee() string { - return m.MessageUnpauseValidatorFee -} - -func (m *MockParams) GetMessageStakeServiceNodeFee() string { - return m.MessageStakeServiceNodeFee -} - -func (m *MockParams) GetMessageEditStakeServiceNodeFee() string { - return m.MessageEditStakeServiceNodeFee -} - -func (m *MockParams) GetMessageUnstakeServiceNodeFee() string { - return m.MessageUnstakeServiceNodeFee -} - -func (m *MockParams) GetMessagePauseServiceNodeFee() string { - return m.MessagePauseServiceNodeFee -} - -func (m *MockParams) GetMessageUnpauseServiceNodeFee() string { - return m.MessageUnpauseServiceNodeFee -} - -func (m *MockParams) GetMessageChangeParameterFee() string { - return m.MessageChangeParameterFee -} - -func (m *MockParams) GetAclOwner() string { - return m.AclOwner -} - -func (m *MockParams) GetBlocksPerSessionOwner() string { - return m.BlocksPerSessionOwner -} - -func (m *MockParams) GetAppMinimumStakeOwner() string { - return m.AppMinimumStakeOwner -} - -func (m *MockParams) GetAppMaxChainsOwner() string { - return m.AppMaxChainsOwner -} - -func (m *MockParams) GetAppBaselineStakeRateOwner() string { - return m.AppBaselineStakeRateOwner -} - -func (m *MockParams) GetAppStakingAdjustmentOwner() string { - return m.AppStakingAdjustmentOwner -} - -func (m *MockParams) GetAppUnstakingBlocksOwner() string { - return m.AppUnstakingBlocksOwner -} - -func (m *MockParams) GetAppMinimumPauseBlocksOwner() string { - return m.AppMinimumPauseBlocksOwner -} - -func (m *MockParams) GetAppMaxPausedBlocksOwner() string { - return m.AppMaxPausedBlocksOwner -} - -func (m *MockParams) GetServiceNodeMinimumStakeOwner() string { - return m.ServiceNodeMinimumStakeOwner -} - -func (m *MockParams) GetServiceNodeMaxChainsOwner() string { - return m.ServiceNodeMaxChainsOwner -} - -func (m *MockParams) GetServiceNodeUnstakingBlocksOwner() string { - return m.ServiceNodeUnstakingBlocksOwner -} - -func (m *MockParams) GetServiceNodeMinimumPauseBlocksOwner() string { - return m.ServiceNodeMinimumPauseBlocksOwner -} - -func (m *MockParams) GetServiceNodeMaxPausedBlocksOwner() string { - return m.ServiceNodeMaxPausedBlocksOwner -} - -func (m *MockParams) GetServiceNodesPerSessionOwner() string { - return m.ServiceNodesPerSessionOwner -} - -func (m *MockParams) GetFishermanMinimumStakeOwner() string { - return m.FishermanMinimumStakeOwner -} - -func (m *MockParams) GetFishermanMaxChainsOwner() string { - return m.FishermanMaxChainsOwner -} - -func (m *MockParams) GetFishermanUnstakingBlocksOwner() string { - return m.FishermanUnstakingBlocksOwner -} - -func (m *MockParams) GetFishermanMinimumPauseBlocksOwner() string { - return m.FishermanMinimumPauseBlocksOwner -} - -func (m *MockParams) GetFishermanMaxPausedBlocksOwner() string { - return m.FishermanMaxPausedBlocksOwner -} - -func (m *MockParams) GetValidatorMinimumStakeOwner() string { - return m.ValidatorMinimumStakeOwner -} - -func (m *MockParams) GetValidatorUnstakingBlocksOwner() string { - return m.ValidatorUnstakingBlocksOwner -} - -func (m *MockParams) GetValidatorMinimumPauseBlocksOwner() string { - return m.ValidatorMinimumPauseBlocksOwner -} - -func (m *MockParams) GetValidatorMaxPausedBlocksOwner() string { - return m.ValidatorMaxPausedBlocksOwner -} - -func (m *MockParams) GetValidatorMaximumMissedBlocksOwner() string { - return m.ValidatorMaximumMissedBlocksOwner -} - -func (m *MockParams) GetValidatorMaxEvidenceAgeInBlocksOwner() string { - return m.ValidatorMaxEvidenceAgeInBlocksOwner -} - -func (m *MockParams) GetProposerPercentageOfFeesOwner() string { - return m.ProposerPercentageOfFeesOwner -} - -func (m *MockParams) GetMissedBlocksBurnPercentageOwner() string { - return m.MissedBlocksBurnPercentageOwner -} - -func (m *MockParams) GetDoubleSignBurnPercentageOwner() string { - return m.DoubleSignBurnPercentageOwner -} - -func (m *MockParams) GetMessageDoubleSignFeeOwner() string { - return m.MessageDoubleSignFeeOwner -} - -func (m *MockParams) GetMessageSendFeeOwner() string { - return m.MessageSendFeeOwner -} - -func (m *MockParams) GetMessageStakeFishermanFeeOwner() string { - return m.MessageStakeFishermanFeeOwner -} - -func (m *MockParams) GetMessageEditStakeFishermanFeeOwner() string { - return m.MessageEditStakeFishermanFeeOwner -} - -func (m *MockParams) GetMessageUnstakeFishermanFeeOwner() string { - return m.MessageUnstakeFishermanFeeOwner -} - -func (m *MockParams) GetMessagePauseFishermanFeeOwner() string { - return m.MessagePauseFishermanFeeOwner -} - -func (m *MockParams) GetMessageUnpauseFishermanFeeOwner() string { - return m.MessageUnpauseFishermanFeeOwner -} - -func (m *MockParams) GetMessageFishermanPauseServiceNodeFeeOwner() string { - return m.MessageFishermanPauseServiceNodeFeeOwner -} - -func (m *MockParams) GetMessageTestScoreFeeOwner() string { - return m.MessageTestScoreFeeOwner -} - -func (m *MockParams) GetMessageProveTestScoreFeeOwner() string { - return m.MessageProveTestScoreFeeOwner -} - -func (m *MockParams) GetMessageStakeAppFeeOwner() string { - return m.MessageStakeAppFeeOwner -} - -func (m *MockParams) GetMessageEditStakeAppFeeOwner() string { - return m.MessageEditStakeAppFeeOwner -} - -func (m *MockParams) GetMessageUnstakeAppFeeOwner() string { - return m.MessageUnstakeAppFeeOwner -} - -func (m *MockParams) GetMessagePauseAppFeeOwner() string { - return m.MessagePauseAppFeeOwner -} - -func (m *MockParams) GetMessageUnpauseAppFeeOwner() string { - return m.MessageUnpauseAppFeeOwner -} - -func (m *MockParams) GetMessageStakeValidatorFeeOwner() string { - return m.MessageStakeValidatorFeeOwner -} - -func (m *MockParams) GetMessageEditStakeValidatorFeeOwner() string { - return m.MessageEditStakeValidatorFeeOwner -} - -func (m *MockParams) GetMessageUnstakeValidatorFeeOwner() string { - return m.MessageUnstakeValidatorFeeOwner -} - -func (m *MockParams) GetMessagePauseValidatorFeeOwner() string { - return m.MessagePauseValidatorFeeOwner -} - -func (m *MockParams) GetMessageUnpauseValidatorFeeOwner() string { - return m.MessageUnpauseValidatorFeeOwner -} - -func (m *MockParams) GetMessageStakeServiceNodeFeeOwner() string { - return m.MessageStakeServiceNodeFeeOwner -} - -func (m *MockParams) GetMessageEditStakeServiceNodeFeeOwner() string { - return m.MessageEditStakeServiceNodeFeeOwner -} - -func (m *MockParams) GetMessageUnstakeServiceNodeFeeOwner() string { - return m.MessageUnstakeServiceNodeFeeOwner -} - -func (m *MockParams) GetMessagePauseServiceNodeFeeOwner() string { - return m.MessagePauseServiceNodeFeeOwner -} - -func (m *MockParams) GetMessageUnpauseServiceNodeFeeOwner() string { - return m.MessageUnpauseServiceNodeFeeOwner -} - -func (m *MockParams) GetMessageChangeParameterFeeOwner() string { - return m.MessageChangeParameterFeeOwner -} diff --git a/telemetry/module.go b/telemetry/module.go index 2c70d7052..50d385f37 100644 --- a/telemetry/module.go +++ b/telemetry/module.go @@ -1,56 +1,40 @@ package telemetry import ( - "encoding/json" - "io/ioutil" - "log" - "github.com/pokt-network/pocket/shared/modules" ) -var _ modules.Module = &telemetryModule{} -var _ modules.TelemetryConfig = &TelemetryConfig{} +var ( + _ modules.Module = &telemetryModule{} + _ modules.TelemetryConfig = &TelemetryConfig{} +) const ( TelemetryModuleName = "telemetry" ) +func Create(runtime modules.RuntimeMgr) (modules.Module, error) { + return new(telemetryModule).Create(runtime) +} + // TODO(pocket/issues/99): Add a switch statement and configuration variable when support for other telemetry modules is added. -func Create(configPath, genesisPath string) (modules.TelemetryModule, error) { - tm := new(telemetryModule) - c, err := tm.InitConfig(configPath) - if err != nil { - return nil, err - } - cfg := c.(*TelemetryConfig) - if cfg.GetEnabled() { - return CreatePrometheusTelemetryModule(cfg) +func (*telemetryModule) Create(runtime modules.RuntimeMgr) (modules.Module, error) { + cfg := runtime.GetConfig() + + telemetryCfg := cfg.GetTelemetryConfig() + + if telemetryCfg.GetEnabled() { + return CreatePrometheusTelemetryModule(runtime) } else { - return CreateNoopTelemetryModule(cfg) + return CreateNoopTelemetryModule(runtime) } } type telemetryModule struct{} -func (t *telemetryModule) InitConfig(pathToConfigJSON string) (config modules.IConfig, err error) { - data, err := ioutil.ReadFile(pathToConfigJSON) - if err != nil { - return - } - // over arching configuration file - rawJSON := make(map[string]json.RawMessage) - if err = json.Unmarshal(data, &rawJSON); err != nil { - log.Fatalf("[ERROR] an error occurred unmarshalling the %s file: %v", pathToConfigJSON, err.Error()) - } - // telemetry specific configuration file - config = new(TelemetryConfig) - err = json.Unmarshal(rawJSON[t.GetModuleName()], config) - return -} - -func (t *telemetryModule) GetModuleName() string { return TelemetryModuleName } -func (t *telemetryModule) InitGenesis(_ string) (genesis modules.IGenesis, err error) { return } -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 TelemetryModuleName } +func (t *telemetryModule) InitGenesis(_ string) (genesis modules.GenesisState, err error) { return } +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 } diff --git a/telemetry/noop_module.go b/telemetry/noop_module.go index a1cbeb9d1..1866e86a3 100644 --- a/telemetry/noop_module.go +++ b/telemetry/noop_module.go @@ -25,7 +25,12 @@ func NOOP() { log.Printf("\n[telemetry=noop]\n") } -func CreateNoopTelemetryModule(_ *TelemetryConfig) (*NoopTelemetryModule, error) { +func CreateNoopTelemetryModule(runtime modules.RuntimeMgr) (modules.Module, error) { + var m NoopTelemetryModule + return m.Create(runtime) +} + +func (m *NoopTelemetryModule) Create(runtime modules.RuntimeMgr) (modules.Module, error) { return &NoopTelemetryModule{}, nil } @@ -39,14 +44,6 @@ func (m *NoopTelemetryModule) Stop() error { return nil } -func (m *NoopTelemetryModule) InitConfig(pathToConfigJSON string) (config modules.IConfig, err error) { - return // No-op -} - -func (m *NoopTelemetryModule) InitGenesis(pathToGenesisJSON string) (genesis modules.IGenesis, err error) { - return // No-op -} - func (m *NoopTelemetryModule) GetModuleName() string { return NoOpModuleName } @@ -62,6 +59,10 @@ func (m *NoopTelemetryModule) GetBus() modules.Bus { return m.bus } +func (*NoopTelemetryModule) ValidateConfig(cfg modules.Config) error { + return nil +} + func (m *NoopTelemetryModule) GetEventMetricsAgent() modules.EventMetricsAgent { return modules.EventMetricsAgent(m) } diff --git a/telemetry/prometheus_module.go b/telemetry/prometheus_module.go index 1c4ff2f6c..c81b3b70e 100644 --- a/telemetry/prometheus_module.go +++ b/telemetry/prometheus_module.go @@ -1,6 +1,7 @@ package telemetry import ( + "fmt" "log" "net/http" @@ -11,18 +12,18 @@ import ( ) var ( - _ modules.TelemetryModule = &PrometheusTelemetryModule{} - _ modules.EventMetricsAgent = &PrometheusTelemetryModule{} - _ modules.TimeSeriesAgent = &PrometheusTelemetryModule{} + _ modules.Module = &PrometheusTelemetryModule{} + _ modules.ConfigurableModule = &PrometheusTelemetryModule{} + _ modules.TelemetryModule = &PrometheusTelemetryModule{} + _ modules.EventMetricsAgent = &PrometheusTelemetryModule{} + _ modules.TimeSeriesAgent = &PrometheusTelemetryModule{} ) // DISCUSS(team): Should the warning logs in this module be handled differently? type PrometheusTelemetryModule struct { - bus modules.Bus - - address string - endpoint string + bus modules.Bus + config modules.TelemetryConfig counters map[string]prometheus.Counter gauges map[string]prometheus.Gauge @@ -33,22 +34,31 @@ const ( PrometheusModuleName = "prometheus" ) -func CreatePrometheusTelemetryModule(cfg *TelemetryConfig) (*PrometheusTelemetryModule, error) { +func CreatePrometheusTelemetryModule(runtime modules.RuntimeMgr) (modules.Module, error) { + var m PrometheusTelemetryModule + return m.Create(runtime) +} + +func (m *PrometheusTelemetryModule) Create(runtime modules.RuntimeMgr) (modules.Module, error) { + cfg := runtime.GetConfig() + if err := m.ValidateConfig(cfg); err != nil { + return nil, fmt.Errorf("config validation failed: %w", err) + } + telemetryCfg := cfg.GetTelemetryConfig() + return &PrometheusTelemetryModule{ + config: telemetryCfg, counters: map[string]prometheus.Counter{}, gauges: map[string]prometheus.Gauge{}, gaugeVectors: map[string]prometheus.GaugeVec{}, - - address: cfg.GetAddress(), - endpoint: cfg.GetEndpoint(), }, nil } func (m *PrometheusTelemetryModule) Start() error { - log.Printf("\nPrometheus metrics exporter: Starting at %s%s...\n", m.address, m.endpoint) + log.Printf("\nPrometheus metrics exporter: Starting at %s%s...\n", m.config.GetAddress(), m.config.GetEndpoint()) - http.Handle(m.endpoint, promhttp.Handler()) - go http.ListenAndServe(m.address, nil) + http.Handle(m.config.GetEndpoint(), promhttp.Handler()) + go http.ListenAndServe(m.config.GetAddress(), nil) log.Println("Prometheus metrics exporter started: OK") @@ -59,14 +69,6 @@ func (m *PrometheusTelemetryModule) Stop() error { return nil } -func (m *PrometheusTelemetryModule) InitConfig(pathToConfigJSON string) (config modules.IConfig, err error) { - return // No-op -} - -func (m *PrometheusTelemetryModule) InitGenesis(pathToGenesisJSON string) (genesis modules.IGenesis, err error) { - return // No-op -} - func (m *PrometheusTelemetryModule) SetBus(bus modules.Bus) { m.bus = bus } @@ -82,6 +84,10 @@ func (m *PrometheusTelemetryModule) GetBus() modules.Bus { return m.bus } +func (*PrometheusTelemetryModule) ValidateConfig(cfg modules.Config) error { + return nil +} + // EventMetricsAgent interface implementation func (m *PrometheusTelemetryModule) GetEventMetricsAgent() modules.EventMetricsAgent { return modules.EventMetricsAgent(m) diff --git a/utility/context.go b/utility/context.go index c3f97f3a8..00c44e9fb 100644 --- a/utility/context.go +++ b/utility/context.go @@ -2,6 +2,7 @@ package utility import ( "encoding/hex" + "github.com/pokt-network/pocket/shared/codec" "github.com/pokt-network/pocket/shared/modules" typesUtil "github.com/pokt-network/pocket/utility/types" @@ -19,7 +20,7 @@ type Context struct { SavePoints [][]byte } -func (u *UtilityModule) NewContext(height int64) (modules.UtilityContext, error) { +func (u *utilityModule) NewContext(height int64) (modules.UtilityContext, error) { ctx, err := u.GetBus().GetPersistenceModule().NewRWContext(height) if err != nil { return nil, typesUtil.ErrNewPersistenceContext(err) diff --git a/utility/doc/CHANGELOG.md b/utility/doc/CHANGELOG.md index 5e0432741..2d2b38045 100644 --- a/utility/doc/CHANGELOG.md +++ b/utility/doc/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.7] - 2022-10-12 + +### [#235](https://github.com/pokt-network/pocket/pull/235) Config and genesis handling + +- Updated to use `RuntimeMgr` +- Made `UtilityModule` struct unexported +- Updated tests and mocks +- Removed some cross-module dependencies + ## [0.0.0.6] - 2022-10-06 - Don't ignore the exit code of `m.Run()` in the unit tests diff --git a/utility/module.go b/utility/module.go index 60ea6fbf3..1e2fd619f 100644 --- a/utility/module.go +++ b/utility/module.go @@ -1,8 +1,7 @@ package utility import ( - "encoding/json" - "io/ioutil" + "fmt" "log" "github.com/pokt-network/pocket/utility/types" @@ -10,11 +9,14 @@ import ( "github.com/pokt-network/pocket/shared/modules" ) -var _ modules.UtilityModule = &UtilityModule{} +var _ modules.UtilityModule = &utilityModule{} var _ modules.UtilityConfig = &types.UtilityConfig{} +var _ modules.Module = &utilityModule{} + +type utilityModule struct { + bus modules.Bus + config modules.UtilityConfig -type UtilityModule struct { - bus modules.Bus Mempool types.Mempool } @@ -22,57 +24,48 @@ const ( UtilityModuleName = "utility" ) -func Create(configPath, genesisPath string) (modules.UtilityModule, error) { - u := new(UtilityModule) - c, err := u.InitConfig(configPath) - if err != nil { - return nil, err - } - config := (c).(*types.UtilityConfig) - return &UtilityModule{ - Mempool: types.NewMempool(config.MaxMempoolTransactionBytes, config.MaxMempoolTransactions), - }, nil +func Create(runtime modules.RuntimeMgr) (modules.Module, error) { + return new(utilityModule).Create(runtime) } -func (u *UtilityModule) InitConfig(pathToConfigJSON string) (config modules.IConfig, err error) { - data, err := ioutil.ReadFile(pathToConfigJSON) - if err != nil { - return - } - // over arching configuration file - rawJSON := make(map[string]json.RawMessage) - if err = json.Unmarshal(data, &rawJSON); err != nil { - log.Fatalf("[ERROR] an error occurred unmarshalling the %s file: %v", pathToConfigJSON, err.Error()) +func (*utilityModule) Create(runtime modules.RuntimeMgr) (modules.Module, error) { + var m *utilityModule + + cfg := runtime.GetConfig() + if err := m.ValidateConfig(cfg); err != nil { + return nil, fmt.Errorf("config validation failed: %w", err) } - // persistence specific configuration file - config = new(types.UtilityConfig) - err = json.Unmarshal(rawJSON[u.GetModuleName()], config) - return -} + utilityCfg := cfg.GetUtilityConfig() -func (u *UtilityModule) InitGenesis(pathToGenesisJSON string) (genesis modules.IGenesis, err error) { - return // No-op + return &utilityModule{ + config: utilityCfg, + Mempool: types.NewMempool(utilityCfg.GetMaxMempoolTransactionBytes(), utilityCfg.GetMaxMempoolTransactions()), + }, nil } -func (u *UtilityModule) Start() error { +func (u *utilityModule) Start() error { return nil } -func (u *UtilityModule) Stop() error { +func (u *utilityModule) Stop() error { return nil } -func (u *UtilityModule) GetModuleName() string { +func (u *utilityModule) GetModuleName() string { return UtilityModuleName } -func (u *UtilityModule) SetBus(bus modules.Bus) { +func (u *utilityModule) SetBus(bus modules.Bus) { u.bus = bus } -func (u *UtilityModule) GetBus() modules.Bus { +func (u *utilityModule) GetBus() modules.Bus { if u.bus == nil { log.Fatalf("Bus is not initialized") } return u.bus } + +func (*utilityModule) ValidateConfig(cfg modules.Config) error { + return nil +} diff --git a/utility/test/account_test.go b/utility/test/account_test.go index 55c56b755..8a825dab7 100644 --- a/utility/test/account_test.go +++ b/utility/test/account_test.go @@ -6,12 +6,11 @@ import ( "sort" "testing" - "github.com/pokt-network/pocket/shared/modules" - "github.com/pokt-network/pocket/shared/test_artifacts" - "github.com/pokt-network/pocket/utility/types" - + "github.com/pokt-network/pocket/runtime/test_artifacts" "github.com/pokt-network/pocket/shared/crypto" + "github.com/pokt-network/pocket/shared/modules" "github.com/pokt-network/pocket/utility" + "github.com/pokt-network/pocket/utility/types" "github.com/stretchr/testify/require" ) diff --git a/utility/test/actor_test.go b/utility/test/actor_test.go index 52fd6e55b..fdb922f37 100644 --- a/utility/test/actor_test.go +++ b/utility/test/actor_test.go @@ -8,9 +8,9 @@ import ( "sort" "testing" + "github.com/pokt-network/pocket/runtime/test_artifacts" "github.com/pokt-network/pocket/shared/crypto" "github.com/pokt-network/pocket/shared/modules" - "github.com/pokt-network/pocket/shared/test_artifacts" "github.com/pokt-network/pocket/utility" typesUtil "github.com/pokt-network/pocket/utility/types" "github.com/stretchr/testify/require" diff --git a/utility/test/block_test.go b/utility/test/block_test.go index 3f5a8bb18..a181d0311 100644 --- a/utility/test/block_test.go +++ b/utility/test/block_test.go @@ -6,10 +6,9 @@ import ( "math/big" "testing" - "github.com/pokt-network/pocket/shared/test_artifacts" - "github.com/stretchr/testify/require" - + "github.com/pokt-network/pocket/runtime/test_artifacts" typesUtil "github.com/pokt-network/pocket/utility/types" + "github.com/stretchr/testify/require" ) func TestUtilityContext_ApplyBlock(t *testing.T) { diff --git a/utility/test/gov_test.go b/utility/test/gov_test.go index 41eee1e2d..42dacb8ed 100644 --- a/utility/test/gov_test.go +++ b/utility/test/gov_test.go @@ -2,11 +2,11 @@ package test import ( "encoding/hex" - "github.com/pokt-network/pocket/shared/codec" - "github.com/pokt-network/pocket/shared/modules" - "github.com/pokt-network/pocket/shared/test_artifacts" "testing" + "github.com/pokt-network/pocket/runtime/test_artifacts" + "github.com/pokt-network/pocket/shared/codec" + "github.com/pokt-network/pocket/shared/modules" typesUtil "github.com/pokt-network/pocket/utility/types" "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/wrapperspb" diff --git a/utility/test/module_test.go b/utility/test/module_test.go index 2a3fd1645..0d76e2857 100644 --- a/utility/test/module_test.go +++ b/utility/test/module_test.go @@ -1,19 +1,17 @@ package test import ( - "encoding/json" - "io/ioutil" - "log" "math/big" "os" "testing" - "github.com/pokt-network/pocket/shared/test_artifacts" - utilTypes "github.com/pokt-network/pocket/utility/types" - + "github.com/golang/mock/gomock" "github.com/pokt-network/pocket/persistence" + "github.com/pokt-network/pocket/runtime/test_artifacts" "github.com/pokt-network/pocket/shared/modules" + mock_modules "github.com/pokt-network/pocket/shared/modules/mocks" "github.com/pokt-network/pocket/utility" + utilTypes "github.com/pokt-network/pocket/utility/types" "github.com/stretchr/testify/require" ) @@ -33,6 +31,7 @@ var ( testSchema = "test_schema" ) +var persistenceDbUrl string var actorTypes = []utilTypes.ActorType{ utilTypes.ActorType_App, utilTypes.ActorType_ServiceNode, @@ -40,23 +39,21 @@ var actorTypes = []utilTypes.ActorType{ utilTypes.ActorType_Validator, } -var testPersistenceMod modules.PersistenceModule - func NewTestingMempool(_ *testing.T) utilTypes.Mempool { return utilTypes.NewMempool(1000000, 1000) } func TestMain(m *testing.M) { pool, resource, dbUrl := test_artifacts.SetupPostgresDocker() - testPersistenceMod = newTestPersistenceModule(m, dbUrl) + persistenceDbUrl = dbUrl exitCode := m.Run() - os.Remove(testingConfigFilePath) - os.Remove(testingGenesisFilePath) test_artifacts.CleanupPostgresDocker(m, pool, resource) os.Exit(exitCode) } func NewTestingUtilityContext(t *testing.T, height int64) utility.UtilityContext { + testPersistenceMod := newTestPersistenceModule(t, persistenceDbUrl) + persistenceContext, err := testPersistenceMod.NewRWContext(height) require.NoError(t, err) @@ -75,58 +72,28 @@ func NewTestingUtilityContext(t *testing.T, height int64) utility.UtilityContext } } -func newTestPersistenceModule(_ *testing.M, databaseUrl string) modules.PersistenceModule { - cfg := modules.Config{ - Persistence: &test_artifacts.MockPersistenceConfig{ - PostgresUrl: databaseUrl, - NodeSchema: testSchema, - BlockStorePath: "", - }, - } +func newTestPersistenceModule(t *testing.T, databaseUrl string) modules.PersistenceModule { + ctrl := gomock.NewController(t) - genesisState, _ := test_artifacts.NewGenesisState(testingValidatorCount, testingServiceNodeCount, testingApplicationCount, testingFishermenCount) - createTestingGenesisAndConfigFiles(cfg, genesisState) - persistenceMod, err := persistence.Create(testingConfigFilePath, testingGenesisFilePath) // TODO (Olshansk) this is the last remaining cross module import and needs a fix... - if err != nil { - log.Fatal(err) - } - if err = persistenceMod.Start(); err != nil { - log.Fatal(err) - } - return persistenceMod -} + mockPersistenceConfig := mock_modules.NewMockPersistenceConfig(ctrl) + mockPersistenceConfig.EXPECT().GetPostgresUrl().Return(databaseUrl).AnyTimes() + mockPersistenceConfig.EXPECT().GetNodeSchema().Return(testSchema).AnyTimes() + mockPersistenceConfig.EXPECT().GetBlockStorePath().Return("").AnyTimes() -const ( - testingGenesisFilePath = "genesis.json" - testingConfigFilePath = "config.json" -) + mockRuntimeConfig := mock_modules.NewMockConfig(ctrl) + mockRuntimeConfig.EXPECT().GetPersistenceConfig().Return(mockPersistenceConfig).AnyTimes() -func createTestingGenesisAndConfigFiles(cfg modules.Config, genesisState modules.GenesisState) { - config, err := json.Marshal(cfg.Persistence) - if err != nil { - log.Fatal(err) - } - genesis, err := json.Marshal(genesisState.PersistenceGenesisState) - if err != nil { - log.Fatal(err) - } - genesisFile := make(map[string]json.RawMessage) - configFile := make(map[string]json.RawMessage) - persistenceModuleName := new(persistence.PersistenceModule).GetModuleName() - genesisFile[test_artifacts.GetGenesisFileName(persistenceModuleName)] = genesis - configFile[persistenceModuleName] = config - genesisFileBz, err := json.MarshalIndent(genesisFile, "", " ") - if err != nil { - log.Fatal(err) - } - configFileBz, err := json.MarshalIndent(configFile, "", " ") - if err != nil { - log.Fatal(err) - } - if err := ioutil.WriteFile(testingGenesisFilePath, genesisFileBz, 0777); err != nil { - log.Fatal(err) - } - if err := ioutil.WriteFile(testingConfigFilePath, configFileBz, 0777); err != nil { - log.Fatal(err) - } + mockRuntimeMgr := mock_modules.NewMockRuntimeMgr(ctrl) + mockRuntimeMgr.EXPECT().GetConfig().Return(mockRuntimeConfig).AnyTimes() + + genesisState, _ := test_artifacts.NewGenesisState(5, 1, 1, 1) + mockRuntimeMgr.EXPECT().GetGenesis().Return(genesisState).AnyTimes() + + persistenceMod, err := persistence.Create(mockRuntimeMgr) + require.NoError(t, err) + + err = persistenceMod.Start() + require.NoError(t, err) + + return persistenceMod.(modules.PersistenceModule) } diff --git a/utility/test/transaction_test.go b/utility/test/transaction_test.go index 42da82f16..be38645c8 100644 --- a/utility/test/transaction_test.go +++ b/utility/test/transaction_test.go @@ -5,9 +5,8 @@ import ( "math/big" "testing" + "github.com/pokt-network/pocket/runtime/test_artifacts" "github.com/pokt-network/pocket/shared/codec" - "github.com/pokt-network/pocket/shared/test_artifacts" - "github.com/pokt-network/pocket/shared/crypto" "github.com/pokt-network/pocket/utility" typesUtil "github.com/pokt-network/pocket/utility/types"