Skip to content

Commit e74cc90

Browse files
committed
E2E State Sync Test
1 parent 6736454 commit e74cc90

28 files changed

+663
-292
lines changed

.gitignore

+3-3
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,6 @@ temp_test.go
5555
test_results.json
5656
coverage.out
5757

58-
# Output of `make build_and_watch`
59-
main
60-
6158
# generated RPC server and client from openapi.yaml
6259
rpc/server.gen.go
6360
rpc/client.gen.go
@@ -90,3 +87,6 @@ tools/wiki
9087

9188
# ggshield
9289
.cache_ggshield
90+
91+
# mock temporary files
92+
**/gomock_reflect_*/

.tiltignore

-3
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ temp_test.go
4141
test_results.json
4242
coverage.out
4343

44-
# Output of `make build_and_watch`
45-
main
46-
4744
# generated RPC server and client from openapi.yaml
4845
rpc/server.gen.go
4946
rpc/client.gen.go

Makefile

+14-20
Original file line numberDiff line numberDiff line change
@@ -163,33 +163,27 @@ develop_test: docker_check ## Run all of the make commands necessary to develop
163163
make develop_start && \
164164
make test_all
165165

166-
.PHONY: client_start
167-
client_start: docker_check ## Run a client daemon which is only used for debugging purposes
166+
.PHONY: lightweight_localnet_client
167+
lightweight_localnet_client: docker_check ## Run a client daemon which is only used for debugging purposes
168+
# Add `--build` to rebuild the client
168169
${docker-compose} up -d client
169170

170-
.PHONY: rebuild_client_start
171-
rebuild_client_start: docker_check ## Rebuild and run a client daemon which is only used for debugging purposes
172-
${docker-compose} up -d --build client
173-
174-
.PHONY: client_connect
175-
client_connect: docker_check ## Connect to the running client debugging daemon
171+
.PHONY: lightweight_localnet_client_debug
172+
lightweight_localnet_client_debug: docker_check ## Connect to the running client debugging daemon
176173
docker exec -it client /bin/bash -c "go run -tags=debug app/client/*.go DebugUI"
177174

178-
.PHONY: build_and_watch
179-
build_and_watch: ## Continous build Pocket's main entrypoint as files change
180-
/bin/sh ${PWD}/build/scripts/watch_build.sh
175+
# IMPROVE: Avoid building the binary on every shell execution and sync it from local instead
176+
.PHONY: lightweight_localnet_shell
177+
lightweight_localnet_shell: docker_check ## Connect to the running client debugging daemon
178+
docker exec -it client /bin/bash -c "go build -tags=debug -o p1 ./app/client/*.go && chmod +x p1 && mv p1 /usr/bin && echo \"Finished building a new p1 binary\" && /bin/bash"
181179

182-
# TODO(olshansky): Need to think of a Pocket related name for `compose_and_watch`, maybe just `pocket_watch`?
183-
.PHONY: compose_and_watch
184-
compose_and_watch: docker_check db_start monitoring_start ## Run a localnet composed of 4 consensus validators w/ hot reload & debugging
180+
.PHONY: lightweight_localnet
181+
lightweight_localnet: docker_check db_start monitoring_start ## Run a lightweight localnet composed of 4 validators w/ hot reload & debugging
182+
# Add `--build` to rebuild the client
185183
${docker-compose} up --force-recreate validator1 validator2 validator3 validator4 servicer1 fisherman1
186184

187-
.PHONY: rebuild_and_compose_and_watch
188-
rebuild_and_compose_and_watch: docker_check db_start monitoring_start ## Rebuilds the container from scratch and launches compose_and_watch
189-
${docker-compose} up --build --force-recreate validator1 validator2 validator3 validator4 servicer1 fisherman1
190-
191185
.PHONY: db_start
192-
db_start: docker_check ## Start a detached local postgres and admin instance; compose_and_watch is responsible for instantiating the actual schemas
186+
db_start: docker_check ## Start a detached local postgres and admin instance; lightweight_localnet is responsible for instantiating the actual schemas
193187
${docker-compose} up --no-recreate -d db pgadmin
194188

195189
.PHONY: db_cli
@@ -245,7 +239,7 @@ docker_wipe_nodes: docker_check prompt_user db_drop ## [WARNING] Remove all the
245239
docker ps -a -q --filter="name=node*" | xargs -r -I {} docker rm {}
246240

247241
.PHONY: monitoring_start
248-
monitoring_start: docker_check ## Start grafana, metrics and logging system (this is auto-triggered by compose_and_watch)
242+
monitoring_start: docker_check ## Start grafana, metrics and logging system (this is auto-triggered by lightweight_localnet)
249243
${docker-compose} up --no-recreate -d grafana loki vm
250244

251245
.PHONY: docker_loki_install

app/client/cli/debug.go

+116-21
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
package cli
22

33
import (
4+
"fmt"
5+
"log"
46
"os"
7+
"os/exec"
8+
"time"
59

610
"github.com/manifoldco/promptui"
711
"github.com/spf13/cobra"
12+
"golang.org/x/exp/slices"
813
"google.golang.org/protobuf/types/known/anypb"
914

1015
"github.com/pokt-network/pocket/app/client/cli/helpers"
@@ -34,43 +39,123 @@ var items = []string{
3439
}
3540

3641
func init() {
42+
dbg := newDebugCommand()
43+
dbg.AddCommand(newDebugSubCommands()...)
44+
rootCmd.AddCommand(dbg)
45+
3746
dbgUI := newDebugUICommand()
38-
dbgUI.AddCommand(newDebugUISubCommands()...)
3947
rootCmd.AddCommand(dbgUI)
4048
}
4149

42-
// newDebugUISubCommands builds out the list of debug subcommands by matching the
43-
// handleSelect dispatch to the appropriate command.
44-
// * To add a debug subcommand, you must add it to the `items` array and then
45-
// write a function handler to match for it in `handleSelect`.
46-
func newDebugUISubCommands() []*cobra.Command {
47-
commands := make([]*cobra.Command, len(items))
48-
for idx, promptItem := range items {
49-
commands[idx] = &cobra.Command{
50-
Use: promptItem,
50+
// newDebugCommand returns the cobra CLI for the Debug command.
51+
func newDebugCommand() *cobra.Command {
52+
return &cobra.Command{
53+
Use: "Debug",
54+
Aliases: []string{"d"},
55+
Short: "Debug utility for rapid development",
56+
Long: "Debug utility to send fire-and-forget messages to the network for development purposes",
57+
Args: cobra.MaximumNArgs(1),
58+
}
59+
}
60+
61+
// newDebugSubCommands is a list of commands that can be "fired & forgotten" (no selection necessary)
62+
func newDebugSubCommands() []*cobra.Command {
63+
cmds := []*cobra.Command{
64+
{
65+
Use: "PrintNodeState",
66+
Aliases: []string{"print", "state"},
67+
Short: "Prints the node state",
68+
Long: "Sends a message to all visible nodes to log the current state of their consensus",
69+
Args: cobra.ExactArgs(0),
5170
PersistentPreRunE: helpers.P2PDependenciesPreRunE,
52-
Run: func(cmd *cobra.Command, _ []string) {
53-
handleSelect(cmd, cmd.Use)
71+
Run: func(cmd *cobra.Command, args []string) {
72+
runWithSleep(func() {
73+
handleSelect(cmd, PromptPrintNodeState)
74+
})
5475
},
55-
ValidArgs: items,
56-
}
76+
},
77+
{
78+
Use: "ResetToGenesis",
79+
Aliases: []string{"reset", "genesis"},
80+
Short: "Reset to genesis",
81+
Long: "Broadcast a message to all visible nodes to reset the state to genesis",
82+
Args: cobra.ExactArgs(0),
83+
PersistentPreRunE: helpers.P2PDependenciesPreRunE,
84+
Run: func(cmd *cobra.Command, args []string) {
85+
runWithSleep(func() {
86+
handleSelect(cmd, PromptResetToGenesis)
87+
})
88+
},
89+
},
90+
{
91+
Use: "TriggerView",
92+
Aliases: []string{"next", "trigger", "view"},
93+
Short: "Trigger the next view in consensus",
94+
Long: "Sends a message to all visible nodes on the network to start the next view (height/step/round) in consensus",
95+
Args: cobra.ExactArgs(0),
96+
PersistentPreRunE: helpers.P2PDependenciesPreRunE,
97+
Run: func(cmd *cobra.Command, args []string) {
98+
runWithSleep(func() {
99+
handleSelect(cmd, PromptTriggerNextView)
100+
})
101+
},
102+
},
103+
{
104+
Use: "TogglePacemakerMode",
105+
Aliases: []string{"toggle", "pcm"},
106+
Short: "Toggle the pacemaker",
107+
Long: "Toggle the consensus pacemaker either on or off so the chain progresses on its own or loses liveness",
108+
Args: cobra.ExactArgs(0),
109+
PersistentPreRunE: helpers.P2PDependenciesPreRunE,
110+
Run: func(cmd *cobra.Command, args []string) {
111+
runWithSleep(func() {
112+
handleSelect(cmd, PromptTogglePacemakerMode)
113+
})
114+
},
115+
},
116+
{
117+
Use: "ScaleActor",
118+
Aliases: []string{"scale"},
119+
Short: "Scales the number of actors up or down",
120+
Long: "Scales the type of actor specified to the number provided",
121+
Args: cobra.ExactArgs(2),
122+
PersistentPreRunE: helpers.P2PDependenciesPreRunE,
123+
Run: func(cmd *cobra.Command, args []string) {
124+
actor := args[0]
125+
numActors := args[1]
126+
validActors := []string{"fishermen", "full_nodes", "servicers", "validators"}
127+
if !slices.Contains(validActors, actor) {
128+
logger.Global.Fatal().Msg("Invalid actor type provided")
129+
}
130+
sedCmd := exec.Command("sed", "-i", fmt.Sprintf("/%s:/,/count:/ s/count: [0-9]*/count: %s/", actor, numActors), "/usr/local/localnet_config.yaml")
131+
err := sedCmd.Run()
132+
if err != nil {
133+
log.Fatal(err)
134+
}
135+
},
136+
},
57137
}
58-
return commands
138+
return cmds
59139
}
60140

61141
// newDebugUICommand returns the cobra CLI for the Debug UI interface.
62142
func newDebugUICommand() *cobra.Command {
63143
return &cobra.Command{
64-
Aliases: []string{"dui"},
65144
Use: "DebugUI",
66-
Short: "Debug selection ui for rapid development",
145+
Aliases: []string{"dui"},
146+
Short: "Debug utility with an interactive UI for development purposes",
147+
Long: "Opens a shell-driven selection UI to view and select from a list of debug actions for development purposes",
67148
Args: cobra.MaximumNArgs(0),
68149
PersistentPreRunE: helpers.P2PDependenciesPreRunE,
69-
RunE: runDebug,
150+
RunE: selectDebugCommand,
70151
}
71152
}
72153

73-
func runDebug(cmd *cobra.Command, _ []string) (err error) {
154+
// selectDebugCommand builds out the list of debug subcommands by matching the
155+
// handleSelect dispatch to the appropriate command.
156+
// - To add a debug subcommand, you must add it to the `items` array and then
157+
// write a function handler to match for it in `handleSelect`.
158+
func selectDebugCommand(cmd *cobra.Command, _ []string) error {
74159
for {
75160
if selection, err := promptGetInput(); err == nil {
76161
handleSelect(cmd, selection)
@@ -158,7 +243,17 @@ func handleSelect(cmd *cobra.Command, selection string) {
158243
}
159244
}
160245

161-
// Broadcast to the entire network.
246+
// HACK: Because of how the p2p module works, we need to surround it with sleep both BEFORE and AFTER the task.
247+
// - Starting the task too early after the debug client initializes results in a lack of visibility of the nodes in the network
248+
// - Ending the task too early before the debug client completes its task results in a lack of propagation of the message or retrieval of the result
249+
// TECHDEBT: There is likely an event based solution to this but it would require a lot more refactoring of the p2p module.
250+
func runWithSleep(task func()) {
251+
time.Sleep(1000 * time.Millisecond)
252+
task()
253+
time.Sleep(1000 * time.Millisecond)
254+
}
255+
256+
// broadcastDebugMessage broadcasts the debug message to the entire visible network.
162257
func broadcastDebugMessage(cmd *cobra.Command, debugMsg *messaging.DebugMessage) {
163258
anyProto, err := anypb.New(debugMsg)
164259
if err != nil {
@@ -174,7 +269,7 @@ func broadcastDebugMessage(cmd *cobra.Command, debugMsg *messaging.DebugMessage)
174269
}
175270
}
176271

177-
// Send to just a single (i.e. first) validator in the set
272+
// sendDebugMessage sends the debug message to just a single (i.e. first) node visible
178273
func sendDebugMessage(cmd *cobra.Command, debugMsg *messaging.DebugMessage) {
179274
anyProto, err := anypb.New(debugMsg)
180275
if err != nil {

build/config/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ It is not recommended at this time to build infrastructure components that rely
1212

1313
## Origin Document
1414

15-
Currently, the Genesis and Configuration generator is necessary to create development `localnet` environments for iterating on V1. A current example (as of 09/2022) of this is the `make compose_and_watch` debug utility that generates a `localnet` using `docker-compose` by injecting the appropriate `config.json` and `genesis.json` files.
15+
Currently, the Genesis and Configuration generator is necessary to create development `localnet` environments for iterating on V1. A current example (as of 09/2022) of this is the `make lightweight_localnet` debug utility that generates a `localnet` using `docker-compose` by injecting the appropriate `config.json` and `genesis.json` files.
1616

1717
## Usage
1818

build/docs/CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
233233
## [0.0.0.1] - 2022-12-29
234234

235235
- Updated all `config*.json` files with the missing `max_mempool_count` value
236-
- Added `is_client_only` to `config1.json` so Viper knows it can be overridden. The config override is done in the Makefile's `client_connect` target. Setting this can be avoided if we merge the changes in https://github.com/pokt-network/pocket/compare/main...issue/cli-viper-environment-vars-fix
236+
- Added `is_client_only` to `config1.json` so Viper knows it can be overridden. The config override is done in the Makefile's `lightweight_localnet_client_debug` target. Setting this can be avoided if we merge the changes in https://github.com/pokt-network/pocket/compare/main...issue/cli-viper-environment-vars-fix
237237

238238
## [0.0.0.0] - 2022-12-22
239239

0 commit comments

Comments
 (0)