diff --git a/Makefile b/Makefile index 16504dde3..75a0bfbc5 100644 --- a/Makefile +++ b/Makefile @@ -89,7 +89,7 @@ go_clean_deps: ## Runs `go mod tidy` && `go mod vendor` .PHONY: go_lint go_lint: ## Run all linters that are triggered by the CI pipeline - docker run -t --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.51.1 golangci-lint run -v + docker run -t --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.51.1 golangci-lint run -v --timeout 2m .PHONY: gofmt gofmt: ## Format all the .go files in the project in place. @@ -463,11 +463,11 @@ localnet_up: ## Starts up a k8s LocalNet with all necessary dependencies (tl;dr .PHONY: localnet_client_debug localnet_client_debug: ## Opens a `client debug` cli to interact with blockchain (e.g. change pacemaker mode, reset to genesis, etc). Though the node binary updates automatiacally on every code change (i.e. hot reloads), if client is already open you need to re-run this command to execute freshly compiled binary. - kubectl exec -it deploy/pocket-v1-cli-client -- client debug + kubectl exec -it deploy/pocket-v1-cli-client --container pocket -- client debug .PHONY: localnet_shell localnet_shell: ## Opens a shell in the pod that has the `client` cli available. The binary updates automatically whenever the code changes (i.e. hot reloads). - kubectl exec -it deploy/pocket-v1-cli-client -- /bin/bash + kubectl exec -it deploy/pocket-v1-cli-client --container pocket -- /bin/bash .PHONY: localnet_logs_validators localnet_logs_validators: ## Outputs logs from all validators @@ -482,6 +482,11 @@ localnet_down: ## Stops LocalNet and cleans up dependencies (tl;dr `tilt down` + tilt down --file=build/localnet/Tiltfile kubectl delete pvc --ignore-not-found=true data-dependencies-postgresql-0 +.PHONY: localnet_db_cli +localnet_db_cli: ## Open a CLI to the local containerized postgres instancedb_cli: + echo "View schema by running 'SELECT schema_name FROM information_schema.schemata;'" + kubectl exec -it services/dependencies-postgresql -- bash -c "psql postgresql://postgres:LocalNetPassword@localhost" + .PHONY: check_cross_module_imports check_cross_module_imports: ## Lists cross-module imports $(eval exclude_common=--exclude=Makefile --exclude-dir=shared --exclude-dir=app --exclude-dir=runtime) diff --git a/app/client/cli/debug.go b/app/client/cli/debug.go index 3f9c9d9f6..bd9f982d5 100644 --- a/app/client/cli/debug.go +++ b/app/client/cli/debug.go @@ -1,16 +1,19 @@ package cli import ( + "fmt" "os" "github.com/manifoldco/promptui" "github.com/pokt-network/pocket/logger" "github.com/pokt-network/pocket/p2p" - debugABP "github.com/pokt-network/pocket/p2p/providers/addrbook_provider/debug" - debugCHP "github.com/pokt-network/pocket/p2p/providers/current_height_provider/debug" + "github.com/pokt-network/pocket/p2p/providers/addrbook_provider" + rpcABP "github.com/pokt-network/pocket/p2p/providers/addrbook_provider/rpc" + "github.com/pokt-network/pocket/p2p/providers/current_height_provider" + rpcCHP "github.com/pokt-network/pocket/p2p/providers/current_height_provider/rpc" + "github.com/pokt-network/pocket/p2p/types" "github.com/pokt-network/pocket/runtime" - coreTypes "github.com/pokt-network/pocket/shared/core/types" - pocketCrypto "github.com/pokt-network/pocket/shared/crypto" + "github.com/pokt-network/pocket/runtime/defaults" "github.com/pokt-network/pocket/shared/messaging" "github.com/pokt-network/pocket/shared/modules" "github.com/spf13/cobra" @@ -44,18 +47,27 @@ var ( PromptSendBlockRequest, } - // validators holds the list of the validators at genesis time so that we can use it to create a debug address book provider. - // Its purpose is to allow the CLI to "discover" the nodes in the network. Since currently we don't have churn and we run nodes only in LocalNet, we can rely on the genesis state. - // HACK(#416): This is a temporary solution that guarantees backward compatibility while we implement peer discovery - validators []*coreTypes.Actor - configPath string = runtime.GetEnv("CONFIG_PATH", "build/config/config1.json") genesisPath string = runtime.GetEnv("GENESIS_PATH", "build/config/genesis.json") + rpcHost string ) +// NOTE: this is required by the linter, otherwise a simple string constant would have been enough +type cliContextKey string + +const busCLICtxKey = "bus" + func init() { debugCmd := NewDebugCommand() rootCmd.AddCommand(debugCmd) + + // by default, we point at the same endpoint used by the CLI but the debug client is used either in docker-compose of K8S, therefore we cater for overriding + validator1Endpoint := defaults.Validator1EndpointDockerCompose + if runtime.IsProcessRunningInsideKubernetes() { + validator1Endpoint = defaults.Validator1EndpointK8S + } + + rpcHost = runtime.GetEnv("RPC_HOST", validator1Endpoint) } func NewDebugCommand() *cobra.Command { @@ -64,24 +76,32 @@ func NewDebugCommand() *cobra.Command { Short: "Debug utility for rapid development", Args: cobra.ExactArgs(0), PersistentPreRun: func(cmd *cobra.Command, args []string) { - runtimeMgr := runtime.NewManagerFromFiles(configPath, genesisPath, runtime.WithClientDebugMode(), runtime.WithRandomPK()) + runtimeMgr := runtime.NewManagerFromFiles( + configPath, genesisPath, + runtime.WithClientDebugMode(), + runtime.WithRandomPK(), + ) + + bus := runtimeMgr.GetBus() + modulesRegistry := bus.GetModulesRegistry() - // HACK(#416): this is a temporary solution that guarantees backward compatibility while we implement peer discovery. - validators = runtimeMgr.GetGenesis().Validators + rpcUrl := fmt.Sprintf("http://%s:%s", rpcHost, defaults.DefaultRPCPort) - debugAddressBookProvider := debugABP.NewDebugAddrBookProvider( - runtimeMgr.GetConfig().P2P, - debugABP.WithActorsByHeight( - map[int64][]*coreTypes.Actor{ - debugABP.ANY_HEIGHT: validators, - }, + addressBookProvider := rpcABP.NewRPCAddrBookProvider( + rpcABP.WithP2PConfig( + runtimeMgr.GetConfig().P2P, ), + rpcABP.WithCustomRPCUrl(rpcUrl), ) + modulesRegistry.RegisterModule(addressBookProvider) - debugCurrentHeightProvider := debugCHP.NewDebugCurrentHeightProvider(0) + currentHeightProvider := rpcCHP.NewRPCCurrentHeightProvider( + rpcCHP.WithCustomRPCUrl(rpcUrl), + ) + modulesRegistry.RegisterModule(currentHeightProvider) - // TODO(#429): refactor injecting the dependencies into the bus so that they can be consumed in an updated `P2PModule.Create()` implementation - p2pM, err := p2p.CreateWithProviders(runtimeMgr.GetBus(), debugAddressBookProvider, debugCurrentHeightProvider) + setValueInCLIContext(cmd, busCLICtxKey, bus) + p2pM, err := p2p.Create(bus) if err != nil { logger.Global.Fatal().Err(err).Msg("Failed to create p2p module") } @@ -98,7 +118,7 @@ func NewDebugCommand() *cobra.Command { func runDebug(cmd *cobra.Command, args []string) (err error) { for { if selection, err := promptGetInput(); err == nil { - handleSelect(selection) + handleSelect(cmd, selection) } else { return err } @@ -126,57 +146,57 @@ func promptGetInput() (string, error) { return result, nil } -func handleSelect(selection string) { +func handleSelect(cmd *cobra.Command, selection string) { switch selection { case PromptResetToGenesis: m := &messaging.DebugMessage{ Action: messaging.DebugMessageAction_DEBUG_CONSENSUS_RESET_TO_GENESIS, Message: nil, } - broadcastDebugMessage(m) + broadcastDebugMessage(cmd, m) case PromptPrintNodeState: m := &messaging.DebugMessage{ Action: messaging.DebugMessageAction_DEBUG_CONSENSUS_PRINT_NODE_STATE, Message: nil, } - broadcastDebugMessage(m) + broadcastDebugMessage(cmd, m) case PromptTriggerNextView: m := &messaging.DebugMessage{ Action: messaging.DebugMessageAction_DEBUG_CONSENSUS_TRIGGER_NEXT_VIEW, Message: nil, } - broadcastDebugMessage(m) + broadcastDebugMessage(cmd, m) case PromptTogglePacemakerMode: m := &messaging.DebugMessage{ Action: messaging.DebugMessageAction_DEBUG_CONSENSUS_TOGGLE_PACE_MAKER_MODE, Message: nil, } - broadcastDebugMessage(m) + broadcastDebugMessage(cmd, m) case PromptShowLatestBlockInStore: m := &messaging.DebugMessage{ Action: messaging.DebugMessageAction_DEBUG_SHOW_LATEST_BLOCK_IN_STORE, Message: nil, } - sendDebugMessage(m) + sendDebugMessage(cmd, m) case PromptSendMetadataRequest: m := &messaging.DebugMessage{ Action: messaging.DebugMessageAction_DEBUG_CONSENSUS_SEND_METADATA_REQ, Message: nil, } - broadcastDebugMessage(m) + broadcastDebugMessage(cmd, m) case PromptSendBlockRequest: m := &messaging.DebugMessage{ Action: messaging.DebugMessageAction_DEBUG_CONSENSUS_SEND_BLOCK_REQ, Message: nil, } - broadcastDebugMessage(m) + broadcastDebugMessage(cmd, m) default: logger.Global.Error().Msg("Selection not yet implemented...") } } // Broadcast to the entire validator set -func broadcastDebugMessage(debugMsg *messaging.DebugMessage) { +func broadcastDebugMessage(cmd *cobra.Command, debugMsg *messaging.DebugMessage) { anyProto, err := anypb.New(debugMsg) if err != nil { logger.Global.Fatal().Err(err).Msg("Failed to create Any proto") @@ -185,10 +205,11 @@ func broadcastDebugMessage(debugMsg *messaging.DebugMessage) { // TODO(olshansky): Once we implement the cleanup layer in RainTree, we'll be able to use // broadcast. The reason it cannot be done right now is because this client is not in the // address book of the actual validator nodes, so `node1.consensus` never receives the message. - // p2pMod.Broadcast(anyProto, messaging.PocketTopic_DEBUG_TOPIC) + // p2pMod.Broadcast(anyProto) - for _, valAddr := range validators { - addr, err := pocketCrypto.NewAddress(valAddr.GetAddress()) + addrBook, err := fetchAddressBook(cmd) + for _, val := range addrBook { + addr := val.Address if err != nil { logger.Global.Fatal().Err(err).Msg("Failed to convert validator address into pocketCrypto.Address") } @@ -196,22 +217,28 @@ func broadcastDebugMessage(debugMsg *messaging.DebugMessage) { logger.Global.Fatal().Err(err).Msg("Failed to send debug message") } } + } // Send to just a single (i.e. first) validator in the set -func sendDebugMessage(debugMsg *messaging.DebugMessage) { +func sendDebugMessage(cmd *cobra.Command, debugMsg *messaging.DebugMessage) { anyProto, err := anypb.New(debugMsg) if err != nil { logger.Global.Error().Err(err).Msg("Failed to create Any proto") } + addrBook, err := fetchAddressBook(cmd) + if err != nil { + logger.Global.Fatal().Msg("Unable to retrieve the addrBook") + } + var validatorAddress []byte - if len(validators) == 0 { + if len(addrBook) == 0 { logger.Global.Fatal().Msg("No validators found") } // if the message needs to be broadcast, it'll be handled by the business logic of the message handler - validatorAddress, err = pocketCrypto.NewAddress(validators[0].GetAddress()) + validatorAddress = addrBook[0].Address if err != nil { logger.Global.Fatal().Err(err).Msg("Failed to convert validator address into pocketCrypto.Address") } @@ -220,3 +247,27 @@ func sendDebugMessage(debugMsg *messaging.DebugMessage) { logger.Global.Fatal().Err(err).Msg("Failed to send debug message") } } + +// fetchAddressBook retrieves the providers from the CLI context and uses them to retrieve the address book for the current height +func fetchAddressBook(cmd *cobra.Command) (types.AddrBook, error) { + bus, ok := getValueFromCLIContext[modules.Bus](cmd, busCLICtxKey) + if !ok || bus == nil { + logger.Global.Fatal().Msg("Unable to retrieve the bus from CLI context") + } + modulesRegistry := bus.GetModulesRegistry() + addrBookProvider, err := modulesRegistry.GetModule(addrbook_provider.ModuleName) + if err != nil { + logger.Global.Fatal().Msg("Unable to retrieve the addrBookProvider") + } + currentHeightProvider, err := modulesRegistry.GetModule(current_height_provider.ModuleName) + if err != nil { + logger.Global.Fatal().Msg("Unable to retrieve the currentHeightProvider") + } + + height := currentHeightProvider.(current_height_provider.CurrentHeightProvider).CurrentHeight() + addrBook, err := addrBookProvider.(addrbook_provider.AddrBookProvider).GetStakedAddrBookAtHeight(height) + if err != nil { + logger.Global.Fatal().Msg("Unable to retrieve the addrBook") + } + return addrBook, err +} diff --git a/app/client/cli/utils.go b/app/client/cli/utils.go index a891d616f..d90798250 100644 --- a/app/client/cli/utils.go +++ b/app/client/cli/utils.go @@ -187,3 +187,12 @@ func rpcResponseCodeUnhealthy(statusCode int, response []byte) error { func boldText[T string | []byte](s T) string { return fmt.Sprintf("\033[1m%s\033[0m", s) } + +func setValueInCLIContext(cmd *cobra.Command, key cliContextKey, value any) { + cmd.SetContext(context.WithValue(cmd.Context(), key, value)) +} + +func getValueFromCLIContext[T any](cmd *cobra.Command, key cliContextKey) (T, bool) { + value, ok := cmd.Context().Value(key).(T) + return value, ok +} diff --git a/app/client/doc/CHANGELOG.md b/app/client/doc/CHANGELOG.md index 698b73929..c3fbe22c3 100644 --- a/app/client/doc/CHANGELOG.md +++ b/app/client/doc/CHANGELOG.md @@ -7,7 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.0.0.14] - 2023-02-17 +## [0.0.0.15] - 2023-02-17 + +- Updated CLI to use to source the address book and the current height from the RPC server leveraging the `rpcAddressBookProvider` and `rpcCurrentHeightProvider` respectively and the `bus` for dependency injection + +## [0.0.0.14] - 2023-02-15 - Introduced logical switch to handle parsing of the debug private keys from a local file OR from Kubernetes secret (PR #517) - Bugfix for `Stake` command. Address erroneously sent instead of the PublicKey. (PR #518) diff --git a/go.mod b/go.mod index 35ec76c52..a9e5ff061 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( require ( github.com/benbjohnson/clock v1.3.0 github.com/celestiaorg/smt v0.2.1-0.20220414134126-dba215ccb884 + github.com/deepmap/oapi-codegen v1.12.4 github.com/dgraph-io/badger/v3 v3.2103.2 github.com/getkin/kin-openapi v0.107.0 github.com/jackc/pgconn v1.13.0 @@ -67,6 +68,7 @@ require ( ) require ( + github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/go-logr/logr v1.2.3 // indirect @@ -74,6 +76,7 @@ require ( github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.1.0 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/jackc/puddle/v2 v2.1.2 // indirect diff --git a/go.sum b/go.sum index c41006b56..e2137e4f7 100644 --- a/go.sum +++ b/go.sum @@ -51,11 +51,14 @@ github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/ProtonMail/go-ecvrf v0.0.1 h1:wv45+kZ0mG4G9oSTMjAlbgKqa4tPbNr4WLoCWqz5/bo= github.com/ProtonMail/go-ecvrf v0.0.1/go.mod h1:fhZbiRYn62/JGnBG2NGwCx0oT+gr/+I5R/hwiyAFpAU= +github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= +github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -63,6 +66,7 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/celestiaorg/smt v0.2.1-0.20220414134126-dba215ccb884 h1:iRNKw2WmAbVgGMNYzDH5Y2yY3+jyxwEK9Hc5pwIjZAE= github.com/celestiaorg/smt v0.2.1-0.20220414134126-dba215ccb884/go.mod h1:/sdYDakowo/XaxS2Fl7CBqtuf/O2uTqF2zmAUFAtAiw= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= @@ -106,6 +110,8 @@ github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxG github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deepmap/oapi-codegen v1.12.4 h1:pPmn6qI9MuOtCz82WY2Xaw46EQjgvxednXXrP7g5Q2s= +github.com/deepmap/oapi-codegen v1.12.4/go.mod h1:3lgHGMu6myQ2vqbbTXH2H1o4eXFTGnFiDaOaKKl5yas= github.com/dgraph-io/badger/v3 v3.2103.2 h1:dpyM5eCJAtQCBcMCZcT4UBZchuTJgCywerHHgmxfxM8= github.com/dgraph-io/badger/v3 v3.2103.2/go.mod h1:RHo4/GmYcKKh5Lxu63wLEMHJ70Pac2JqZRYGhlyAo2M= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= @@ -240,6 +246,8 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= @@ -311,6 +319,7 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -483,6 +492,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU= github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= +github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= 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= diff --git a/p2p/CHANGELOG.md b/p2p/CHANGELOG.md index 7ac5febf4..2f82db9e9 100644 --- a/p2p/CHANGELOG.md +++ b/p2p/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.27] - 2023-02-17 + +- Deprecated `debugAddressBookProvider` +- Added `rpcAddressBookProvider` to source the address book from the RPC server +- Leveraging `bus` for dependency injection of the `addressBookProvider` and `currentHeightProvider` +- Deprecated `debugCurrentHeightProvider` +- Added `rpcCurrentHeightProvider` to source the current height from the RPC server +- Fixed raintree to use the `currentHeightProvider` instead of consensus (that was what we wanted to avoid in the first place) +- Added `getAddrBookDelta` to calculate changes to the address book between heights and update the internal state and componentry accordingly + ## [0.0.0.26] - 2023-02-17 - Modules embed `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness diff --git a/p2p/addrbook_delta.go b/p2p/addrbook_delta.go new file mode 100644 index 000000000..5484ab277 --- /dev/null +++ b/p2p/addrbook_delta.go @@ -0,0 +1,25 @@ +package p2p + +import typesP2P "github.com/pokt-network/pocket/p2p/types" + +// getAddrBookDelta returns the difference between two AddrBook slices +func getAddrBookDelta(before, after typesP2P.AddrBook) (added, removed []*typesP2P.NetworkPeer) { + oldMap := make(map[string]*typesP2P.NetworkPeer) + for _, np := range before { + oldMap[np.Address.String()] = np + } + + for _, np := range after { + if _, ok := oldMap[np.Address.String()]; !ok { + added = append(added, np) + continue + } + delete(oldMap, np.Address.String()) + } + + for _, u := range oldMap { + removed = append(removed, u) + } + + return +} diff --git a/p2p/addrbook_delta_test.go b/p2p/addrbook_delta_test.go new file mode 100644 index 000000000..4539f1726 --- /dev/null +++ b/p2p/addrbook_delta_test.go @@ -0,0 +1,66 @@ +package p2p + +import ( + "testing" + + typesP2P "github.com/pokt-network/pocket/p2p/types" + "github.com/pokt-network/pocket/shared/crypto" + "github.com/stretchr/testify/require" +) + +func Test_getAddrBookDelta(t *testing.T) { + type args struct { + before typesP2P.AddrBook + after typesP2P.AddrBook + } + tests := []struct { + name string + args args + wantAdded []*typesP2P.NetworkPeer + wantRemoved []*typesP2P.NetworkPeer + }{ + { + name: "empty slices should return empty slices", + args: args{ + before: []*typesP2P.NetworkPeer{}, + after: []*typesP2P.NetworkPeer{}, + }, + wantAdded: []*typesP2P.NetworkPeer{}, + wantRemoved: []*typesP2P.NetworkPeer{}, + }, + { + name: "when a peer is added, it should be in the added slice", + args: args{ + before: []*typesP2P.NetworkPeer{}, + after: []*typesP2P.NetworkPeer{{Address: crypto.AddressFromString("000000000000000000000000000000000001")}}, + }, + wantAdded: []*typesP2P.NetworkPeer{{Address: crypto.AddressFromString("000000000000000000000000000000000001")}}, + wantRemoved: []*typesP2P.NetworkPeer{}, + }, + { + name: "when a peer is removed, it should be in the removed slice", + args: args{ + before: []*typesP2P.NetworkPeer{{Address: crypto.AddressFromString("000000000000000000000000000000000001")}}, + after: []*typesP2P.NetworkPeer{}, + }, + wantAdded: []*typesP2P.NetworkPeer{}, + wantRemoved: []*typesP2P.NetworkPeer{{Address: crypto.AddressFromString("000000000000000000000000000000000001")}}, + }, + { + name: "when no peers are added or removed, both slices should be empty", + args: args{ + before: []*typesP2P.NetworkPeer{{Address: crypto.AddressFromString("000000000000000000000000000000000001")}, {Address: crypto.AddressFromString("000000000000000000000000000000000002")}}, + after: []*typesP2P.NetworkPeer{{Address: crypto.AddressFromString("000000000000000000000000000000000001")}, {Address: crypto.AddressFromString("000000000000000000000000000000000002")}}, + }, + wantAdded: []*typesP2P.NetworkPeer{}, + wantRemoved: []*typesP2P.NetworkPeer{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotAdded, gotRemoved := getAddrBookDelta(tt.args.before, tt.args.after) + require.ElementsMatch(t, gotAdded, tt.wantAdded) + require.ElementsMatch(t, gotRemoved, tt.wantRemoved) + }) + } +} diff --git a/p2p/event_handler.go b/p2p/event_handler.go index 4d920231f..7041235f4 100644 --- a/p2p/event_handler.go +++ b/p2p/event_handler.go @@ -1,10 +1,48 @@ package p2p import ( + "fmt" + + "github.com/pokt-network/pocket/shared/codec" + "github.com/pokt-network/pocket/shared/messaging" "google.golang.org/protobuf/types/known/anypb" ) func (m *p2pModule) HandleEvent(event *anypb.Any) error { - // no-op (for now... PRs are already cooked) + evt, err := codec.GetCodec().FromAny(event) + if err != nil { + return err + } + + switch event.MessageName() { + case messaging.ConsensusNewHeightEventType: + consensusNewHeightEvent, ok := evt.(*messaging.ConsensusNewHeightEvent) + if !ok { + return fmt.Errorf("failed to cast event to ConsensusNewHeightEvent") + } + + addrBook := m.network.GetAddrBook() + newAddrBook, err := m.addrBookProvider.GetStakedAddrBookAtHeight(consensusNewHeightEvent.Height) + + if err != nil { + return err + } + + added, removed := getAddrBookDelta(addrBook, newAddrBook) + for _, add := range added { + if err := m.network.AddPeerToAddrBook(add); err != nil { + return err + } + } + for _, rm := range removed { + if err := m.network.RemovePeerFromAddrBook(rm); err != nil { + return err + } + } + + default: + return fmt.Errorf("unknown event type: %s", event.MessageName()) + } + return nil } diff --git a/p2p/module.go b/p2p/module.go index 8a9985d9e..5968cc9e1 100644 --- a/p2p/module.go +++ b/p2p/module.go @@ -5,7 +5,9 @@ import ( "github.com/pokt-network/pocket/logger" "github.com/pokt-network/pocket/p2p/providers" + "github.com/pokt-network/pocket/p2p/providers/addrbook_provider" persABP "github.com/pokt-network/pocket/p2p/providers/addrbook_provider/persistence" + "github.com/pokt-network/pocket/p2p/providers/current_height_provider" "github.com/pokt-network/pocket/p2p/raintree" "github.com/pokt-network/pocket/p2p/stdnetwork" "github.com/pokt-network/pocket/p2p/transport" @@ -31,43 +33,14 @@ type p2pModule struct { network typesP2P.Network - injectedAddrBookProvider providers.AddrBookProvider - injectedCurrentHeightProvider providers.CurrentHeightProvider + addrBookProvider providers.AddrBookProvider + currentHeightProvider providers.CurrentHeightProvider } func Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { return new(p2pModule).Create(bus, options...) } -// TODO(#429): need to define a better pattern for dependency injection. Currently we are probably limiting ourselves by having a common constructor `Create(bus modules.Bus) (modules.Module, error)` for all modules. -func CreateWithProviders(bus modules.Bus, addrBookProvider providers.AddrBookProvider, currentHeightProvider providers.CurrentHeightProvider) (modules.Module, error) { - log.Println("Creating network module") - m := &p2pModule{} - bus.RegisterModule(m) - - runtimeMgr := bus.GetRuntimeMgr() - cfg := runtimeMgr.GetConfig() - p2pCfg := cfg.P2P - - privateKey, err := cryptoPocket.NewPrivateKey(p2pCfg.GetPrivateKey()) - if err != nil { - return nil, err - } - m.address = privateKey.Address() - m.injectedAddrBookProvider = addrBookProvider - m.injectedCurrentHeightProvider = currentHeightProvider - - if !cfg.ClientDebugMode { - l, err := transport.CreateListener(p2pCfg) - if err != nil { - return nil, err - } - m.listener = l - } - - return m, nil -} - func (*p2pModule) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { log.Println("Creating network module") m := &p2pModule{} @@ -88,6 +61,8 @@ func (*p2pModule) Create(bus modules.Bus, options ...modules.ModuleOption) (modu } m.address = privateKey.Address() + m.setupDependencies() + if !cfg.ClientDebugMode { l, err := transport.CreateListener(p2pCfg) if err != nil { @@ -99,6 +74,20 @@ func (*p2pModule) Create(bus modules.Bus, options ...modules.ModuleOption) (modu return m, nil } +func (m *p2pModule) setupDependencies() { + addrBookProvider, err := m.GetBus().GetModulesRegistry().GetModule(addrbook_provider.ModuleName) + if err != nil { + addrBookProvider = persABP.NewPersistenceAddrBookProvider(m.GetBus()) + } + m.addrBookProvider = addrBookProvider.(providers.AddrBookProvider) + + currentHeightProvider, err := m.GetBus().GetModulesRegistry().GetModule(current_height_provider.ModuleName) + if err != nil { + currentHeightProvider = m.GetBus().GetConsensusModule() + } + m.currentHeightProvider = currentHeightProvider.(providers.CurrentHeightProvider) +} + func (m *p2pModule) GetModuleName() string { return modules.P2PModuleName } @@ -107,16 +96,13 @@ func (m *p2pModule) Start() error { m.logger = logger.Global.CreateLoggerForModule(m.GetModuleName()) m.logger.Info().Msg("Starting network module") - addrbookProvider := getAddrBookProvider(m) - currentHeightProvider := getCurrentHeightProvider(m) - cfg := m.GetBus().GetRuntimeMgr().GetConfig() // TODO: pass down logger if cfg.P2P.UseRainTree { - m.network = raintree.NewRainTreeNetwork(m.address, m.GetBus(), addrbookProvider, currentHeightProvider) + m.network = raintree.NewRainTreeNetwork(m.address, m.GetBus(), m.addrBookProvider, m.currentHeightProvider) } else { - m.network = stdnetwork.NewNetwork(m.GetBus(), addrbookProvider, currentHeightProvider) + m.network = stdnetwork.NewNetwork(m.GetBus(), m.addrBookProvider, m.currentHeightProvider) } if cfg.ClientDebugMode { @@ -150,28 +136,6 @@ func (m *p2pModule) Start() error { return nil } -// CLEANUP(#429): marked for removal since we'll implement a better pattern for dependency injection -func getAddrBookProvider(m *p2pModule) providers.AddrBookProvider { - var addrbookProvider providers.AddrBookProvider - if m.injectedAddrBookProvider == nil { - addrbookProvider = persABP.NewPersistenceAddrBookProvider(m.GetBus()) - } else { - addrbookProvider = m.injectedAddrBookProvider - } - return addrbookProvider -} - -// CLEANUP(#429): marked for removal since we'll implement a better pattern for dependency injection -func getCurrentHeightProvider(m *p2pModule) providers.CurrentHeightProvider { - var currentHeightProvider providers.CurrentHeightProvider - if m.injectedCurrentHeightProvider == nil { - currentHeightProvider = m.GetBus().GetConsensusModule() - } else { - currentHeightProvider = m.injectedCurrentHeightProvider - } - return currentHeightProvider -} - func (m *p2pModule) Stop() error { m.logger.Info().Msg("Stopping network module") if err := m.listener.Close(); err != nil { diff --git a/p2p/providers/addrbook_provider/addrbook_provider.go b/p2p/providers/addrbook_provider/addrbook_provider.go index 1820259cd..b42dcb4a2 100644 --- a/p2p/providers/addrbook_provider/addrbook_provider.go +++ b/p2p/providers/addrbook_provider/addrbook_provider.go @@ -10,10 +10,16 @@ import ( "github.com/pokt-network/pocket/runtime/configs" coreTypes "github.com/pokt-network/pocket/shared/core/types" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" + "github.com/pokt-network/pocket/shared/modules" ) +const ModuleName = "addrbook_provider" + // AddrBookProvider is an interface that provides AddrBook accessors type AddrBookProvider interface { + modules.IntegratableModule + modules.InterruptableModule + GetStakedAddrBookAtHeight(height uint64) (typesP2P.AddrBook, error) GetConnFactory() typesP2P.ConnectionFactory GetP2PConfig() *configs.P2PConfig diff --git a/p2p/providers/addrbook_provider/debug/provider.go b/p2p/providers/addrbook_provider/debug/provider.go deleted file mode 100644 index a5afa14f0..000000000 --- a/p2p/providers/addrbook_provider/debug/provider.go +++ /dev/null @@ -1,74 +0,0 @@ -package debug - -import ( - "log" - - "github.com/pokt-network/pocket/p2p/providers/addrbook_provider" - "github.com/pokt-network/pocket/p2p/transport" - typesP2P "github.com/pokt-network/pocket/p2p/types" - "github.com/pokt-network/pocket/runtime/configs" - coreTypes "github.com/pokt-network/pocket/shared/core/types" -) - -const ( - // ANY_HEIGHT is a special height that will be used to indicate that the actors are valid for all heights (including future heights) - ANY_HEIGHT = -1 -) - -var _ addrbook_provider.AddrBookProvider = &debugAddrBookProvider{} - -type debugAddrBookProvider struct { - p2pCfg *configs.P2PConfig - actorsByHeight map[int64][]*coreTypes.Actor - connFactory typesP2P.ConnectionFactory -} - -func NewDebugAddrBookProvider(p2pCfg *configs.P2PConfig, options ...func(*debugAddrBookProvider)) *debugAddrBookProvider { - dabp := &debugAddrBookProvider{ - p2pCfg: p2pCfg, - connFactory: transport.CreateDialer, // default connection factory, overridable with WithConnectionFactory() - } - - for _, o := range options { - o(dabp) - } - - return dabp -} - -func WithActorsByHeight(actorsByHeight map[int64][]*coreTypes.Actor) func(*debugAddrBookProvider) { - return func(pabp *debugAddrBookProvider) { - pabp.actorsByHeight = actorsByHeight - } -} - -func (dabp *debugAddrBookProvider) getActorsByHeight(height uint64) []*coreTypes.Actor { - if stakedActors, ok := dabp.actorsByHeight[ANY_HEIGHT]; ok { - log.Println("[DEBUG] Ignoring height param in debugAddrBookProvider") - return stakedActors - } - - if stakedActors, ok := dabp.actorsByHeight[int64(height)]; ok { - return stakedActors - } - - log.Fatalf("No actors found for height %d. Please make sure you configured the provider via WithActorsByHeight", height) - return nil -} - -func (dabp *debugAddrBookProvider) GetStakedAddrBookAtHeight(height uint64) (typesP2P.AddrBook, error) { - stakedActors := dabp.getActorsByHeight(height) - return addrbook_provider.ActorsToAddrBook(dabp, stakedActors) -} - -func (dabp *debugAddrBookProvider) GetConnFactory() typesP2P.ConnectionFactory { - return dabp.connFactory -} - -func (dabp *debugAddrBookProvider) GetP2PConfig() *configs.P2PConfig { - return dabp.p2pCfg -} - -func (dabp *debugAddrBookProvider) SetConnectionFactory(connFactory typesP2P.ConnectionFactory) { - dabp.connFactory = connFactory -} diff --git a/p2p/providers/addrbook_provider/persistence/provider.go b/p2p/providers/addrbook_provider/persistence/provider.go index 5ece1a2f5..234e8cf13 100644 --- a/p2p/providers/addrbook_provider/persistence/provider.go +++ b/p2p/providers/addrbook_provider/persistence/provider.go @@ -6,20 +6,22 @@ import ( typesP2P "github.com/pokt-network/pocket/p2p/types" "github.com/pokt-network/pocket/runtime/configs" "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" ) -var _ modules.IntegratableModule = &persistenceAddrBookProvider{} var _ addrbook_provider.AddrBookProvider = &persistenceAddrBookProvider{} type persistenceAddrBookProvider struct { - bus modules.Bus + base_modules.IntegratableModule + base_modules.InterruptableModule + connFactory typesP2P.ConnectionFactory } func NewPersistenceAddrBookProvider(bus modules.Bus, options ...func(*persistenceAddrBookProvider)) *persistenceAddrBookProvider { pabp := &persistenceAddrBookProvider{ - bus: bus, - connFactory: transport.CreateDialer, // default connection factory, overridable with WithConnectionFactory() + IntegratableModule: *base_modules.NewIntegratableModule(bus), + connFactory: transport.CreateDialer, // default connection factory, overridable with WithConnectionFactory() } for _, o := range options { @@ -29,12 +31,16 @@ func NewPersistenceAddrBookProvider(bus modules.Bus, options ...func(*persistenc return pabp } -func (pabp *persistenceAddrBookProvider) GetBus() modules.Bus { - return pabp.bus +func Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return new(persistenceAddrBookProvider).Create(bus, options...) +} + +func (*persistenceAddrBookProvider) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return NewPersistenceAddrBookProvider(bus), nil } -func (pabp *persistenceAddrBookProvider) SetBus(bus modules.Bus) { - pabp.bus = bus +func (*persistenceAddrBookProvider) GetModuleName() string { + return addrbook_provider.ModuleName } func (pabp *persistenceAddrBookProvider) GetStakedAddrBookAtHeight(height uint64) (typesP2P.AddrBook, error) { diff --git a/p2p/providers/addrbook_provider/rpc/provider.go b/p2p/providers/addrbook_provider/rpc/provider.go new file mode 100644 index 000000000..f715d93af --- /dev/null +++ b/p2p/providers/addrbook_provider/rpc/provider.go @@ -0,0 +1,138 @@ +package rpc + +import ( + "context" + "fmt" + "log" + "net/http" + "time" + + "github.com/pokt-network/pocket/p2p/providers/addrbook_provider" + "github.com/pokt-network/pocket/p2p/transport" + typesP2P "github.com/pokt-network/pocket/p2p/types" + "github.com/pokt-network/pocket/rpc" + "github.com/pokt-network/pocket/runtime" + "github.com/pokt-network/pocket/runtime/configs" + "github.com/pokt-network/pocket/runtime/defaults" + "github.com/pokt-network/pocket/shared/core/types" + "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" +) + +var ( + _ addrbook_provider.AddrBookProvider = &rpcAddrBookProvider{} + rpcHost string +) + +func init() { + // by default, we point at the same endpoint used by the CLI but the debug client is used either in docker-compose of K8S, therefore we cater for overriding + rpcHost = runtime.GetEnv("RPC_HOST", defaults.DefaultRPCHost) +} + +type rpcAddrBookProvider struct { + base_modules.IntegratableModule + base_modules.InterruptableModule + + rpcUrl string + p2pCfg *configs.P2PConfig + rpcClient *rpc.ClientWithResponses + + connFactory typesP2P.ConnectionFactory +} + +func NewRPCAddrBookProvider(options ...modules.ModuleOption) *rpcAddrBookProvider { + rabp := &rpcAddrBookProvider{ + rpcUrl: fmt.Sprintf("http://%s:%s", rpcHost, defaults.DefaultRPCPort), // TODO: Make port configurable + connFactory: transport.CreateDialer, // default connection factory, overridable with WithConnectionFactory() + } + + for _, o := range options { + o(rabp) + } + + rabp.initRPCClient() + + return rabp +} + +func Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return new(rpcAddrBookProvider).Create(bus, options...) +} + +func (*rpcAddrBookProvider) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return NewRPCAddrBookProvider(options...), nil +} + +func (*rpcAddrBookProvider) GetModuleName() string { + return addrbook_provider.ModuleName +} + +func (rabp *rpcAddrBookProvider) GetStakedAddrBookAtHeight(height uint64) (typesP2P.AddrBook, error) { + ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second) + defer cancel() + + var ( + h int64 = int64(height) + actorType rpc.ActorTypesEnum = "validator" + ) + response, err := rabp.rpcClient.GetV1P2pStakedActorsAddressBookWithResponse(ctx, &rpc.GetV1P2pStakedActorsAddressBookParams{Height: &h, ActorType: &actorType}) + if err != nil { + return nil, err + } + statusCode := response.StatusCode() + if statusCode != http.StatusOK { + return nil, fmt.Errorf("error retrieving addressbook via rpc. Unexpected status code: %d", statusCode) + } + + rpcActors := response.JSON200.Actors + var coreActors []*types.Actor + for _, rpcActor := range rpcActors { + coreActors = append(coreActors, &types.Actor{ + Address: rpcActor.Address, + PublicKey: rpcActor.PublicKey, + GenericParam: rpcActor.ServiceUrl, + ActorType: types.ActorType_ACTOR_TYPE_VAL, + }) + } + + return addrbook_provider.ActorsToAddrBook(rabp, coreActors) +} + +func (rabp *rpcAddrBookProvider) GetConnFactory() typesP2P.ConnectionFactory { + return rabp.connFactory +} + +func (rabp *rpcAddrBookProvider) GetP2PConfig() *configs.P2PConfig { + if rabp.p2pCfg == nil { + return rabp.GetBus().GetRuntimeMgr().GetConfig().P2P + } + return rabp.p2pCfg +} + +func (rabp *rpcAddrBookProvider) SetConnectionFactory(connFactory typesP2P.ConnectionFactory) { + rabp.connFactory = connFactory +} + +func (rabp *rpcAddrBookProvider) initRPCClient() { + rpcClient, err := rpc.NewClientWithResponses(rabp.rpcUrl) + if err != nil { + log.Fatalf("could not create RPC client: %v", err) + } + rabp.rpcClient = rpcClient +} + +// options + +// WithP2PConfig allows to specify a custom P2P config +func WithP2PConfig(p2pCfg *configs.P2PConfig) modules.ModuleOption { + return func(rabp modules.InitializableModule) { + rabp.(*rpcAddrBookProvider).p2pCfg = p2pCfg + } +} + +// WithCustomRPCUrl allows to specify a custom RPC URL +func WithCustomRPCUrl(rpcUrl string) modules.ModuleOption { + return func(rabp modules.InitializableModule) { + rabp.(*rpcAddrBookProvider).rpcUrl = rpcUrl + } +} diff --git a/p2p/providers/current_height_provider/current_height_provider.go b/p2p/providers/current_height_provider/current_height_provider.go index feb858bc2..9d797fffd 100644 --- a/p2p/providers/current_height_provider/current_height_provider.go +++ b/p2p/providers/current_height_provider/current_height_provider.go @@ -2,6 +2,13 @@ package current_height_provider //go:generate mockgen -source=$GOFILE -destination=../../types/mocks/current_height_provider_mock.go -package=mock_types github.com/pokt-network/pocket/p2p/types CurrentHeightProvider +import "github.com/pokt-network/pocket/shared/modules" + +const ModuleName = "current_height_provider" + type CurrentHeightProvider interface { + modules.IntegratableModule + modules.InterruptableModule + CurrentHeight() uint64 } diff --git a/p2p/providers/current_height_provider/debug/provider.go b/p2p/providers/current_height_provider/debug/provider.go deleted file mode 100644 index 7575cdd9e..000000000 --- a/p2p/providers/current_height_provider/debug/provider.go +++ /dev/null @@ -1,21 +0,0 @@ -package debug - -import "github.com/pokt-network/pocket/p2p/providers/current_height_provider" - -var _ current_height_provider.CurrentHeightProvider = &debugCurrentHeightProvider{} - -type debugCurrentHeightProvider struct { - currentHeight uint64 -} - -func (dchp *debugCurrentHeightProvider) CurrentHeight() uint64 { - return dchp.currentHeight -} - -func NewDebugCurrentHeightProvider(height uint64) *debugCurrentHeightProvider { - dchp := &debugCurrentHeightProvider{ - currentHeight: height, - } - - return dchp -} diff --git a/p2p/providers/current_height_provider/rpc/provider.go b/p2p/providers/current_height_provider/rpc/provider.go new file mode 100644 index 000000000..972b399fb --- /dev/null +++ b/p2p/providers/current_height_provider/rpc/provider.go @@ -0,0 +1,95 @@ +package rpc + +import ( + "context" + "fmt" + "log" + "net/http" + "time" + + "github.com/pokt-network/pocket/p2p/providers/current_height_provider" + "github.com/pokt-network/pocket/rpc" + "github.com/pokt-network/pocket/runtime" + "github.com/pokt-network/pocket/runtime/defaults" + "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" +) + +var ( + _ current_height_provider.CurrentHeightProvider = &rpcCurrentHeightProvider{} + rpcHost string +) + +func init() { + rpcHost = runtime.GetEnv("RPC_HOST", defaults.DefaultRPCHost) +} + +type rpcCurrentHeightProvider struct { + base_modules.IntegratableModule + base_modules.InterruptableModule + + rpcUrl string + rpcClient *rpc.ClientWithResponses +} + +func Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return new(rpcCurrentHeightProvider).Create(bus, options...) +} + +// Create implements current_height_provider.CurrentHeightProvider +func (*rpcCurrentHeightProvider) Create(bus modules.Bus, options ...modules.ModuleOption) (modules.Module, error) { + return NewRPCCurrentHeightProvider(options...), nil +} + +// GetModuleName implements current_height_provider.CurrentHeightProvider +func (*rpcCurrentHeightProvider) GetModuleName() string { + return current_height_provider.ModuleName +} + +func (rchp *rpcCurrentHeightProvider) CurrentHeight() uint64 { + ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second) + + response, err := rchp.rpcClient.GetV1ConsensusStateWithResponse(ctx) + if err != nil { + cancel() + log.Fatalf("could not get consensus state from RPC: %v", err) + } + statusCode := response.StatusCode() + if statusCode != http.StatusOK { + cancel() + log.Fatalf("error retrieving consensus state from RPC. Unexpected status code: %d", statusCode) + } + cancel() + return uint64(response.JSONDefault.Height) +} + +func NewRPCCurrentHeightProvider(options ...modules.ModuleOption) *rpcCurrentHeightProvider { + rchp := &rpcCurrentHeightProvider{ + rpcUrl: fmt.Sprintf("http://%s:%s", rpcHost, defaults.DefaultRPCPort), + } + + for _, o := range options { + o(rchp) + } + + rchp.initRPCClient() + + return rchp +} + +func (rchp *rpcCurrentHeightProvider) initRPCClient() { + rpcClient, err := rpc.NewClientWithResponses(rchp.rpcUrl) + if err != nil { + log.Fatalf("could not create RPC client: %v", err) + } + rchp.rpcClient = rpcClient +} + +// options + +// WithCustomRPCUrl allows to specify a custom RPC URL +func WithCustomRPCUrl(rpcUrl string) modules.ModuleOption { + return func(rabp modules.InitializableModule) { + rabp.(*rpcCurrentHeightProvider).rpcUrl = rpcUrl + } +} diff --git a/p2p/raintree/addrbook_utils.go b/p2p/raintree/addrbook_utils.go index 55109a8ac..bfe14c439 100644 --- a/p2p/raintree/addrbook_utils.go +++ b/p2p/raintree/addrbook_utils.go @@ -17,7 +17,7 @@ func (n *rainTreeNetwork) getAddrBookLength(level uint32, height uint64) int { peersManagerStateView := n.peersManager.getNetworkView() // if we are propagating a message from a previous height, we need to instantiate an ephemeral peersManager (without add/remove) - if height < n.GetBus().GetConsensusModule().CurrentHeight() { + if height < n.currentHeightProvider.CurrentHeight() { peersManagerWithAddrBookProvider, err := newPeersManagerWithAddrBookProvider(n.selfAddr, n.addrBookProvider, height) if err != nil { n.logger.Fatal().Err(err).Msg("Error initializing rainTreeNetwork peersManagerWithAddrBookProvider") @@ -31,7 +31,7 @@ func (n *rainTreeNetwork) getAddrBookLength(level uint32, height uint64) int { // getTargetsAtLevel returns the targets for a given level func (n *rainTreeNetwork) getTargetsAtLevel(level uint32) []target { - height := n.GetBus().GetConsensusModule().CurrentHeight() + height := n.currentHeightProvider.CurrentHeight() addrBookLengthAtHeight := n.getAddrBookLength(level, height) firstTarget := n.getTarget(firstMsgTargetPercentage, addrBookLengthAtHeight, level) secondTarget := n.getTarget(secondMsgTargetPercentage, addrBookLengthAtHeight, level) diff --git a/p2p/raintree/network.go b/p2p/raintree/network.go index 3b19cd883..9630059e4 100644 --- a/p2p/raintree/network.go +++ b/p2p/raintree/network.go @@ -14,17 +14,15 @@ import ( "github.com/pokt-network/pocket/shared/mempool" "github.com/pokt-network/pocket/shared/messaging" "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" telemetry "github.com/pokt-network/pocket/telemetry" "google.golang.org/protobuf/proto" ) -var ( - _ typesP2P.Network = &rainTreeNetwork{} - _ modules.IntegratableModule = &rainTreeNetwork{} -) +var _ typesP2P.Network = &rainTreeNetwork{} type rainTreeNetwork struct { - bus modules.Bus + base_modules.IntegratableModule selfAddr cryptoPocket.Address addrBookProvider addrbook_provider.AddrBookProvider @@ -32,6 +30,8 @@ type rainTreeNetwork struct { peersManager *peersManager nonceDeduper *mempool.GenericFIFOSet[uint64, uint64] + currentHeightProvider providers.CurrentHeightProvider + logger modules.Logger } @@ -52,11 +52,12 @@ func NewRainTreeNetwork(addr cryptoPocket.Address, bus modules.Bus, addrBookProv p2pCfg := bus.GetRuntimeMgr().GetConfig().P2P n := &rainTreeNetwork{ - selfAddr: addr, - peersManager: pm, - nonceDeduper: mempool.NewGenericFIFOSet[uint64, uint64](int(p2pCfg.MaxMempoolCount)), - addrBookProvider: addrBookProvider, - logger: networkLogger, + selfAddr: addr, + peersManager: pm, + nonceDeduper: mempool.NewGenericFIFOSet[uint64, uint64](int(p2pCfg.MaxMempoolCount)), + addrBookProvider: addrBookProvider, + currentHeightProvider: currentHeightProvider, + logger: networkLogger, } n.SetBus(bus) return typesP2P.Network(n) @@ -223,21 +224,13 @@ func (n *rainTreeNetwork) AddPeerToAddrBook(peer *typesP2P.NetworkPeer) error { return nil } -func (n *rainTreeNetwork) RemovePeerToAddrBook(peer *typesP2P.NetworkPeer) error { +func (n *rainTreeNetwork) RemovePeerFromAddrBook(peer *typesP2P.NetworkPeer) error { n.peersManager.wg.Add(1) n.peersManager.eventCh <- addressBookEvent{removeFromAddressBook, peer} n.peersManager.wg.Wait() return nil } -func (n *rainTreeNetwork) SetBus(bus modules.Bus) { - n.bus = bus -} - -func (n *rainTreeNetwork) GetBus() modules.Bus { - return n.bus -} - func shouldSendToTarget(target target) bool { return !target.isSelf } diff --git a/p2p/raintree/network_test.go b/p2p/raintree/network_test.go index ba082b645..311f64715 100644 --- a/p2p/raintree/network_test.go +++ b/p2p/raintree/network_test.go @@ -46,7 +46,7 @@ func TestRainTreeNetwork_AddPeerToAddrBook(t *testing.T) { require.Equal(t, peer, stateView.addrBookMap[peerAddr.String()], "addrBookMap does not contain peer") } -func TestRainTreeNetwork_RemovePeerToAddrBook(t *testing.T) { +func TestRainTreeNetwork_RemovePeerFromAddrBook(t *testing.T) { ctrl := gomock.NewController(t) // starting with an address book having only self and an arbitrary number of peers `numAddressesInAddressBook`` @@ -67,7 +67,7 @@ func TestRainTreeNetwork_RemovePeerToAddrBook(t *testing.T) { // removing a peer peer := addrBook[1] - err = network.RemovePeerToAddrBook(peer) + err = network.RemovePeerFromAddrBook(peer) require.NoError(t, err) stateView = network.peersManager.getNetworkView() diff --git a/p2p/stdnetwork/network.go b/p2p/stdnetwork/network.go index 841edeebc..712bd61ed 100644 --- a/p2p/stdnetwork/network.go +++ b/p2p/stdnetwork/network.go @@ -84,7 +84,7 @@ func (n *network) AddPeerToAddrBook(peer *typesP2P.NetworkPeer) error { return nil } -func (n *network) RemovePeerToAddrBook(peer *typesP2P.NetworkPeer) error { +func (n *network) RemovePeerFromAddrBook(peer *typesP2P.NetworkPeer) error { delete(n.addrBookMap, peer.Address.String()) return nil } diff --git a/p2p/types/network.go b/p2p/types/network.go index 90daedb91..66daaa8ae 100644 --- a/p2p/types/network.go +++ b/p2p/types/network.go @@ -18,7 +18,7 @@ type Network interface { // Address book helpers GetAddrBook() AddrBook AddPeerToAddrBook(peer *NetworkPeer) error - RemovePeerToAddrBook(peer *NetworkPeer) error + RemovePeerFromAddrBook(peer *NetworkPeer) error // This function was added to specifically support the RainTree implementation. // Handles the raw data received from the network and returns the data to be processed diff --git a/p2p/utils_test.go b/p2p/utils_test.go index dcab6c141..b6cdbf560 100644 --- a/p2p/utils_test.go +++ b/p2p/utils_test.go @@ -11,8 +11,11 @@ import ( "time" "github.com/golang/mock/gomock" + "github.com/pokt-network/pocket/p2p/providers/addrbook_provider" + "github.com/pokt-network/pocket/p2p/providers/current_height_provider" typesP2P "github.com/pokt-network/pocket/p2p/types" mocksP2P "github.com/pokt-network/pocket/p2p/types/mocks" + "github.com/pokt-network/pocket/runtime" "github.com/pokt-network/pocket/runtime/configs" types "github.com/pokt-network/pocket/runtime/configs/types" "github.com/pokt-network/pocket/runtime/genesis" @@ -153,6 +156,8 @@ func createMockBus(t *testing.T, runtimeMgr modules.RuntimeMgr) *mockModules.Moc m.SetBus(mockBus) }).AnyTimes() mockModulesRegistry := mockModules.NewMockModulesRegistry(ctrl) + mockModulesRegistry.EXPECT().GetModule(addrbook_provider.ModuleName).Return(nil, runtime.ErrModuleNotRegistered(addrbook_provider.ModuleName)).AnyTimes() + mockModulesRegistry.EXPECT().GetModule(current_height_provider.ModuleName).Return(nil, runtime.ErrModuleNotRegistered(current_height_provider.ModuleName)).AnyTimes() mockBus.EXPECT().GetModulesRegistry().Return(mockModulesRegistry).AnyTimes() mockBus.EXPECT().PublishEventToBus(gomock.Any()).AnyTimes() return mockBus diff --git a/rpc/doc/CHANGELOG.md b/rpc/doc/CHANGELOG.md index 9c186294b..e55a0dcad 100644 --- a/rpc/doc/CHANGELOG.md +++ b/rpc/doc/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.12] - 2023-02-17 + +- Updated RPC to expose the node's address book via GET `/v1/p2p/staked_actors_address_book` + ## [0.0.0.11] - 2023-02-17 - Updated modules to embed `base_modules.IntegratableModule` and `base_modules.InterruptableModule` for DRYness diff --git a/rpc/handlers.go b/rpc/handlers.go index 10fc44834..2f7a4225f 100644 --- a/rpc/handlers.go +++ b/rpc/handlers.go @@ -7,6 +7,8 @@ import ( "github.com/labstack/echo/v4" "github.com/pokt-network/pocket/app" "github.com/pokt-network/pocket/shared/codec" + typesCore "github.com/pokt-network/pocket/shared/core/types" + "github.com/pokt-network/pocket/shared/modules" typesUtil "github.com/pokt-network/pocket/utility/types" ) @@ -67,3 +69,78 @@ func (s *rpcServer) broadcastMessage(msgBz []byte) error { } return nil } + +func (s *rpcServer) GetV1P2pStakedActorsAddressBook(ctx echo.Context, params GetV1P2pStakedActorsAddressBookParams) error { + var height int64 + var actors []Actor + + if params.Height != nil { + height = *params.Height + } else { + height = int64(s.GetBus().GetConsensusModule().CurrentHeight()) + } + + persistenceContext, err := s.GetBus().GetPersistenceModule().NewReadContext(height) + if err != nil { + return ctx.String(http.StatusInternalServerError, err.Error()) + } + defer persistenceContext.Close() + + protocolActorGetter := getProtocolActorGetter(persistenceContext, params) + + protocolActors, err := protocolActorGetter(height) + if err != nil { + return ctx.String(http.StatusInternalServerError, err.Error()) + } + + for _, protocolActor := range protocolActors { + actors = append(actors, Actor{ + Address: protocolActor.Address, + Type: protocolActorToRPCActorTypeEnum(protocolActor.ActorType), + PublicKey: protocolActor.PublicKey, + ServiceUrl: protocolActor.GenericParam, + }) + } + + response := P2PStakedActorsResponse{ + Actors: actors, + Height: height, + } + + return ctx.JSON(http.StatusOK, response) +} + +// protocolActorToRPCActorTypeEnum converts a protocol actor type to the rpc actor type enum +func protocolActorToRPCActorTypeEnum(protocolActorType typesCore.ActorType) ActorTypesEnum { + switch protocolActorType { + case typesCore.ActorType_ACTOR_TYPE_APP: + return Application + case typesCore.ActorType_ACTOR_TYPE_FISH: + return Fisherman + case typesCore.ActorType_ACTOR_TYPE_SERVICENODE: + return ServiceNode + case typesCore.ActorType_ACTOR_TYPE_VAL: + return Validator + default: + panic("invalid actor type") + } +} + +// getProtocolActorGetter returns the correct protocol actor getter function based on the actor type parameter +func getProtocolActorGetter(persistenceContext modules.PersistenceReadContext, params GetV1P2pStakedActorsAddressBookParams) func(height int64) ([]*typesCore.Actor, error) { + var protocolActorGetter func(height int64) ([]*typesCore.Actor, error) = persistenceContext.GetAllStakedActors + if params.ActorType == nil { + return persistenceContext.GetAllStakedActors + } + switch *params.ActorType { + case Application: + protocolActorGetter = persistenceContext.GetAllApps + case Fisherman: + protocolActorGetter = persistenceContext.GetAllFishermen + case ServiceNode: + protocolActorGetter = persistenceContext.GetAllServiceNodes + case Validator: + protocolActorGetter = persistenceContext.GetAllValidators + } + return protocolActorGetter +} diff --git a/rpc/rpc.go b/rpc/rpc.go index ec9117584..76794bbdc 100644 --- a/rpc/rpc.go +++ b/rpc/rpc.go @@ -2,6 +2,7 @@ package rpc // importing because used by code-generated files that are git ignored and to allow go mod tidy and go mod vendor to function properly import ( + _ "github.com/deepmap/oapi-codegen/pkg/runtime" _ "github.com/getkin/kin-openapi/openapi3" _ "github.com/labstack/echo/v4" ) diff --git a/rpc/v1/openapi.yaml b/rpc/v1/openapi.yaml index 3183d561b..aefe9f481 100644 --- a/rpc/v1/openapi.yaml +++ b/rpc/v1/openapi.yaml @@ -1,6 +1,6 @@ openapi: 3.0.3 servers: - - url: 'http://localhost:50832' + - url: "http://localhost:50832" info: description: >- This is the API definition Pocket Network Node RPC interface. @@ -12,12 +12,12 @@ info: Pocket verifies all relayed data and proportionally rewards the participating nodes with POKT. version: 1.0.0 title: Pocket Network - termsOfService: 'https://pokt.network/terms/' + termsOfService: "https://pokt.network/terms/" contact: email: hola@pokt.network license: name: MIT License - url: 'https://github.com/pokt-network/pocket/blob/main/LICENSE' + url: "https://github.com/pokt-network/pocket/blob/main/LICENSE" tags: - name: version description: Version of the Pocket API @@ -34,11 +34,11 @@ paths: - health summary: Get the liveness of the Pocket API node responses: - '200': + "200": description: Healthy - '404': + "404": description: Unhealthy - Unreachable - '500': + "500": description: Unhealthy - Server Error /v1/version: get: @@ -64,13 +64,8 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ConsensusState' - example: - { - "height": 75016, - "round": 0, - "step": 3 - } + $ref: "#/components/schemas/ConsensusState" + example: { "height": 75016, "round": 0, "step": 3 } /v1/client/broadcast_tx_sync: post: tags: @@ -82,23 +77,64 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/RawTXRequest' + $ref: "#/components/schemas/RawTXRequest" responses: - '200': + "200": description: Transaction added to the mempool without errors - '400': + "400": description: Bad request content: text/plain: example: "description of failure" - '500': + "500": description: An error occurred while adding the transaction to the mempool content: text/plain: example: "description of failure" + + /v1/p2p/staked_actors_address_book: + get: + tags: + - p2p + summary: Returns the protocol actor address book + parameters: + - in: query + name: height + required: false + schema: + type: integer + format: int64 + minimum: 0 + description: The height the query will be executed on. By default it uses the current height of the consensus module. This may be the latest height if synched or an earlier height if synching. + - in: query + name: actor_type + required: false + schema: + $ref: "#/components/schemas/ActorTypesEnum" + description: The type of actor the address book will be populated with. By default it returns an address book for all protocol actors supported by the blockchain + + responses: + "200": + description: Staked actors response + content: + application/json: + schema: + $ref: "#/components/schemas/P2PStakedActorsResponse" + + "400": + description: Bad request + content: + text/plain: + example: "description of failure" + "500": + description: An error occurred while retrieving the staked actors address book + content: + text/plain: + example: "description of failure" + externalDocs: description: Find out more about Pocket Network - url: 'https://pokt.network' + url: "https://pokt.network" components: schemas: RawTXRequest: @@ -112,23 +148,61 @@ components: raw_hex_bytes: type: string ConsensusState: - type: object - required: - - height - - round - - step - properties: - height: - type: integer - format: int64 - round: - type: integer - format: int64 - step: - type: integer - format: int64 - requestBodies: {} + type: object + required: + - height + - round + - step + properties: + height: + type: integer + format: int64 + round: + type: integer + format: int64 + step: + type: integer + format: int64 + Actor: + type: object + required: + - type + - address + - public_key + - service_url + properties: + type: + $ref: "#/components/schemas/ActorTypesEnum" + address: + type: string + public_key: + type: string + service_url: + type: string + + P2PStakedActorsResponse: + type: object + required: + - actors + - height + properties: + actors: + type: "array" + items: + $ref: "#/components/schemas/Actor" + height: + type: integer + format: int64 + + ActorTypesEnum: + type: string + enum: + - validator + - service_node + - fisherman + - application + securitySchemes: {} links: {} callbacks: {} -security: [] \ No newline at end of file +security: [] diff --git a/runtime/configs/config.go b/runtime/configs/config.go index 21e18ea5f..44af2c544 100644 --- a/runtime/configs/config.go +++ b/runtime/configs/config.go @@ -51,8 +51,8 @@ func NewDefaultConfig(options ...func(*Config)) *Config { Format: defaults.DefaultLoggerFormat, }, RPC: &RPCConfig{ - Timeout: defaults.DefaultRpcTimeout, - Port: defaults.DefaultRpcPort, + Timeout: defaults.DefaultRPCTimeout, + Port: defaults.DefaultRPCPort, }, } diff --git a/runtime/defaults/defaults.go b/runtime/defaults/defaults.go index f83bdf815..1d2cca21c 100644 --- a/runtime/defaults/defaults.go +++ b/runtime/defaults/defaults.go @@ -3,18 +3,21 @@ package defaults import ( "fmt" - types "github.com/pokt-network/pocket/runtime/configs/types" + "github.com/pokt-network/pocket/runtime/configs/types" ) const ( - defaultRPCPort = "50832" - defaultRPCHost = "localhost" - defaultRPCTimeout = 30000 - DefaultBusBufferSize = 100 + DefaultRPCPort = "50832" + DefaultBusBufferSize = 100 + DefaultRPCHost = "localhost" + Validator1EndpointDockerCompose = "node1.consensus" + Validator1EndpointK8S = "v1-validator001" + + defaultRPCTimeout = 30000 ) var ( - DefaultRemoteCLIURL = fmt.Sprintf("http://%s:%s", defaultRPCHost, defaultRPCPort) + DefaultRemoteCLIURL = fmt.Sprintf("http://%s:%s", DefaultRPCHost, DefaultRPCPort) // consensus DefaultConsensusMaxMempoolBytes = uint64(500000000) @@ -41,6 +44,5 @@ var ( DefaultLoggerLevel = "debug" DefaultLoggerFormat = "pretty" // rpc - DefaultRpcPort = defaultRPCPort - DefaultRpcTimeout = uint64(defaultRPCTimeout) + DefaultRPCTimeout = uint64(defaultRPCTimeout) ) diff --git a/runtime/docs/CHANGELOG.md b/runtime/docs/CHANGELOG.md index 8dbb058e7..f449d582f 100644 --- a/runtime/docs/CHANGELOG.md +++ b/runtime/docs/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.20] - 2023-02-17 + +- Nits: variables visibility, comments + ## [0.0.0.19] - 2023-02-17 - Introduced `modules.ModulesRegistry` for better separation of concerns diff --git a/shared/CHANGELOG.md b/shared/CHANGELOG.md index 0718222bc..4e976b6c7 100644 --- a/shared/CHANGELOG.md +++ b/shared/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.0.0.28] - 2023-02-17 + +- Added `UnmarshalText` to `Ed25519PrivateKey` +- Fan-ing out `ConsensusNewHeightEventType` events + ## [0.0.0.27] - 2023-02-17 - Added events `ConsensusNewHeightEvent` and `StateMachineTransitionEvent` diff --git a/shared/core/types/README.md b/shared/core/types/README.md index 56310b46e..812ffc615 100644 --- a/shared/core/types/README.md +++ b/shared/core/types/README.md @@ -1,7 +1,7 @@ # Core Types -The types defined in this package are responsible for state commitment. +The types defined in this package are responsible for cross-cutting concerns like state commitment and Finite State Machine (FSM) interaction. -The field types, values and order of serialization is critical in ensuring the integrity of the blockchain. +With regards to state commitment, the field types, values and order of serialization is critical in ensuring the integrity of the blockchain. See the [Persistence Specification](https://github.com/pokt-network/pocket-network-protocol/tree/main/persistence) for full details. diff --git a/shared/crypto/ed25519.go b/shared/crypto/ed25519.go index fed0f5925..9d1cd66a0 100644 --- a/shared/crypto/ed25519.go +++ b/shared/crypto/ed25519.go @@ -119,6 +119,11 @@ func (priv *Ed25519PrivateKey) UnmarshalJSON(data []byte) error { if err != nil { return err } + return priv.UnmarshalText([]byte(privateKey)) +} + +func (priv *Ed25519PrivateKey) UnmarshalText(data []byte) error { + privateKey := string(data) keyBytes, err := hex.DecodeString(privateKey) if err != nil { return err diff --git a/shared/node.go b/shared/node.go index 4f6a2a238..75597b6d4 100644 --- a/shared/node.go +++ b/shared/node.go @@ -142,6 +142,8 @@ func (node *Node) handleEvent(message *messaging.PocketEnvelope) error { return node.GetBus().GetUtilityModule().HandleMessage(message.Content) case messaging.DebugMessageEventType: return node.handleDebugMessage(message) + case messaging.ConsensusNewHeightEventType: + return node.GetBus().GetP2PModule().HandleEvent(message.Content) default: logger.Global.Warn().Msgf("Unsupported message content type: %s", contentType) }