Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Consensus] Add MinBlockTime to delay mempool reaping #924

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8608bce
[WIP] Add MinBlockTime
red-0ne Jul 21, 2023
4a25b62
[Consensus] Feat: Configurable min block production time
red-0ne Jul 25, 2023
1028ae9
[Consensus] Refactor: decouple timer registration from subscription
red-0ne Jul 26, 2023
a7fd743
address review comments
red-0ne Jul 31, 2023
867e841
[Docs] Update development docs to warn to not use the changelog hook …
h5law Jul 24, 2023
0d448c9
[IBC] chore: Rename FlushAllEntries => FlushCachesToStore (#934)
h5law Jul 24, 2023
accccfc
[Utility] Feat: add client-side session cache (#888)
adshmh Jul 25, 2023
3165b8d
[IBC] Clone `cosmos/ics23` protobuf definitions into IBC repo (#922)
h5law Jul 26, 2023
990321e
[CLI] Consistent config/flag parsing & common helpers (#891)
bryanchriswhite Jul 26, 2023
21d7024
[IBC] Change Events to not have a Height field and use uint64 in quer…
h5law Jul 26, 2023
c67fa14
[IBC] Add ICS-02 Client Interfaces (#932)
h5law Jul 26, 2023
db8d8d6
[Persistence] Adds `node` subcommand to CLI (#935)
dylanlott Jul 26, 2023
74a5816
[IBC] chore: enable IBC module in k8s validators (#941)
h5law Jul 27, 2023
950ccc3
[Utility] Use TreeStore as source of truth (#937)
h5law Jul 27, 2023
d3bf0ad
[IBC] Enable validators and thus IBC host creation in K8s (#942)
h5law Jul 28, 2023
c903ca1
[Utility] Create trustless_relay_validation.md (#938)
adshmh Jul 31, 2023
298b08f
[Persistence] Adds atomic Update for TreeStore (#861)
dylanlott Jul 31, 2023
a68af5c
[chore] Replaces multierr usage with go native errors package (#939)
dylanlott Jul 31, 2023
0941549
hack: 😴 sleep enough for cli debug subcommands to broadcast (#954)
0xBigBoss Jul 31, 2023
50f8846
DevLog 12 (#957)
Olshansk Aug 1, 2023
e0e9fd4
[Utility] servicer signs relays (#952)
adshmh Aug 1, 2023
2a226cc
[LocalNet] Fix metrics scraping (#940)
okdas Aug 1, 2023
6c7599e
prevent sending to closed channels
red-0ne Aug 2, 2023
92ece19
disable block preparation delay when manual mode is on
red-0ne Aug 4, 2023
fef4217
[E2E Test] Utilities for State Sync Test (#874)
Olshansk Aug 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,4 +197,4 @@ jobs:
- id: "run-e2e-tests"
run: |
./argo-linux-amd64 submit --wait --log --namespace devnet-issue-${{ github.event.pull_request.number }} --from 'wftmpl/dev-e2e-tests' --parameter gitsha="${{ github.event.pull_request.head.sha }}"
./argo-linux-amd64 submit --wait --log --namespace devnet-issue-${{ github.event.pull_request.number }} --from 'wftmpl/dev-e2e-tests' --parameter tags="~@skip_in_ci" --parameter gitsha="${{ github.event.pull_request.head.sha }}"
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,6 @@ temp_test.go
test_results.json
coverage.out

# Output of `make build_and_watch`
main

# generated RPC server and client from openapi.yaml
rpc/server.gen.go
rpc/client.gen.go
Expand Down Expand Up @@ -90,3 +87,6 @@ tools/wiki

# ggshield
.cache_ggshield

# mock temporary files
**/gomock_reflect_*/
3 changes: 0 additions & 3 deletions .tiltignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ temp_test.go
test_results.json
coverage.out

# Output of `make build_and_watch`
main

# generated RPC server and client from openapi.yaml
rpc/server.gen.go
rpc/client.gen.go
Expand Down
75 changes: 53 additions & 22 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ CWD ?= CURRENT_WORKING_DIRECTIONRY_NOT_SUPPLIED
# `VERBOSE_TEST="" make test_persistence` is an easy way to run the same tests without verbose output
VERBOSE_TEST ?= -v

# Detect OS using the $(shell uname -s) command
ifeq ($(shell uname -s),Darwin)
# Add macOS-specific commands here
SEDI = sed -i ''
else ifeq ($(shell uname -s),Linux)
# Add Linux-specific commands here
SEDI = sed -i
endif

.SILENT:

.PHONY: list ## List all make targets
Expand All @@ -29,7 +38,7 @@ help:
docker_check:
{ \
if ( ! ( command -v docker >/dev/null && (docker compose version >/dev/null || command -v docker-compose >/dev/null) )); then \
echo "Seems like you don't have Docker or docker-compose installed. Make sure you review docs/development/README.md before continuing"; \
echo "Seems like you don't have Docker or docker-compose installed. Make sure you review build/localnet/README.md and docs/development/README.md before continuing"; \
exit 1; \
fi; \
}
Expand All @@ -38,11 +47,21 @@ docker_check:
kubectl_check:
{ \
if ( ! ( command -v kubectl >/dev/null )); then \
echo "Seems like you don't have Kubectl installed. Make sure you review docs/development/README.md before continuing"; \
echo "Seems like you don't have Kubectl installed. Make sure you review build/localnet/README.md and docs/development/README.md before continuing"; \
exit 1; \
fi; \
}

# Internal helper target - check if rsync is installed.
rsync_check:
{ \
if ( ! ( command -v kubectl >/dev/null )); then \
echo "Seems like you don't have rsync installed. Make sure you review build/localnet/README.md and docs/development/README.md before continuing"; \
exit 1; \
fi; \
}


.PHONY: trigger_ci
trigger_ci: ## Trigger the CI pipeline by submitting an empty commit; See https://github.com/pokt-network/pocket/issues/900 for details
git commit --allow-empty -m "Empty commit"
Expand Down Expand Up @@ -124,6 +143,9 @@ go_imports: ## Group imports using rinchsan/gosimports
go_fmt: ## Format all the .go files in the project in place.
gofmt -w -s .

# TODO(#964): add `rsync_check`, `kubectl_check`, `docker_check` as a validation in `install_cli_deps`; https://github.com/pokt-network/pocket/assets/1892194/a7a24a11-f54d-46e2-a73e-9e8ea7d06726
# .PHONY: install_cli_deps
# install_cli_deps: rsync_check kubectl_check docker_check ## Installs `helm`, `tilt` and the underlying `ci_deps`
.PHONY: install_cli_deps
install_cli_deps: ## Installs `helm`, `tilt` and the underlying `ci_deps`
make install_ci_deps
Expand Down Expand Up @@ -154,33 +176,27 @@ develop_test: docker_check ## Run all of the make commands necessary to develop
make develop_start && \
make test_all

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

.PHONY: rebuild_client_start
rebuild_client_start: docker_check ## Rebuild and run a client daemon which is only used for debugging purposes
${docker-compose} up -d --build client

.PHONY: client_connect
client_connect: docker_check ## Connect to the running client debugging daemon
.PHONY: lightweight_localnet_client_debug
lightweight_localnet_client_debug: docker_check ## Connect to the running client debugging daemon
docker exec -it client /bin/bash -c "go run -tags=debug app/client/*.go DebugUI"

.PHONY: build_and_watch
build_and_watch: ## Continous build Pocket's main entrypoint as files change
/bin/sh ${PWD}/build/scripts/watch_build.sh
# IMPROVE: Avoid building the binary on every shell execution and sync it from local instead
.PHONY: lightweight_localnet_shell
lightweight_localnet_shell: docker_check ## Connect to the running client debugging daemon
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"

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

.PHONY: rebuild_and_compose_and_watch
rebuild_and_compose_and_watch: docker_check db_start monitoring_start ## Rebuilds the container from scratch and launches compose_and_watch
${docker-compose} up --build --force-recreate validator1 validator2 validator3 validator4 servicer1 fisherman1

.PHONY: db_start
db_start: docker_check ## Start a detached local postgres and admin instance; compose_and_watch is responsible for instantiating the actual schemas
db_start: docker_check ## Start a detached local postgres and admin instance; lightweight_localnet is responsible for instantiating the actual schemas
${docker-compose} up --no-recreate -d db pgadmin

.PHONY: db_cli
Expand Down Expand Up @@ -236,7 +252,7 @@ docker_wipe_nodes: docker_check prompt_user db_drop ## [WARNING] Remove all the
docker ps -a -q --filter="name=node*" | xargs -r -I {} docker rm {}

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

.PHONY: docker_loki_install
Expand Down Expand Up @@ -309,13 +325,28 @@ protogen_local: go_protoc-go-inject-tag ## Generate go structures for all of the
$(PROTOC_SHARED) -I=./p2p/types/proto --go_out=./p2p/types ./p2p/types/proto/*.proto

# IBC
@if test ! -e "./ibc/types/proto/proofs.proto"; then \
make download_ics23_proto; \
fi
$(PROTOC_SHARED) -I=./ibc/types/proto --go_out=./ibc/types ./ibc/types/proto/*.proto
$(PROTOC_SHARED) -I=./ibc/client/types/proto --go_out=./ibc/client/types ./ibc/client/types/proto/*.proto
$(PROTOC_SHARED) -I=./ibc/client/types/proto -I=./ibc/client/light_clients/types/proto -I=./shared/core/types/proto -I=./ibc/types/proto --go_out=./ibc/client/light_clients/types ./ibc/client/light_clients/types/proto/*.proto

# echo "View generated proto files by running: make protogen_show"

# CONSIDERATION: Some proto files contain unused gRPC services so we may need to add the following
# if/when we decide to include it: `grpc--go-grpc_opt=paths=source_relative --go-grpc_out=./output/path`

.PHONY: download_ics23_proto
download_ics23_proto:
echo "Downloading cosmos/ics23 proto definitions..."; \
curl -s -o ./ibc/types/proto/proofs.proto https://raw.githubusercontent.com/cosmos/ics23/master/proto/cosmos/ics23/v1/proofs.proto; \
$(SEDI) \
-e '/^package/{N;d;}' \
-e '[email protected]/.*"@github.com/pokt-network/pocket/ibc/types"@g' \
./ibc/types/proto/proofs.proto && \
awk 'BEGIN { print "// ===== !! THIS IS CLONED FROM cosmos/ics23 !! =====\n" } { print }' ./ibc/types/proto/proofs.proto > tmpfile && mv tmpfile ./ibc/types/proto/proofs.proto; \

.PHONY: protogen_docker_m1
## TECHDEBT: Test, validate & update.
protogen_docker_m1: docker_check
Expand Down
87 changes: 87 additions & 0 deletions app/client/cli/cache/session.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package cache

// TODO: add a TTL for cached sessions, since we know the sessions' length
import (
"encoding/json"
"errors"
"fmt"

"github.com/pokt-network/pocket/persistence/kvstore"
"github.com/pokt-network/pocket/rpc"
)

var errSessionNotFound = errors.New("session not found in cache")

// SessionCache defines the set of methods used to interact with the client-side session cache
type SessionCache interface {
Get(appAddr, chain string) (*rpc.Session, error)
Set(session *rpc.Session) error
Stop() error
}

// sessionCache stores and retrieves sessions for application+relaychain pairs
//
// It uses a key-value store as backing storage
type sessionCache struct {
// store is the local store for cached sessions
store kvstore.KVStore
}

// NewSessionCache returns a session cache backed by a kvstore using the provided database path.
func NewSessionCache(databasePath string) (SessionCache, error) {
store, err := kvstore.NewKVStore(databasePath)
if err != nil {
return nil, fmt.Errorf("Error initializing key-value store using path %s: %w", databasePath, err)
}

return &sessionCache{
store: store,
}, nil
}

// Get returns the cached session, if found, for an app+chain combination.
// The caller is responsible to verify that the returned session is valid for the current block height.
// Get is NOT safe to use concurrently
// DISCUSS: do we need concurrency here?
func (s *sessionCache) Get(appAddr, chain string) (*rpc.Session, error) {
key := sessionKey(appAddr, chain)
bz, err := s.store.Get(key)
if err != nil {
return nil, fmt.Errorf("error getting session from the store: %s %w", err.Error(), errSessionNotFound)
}

var session rpc.Session
if err := json.Unmarshal(bz, &session); err != nil {
return nil, fmt.Errorf("error unmarshalling session from store: %w", err)
}

return &session, nil
}

// Set stores the provided session in the cache with the key being the app+chain combination.
// For each app+chain combination, a single session will be stored. Subsequent calls to Set will overwrite the entry for the provided app and chain.
// Set is NOT safe to use concurrently
func (s *sessionCache) Set(session *rpc.Session) error {
bz, err := json.Marshal(*session)
if err != nil {
return fmt.Errorf("error marshalling session for app: %s, chain: %s, session height: %d: %w", session.Application.Address, session.Chain, session.SessionHeight, err)
}

key := sessionKey(session.Application.Address, session.Chain)
if err := s.store.Set(key, bz); err != nil {
return fmt.Errorf("error storing session for app: %s, chain: %s, session height: %d in the cache: %w", session.Application.Address, session.Chain, session.SessionHeight, err)
}
return nil
}

// Stop call stop on the backing store. No calls should be made to Get or Set after calling Stop.
func (s *sessionCache) Stop() error {
return s.store.Stop()
}

// sessionKey returns a key to get/set a session, based on application's address and the relay chain.
//
// The height is not used as part of the key, because for each app+chain combination only one session, i.e. the current one, is of interest.
func sessionKey(appAddr, chain string) []byte {
return []byte(fmt.Sprintf("%s-%s", appAddr, chain))
}
75 changes: 75 additions & 0 deletions app/client/cli/cache/session_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package cache

import (
"os"
"testing"

"github.com/stretchr/testify/require"

"github.com/pokt-network/pocket/rpc"
)

func TestGet(t *testing.T) {
const (
app1 = "app1Addr"
relaychainEth = "ETH-Goerli"
numSessionBlocks = 4
sessionHeight = 8
sessionNumber = 2
)

session1 := &rpc.Session{
Application: rpc.ProtocolActor{
ActorType: rpc.Application,
Address: "app1Addr",
Chains: []string{relaychainEth},
},
Chain: relaychainEth,
NumSessionBlocks: numSessionBlocks,
SessionHeight: sessionHeight,
SessionNumber: sessionNumber,
}

testCases := []struct {
name string
cacheContents []*rpc.Session
app string
chain string
expected *rpc.Session
expectedErr error
}{
{
name: "Return cached session",
cacheContents: []*rpc.Session{session1},
app: app1,
chain: relaychainEth,
expected: session1,
},
{
name: "Error returned for session not found in cache",
app: "foo",
chain: relaychainEth,
expectedErr: errSessionNotFound,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
dbPath, err := os.MkdirTemp("", "cacheStoragePath")
require.NoError(t, err)
defer os.RemoveAll(dbPath)

cache, err := NewSessionCache(dbPath)
require.NoError(t, err)

for _, s := range tc.cacheContents {
err := cache.Set(s)
require.NoError(t, err)
}

got, err := cache.Get(tc.app, tc.chain)
require.ErrorIs(t, err, tc.expectedErr)
require.EqualValues(t, tc.expected, got)
})
}
}
Loading