From 3267392074dbb151e4d90c9d547182469de1c5b5 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 2 Aug 2022 20:51:29 -0700 Subject: [PATCH 1/7] Added updateStateCommitment and GetAppsUpdated --- persistence/application.go | 35 +++++++++++++++++++ persistence/pre_persistence/app.go | 5 +++ persistence/schema/base_actor.go | 4 +++ persistence/schema/protocol_actor.go | 2 ++ persistence/schema/shared_sql.go | 5 +++ persistence/shared_sql.go | 52 ++++++++++++++++++++++++++++ persistence/test/state_hash_test.go | 7 ++++ shared/modules/persistence_module.go | 1 + shared/types/genesis/validator.go | 3 ++ utility/block.go | 3 ++ utility/state.go | 44 +++++++++++++++++++++++ 11 files changed, 161 insertions(+) create mode 100644 persistence/test/state_hash_test.go create mode 100644 utility/state.go diff --git a/persistence/application.go b/persistence/application.go index 169524df4..e2cf8ee13 100644 --- a/persistence/application.go +++ b/persistence/application.go @@ -4,16 +4,51 @@ import ( "encoding/hex" "log" + "github.com/golang/protobuf/proto" "github.com/pokt-network/pocket/persistence/schema" "github.com/pokt-network/pocket/shared/types" + + typesGenesis "github.com/pokt-network/pocket/shared/types/genesis" ) func (p PostgresContext) GetAppExists(address []byte, height int64) (exists bool, err error) { return p.GetExists(schema.ApplicationActor, address, height) } +func (p PostgresContext) GetAppsUpdated(height int64) (apps [][]byte, err error) { + actors, err := p.GetActorsUpdated(schema.ApplicationActor, height) + if err != nil { + return nil, err + } + + for _, actor := range actors { + // This breaks the pattern of protos in persistence + app := typesGenesis.App{ + Address: []byte(actor.Address), + PublicKey: []byte(actor.PublicKey), + // Paused: actor.Paused, + // Status: actor.Status, + Chains: actor.Chains, + MaxRelays: actor.ActorSpecificParam, + StakedTokens: actor.StakedTokens, + PausedHeight: actor.PausedHeight, + UnstakingHeight: actor.UnstakingHeight, + Output: []byte(actor.OutputAddress), + } + appBytes, err := proto.Marshal(&app) + if err != nil { + return nil, err + } + apps = append(apps, appBytes) + } + return +} + func (p PostgresContext) GetApp(address []byte, height int64) (operator, publicKey, stakedTokens, maxRelays, outputAddress string, pauseHeight, unstakingHeight int64, chains []string, err error) { actor, err := p.GetActor(schema.ApplicationActor, address, height) + if err != nil { + return + } operator = actor.Address publicKey = actor.PublicKey stakedTokens = actor.StakedTokens diff --git a/persistence/pre_persistence/app.go b/persistence/pre_persistence/app.go index a1d5ac455..e0de24234 100644 --- a/persistence/pre_persistence/app.go +++ b/persistence/pre_persistence/app.go @@ -11,6 +11,11 @@ import ( "google.golang.org/protobuf/proto" ) +func (m *PrePersistenceContext) GetAppsUpdated(height int64) ([][]byte, error) { + // Not implemented + return nil, nil +} + func (m *PrePersistenceContext) GetAppExists(address []byte, height int64) (exists bool, err error) { db := m.Store() key := append(AppPrefixKey, address...) diff --git a/persistence/schema/base_actor.go b/persistence/schema/base_actor.go index 3b0c6c0a3..77c92842c 100644 --- a/persistence/schema/base_actor.go +++ b/persistence/schema/base_actor.go @@ -64,6 +64,10 @@ func (actor *BaseProtocolActorSchema) GetChainsTableSchema() string { return ProtocolActorChainsTableSchema(actor.chainsHeightConstraintName) } +func (actor *BaseProtocolActorSchema) GetUpdatedAtHeightQuery(height int64) string { + return SelectAtHeight(AllColsSelector, height, actor.tableName) +} + func (actor *BaseProtocolActorSchema) GetQuery(address string, height int64) string { return Select(AllColsSelector, address, height, actor.tableName) } diff --git a/persistence/schema/protocol_actor.go b/persistence/schema/protocol_actor.go index a24bf1afd..19cc5f461 100644 --- a/persistence/schema/protocol_actor.go +++ b/persistence/schema/protocol_actor.go @@ -16,6 +16,8 @@ type ProtocolActorSchema interface { /*** Read/Get Queries ***/ + // Returns a query to retrieve all of a Actors updated at that specific height. + GetUpdatedAtHeightQuery(height int64) string // Returns a query to retrieve all of a single Actor's attributes. GetQuery(address string, height int64) string // Returns a query for the existence of an Actor given its address. diff --git a/persistence/schema/shared_sql.go b/persistence/schema/shared_sql.go index 63f059051..a47ae7ab3 100644 --- a/persistence/schema/shared_sql.go +++ b/persistence/schema/shared_sql.go @@ -69,6 +69,11 @@ func ProtocolActorChainsTableSchema(constraintName string) string { )`, AddressCol, ChainIDCol, HeightCol, DefaultBigInt, constraintName, AddressCol, ChainIDCol, HeightCol) } +func SelectAtHeight(selector string, height int64, tableName string) string { + return fmt.Sprintf(`SELECT %s FROM %s WHERE height=%d`, + selector, tableName, height) +} + func Select(selector, address string, height int64, tableName string) string { return fmt.Sprintf(`SELECT %s FROM %s WHERE address='%s' AND height<=%d ORDER BY height DESC LIMIT 1`, selector, tableName, address, height) diff --git a/persistence/shared_sql.go b/persistence/shared_sql.go index 369cbe402..4319ced81 100644 --- a/persistence/shared_sql.go +++ b/persistence/shared_sql.go @@ -41,6 +41,58 @@ func (p *PostgresContext) GetExists(actorSchema schema.ProtocolActorSchema, addr return } +func (p *PostgresContext) GetActorsUpdated(actorSchema schema.ProtocolActorSchema, height int64) (actors []schema.BaseActor, err error) { + ctx, conn, err := p.GetCtxAndConnection() + if err != nil { + return + } + + rows, err := conn.Query(ctx, actorSchema.GetUpdatedAtHeightQuery(height)) + if err != nil { + return nil, err + } + defer rows.Close() + + var actor schema.BaseActor + for rows.Next() { + if err = rows.Scan( + &actor.Address, &actor.PublicKey, &actor.StakedTokens, &actor.ActorSpecificParam, + &actor.OutputAddress, &actor.PausedHeight, &actor.UnstakingHeight, + &actor.Chains, &height, + ); err != nil { + return + } + + if actorSchema.GetChainsTableName() == "" { + continue + } + + chainRows, chainsErr := conn.Query(ctx, actorSchema.GetChainsQuery(actor.Address, height)) + if err != nil { + return nil, chainsErr // Why couldn't I just `return` here and use `err`? + } + defer chainRows.Close() + + var chainAddr string + var chainID string + var chainEndHeight int64 // unused + for rows.Next() { + err = rows.Scan(&chainAddr, &chainID, &chainEndHeight) + if err != nil { + return + } + if chainAddr != actor.Address { + return nil, fmt.Errorf("weird") + } + actor.Chains = append(actor.Chains, chainID) + } + + actors = append(actors, actor) + } + + return +} + func (p *PostgresContext) GetActor(actorSchema schema.ProtocolActorSchema, address []byte, height int64) (actor schema.BaseActor, err error) { ctx, conn, err := p.GetCtxAndConnection() if err != nil { diff --git a/persistence/test/state_hash_test.go b/persistence/test/state_hash_test.go new file mode 100644 index 000000000..c57c2c699 --- /dev/null +++ b/persistence/test/state_hash_test.go @@ -0,0 +1,7 @@ +package test + +import "testing" + +func TestSomething(t *testing.T) { + +} diff --git a/shared/modules/persistence_module.go b/shared/modules/persistence_module.go index 06854ca39..d9b6fd4e4 100644 --- a/shared/modules/persistence_module.go +++ b/shared/modules/persistence_module.go @@ -71,6 +71,7 @@ type PersistenceContext interface { SetAccountAmount(address []byte, amount string) error // TECHDEBT(team): Delete this function // App Operations + GetAppsUpdated(height int64) ([][]byte, error) // Returns the apps updates at the given height GetAppExists(address []byte, height int64) (exists bool, err error) InsertApp(address []byte, publicKey []byte, output []byte, paused bool, status int, maxRelays string, stakedAmount string, chains []string, pausedHeight int64, unstakingHeight int64) error UpdateApp(address []byte, maxRelays string, stakedAmount string, chainsToUpdate []string) error diff --git a/shared/types/genesis/validator.go b/shared/types/genesis/validator.go index d40406af8..0030f4452 100644 --- a/shared/types/genesis/validator.go +++ b/shared/types/genesis/validator.go @@ -7,6 +7,9 @@ import ( "google.golang.org/protobuf/encoding/protojson" ) +// TODO_IN_THIS_COMMIT: See https://github.com/pokt-network/pocket/pull/139/files to remove this shit + + // HACK: Since the protocol actor protobufs (e.g. validator, fisherman, etc) use `bytes` for some // fields (e.g. `address`, `output`, `publicKey`), we need to use a helper struct to unmarshal the // the types when they are defined via json (e.g. genesis file, testing configurations, etc...). diff --git a/utility/block.go b/utility/block.go index 8d57dcbac..3a8d2e501 100644 --- a/utility/block.go +++ b/utility/block.go @@ -74,6 +74,9 @@ func (u *UtilityContext) EndBlock(proposer []byte) types.Error { if err := u.BeginUnstakingMaxPaused(); err != nil { return err } + if err := u.updateStateCommitment(); err != nil { + return err + } return nil } diff --git a/utility/state.go b/utility/state.go new file mode 100644 index 000000000..4f128ac2a --- /dev/null +++ b/utility/state.go @@ -0,0 +1,44 @@ +package utility + +import ( + "fmt" + "log" + + "github.com/pokt-network/pocket/shared/types" + typesUtil "github.com/pokt-network/pocket/utility/types" +) + +func (u *UtilityContext) updateStateCommitment() types.Error { + // Update the Merkle Tree associated with each actor + for _, actorType := range typesUtil.ActorTypes { + // Need to get all the actors updated at this height + switch actorType { + case typesUtil.ActorType_App: + apps, err := u.Context.GetAppsUpdated(u.LatestHeight) // shouldn't need to pass in a height here + if err != nil { + return types.NewError(types.Code(42), "Couldn't figure out apps updated") + } + fmt.Println("apps: ", apps) + case typesUtil.ActorType_Val: + fallthrough + case typesUtil.ActorType_Fish: + fallthrough + case typesUtil.ActorType_Node: + fallthrough + default: + log.Fatalf("Not supported yet") + } + } + + // TODO: Update Merkle Tree for Accounts + + // TODO: Update Merkle Tree for Pools + + // TODO:Update Merkle Tree for Blocks + + // TODO: Update Merkle Tree for Params + + // TODO: Update Merkle Tree for Flags + + return nil +} From b0bbbb4e0fed1ff1c461dfb205e45dac16a8d7e0 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 2 Aug 2022 20:55:00 -0700 Subject: [PATCH 2/7] Added celestiaorg/smt tree --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index fca0bc766..11300d8ae 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,7 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.2 github.com/golang/snappy v0.0.3 // indirect github.com/google/flatbuffers v1.12.1 // indirect github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect From b52d59a0e4eeceebcd8a351f2f24be25fc718082 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 2 Aug 2022 21:49:03 -0700 Subject: [PATCH 3/7] Added updating merkle tree using app protos --- go.mod | 1 + go.sum | 2 ++ persistence/application.go | 13 +++++++ persistence/db.go | 6 ++-- persistence/module.go | 51 ++++++++++++++++++++++++++++ persistence/pre_persistence/app.go | 5 +++ shared/modules/persistence_module.go | 4 ++- utility/state.go | 5 +-- 8 files changed, 82 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 11300d8ae..3b51bf12d 100644 --- a/go.mod +++ b/go.mod @@ -58,6 +58,7 @@ require ( require ( filippo.io/edwards25519 v1.0.0-rc.1 // indirect + github.com/celestiaorg/smt v0.2.1-0.20220414134126-dba215ccb884 // indirect github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect diff --git a/go.sum b/go.sum index 786bc0d0c..873a26c37 100644 --- a/go.sum +++ b/go.sum @@ -21,6 +21,8 @@ github.com/ProtonMail/go-ecvrf v0.0.1/go.mod h1:fhZbiRYn62/JGnBG2NGwCx0oT+gr/+I5 github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +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= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= diff --git a/persistence/application.go b/persistence/application.go index e2cf8ee13..ccc1a5ff9 100644 --- a/persistence/application.go +++ b/persistence/application.go @@ -15,6 +15,19 @@ func (p PostgresContext) GetAppExists(address []byte, height int64) (exists bool return p.GetExists(schema.ApplicationActor, address, height) } +func (p PostgresContext) UpdateAppTree(apps [][]byte) error { + for _, app := range apps { + appProto := typesGenesis.App{} + if err := proto.Unmarshal(app, &appProto); err != nil { + return err + } + if _, err := p.MerkleTrees[AppMerkleTree].Update(appProto.Address, app); err != nil { + return err + } + } + return nil +} + func (p PostgresContext) GetAppsUpdated(height int64) (apps [][]byte, err error) { actors, err := p.GetActorsUpdated(schema.ApplicationActor, height) if err != nil { diff --git a/persistence/db.go b/persistence/db.go index 56e6be62c..a144d1ce0 100644 --- a/persistence/db.go +++ b/persistence/db.go @@ -7,6 +7,7 @@ import ( "math/rand" "time" + "github.com/celestiaorg/smt" "github.com/jackc/pgx/v4" "github.com/pokt-network/pocket/persistence/kvstore" "github.com/pokt-network/pocket/persistence/schema" @@ -35,8 +36,9 @@ type PostgresContext struct { // IMPROVE: Depending on how the use of `PostgresContext` evolves, we may be able to get // access to these directly via the postgres module. - PostgresDB *pgx.Conn - BlockStore kvstore.KVStore + PostgresDB *pgx.Conn + BlockStore kvstore.KVStore + MerkleTrees map[MerkleTree]*smt.SparseMerkleTree } func (pg *PostgresContext) GetCtxAndConnection() (context.Context, *pgx.Conn, error) { diff --git a/persistence/module.go b/persistence/module.go index 49f21d627..f5ed6d152 100644 --- a/persistence/module.go +++ b/persistence/module.go @@ -1,8 +1,10 @@ package persistence import ( + "crypto/sha256" "log" + "github.com/celestiaorg/smt" "github.com/jackc/pgx/v4" "github.com/pokt-network/pocket/persistence/kvstore" "github.com/pokt-network/pocket/shared/config" @@ -46,6 +48,20 @@ func (p PostgresContext) SetValidatorStakeAmount(address []byte, stakeAmount str panic("TODO: implement PostgresContext.SetValidatorStakeAmount") } +type MerkleTree float64 + +const ( + AppMerkleTree MerkleTree = iota + ValMerkleTree + FishMerkleTree + ServiceNodeMerkleTree + AccountMerkleTree + PoolMerkleTree + BlocksMerkleTree + ParamsMerkleTree + FlagsMerkleTree +) + type persistenceModule struct { bus modules.Bus @@ -56,6 +72,8 @@ type persistenceModule struct { blockStore kvstore.KVStore // A mapping of context IDs to persistence contexts contexts map[contextId]modules.PersistenceContext + // Merkle trees + trees map[MerkleTree]*smt.SparseMerkleTree } type contextId uint64 @@ -77,6 +95,7 @@ func Create(c *config.Config) (modules.PersistenceModule, error) { postgresConn: postgresDb, blockStore: blockStore, contexts: make(map[contextId]modules.PersistenceContext), + trees: make(map[MerkleTree]*smt.SparseMerkleTree), }, nil } @@ -98,6 +117,10 @@ func (p *persistenceModule) Start() error { log.Println("Loading state from previous state...") } + if err != p.initializeTrees() { + return err + } + return nil } @@ -159,3 +182,31 @@ func (m *persistenceModule) shouldHydrateGenesisDb() (bool, error) { return m.blockStore.Exists(heightToBytes(int64(maxHeight))) } + +func (m *persistenceModule) initializeTrees() error { + // Initialise two new key-value store to store the nodes and values of the tree + nodeStore := smt.NewSimpleMap() + valueStore := smt.NewSimpleMap() + + // Initialise the tree + tree := smt.NewSparseMerkleTree(nodeStore, valueStore, sha256.New()) + + m.trees[AppMerkleTree] = tree + + return nil +} + +// // Update the key "foo" with the value "bar" +// _, _ = tree.Update([]byte("foo"), []byte("bar")) + +// // Generate a Merkle proof for foo=bar +// proof, _ := tree.Prove([]byte("foo")) +// root := tree.Root() // We also need the current tree root for the proof + +// // Verify the Merkle proof for foo=bar +// if smt.VerifyProof(proof, root, []byte("foo"), []byte("bar"), sha256.New()) { +// fmt.Println("Proof verification succeeded.") +// } else { +// fmt.Println("Proof verification failed.") +// } +// } diff --git a/persistence/pre_persistence/app.go b/persistence/pre_persistence/app.go index e0de24234..1d1b1a9ae 100644 --- a/persistence/pre_persistence/app.go +++ b/persistence/pre_persistence/app.go @@ -16,6 +16,11 @@ func (m *PrePersistenceContext) GetAppsUpdated(height int64) ([][]byte, error) { return nil, nil } +func (m *PrePersistenceContext) UpdateAppTree([][]byte) error { + // Not implemented + return nil +} + func (m *PrePersistenceContext) GetAppExists(address []byte, height int64) (exists bool, err error) { db := m.Store() key := append(AppPrefixKey, address...) diff --git a/shared/modules/persistence_module.go b/shared/modules/persistence_module.go index d9b6fd4e4..a03deb5d4 100644 --- a/shared/modules/persistence_module.go +++ b/shared/modules/persistence_module.go @@ -71,7 +71,6 @@ type PersistenceContext interface { SetAccountAmount(address []byte, amount string) error // TECHDEBT(team): Delete this function // App Operations - GetAppsUpdated(height int64) ([][]byte, error) // Returns the apps updates at the given height GetAppExists(address []byte, height int64) (exists bool, err error) InsertApp(address []byte, publicKey []byte, output []byte, paused bool, status int, maxRelays string, stakedAmount string, chains []string, pausedHeight int64, unstakingHeight int64) error UpdateApp(address []byte, maxRelays string, stakedAmount string, chainsToUpdate []string) error @@ -85,6 +84,9 @@ type PersistenceContext interface { SetAppStatusAndUnstakingHeightIfPausedBefore(pausedBeforeHeight, unstakingHeight int64, status int) error SetAppPauseHeight(address []byte, height int64) error GetAppOutputAddress(operator []byte, height int64) (output []byte, err error) + // App Operations - For Tree Merkling + GetAppsUpdated(height int64) ([][]byte, error) // Returns the apps updates at the given height + UpdateAppTree([][]byte) error // ServiceNode Operations GetServiceNodeExists(address []byte, height int64) (exists bool, err error) diff --git a/utility/state.go b/utility/state.go index 4f128ac2a..b75e02287 100644 --- a/utility/state.go +++ b/utility/state.go @@ -1,7 +1,6 @@ package utility import ( - "fmt" "log" "github.com/pokt-network/pocket/shared/types" @@ -18,7 +17,9 @@ func (u *UtilityContext) updateStateCommitment() types.Error { if err != nil { return types.NewError(types.Code(42), "Couldn't figure out apps updated") } - fmt.Println("apps: ", apps) + if err := u.Context.UpdateAppTree(apps); err != nil { + return nil + } case typesUtil.ActorType_Val: fallthrough case typesUtil.ActorType_Fish: From 24f358ada37154b8799e6d48cc15c4320ef2b3c0 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Fri, 5 Aug 2022 23:14:07 -0400 Subject: [PATCH 4/7] WIP - trees --- Makefile | 5 ++ persistence/application.go | 17 ++-- persistence/block.go | 8 ++ persistence/db.go | 4 +- persistence/kvstore/kvstore.go | 11 ++- persistence/module.go | 66 +++----------- persistence/pre_persistence/app.go | 8 +- persistence/state.go | 124 +++++++++++++++++++++++++++ persistence/state_test.go | 15 ++++ persistence/test/state_hash_test.go | 7 -- shared/modules/persistence_module.go | 2 +- utility/state.go | 45 ---------- 12 files changed, 191 insertions(+), 121 deletions(-) create mode 100644 persistence/state.go create mode 100644 persistence/state_test.go delete mode 100644 persistence/test/state_hash_test.go delete mode 100644 utility/state.go diff --git a/Makefile b/Makefile index 61c5621c6..9c59a435c 100644 --- a/Makefile +++ b/Makefile @@ -221,6 +221,11 @@ test_sortition: test_persistence: go test ${VERBOSE_TEST} -p=1 ./persistence/... +.PHONY: test_persistence_state_hash +## Run all go unit tests in the Persistence module +test_persistence_state_hash: + go test -run StateHash ${VERBOSE_TEST} -p=1 ./persistence/... + .PHONY: benchmark_sortition ## Benchmark the Sortition library benchmark_sortition: diff --git a/persistence/application.go b/persistence/application.go index ccc1a5ff9..98d62fd7f 100644 --- a/persistence/application.go +++ b/persistence/application.go @@ -28,7 +28,9 @@ func (p PostgresContext) UpdateAppTree(apps [][]byte) error { return nil } -func (p PostgresContext) GetAppsUpdated(height int64) (apps [][]byte, err error) { +// TODO_IN_THIS_COMMIT: Not exposed via interface yet +// func (p PostgresContext) getAppsUpdated(height int64) (apps [][]byte, err error) { +func (p PostgresContext) getAppsUpdated(height int64) (apps []*typesGenesis.App, err error) { actors, err := p.GetActorsUpdated(schema.ApplicationActor, height) if err != nil { return nil, err @@ -36,7 +38,7 @@ func (p PostgresContext) GetAppsUpdated(height int64) (apps [][]byte, err error) for _, actor := range actors { // This breaks the pattern of protos in persistence - app := typesGenesis.App{ + app := &typesGenesis.App{ Address: []byte(actor.Address), PublicKey: []byte(actor.PublicKey), // Paused: actor.Paused, @@ -48,11 +50,12 @@ func (p PostgresContext) GetAppsUpdated(height int64) (apps [][]byte, err error) UnstakingHeight: actor.UnstakingHeight, Output: []byte(actor.OutputAddress), } - appBytes, err := proto.Marshal(&app) - if err != nil { - return nil, err - } - apps = append(apps, appBytes) + // appBytes, err := proto.Marshal(&app) + // if err != nil { + // return nil, err + // } + // apps = append(apps, appBytes) + apps = append(apps, app) } return } diff --git a/persistence/block.go b/persistence/block.go index fc9c3eceb..8055ee566 100644 --- a/persistence/block.go +++ b/persistence/block.go @@ -4,10 +4,18 @@ import ( "encoding/binary" "encoding/hex" "log" + "os" "github.com/pokt-network/pocket/persistence/schema" ) +func (p *persistenceModule) shouldLoadBlockStore() bool { + if _, err := os.Stat(p.GetBus().GetConfig().Persistence.BlockStorePath); err == nil { + return true + } + return false +} + // OPTIMIZE(team): get from blockstore or keep in cache/memory func (p PostgresContext) GetLatestBlockHeight() (latestHeight int64, err error) { ctx, conn, err := p.GetCtxAndConnection() diff --git a/persistence/db.go b/persistence/db.go index a144d1ce0..2a2f411a6 100644 --- a/persistence/db.go +++ b/persistence/db.go @@ -37,8 +37,8 @@ type PostgresContext struct { // IMPROVE: Depending on how the use of `PostgresContext` evolves, we may be able to get // access to these directly via the postgres module. PostgresDB *pgx.Conn - BlockStore kvstore.KVStore - MerkleTrees map[MerkleTree]*smt.SparseMerkleTree + BlockStore kvstore.KVStore // REARCHITECT_IN_THIS_COMMIT: This is a passthrough from the module (i.e. not context) + MerkleTrees map[MerkleTree]*smt.SparseMerkleTree // REARCHITECT_IN_THIS_COMMIT: This is a passthrough from the module (i.e. not context) } func (pg *PostgresContext) GetCtxAndConnection() (context.Context, *pgx.Conn, error) { diff --git a/persistence/kvstore/kvstore.go b/persistence/kvstore/kvstore.go index b598038f9..ec00c5427 100644 --- a/persistence/kvstore/kvstore.go +++ b/persistence/kvstore/kvstore.go @@ -1,6 +1,7 @@ package kvstore import ( + "errors" "log" badger "github.com/dgraph-io/badger/v3" @@ -19,11 +20,19 @@ type KVStore interface { var _ KVStore = &badgerKVStore{} +var ( + ErrKVStoreExists = errors.New("kvstore already exists") + ErrKVStoreNotExists = errors.New("kvstore does not exist") +) + type badgerKVStore struct { db *badger.DB } -func NewKVStore(path string) (KVStore, error) { +// REFACTOR: Loads or creates a badgerDb at `path`. This may potentially need to be refactored +// into `NewKVStore` and `LoadKVStore` depending on how state sync evolves by leveraging `os.Stat` +// on the file path. +func OpenKVStore(path string) (KVStore, error) { db, err := badger.Open(badger.DefaultOptions(path)) if err != nil { return nil, err diff --git a/persistence/module.go b/persistence/module.go index f5ed6d152..08346c423 100644 --- a/persistence/module.go +++ b/persistence/module.go @@ -1,7 +1,6 @@ package persistence import ( - "crypto/sha256" "log" "github.com/celestiaorg/smt" @@ -48,20 +47,6 @@ func (p PostgresContext) SetValidatorStakeAmount(address []byte, stakeAmount str panic("TODO: implement PostgresContext.SetValidatorStakeAmount") } -type MerkleTree float64 - -const ( - AppMerkleTree MerkleTree = iota - ValMerkleTree - FishMerkleTree - ServiceNodeMerkleTree - AccountMerkleTree - PoolMerkleTree - BlocksMerkleTree - ParamsMerkleTree - FlagsMerkleTree -) - type persistenceModule struct { bus modules.Bus @@ -84,7 +69,7 @@ func Create(c *config.Config) (modules.PersistenceModule, error) { return nil, err } - blockStore, err := kvstore.NewKVStore(c.Persistence.BlockStorePath) + blockStore, err := kvstore.OpenKVStore(c.Persistence.BlockStorePath) if err != nil { return nil, err } @@ -102,24 +87,25 @@ func Create(c *config.Config) (modules.PersistenceModule, error) { func (p *persistenceModule) Start() error { log.Println("Starting persistence module...") - shouldHydrateGenesis := false - shouldHydrateGenesis, err := p.shouldHydrateGenesisDb() - if err != nil { - return err - } - - if shouldHydrateGenesis { + if shouldHydrateGenesis, err := p.shouldHydrateGenesisDb(); err != nil { + return nil + } else if shouldHydrateGenesis { + log.Println("Hydrating genesis state...") if err := p.hydrateGenesisDbState(); err != nil { return err } - log.Println("Hydrating genesis state...") } else { - log.Println("Loading state from previous state...") + log.Println("TODO: Finish loading previous state...") + } - if err != p.initializeTrees() { + // DISCUSS_IN_THIS_COMMIT: We've been using the module function pattern, but this is cleaner and easier to test + trees, err := initializeTrees() + if err != nil { return err } + // TODO_IN_THIS_COMMIT: load trees from state + p.trees = trees return nil } @@ -182,31 +168,3 @@ func (m *persistenceModule) shouldHydrateGenesisDb() (bool, error) { return m.blockStore.Exists(heightToBytes(int64(maxHeight))) } - -func (m *persistenceModule) initializeTrees() error { - // Initialise two new key-value store to store the nodes and values of the tree - nodeStore := smt.NewSimpleMap() - valueStore := smt.NewSimpleMap() - - // Initialise the tree - tree := smt.NewSparseMerkleTree(nodeStore, valueStore, sha256.New()) - - m.trees[AppMerkleTree] = tree - - return nil -} - -// // Update the key "foo" with the value "bar" -// _, _ = tree.Update([]byte("foo"), []byte("bar")) - -// // Generate a Merkle proof for foo=bar -// proof, _ := tree.Prove([]byte("foo")) -// root := tree.Root() // We also need the current tree root for the proof - -// // Verify the Merkle proof for foo=bar -// if smt.VerifyProof(proof, root, []byte("foo"), []byte("bar"), sha256.New()) { -// fmt.Println("Proof verification succeeded.") -// } else { -// fmt.Println("Proof verification failed.") -// } -// } diff --git a/persistence/pre_persistence/app.go b/persistence/pre_persistence/app.go index 1d1b1a9ae..cad4d4ce2 100644 --- a/persistence/pre_persistence/app.go +++ b/persistence/pre_persistence/app.go @@ -11,10 +11,10 @@ import ( "google.golang.org/protobuf/proto" ) -func (m *PrePersistenceContext) GetAppsUpdated(height int64) ([][]byte, error) { - // Not implemented - return nil, nil -} +// func (m *PrePersistenceContext) GetAppsUpdated(height int64) ([][]byte, error) { +// // Not implemented +// return nil, nil +// } func (m *PrePersistenceContext) UpdateAppTree([][]byte) error { // Not implemented diff --git a/persistence/state.go b/persistence/state.go new file mode 100644 index 000000000..ffab52aea --- /dev/null +++ b/persistence/state.go @@ -0,0 +1,124 @@ +package persistence + +import ( + "bytes" + "crypto/sha256" + "log" + "sort" + + "github.com/celestiaorg/smt" + "github.com/pokt-network/pocket/shared/types" + "google.golang.org/protobuf/proto" +) + +type MerkleTree float64 + +// A work-in-progress list of all the trees we need to update to maintain the overall state +const ( + AppMerkleTree MerkleTree = iota + ValMerkleTree + FishMerkleTree + ServiceNodeMerkleTree + AccountMerkleTree + PoolMerkleTree + BlocksMerkleTree + ParamsMerkleTree + FlagsMerkleTree + lastMerkleTree // Used for iteration purposes only - see https://stackoverflow.com/a/64178235/768439 +) + +func initializeTrees() (map[MerkleTree]*smt.SparseMerkleTree, error) { + // We need a separate Merkle tree for each type of actor or storage + trees := make(map[MerkleTree]*smt.SparseMerkleTree, int(lastMerkleTree)) + + for treeType := MerkleTree(0); treeType < lastMerkleTree; treeType++ { + // Initialize two new key-value store to store the nodes and values of the tree + nodeStore := smt.NewSimpleMap() + valueStore := smt.NewSimpleMap() + + trees[treeType] = smt.NewSparseMerkleTree(nodeStore, valueStore, sha256.New()) + } + return trees, nil +} + +func loadTrees(map[MerkleTree]*smt.SparseMerkleTree, error) { + +} + +func (p *PostgresContext) updateStateCommitment() ([]byte, error) { + for treeType := MerkleTree(0); treeType < lastMerkleTree; treeType++ { + switch treeType { + case AppMerkleTree: + apps, err := p.getAppsUpdated(p.Height) + if err != nil { + return nil, types.NewError(types.Code(42), "Couldn't figure out apps updated") // TODO_IN_THIS_COMMIT + } + for _, app := range apps { + // OPTIMIZE: Do we want to store the serialized bytes or a hash of it in the KV store? + appBytes, err := proto.Marshal(app) + if err != nil { + return nil, err + } + if _, err := p.MerkleTrees[treeType].Update(app.Address, appBytes); err != nil { + return nil, err + } + } + default: + log.Fatalln("Not handeled uet in state commitment update") + } + } + + // Get the root of each Merkle Tree + roots := make([][]byte, 0) + for treeType := MerkleTree(0); treeType < lastMerkleTree; treeType++ { + roots = append(roots, p.MerkleTrees[treeType].Root()) + } + + // Sort the merkle roots lexicographically + sort.Slice(roots, func(r1, r2 int) bool { + return bytes.Compare(roots[r1], roots[r2]) < 0 + }) + + // Get the state hash + rootsConcat := bytes.Join(roots, []byte{}) + stateHash := sha256.Sum256(rootsConcat) + + return stateHash[:], nil +} + +// computeStateHash(root) +// context := p. +// Update the Merkle Tree associated with each actor +// for _, actorType := range typesUtil.ActorTypes { +// // Need to get all the actors updated at this height +// switch actorType { +// case typesUtil.ActorType_App: +// apps, err := u.Context.GetAppsUpdated(u.LatestHeight) // shouldn't need to pass in a height here +// if err != nil { +// return types.NewError(types.Code(42), "Couldn't figure out apps updated") +// } +// if err := u.Context.UpdateAppTree(apps); err != nil { +// return nil +// } +// case typesUtil.ActorType_Val: +// fallthrough +// case typesUtil.ActorType_Fish: +// fallthrough +// case typesUtil.ActorType_Node: +// fallthrough +// default: +// log.Fatalf("Actor type not supported: %s", actorType) +// } +// } + +// TODO: Update Merkle Tree for Accounts + +// TODO: Update Merkle Tree for Pools + +// TODO:Update Merkle Tree for Blocks + +// TODO: Update Merkle Tree for Params + +// TODO: Update Merkle Tree for Flags + +// return nil diff --git a/persistence/state_test.go b/persistence/state_test.go new file mode 100644 index 000000000..9570f4c00 --- /dev/null +++ b/persistence/state_test.go @@ -0,0 +1,15 @@ +package persistence + +import "testing" + +func TestStateHash_InitializeTrees(t *testing.T) { + +} + +func TestStateHash_LoadTrees(t *testing.T) { + +} + +func TestStateHash_ComputeStateHash(t *testing.T) { + +} diff --git a/persistence/test/state_hash_test.go b/persistence/test/state_hash_test.go deleted file mode 100644 index c57c2c699..000000000 --- a/persistence/test/state_hash_test.go +++ /dev/null @@ -1,7 +0,0 @@ -package test - -import "testing" - -func TestSomething(t *testing.T) { - -} diff --git a/shared/modules/persistence_module.go b/shared/modules/persistence_module.go index a03deb5d4..a3a7242d4 100644 --- a/shared/modules/persistence_module.go +++ b/shared/modules/persistence_module.go @@ -85,7 +85,7 @@ type PersistenceContext interface { SetAppPauseHeight(address []byte, height int64) error GetAppOutputAddress(operator []byte, height int64) (output []byte, err error) // App Operations - For Tree Merkling - GetAppsUpdated(height int64) ([][]byte, error) // Returns the apps updates at the given height + // GetAppsUpdated(height int64) ([][]byte, error) // Returns the apps updates at the given height UpdateAppTree([][]byte) error // ServiceNode Operations diff --git a/utility/state.go b/utility/state.go deleted file mode 100644 index b75e02287..000000000 --- a/utility/state.go +++ /dev/null @@ -1,45 +0,0 @@ -package utility - -import ( - "log" - - "github.com/pokt-network/pocket/shared/types" - typesUtil "github.com/pokt-network/pocket/utility/types" -) - -func (u *UtilityContext) updateStateCommitment() types.Error { - // Update the Merkle Tree associated with each actor - for _, actorType := range typesUtil.ActorTypes { - // Need to get all the actors updated at this height - switch actorType { - case typesUtil.ActorType_App: - apps, err := u.Context.GetAppsUpdated(u.LatestHeight) // shouldn't need to pass in a height here - if err != nil { - return types.NewError(types.Code(42), "Couldn't figure out apps updated") - } - if err := u.Context.UpdateAppTree(apps); err != nil { - return nil - } - case typesUtil.ActorType_Val: - fallthrough - case typesUtil.ActorType_Fish: - fallthrough - case typesUtil.ActorType_Node: - fallthrough - default: - log.Fatalf("Not supported yet") - } - } - - // TODO: Update Merkle Tree for Accounts - - // TODO: Update Merkle Tree for Pools - - // TODO:Update Merkle Tree for Blocks - - // TODO: Update Merkle Tree for Params - - // TODO: Update Merkle Tree for Flags - - return nil -} From a493f1f1870b860df64e7545fb6e8711e623d5d1 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Sat, 6 Aug 2022 19:27:19 -0400 Subject: [PATCH 5/7] Update go.mod --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 3b51bf12d..65f7bd77d 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( ) require ( + github.com/celestiaorg/smt v0.2.1-0.20220414134126-dba215ccb884 github.com/dgraph-io/badger/v3 v3.2103.2 github.com/iancoleman/strcase v0.2.0 ) @@ -58,7 +59,6 @@ require ( require ( filippo.io/edwards25519 v1.0.0-rc.1 // indirect - github.com/celestiaorg/smt v0.2.1-0.20220414134126-dba215ccb884 // indirect github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect From fce0b424611042392ebb43f6a39314f014e19472 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Sat, 6 Aug 2022 20:04:32 -0400 Subject: [PATCH 6/7] Got tests to pass after self review --- consensus/module.go | 2 +- persistence/application.go | 10 ++-- persistence/block.go | 3 +- persistence/context.go | 17 +++++- persistence/db.go | 5 +- persistence/kvstore/kvstore.go | 18 ++++-- persistence/module.go | 5 +- persistence/pre_persistence/persistence.go | 5 ++ persistence/shared_sql.go | 13 ++++- persistence/state.go | 64 +++++++--------------- shared/modules/persistence_module.go | 1 + utility/block.go | 4 +- 12 files changed, 79 insertions(+), 68 deletions(-) diff --git a/consensus/module.go b/consensus/module.go index 832ce5f0e..1008a715c 100644 --- a/consensus/module.go +++ b/consensus/module.go @@ -243,7 +243,7 @@ func (m *consensusModule) handleHotstuffMessage(msg *typesCons.HotstuffMessage) } func (m *consensusModule) AppHash() string { - return m.appHash + return m.appHash // TODO: This is a problem } func (m *consensusModule) CurrentHeight() uint64 { diff --git a/persistence/application.go b/persistence/application.go index 98d62fd7f..c3a13e0f2 100644 --- a/persistence/application.go +++ b/persistence/application.go @@ -28,8 +28,6 @@ func (p PostgresContext) UpdateAppTree(apps [][]byte) error { return nil } -// TODO_IN_THIS_COMMIT: Not exposed via interface yet -// func (p PostgresContext) getAppsUpdated(height int64) (apps [][]byte, err error) { func (p PostgresContext) getAppsUpdated(height int64) (apps []*typesGenesis.App, err error) { actors, err := p.GetActorsUpdated(schema.ApplicationActor, height) if err != nil { @@ -37,12 +35,14 @@ func (p PostgresContext) getAppsUpdated(height int64) (apps []*typesGenesis.App, } for _, actor := range actors { - // This breaks the pattern of protos in persistence + // DISCUSS_IN_THIS_COMMIT: This breaks the pattern of protos in persistence. + // - Is it okay? + // - Do we embed this logic in `UpdateAppTree` app := &typesGenesis.App{ Address: []byte(actor.Address), PublicKey: []byte(actor.PublicKey), - // Paused: actor.Paused, - // Status: actor.Status, + // Paused: actor.Paused, // DISCUSS_IN_THIS_COMMIT: Is this just a check for pause height = -1? + // Status: actor.Status, // TODO_IN_THIS_COMMIT: Use logic from `GetActorStatus` without an extra query Chains: actor.Chains, MaxRelays: actor.ActorSpecificParam, StakedTokens: actor.StakedTokens, diff --git a/persistence/block.go b/persistence/block.go index 8055ee566..2f01afeca 100644 --- a/persistence/block.go +++ b/persistence/block.go @@ -9,6 +9,7 @@ import ( "github.com/pokt-network/pocket/persistence/schema" ) +// TODO_IN_THIS_COMMIT: Out of scope so we might just need to do this as part of state sync func (p *persistenceModule) shouldLoadBlockStore() bool { if _, err := os.Stat(p.GetBus().GetConfig().Persistence.BlockStorePath); err == nil { return true @@ -61,7 +62,7 @@ func (p PostgresContext) StoreBlock(blockProtoBytes []byte) error { // INVESTIGATE: Note that we are writing this directly to the blockStore. Depending on how // the use of the PostgresContext evolves, we may need to write this to `ContextStore` and copy // over to `BlockStore` when the block is committed. - return p.BlockStore.Put(heightToBytes(p.Height), blockProtoBytes) + return p.BlockStore.Set(heightToBytes(p.Height), blockProtoBytes) } func (p PostgresContext) InsertBlock(height uint64, hash string, proposerAddr []byte, quorumCert []byte) error { diff --git a/persistence/context.go b/persistence/context.go index 1cbf22739..9809bbd2c 100644 --- a/persistence/context.go +++ b/persistence/context.go @@ -14,9 +14,17 @@ func (p PostgresContext) RollbackToSavePoint(bytes []byte) error { return nil } +func (p PostgresContext) UpdateAppHash() ([]byte, error) { + if _, err := p.updateStateHash(); err != nil { + return nil, err + } + return p.StateHash, nil +} + func (p PostgresContext) AppHash() ([]byte, error) { - log.Println("TODO: AppHash not implemented") - return []byte("A real app hash, I am not"), nil + // log.Println("TODO: AppHash not implemented") + // return []byte("A real app hash, I am not"), n + return p.StateHash, nil } func (p PostgresContext) Reset() error { @@ -24,8 +32,11 @@ func (p PostgresContext) Reset() error { } func (p PostgresContext) Commit() error { - // HACK: The data has already been written to the postgres DB, so what should we do here? The idea I have is: log.Println("TODO: Postgres context commit is currently a NOOP") + // HACK: The data has already been written to the postgres DB, so what should we do here? The idea I have is: + // if _, err := p.updateStateHash(); err != nil { + // return err + // } return nil } diff --git a/persistence/db.go b/persistence/db.go index 2a2f411a6..469f7abf7 100644 --- a/persistence/db.go +++ b/persistence/db.go @@ -33,12 +33,13 @@ var _ modules.PersistenceContext = &PostgresContext{} type PostgresContext struct { Height int64 ContextStore kvstore.KVStore + StateHash []byte // IMPROVE: Depending on how the use of `PostgresContext` evolves, we may be able to get // access to these directly via the postgres module. PostgresDB *pgx.Conn - BlockStore kvstore.KVStore // REARCHITECT_IN_THIS_COMMIT: This is a passthrough from the module (i.e. not context) - MerkleTrees map[MerkleTree]*smt.SparseMerkleTree // REARCHITECT_IN_THIS_COMMIT: This is a passthrough from the module (i.e. not context) + BlockStore kvstore.KVStore // REARCHITECT_IN_THIS_COMMIT: This is a passthrough from the persistence module (i.e. not context) + MerkleTrees map[MerkleTree]*smt.SparseMerkleTree // REARCHITECT_IN_THIS_COMMIT: This is a passthrough from the persistence module (i.e. not context) } func (pg *PostgresContext) GetCtxAndConnection() (context.Context, *pgx.Conn, error) { diff --git a/persistence/kvstore/kvstore.go b/persistence/kvstore/kvstore.go index ec00c5427..7eb632089 100644 --- a/persistence/kvstore/kvstore.go +++ b/persistence/kvstore/kvstore.go @@ -4,21 +4,26 @@ import ( "errors" "log" + "github.com/celestiaorg/smt" badger "github.com/dgraph-io/badger/v3" ) +// TODO_IN_THIS_COMMIT: We might be able to remove the `KVStore` interface altogether if we end up using smt.MapStore type KVStore interface { // Lifecycle methods Stop() error - // Accessors - Put(key []byte, value []byte) error - Get(key []byte) ([]byte, error) Exists(key []byte) (bool, error) ClearAll() error + + // Same interface as in `smt.MapStore`` + Set(key []byte, value []byte) error + Get(key []byte) ([]byte, error) + Delete(key []byte) error } var _ KVStore = &badgerKVStore{} +var _ smt.MapStore = &badgerKVStore{} var ( ErrKVStoreExists = errors.New("kvstore already exists") @@ -48,7 +53,7 @@ func NewMemKVStore() KVStore { return badgerKVStore{db: db} } -func (store badgerKVStore) Put(key []byte, value []byte) error { +func (store badgerKVStore) Set(key []byte, value []byte) error { txn := store.db.NewTransaction(true) defer txn.Discard() @@ -85,6 +90,11 @@ func (store badgerKVStore) Get(key []byte) ([]byte, error) { return value, nil } +func (store badgerKVStore) Delete(key []byte) error { + log.Fatalf("badgerKVStore.Delete not implemented yet") + return nil +} + func (store badgerKVStore) Exists(key []byte) (bool, error) { val, err := store.Get(key) if err != nil { diff --git a/persistence/module.go b/persistence/module.go index 08346c423..3ca47ddcc 100644 --- a/persistence/module.go +++ b/persistence/module.go @@ -99,8 +99,9 @@ func (p *persistenceModule) Start() error { } - // DISCUSS_IN_THIS_COMMIT: We've been using the module function pattern, but this is cleaner and easier to test - trees, err := initializeTrees() + // DISCUSS_IN_THIS_COMMIT: We've been using the module function pattern, but this making `initializeTrees` + // be able to create and/or load trees outside the scope of the persistence module makes it easier to test. + trees, err := newMerkleTrees() if err != nil { return err } diff --git a/persistence/pre_persistence/persistence.go b/persistence/pre_persistence/persistence.go index 7bdb3b7b4..237ba93f1 100644 --- a/persistence/pre_persistence/persistence.go +++ b/persistence/pre_persistence/persistence.go @@ -184,6 +184,11 @@ func (m *PrePersistenceContext) RollbackToSavePoint(bytes []byte) error { return nil } +func (m *PrePersistenceContext) UpdateAppHash() ([]byte, error) { + // log.Fatalf("PrePersistenceContext not implementing UpdateAppHash") + return nil, nil +} + // AppHash creates a unique hash based on the global state object // NOTE: AppHash is an inefficient, arbitrary, mock implementation that enables the functionality // TODO written for replacement, taking any and all better implementation suggestions - even if a temporary measure diff --git a/persistence/shared_sql.go b/persistence/shared_sql.go index 4319ced81..aacfb36e5 100644 --- a/persistence/shared_sql.go +++ b/persistence/shared_sql.go @@ -41,6 +41,7 @@ func (p *PostgresContext) GetExists(actorSchema schema.ProtocolActorSchema, addr return } +// TODO_IN_THIS_COMMIT: Consolidate logic with `GetActor` to reduce code footprint func (p *PostgresContext) GetActorsUpdated(actorSchema schema.ProtocolActorSchema, height int64) (actors []schema.BaseActor, err error) { ctx, conn, err := p.GetCtxAndConnection() if err != nil { @@ -56,9 +57,15 @@ func (p *PostgresContext) GetActorsUpdated(actorSchema schema.ProtocolActorSchem var actor schema.BaseActor for rows.Next() { if err = rows.Scan( - &actor.Address, &actor.PublicKey, &actor.StakedTokens, &actor.ActorSpecificParam, - &actor.OutputAddress, &actor.PausedHeight, &actor.UnstakingHeight, - &actor.Chains, &height, + &actor.Address, + &actor.PublicKey, + &actor.StakedTokens, + &actor.ActorSpecificParam, + &actor.OutputAddress, + &actor.PausedHeight, + &actor.UnstakingHeight, + &actor.Chains, + &height, ); err != nil { return } diff --git a/persistence/state.go b/persistence/state.go index ffab52aea..b685208ba 100644 --- a/persistence/state.go +++ b/persistence/state.go @@ -15,24 +15,26 @@ type MerkleTree float64 // A work-in-progress list of all the trees we need to update to maintain the overall state const ( + // Actors AppMerkleTree MerkleTree = iota ValMerkleTree FishMerkleTree ServiceNodeMerkleTree AccountMerkleTree PoolMerkleTree + // Data / state BlocksMerkleTree ParamsMerkleTree FlagsMerkleTree lastMerkleTree // Used for iteration purposes only - see https://stackoverflow.com/a/64178235/768439 ) -func initializeTrees() (map[MerkleTree]*smt.SparseMerkleTree, error) { +func newMerkleTrees() (map[MerkleTree]*smt.SparseMerkleTree, error) { // We need a separate Merkle tree for each type of actor or storage trees := make(map[MerkleTree]*smt.SparseMerkleTree, int(lastMerkleTree)) for treeType := MerkleTree(0); treeType < lastMerkleTree; treeType++ { - // Initialize two new key-value store to store the nodes and values of the tree + // TODO_IN_THIS_COMMIT: Rather than using `NewSimpleMap`, use a disk based key-value store nodeStore := smt.NewSimpleMap() valueStore := smt.NewSimpleMap() @@ -41,11 +43,18 @@ func initializeTrees() (map[MerkleTree]*smt.SparseMerkleTree, error) { return trees, nil } -func loadTrees(map[MerkleTree]*smt.SparseMerkleTree, error) { - +func loadMerkleTrees(map[MerkleTree]*smt.SparseMerkleTree, error) { + log.Fatalf("loadMerkleTrees not implemented yet") } -func (p *PostgresContext) updateStateCommitment() ([]byte, error) { +// DISCUSS_IN_THIS_COMMIT(drewskey): Thoughts on this approach? +// 1. Retrieves all of the actors / data types updated at the current height +// 2. Updates the Merkle Tree associated with each actor / data type +// - This operation is idempotent so you can call `updateStateHash` as often as you want +// 3. Update the context's "cached" state hash +// 4. Returns the state hash +func (p *PostgresContext) updateStateHash() ([]byte, error) { + // Update all the merkle trees for treeType := MerkleTree(0); treeType < lastMerkleTree; treeType++ { switch treeType { case AppMerkleTree: @@ -54,17 +63,18 @@ func (p *PostgresContext) updateStateCommitment() ([]byte, error) { return nil, types.NewError(types.Code(42), "Couldn't figure out apps updated") // TODO_IN_THIS_COMMIT } for _, app := range apps { - // OPTIMIZE: Do we want to store the serialized bytes or a hash of it in the KV store? appBytes, err := proto.Marshal(app) if err != nil { return nil, err } + // An update results in a create/update that is idempotent if _, err := p.MerkleTrees[treeType].Update(app.Address, appBytes); err != nil { return nil, err } + // TODO_IN_THIS_COMMIT: Add support for `Delete` operations to remove it from the tree } default: - log.Fatalln("Not handeled uet in state commitment update") + log.Fatalln("Not handled yet in state commitment update", treeType) } } @@ -83,42 +93,6 @@ func (p *PostgresContext) updateStateCommitment() ([]byte, error) { rootsConcat := bytes.Join(roots, []byte{}) stateHash := sha256.Sum256(rootsConcat) - return stateHash[:], nil + p.StateHash = stateHash[:] + return p.StateHash, nil } - -// computeStateHash(root) -// context := p. -// Update the Merkle Tree associated with each actor -// for _, actorType := range typesUtil.ActorTypes { -// // Need to get all the actors updated at this height -// switch actorType { -// case typesUtil.ActorType_App: -// apps, err := u.Context.GetAppsUpdated(u.LatestHeight) // shouldn't need to pass in a height here -// if err != nil { -// return types.NewError(types.Code(42), "Couldn't figure out apps updated") -// } -// if err := u.Context.UpdateAppTree(apps); err != nil { -// return nil -// } -// case typesUtil.ActorType_Val: -// fallthrough -// case typesUtil.ActorType_Fish: -// fallthrough -// case typesUtil.ActorType_Node: -// fallthrough -// default: -// log.Fatalf("Actor type not supported: %s", actorType) -// } -// } - -// TODO: Update Merkle Tree for Accounts - -// TODO: Update Merkle Tree for Pools - -// TODO:Update Merkle Tree for Blocks - -// TODO: Update Merkle Tree for Params - -// TODO: Update Merkle Tree for Flags - -// return nil diff --git a/shared/modules/persistence_module.go b/shared/modules/persistence_module.go index a3a7242d4..555075312 100644 --- a/shared/modules/persistence_module.go +++ b/shared/modules/persistence_module.go @@ -37,6 +37,7 @@ type PersistenceContext interface { Commit() error Release() // IMPROVE: Return an error? + UpdateAppHash() ([]byte, error) AppHash() ([]byte, error) GetHeight() (int64, error) diff --git a/utility/block.go b/utility/block.go index 3a8d2e501..4ce17aaf3 100644 --- a/utility/block.go +++ b/utility/block.go @@ -74,8 +74,8 @@ func (u *UtilityContext) EndBlock(proposer []byte) types.Error { if err := u.BeginUnstakingMaxPaused(); err != nil { return err } - if err := u.updateStateCommitment(); err != nil { - return err + if _, err := u.Context.UpdateAppHash(); err != nil { + return types.ErrAppHash(err) } return nil } From 4551843bad85bcf5cd4704f3ec0c852fda078548 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 20 Sep 2022 16:04:50 -0700 Subject: [PATCH 7/7] Resolved some conflicts to make 'make develop_test' work --- go.mod | 2 +- persistence/application.go | 30 +++++----- persistence/block.go | 5 +- persistence/kvstore/kvstore.go | 2 - persistence/module.go | 28 ++++----- persistence/shared_sql.go | 10 ++-- persistence/state.go | 11 +++- shared/indexer/indexer.go | 11 ++-- shared/types/genesis/validator.go | 95 +++++++++++++++---------------- utility/block.go | 2 +- 10 files changed, 100 insertions(+), 96 deletions(-) diff --git a/go.mod b/go.mod index 72201023a..f1507cdd9 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( github.com/dustin/go-humanize v1.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect - github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect + github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/golang/protobuf v1.5.2 github.com/golang/snappy v0.0.3 // indirect github.com/google/flatbuffers v1.12.1 // indirect diff --git a/persistence/application.go b/persistence/application.go index a7f2c4325..cc5a8ed72 100644 --- a/persistence/application.go +++ b/persistence/application.go @@ -5,10 +5,9 @@ import ( "log" "github.com/golang/protobuf/proto" - "github.com/pokt-network/pocket/persistence/schema" - "github.com/pokt-network/pocket/shared/types" + "github.com/pokt-network/pocket/persistence/types" - typesGenesis "github.com/pokt-network/pocket/shared/types/genesis" + "github.com/pokt-network/pocket/shared/modules" ) func (p PostgresContext) GetAppExists(address []byte, height int64) (exists bool, err error) { @@ -17,19 +16,20 @@ func (p PostgresContext) GetAppExists(address []byte, height int64) (exists bool func (p PostgresContext) UpdateAppTree(apps [][]byte) error { for _, app := range apps { - appProto := typesGenesis.App{} + appProto := types.Actor{} if err := proto.Unmarshal(app, &appProto); err != nil { return err } - if _, err := p.MerkleTrees[AppMerkleTree].Update(appProto.Address, app); err != nil { + bzAddr, _ := hex.DecodeString(appProto.Address) + if _, err := p.MerkleTrees[AppMerkleTree].Update(bzAddr, app); err != nil { return err } } return nil } -func (p PostgresContext) getAppsUpdated(height int64) (apps []*typesGenesis.App, err error) { - actors, err := p.GetActorsUpdated(schema.ApplicationActor, height) +func (p PostgresContext) getAppsUpdated(height int64) (apps []*types.Actor, err error) { + actors, err := p.GetActorsUpdated(types.ApplicationActor, height) if err != nil { return nil, err } @@ -38,17 +38,17 @@ func (p PostgresContext) getAppsUpdated(height int64) (apps []*typesGenesis.App, // DISCUSS_IN_THIS_COMMIT: This breaks the pattern of protos in persistence. // - Is it okay? // - Do we embed this logic in `UpdateAppTree` - app := &typesGenesis.App{ - Address: []byte(actor.Address), - PublicKey: []byte(actor.PublicKey), + app := &types.Actor{ + Address: actor.Address, + PublicKey: actor.PublicKey, // Paused: actor.Paused, // DISCUSS_IN_THIS_COMMIT: Is this just a check for pause height = -1? // Status: actor.Status, // TODO_IN_THIS_COMMIT: Use logic from `GetActorStatus` without an extra query - Chains: actor.Chains, - MaxRelays: actor.ActorSpecificParam, - StakedTokens: actor.StakedTokens, + Chains: actor.Chains, + // MaxRelays: actor.ActorSpecificParam, + // StakedTokens: actor.StakedTokens, PausedHeight: actor.PausedHeight, UnstakingHeight: actor.UnstakingHeight, - Output: []byte(actor.OutputAddress), + Output: actor.OutputAddress, } // appBytes, err := proto.Marshal(&app) // if err != nil { @@ -61,7 +61,7 @@ func (p PostgresContext) getAppsUpdated(height int64) (apps []*typesGenesis.App, } func (p PostgresContext) GetApp(address []byte, height int64) (operator, publicKey, stakedTokens, maxRelays, outputAddress string, pauseHeight, unstakingHeight int64, chains []string, err error) { - actor, err := p.GetActor(schema.ApplicationActor, address, height) + actor, err := p.GetActor(types.ApplicationActor, address, height) if err != nil { return } diff --git a/persistence/block.go b/persistence/block.go index 170f81984..a6ba799a8 100644 --- a/persistence/block.go +++ b/persistence/block.go @@ -3,8 +3,9 @@ package persistence import ( "encoding/binary" "encoding/hex" - "github.com/pokt-network/pocket/persistence/types" "log" + + "github.com/pokt-network/pocket/persistence/types" ) // OPTIMIZE(team): get from blockstore or keep in memory @@ -52,7 +53,7 @@ func (p PostgresContext) StoreBlock(blockProtoBytes []byte) error { // INVESTIGATE: Note that we are writing this directly to the blockStore. Depending on how // the use of the PostgresContext evolves, we may need to write this to `ContextStore` and copy // over to `BlockStore` when the block is committed. - return p.DB.Blockstore.Put(heightToBytes(p.Height), blockProtoBytes) + return p.DB.Blockstore.Set(heightToBytes(p.Height), blockProtoBytes) } func (p PostgresContext) InsertBlock(height uint64, hash string, proposerAddr []byte, quorumCert []byte) error { diff --git a/persistence/kvstore/kvstore.go b/persistence/kvstore/kvstore.go index 03ee1b83a..b2b11a5bd 100644 --- a/persistence/kvstore/kvstore.go +++ b/persistence/kvstore/kvstore.go @@ -15,8 +15,6 @@ type KVStore interface { // Accessors // TODO: Add a proper iterator interface - Put(key []byte, value []byte) error - Get(key []byte) ([]byte, error) // TODO: Add pagination for `GetAll` GetAll(prefixKey []byte, descending bool) ([][]byte, error) diff --git a/persistence/module.go b/persistence/module.go index b9007bee4..a8ece5bae 100644 --- a/persistence/module.go +++ b/persistence/module.go @@ -26,7 +26,6 @@ type PersistenceModule struct { postgresURL string nodeSchema string genesisPath string - blockStore kvstore.KVStore // INVESTIGATE: We may need to create a custom `BlockStore` package in the future // TECHDEBT: Need to implement context pooling (for writes), timeouts (for read & writes), etc... writeContext *PostgresContext // only one write context is allowed at a time @@ -37,7 +36,7 @@ type PersistenceModule struct { // INVESTIGATE: We may need to create a custom `BlockStore` package in the future. blockStore kvstore.KVStore // A mapping of context IDs to persistence contexts - contexts map[contextId]modules.PersistenceContext + // contexts map[contextId]modules.PersistenceRWContext // Merkle trees trees map[MerkleTree]*smt.SparseMerkleTree } @@ -81,10 +80,20 @@ func Create(configPath, genesisPath string) (modules.PersistenceModule, error) { genesisPath: genesisPath, blockStore: blockStore, writeContext: nil, - contexts: make(map[contextId]modules.PersistenceContext), - trees: make(map[MerkleTree]*smt.SparseMerkleTree), + // contexts: make(map[contextId]modules.PersistenceContext), + trees: make(map[MerkleTree]*smt.SparseMerkleTree), } + // DISCUSS_IN_THIS_COMMIT: We've been using the module function pattern, but this making `initializeTrees` + // be able to create and/or load trees outside the scope of the persistence module makes it easier to test. + trees, err := newMerkleTrees() + if err != nil { + return nil, err + } + + // TODO_IN_THIS_COMMIT: load trees from state + persistenceMod.trees = trees + // Determine if we should hydrate the genesis db or use the current state of the DB attached if shouldHydrateGenesis, err := persistenceMod.shouldHydrateGenesisDb(); err != nil { return nil, err @@ -98,15 +107,6 @@ func Create(configPath, genesisPath string) (modules.PersistenceModule, error) { log.Println("Loading state from previous state...") } - // DISCUSS_IN_THIS_COMMIT: We've been using the module function pattern, but this making `initializeTrees` - // be able to create and/or load trees outside the scope of the persistence module makes it easier to test. - trees, err := newMerkleTrees() - if err != nil { - return err - } - // TODO_IN_THIS_COMMIT: load trees from state - p.trees = trees - return persistenceMod, nil } @@ -241,7 +241,7 @@ func initializeBlockStore(blockStorePath string) (kvstore.KVStore, error) { if blockStorePath == "" { return kvstore.NewMemKVStore(), nil } - return kvstore.NewKVStore(blockStorePath) + return kvstore.OpenKVStore(blockStorePath) } // TODO(drewsky): Simplify and externalize the logic for whether genesis should be populated and diff --git a/persistence/shared_sql.go b/persistence/shared_sql.go index d0b1a323d..1721ce884 100644 --- a/persistence/shared_sql.go +++ b/persistence/shared_sql.go @@ -45,19 +45,19 @@ func (p *PostgresContext) GetExists(actorSchema types.ProtocolActorSchema, addre } // TODO_IN_THIS_COMMIT: Consolidate logic with `GetActor` to reduce code footprint -func (p *PostgresContext) GetActorsUpdated(actorSchema schema.ProtocolActorSchema, height int64) (actors []schema.BaseActor, err error) { - ctx, conn, err := p.GetCtxAndConnection() +func (p *PostgresContext) GetActorsUpdated(actorSchema types.ProtocolActorSchema, height int64) (actors []types.BaseActor, err error) { + ctx, tx, err := p.DB.GetCtxAndTxn() if err != nil { return } - rows, err := conn.Query(ctx, actorSchema.GetUpdatedAtHeightQuery(height)) + rows, err := tx.Query(ctx, actorSchema.GetUpdatedAtHeightQuery(height)) if err != nil { return nil, err } defer rows.Close() - var actor schema.BaseActor + var actor types.BaseActor for rows.Next() { if err = rows.Scan( &actor.Address, @@ -77,7 +77,7 @@ func (p *PostgresContext) GetActorsUpdated(actorSchema schema.ProtocolActorSchem continue } - chainRows, chainsErr := conn.Query(ctx, actorSchema.GetChainsQuery(actor.Address, height)) + chainRows, chainsErr := tx.Query(ctx, actorSchema.GetChainsQuery(actor.Address, height)) if err != nil { return nil, chainsErr // Why couldn't I just `return` here and use `err`? } diff --git a/persistence/state.go b/persistence/state.go index b685208ba..6e7abd9e7 100644 --- a/persistence/state.go +++ b/persistence/state.go @@ -3,11 +3,12 @@ package persistence import ( "bytes" "crypto/sha256" + "encoding/hex" "log" "sort" "github.com/celestiaorg/smt" - "github.com/pokt-network/pocket/shared/types" + typesUtil "github.com/pokt-network/pocket/utility/types" "google.golang.org/protobuf/proto" ) @@ -60,7 +61,7 @@ func (p *PostgresContext) updateStateHash() ([]byte, error) { case AppMerkleTree: apps, err := p.getAppsUpdated(p.Height) if err != nil { - return nil, types.NewError(types.Code(42), "Couldn't figure out apps updated") // TODO_IN_THIS_COMMIT + return nil, typesUtil.NewError(typesUtil.Code(42), "Couldn't figure out apps updated") // TODO_IN_THIS_COMMIT } for _, app := range apps { appBytes, err := proto.Marshal(app) @@ -68,7 +69,11 @@ func (p *PostgresContext) updateStateHash() ([]byte, error) { return nil, err } // An update results in a create/update that is idempotent - if _, err := p.MerkleTrees[treeType].Update(app.Address, appBytes); err != nil { + addrBz, err := hex.DecodeString(app.Address) + if err != nil { + return nil, err + } + if _, err := p.MerkleTrees[treeType].Update(addrBz, appBytes); err != nil { return nil, err } // TODO_IN_THIS_COMMIT: Add support for `Delete` operations to remove it from the tree diff --git a/shared/indexer/indexer.go b/shared/indexer/indexer.go index 559ca1f6e..3c5d7167a 100644 --- a/shared/indexer/indexer.go +++ b/shared/indexer/indexer.go @@ -5,6 +5,7 @@ package indexer import ( "encoding/hex" "fmt" + "github.com/pokt-network/pocket/shared/codec" "github.com/jordanorelli/lexnum" @@ -111,7 +112,7 @@ type txIndexer struct { } func NewTxIndexer(databasePath string) (TxIndexer, error) { - db, err := kvstore.NewKVStore(databasePath) + db, err := kvstore.OpenKVStore(databasePath) return &txIndexer{ db: db, }, err @@ -198,22 +199,22 @@ func (indexer *txIndexer) get(key []byte) (TxResult, error) { func (indexer *txIndexer) indexByHash(hash, bz []byte) (hashKey []byte, err error) { key := indexer.hashKey(hash) - return key, indexer.db.Put(key, bz) + return key, indexer.db.Set(key, bz) } func (indexer *txIndexer) indexByHeightAndIndex(height int64, index int32, bz []byte) error { - return indexer.db.Put(indexer.heightAndIndexKey(height, index), bz) + return indexer.db.Set(indexer.heightAndIndexKey(height, index), bz) } func (indexer *txIndexer) indexBySender(sender string, bz []byte) error { - return indexer.db.Put(indexer.senderKey(sender), bz) + return indexer.db.Set(indexer.senderKey(sender), bz) } func (indexer *txIndexer) indexByRecipient(recipient string, bz []byte) error { if recipient == "" { return nil } - return indexer.db.Put(indexer.recipientKey(recipient), bz) + return indexer.db.Set(indexer.recipientKey(recipient), bz) } // key helper functions diff --git a/shared/types/genesis/validator.go b/shared/types/genesis/validator.go index 0030f4452..17c2af5fd 100644 --- a/shared/types/genesis/validator.go +++ b/shared/types/genesis/validator.go @@ -1,50 +1,49 @@ package genesis -import ( - "encoding/hex" - "encoding/json" - - "google.golang.org/protobuf/encoding/protojson" -) - -// TODO_IN_THIS_COMMIT: See https://github.com/pokt-network/pocket/pull/139/files to remove this shit - - -// HACK: Since the protocol actor protobufs (e.g. validator, fisherman, etc) use `bytes` for some -// fields (e.g. `address`, `output`, `publicKey`), we need to use a helper struct to unmarshal the -// the types when they are defined via json (e.g. genesis file, testing configurations, etc...). -// Alternative solutions could include whole wrapper structs (i.e. duplication of schema definition), -// using strings instead of bytes (i.e. major change with downstream effects) or avoid defining these -// types in json altogether (i.e. limitation of usability). -type JsonBytesLoaderHelper struct { - Address HexData `json:"address,omitempty"` - PublicKey HexData `json:"public_key,omitempty"` - Output HexData `json:"output,omitempty"` -} - -type HexData []byte - -func (h *HexData) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - decoded, err := hex.DecodeString(s) - if err != nil { - return err - } - *h = HexData(decoded) - return nil -} - -func (v *Validator) UnmarshalJSON(data []byte) error { - var jh JsonBytesLoaderHelper - json.Unmarshal(data, &jh) - - protojson.Unmarshal(data, v) - v.Address = jh.Address - v.PublicKey = jh.PublicKey - v.Output = jh.Output - - return nil -} +// import ( +// "encoding/hex" +// "encoding/json" + +// "google.golang.org/protobuf/encoding/protojson" +// ) + +// // TODO_IN_THIS_COMMIT: See https://github.com/pokt-network/pocket/pull/139/files to remove this shit + +// // HACK: Since the protocol actor protobufs (e.g. validator, fisherman, etc) use `bytes` for some +// // fields (e.g. `address`, `output`, `publicKey`), we need to use a helper struct to unmarshal the +// // the types when they are defined via json (e.g. genesis file, testing configurations, etc...). +// // Alternative solutions could include whole wrapper structs (i.e. duplication of schema definition), +// // using strings instead of bytes (i.e. major change with downstream effects) or avoid defining these +// // types in json altogether (i.e. limitation of usability). +// type JsonBytesLoaderHelper struct { +// Address HexData `json:"address,omitempty"` +// PublicKey HexData `json:"public_key,omitempty"` +// Output HexData `json:"output,omitempty"` +// } + +// type HexData []byte + +// func (h *HexData) UnmarshalJSON(data []byte) error { +// var s string +// if err := json.Unmarshal(data, &s); err != nil { +// return err +// } +// decoded, err := hex.DecodeString(s) +// if err != nil { +// return err +// } +// *h = HexData(decoded) +// return nil +// } + +// func (v *Validator) UnmarshalJSON(data []byte) error { +// var jh JsonBytesLoaderHelper +// json.Unmarshal(data, &jh) + +// protojson.Unmarshal(data, v) +// v.Address = jh.Address +// v.PublicKey = jh.PublicKey +// v.Output = jh.Output + +// return nil +// } diff --git a/utility/block.go b/utility/block.go index bc387fabf..acf148ca4 100644 --- a/utility/block.go +++ b/utility/block.go @@ -90,7 +90,7 @@ func (u *UtilityContext) EndBlock(proposer []byte) typesUtil.Error { return err } if _, err := u.Context.UpdateAppHash(); err != nil { - return types.ErrAppHash(err) + return typesUtil.ErrAppHash(err) } return nil }