From 0e54712c565f878091811d57834aa1bfafeeb41e Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 4 Jul 2024 11:24:08 +0200 Subject: [PATCH 01/17] chore: add ProofQueryClient interface & implementation --- pkg/client/interface.go | 6 ++++ pkg/client/query/proofquerier.go | 51 ++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 pkg/client/query/proofquerier.go diff --git a/pkg/client/interface.go b/pkg/client/interface.go index 8ffab0e70..e10b1e8aa 100644 --- a/pkg/client/interface.go +++ b/pkg/client/interface.go @@ -30,6 +30,7 @@ import ( "github.com/pokt-network/poktroll/pkg/observable" "github.com/pokt-network/poktroll/pkg/relayer" apptypes "github.com/pokt-network/poktroll/x/application/types" + prooftypes "github.com/pokt-network/poktroll/x/proof/types" sessiontypes "github.com/pokt-network/poktroll/x/session/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" ) @@ -313,3 +314,8 @@ type SharedQueryClient interface { type BlockQueryClient interface { Block(ctx context.Context, height *int64) (*coretypes.ResultBlock, error) } + +type ProofQueryClient interface { + // GetParams queries the chain for the current shared module parameters. + GetParams(ctx context.Context) (*prooftypes.Params, error) +} diff --git a/pkg/client/query/proofquerier.go b/pkg/client/query/proofquerier.go new file mode 100644 index 000000000..4c2598f07 --- /dev/null +++ b/pkg/client/query/proofquerier.go @@ -0,0 +1,51 @@ +package query + +import ( + "context" + + "cosmossdk.io/depinject" + "github.com/cosmos/gogoproto/grpc" + + "github.com/pokt-network/poktroll/pkg/client" + prooftypes "github.com/pokt-network/poktroll/x/proof/types" +) + +// proofQuerier is a wrapper around the prooftypes.QueryClient that enables the +// querying of on-chain proof information through a single exposed method +// which returns an sharedtypes.Supplier struct +type proofQuerier struct { + clientConn grpc.ClientConn + proofQuerier prooftypes.QueryClient +} + +// NewProofQuerier returns a new instance of a client.ProofQueryClient by +// injecting the dependecies provided by the depinject.Config. +// +// Required dependencies: +// - grpc.ClientConn +func NewProofQuerier(deps depinject.Config) (client.ProofQueryClient, error) { + querier := &proofQuerier{} + + if err := depinject.Inject( + deps, + &querier.clientConn, + ); err != nil { + return nil, err + } + + querier.proofQuerier = prooftypes.NewQueryClient(querier.clientConn) + + return querier, nil +} + +// GetParams queries the chain for the current proof module parameters. +func (pq *proofQuerier) GetParams( + ctx context.Context, +) (*prooftypes.Params, error) { + req := &prooftypes.QueryParamsRequest{} + res, err := pq.proofQuerier.Params(ctx, req) + if err != nil { + return nil, err + } + return &res.Params, nil +} From 2d2a9b1b20f8fcb3bba7d60b759d52a988c66f6f Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 4 Jul 2024 11:26:10 +0200 Subject: [PATCH 02/17] chore: supply ProofQueryClient in relayminer via depinject --- pkg/deps/config/suppliers.go | 18 ++++++++++++++++++ pkg/relayer/cmd/cmd.go | 1 + 2 files changed, 19 insertions(+) diff --git a/pkg/deps/config/suppliers.go b/pkg/deps/config/suppliers.go index 2fff97c1e..1c4334214 100644 --- a/pkg/deps/config/suppliers.go +++ b/pkg/deps/config/suppliers.go @@ -446,6 +446,24 @@ func NewSupplySharedQueryClientFn() SupplierFn { } } +// NewSupplyProofQueryClientFn returns a function which constructs a +// ProofQueryClient instance and returns a new depinject.Config which +// is supplied with the given deps and the new ProofQueryClient. +func NewSupplyProofQueryClientFn() SupplierFn { + return func( + _ context.Context, + deps depinject.Config, + _ *cobra.Command, + ) (depinject.Config, error) { + proofQuerier, err := query.NewProofQuerier(deps) + if err != nil { + return nil, err + } + + return depinject.Configs(deps, depinject.Supply(proofQuerier)), nil + } +} + // newSupplyTxClientFn returns a new depinject.Config which is supplied with // the given deps and the new TxClient. func newSupplyTxClientsFn(ctx context.Context, deps depinject.Config, signingKeyName string) (depinject.Config, error) { diff --git a/pkg/relayer/cmd/cmd.go b/pkg/relayer/cmd/cmd.go index 8fd8c8994..067690c21 100644 --- a/pkg/relayer/cmd/cmd.go +++ b/pkg/relayer/cmd/cmd.go @@ -195,6 +195,7 @@ func setupRelayerDependencies( config.NewSupplyTxClientContextFn(queryNodeGRPCUrl, txNodeRPCUrl), // leaf config.NewSupplyDelegationClientFn(), // leaf config.NewSupplySharedQueryClientFn(), // leaf + config.NewSupplyProofQueryClientFn(), config.NewSupplyAccountQuerierFn(), config.NewSupplyApplicationQuerierFn(), config.NewSupplySupplierQuerierFn(), From 8f574af5a20dd1376ab68e9da5e6fe54414e7037 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 4 Jul 2024 12:02:30 +0200 Subject: [PATCH 03/17] fix: import cycle --- pkg/client/interface.go | 14 ++++++++++++-- pkg/client/query/proofquerier.go | 2 +- x/proof/types/params.go | 2 ++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/pkg/client/interface.go b/pkg/client/interface.go index e10b1e8aa..c4e732c34 100644 --- a/pkg/client/interface.go +++ b/pkg/client/interface.go @@ -8,6 +8,7 @@ //go:generate mockgen -destination=../../testutil/mockclient/supplier_query_client_mock.go -package=mockclient . SupplierQueryClient //go:generate mockgen -destination=../../testutil/mockclient/session_query_client_mock.go -package=mockclient . SessionQueryClient //go:generate mockgen -destination=../../testutil/mockclient/shared_query_client_mock.go -package=mockclient . SharedQueryClient +//go:generate mockgen -destination=../../testutil/mockclient/proof_query_client_mock.go -package=mockclient . ProofQueryClient //go:generate mockgen -destination=../../testutil/mockclient/cosmos_tx_builder_mock.go -package=mockclient github.com/cosmos/cosmos-sdk/client TxBuilder //go:generate mockgen -destination=../../testutil/mockclient/cosmos_keyring_mock.go -package=mockclient github.com/cosmos/cosmos-sdk/crypto/keyring Keyring //go:generate mockgen -destination=../../testutil/mockclient/cosmos_client_mock.go -package=mockclient github.com/cosmos/cosmos-sdk/client AccountRetriever @@ -30,7 +31,6 @@ import ( "github.com/pokt-network/poktroll/pkg/observable" "github.com/pokt-network/poktroll/pkg/relayer" apptypes "github.com/pokt-network/poktroll/x/application/types" - prooftypes "github.com/pokt-network/poktroll/x/proof/types" sessiontypes "github.com/pokt-network/poktroll/x/session/types" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" ) @@ -315,7 +315,17 @@ type BlockQueryClient interface { Block(ctx context.Context, height *int64) (*coretypes.ResultBlock, error) } +// ProofParams is a go interface type which corresponds to the poktroll.proof.Params +// protobuf message. Since the generated go types don't include interface types, this +// is necessary to prevent dependency cycles. +type ProofParams interface { + GetMinRelayDifficultyBits() uint64 + GetProofRequestProbability() float32 + GetProofRequirementThreshold() uint64 + GetProofMissingPenalty() *cosmostypes.Coin +} + type ProofQueryClient interface { // GetParams queries the chain for the current shared module parameters. - GetParams(ctx context.Context) (*prooftypes.Params, error) + GetParams(ctx context.Context) (ProofParams, error) } diff --git a/pkg/client/query/proofquerier.go b/pkg/client/query/proofquerier.go index 4c2598f07..6f871627b 100644 --- a/pkg/client/query/proofquerier.go +++ b/pkg/client/query/proofquerier.go @@ -41,7 +41,7 @@ func NewProofQuerier(deps depinject.Config) (client.ProofQueryClient, error) { // GetParams queries the chain for the current proof module parameters. func (pq *proofQuerier) GetParams( ctx context.Context, -) (*prooftypes.Params, error) { +) (client.ProofParams, error) { req := &prooftypes.QueryParamsRequest{} res, err := pq.proofQuerier.Params(ctx, req) if err != nil { diff --git a/x/proof/types/params.go b/x/proof/types/params.go index 57d0e4920..d42392ab0 100644 --- a/x/proof/types/params.go +++ b/x/proof/types/params.go @@ -6,9 +6,11 @@ import ( paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/pokt-network/poktroll/app/volatile" + "github.com/pokt-network/poktroll/pkg/client" ) var ( + _ client.ProofParams = (*Params)(nil) _ paramtypes.ParamSet = (*Params)(nil) KeyMinRelayDifficultyBits = []byte("MinRelayDifficultyBits") From 1780954195afa10261981733d5a45a7e55e8650d Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 4 Jul 2024 12:03:23 +0200 Subject: [PATCH 04/17] chore: add ProofQueryClient to miner & query for minRelayDifficultyBits --- pkg/relayer/cmd/cmd.go | 2 +- pkg/relayer/miner/miner.go | 39 ++++++++++++++++++++++++++------- pkg/relayer/miner/miner_test.go | 17 ++++++++++++-- pkg/relayer/miner/options.go | 2 +- 4 files changed, 48 insertions(+), 12 deletions(-) diff --git a/pkg/relayer/cmd/cmd.go b/pkg/relayer/cmd/cmd.go index 067690c21..e498073c3 100644 --- a/pkg/relayer/cmd/cmd.go +++ b/pkg/relayer/cmd/cmd.go @@ -218,7 +218,7 @@ func supplyMiner( deps depinject.Config, _ *cobra.Command, ) (depinject.Config, error) { - mnr, err := miner.NewMiner() + mnr, err := miner.NewMiner(deps) if err != nil { return nil, err } diff --git a/pkg/relayer/miner/miner.go b/pkg/relayer/miner/miner.go index fb3bed054..47bdb3d87 100644 --- a/pkg/relayer/miner/miner.go +++ b/pkg/relayer/miner/miner.go @@ -3,6 +3,9 @@ package miner import ( "context" + "cosmossdk.io/depinject" + + "github.com/pokt-network/poktroll/pkg/client" "github.com/pokt-network/poktroll/pkg/either" "github.com/pokt-network/poktroll/pkg/observable" "github.com/pokt-network/poktroll/pkg/observable/channel" @@ -25,29 +28,42 @@ var ( // difficulty of each, finally publishing those with sufficient difficulty to // minedRelayObs as they are applicable for relay volume. // -// Available options: -// - WithDifficulty -// // TODO_BLOCKER(@Olshansk): The relay hashing and relay difficulty mechanisms & values must come // from on-chain. type miner struct { + // proofQueryClient is ... + proofQueryClient client.ProofQueryClient + // relayDifficultyBits is the minimum difficulty that a relay must have to be // volume / reward applicable. - relayDifficultyBits int + relayDifficultyBits uint64 } // NewMiner creates a new miner from the given dependencies and options. It // returns an error if it has not been sufficiently configured or supplied. +// +// Required Dependencies: +// - ProofQueryClient +// +// Available options: +// - WithDifficulty func NewMiner( + deps depinject.Config, opts ...relayer.MinerOption, ) (*miner, error) { mnr := &miner{} + if err := depinject.Inject(deps, &mnr.proofQueryClient); err != nil { + return nil, err + } + for _, opt := range opts { opt(mnr) } - mnr.setDefaults() + if err := mnr.setDefaults(); err != nil { + return nil, err + } return mnr, nil } @@ -77,10 +93,17 @@ func (mnr *miner) MinedRelays( // setDefaults ensures that the miner has been configured with a hasherConstructor and uses // the default hasherConstructor if not. -func (mnr *miner) setDefaults() { +func (mnr *miner) setDefaults() error { + ctx := context.TODO() + params, err := mnr.proofQueryClient.GetParams(ctx) + if err != nil { + return err + } + if mnr.relayDifficultyBits == 0 { - mnr.relayDifficultyBits = defaultRelayDifficultyBits + mnr.relayDifficultyBits = params.GetMinRelayDifficultyBits() } + return nil } // mapMineRelay is intended to be used as a MapFn. @@ -102,7 +125,7 @@ func (mnr *miner) mapMineRelay( relayHash := relayHashArr[:] // The relay IS NOT volume / reward applicable - if protocol.MustCountDifficultyBits(relayHash) < mnr.relayDifficultyBits { + if uint64(protocol.MustCountDifficultyBits(relayHash)) < mnr.relayDifficultyBits { return either.Success[*relayer.MinedRelay](nil), true } diff --git a/pkg/relayer/miner/miner_test.go b/pkg/relayer/miner/miner_test.go index fbebf8ac6..c2faa0a86 100644 --- a/pkg/relayer/miner/miner_test.go +++ b/pkg/relayer/miner/miner_test.go @@ -12,15 +12,19 @@ import ( "testing" "time" + "cosmossdk.io/depinject" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "github.com/pokt-network/poktroll/pkg/observable/channel" "github.com/pokt-network/poktroll/pkg/relayer" "github.com/pokt-network/poktroll/pkg/relayer/miner" + "github.com/pokt-network/poktroll/testutil/mockclient" + prooftypes "github.com/pokt-network/poktroll/x/proof/types" servicetypes "github.com/pokt-network/poktroll/x/service/types" ) -const testDifficulty = 16 +const testDifficulty = uint64(16) // TestMiner_MinedRelays constructs an observable of mined relays, through which // it pipes pre-mined relay fixtures. It asserts that the observable only emits @@ -38,7 +42,16 @@ func TestMiner_MinedRelays(t *testing.T) { expectedMinedRelays = unmarshalHexMinedRelays(t, marshaledMinableRelaysHex) ) - mnr, err := miner.NewMiner(miner.WithDifficulty(testDifficulty)) + // TODO_IN_THIS_COMMIT: move to shared testutil. + ctrl := gomock.NewController(t) + defaultProofParams := prooftypes.DefaultParams() + proofQueryClientMock := mockclient.NewMockProofQueryClient(ctrl) + proofQueryClientMock.EXPECT(). + GetParams(gomock.Any()). + Return(&defaultProofParams, nil). + AnyTimes() + deps := depinject.Supply(proofQueryClientMock) + mnr, err := miner.NewMiner(deps, miner.WithDifficulty(testDifficulty)) require.NoError(t, err) minedRelays := mnr.MinedRelays(ctx, mockRelaysObs) diff --git a/pkg/relayer/miner/options.go b/pkg/relayer/miner/options.go index fae783d85..da87dc27f 100644 --- a/pkg/relayer/miner/options.go +++ b/pkg/relayer/miner/options.go @@ -4,7 +4,7 @@ import "github.com/pokt-network/poktroll/pkg/relayer" // WithDifficulty sets the difficulty of the miner, where difficultyBytes is the // minimum number of leading zero bytes. -func WithDifficulty(difficultyBits int) relayer.MinerOption { +func WithDifficulty(difficultyBits uint64) relayer.MinerOption { return func(mnr relayer.Miner) { mnr.(*miner).relayDifficultyBits = difficultyBits } From 021aba0b1ac60c61d6aa9be28511e649ee69cb47 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 4 Jul 2024 12:18:56 +0200 Subject: [PATCH 05/17] refactor: mock proof query client to shared testutil --- pkg/relayer/miner/miner_test.go | 13 ++-------- .../testqueryclients/proofquerier.go | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 11 deletions(-) create mode 100644 testutil/testclient/testqueryclients/proofquerier.go diff --git a/pkg/relayer/miner/miner_test.go b/pkg/relayer/miner/miner_test.go index c2faa0a86..34fb99d43 100644 --- a/pkg/relayer/miner/miner_test.go +++ b/pkg/relayer/miner/miner_test.go @@ -13,14 +13,12 @@ import ( "time" "cosmossdk.io/depinject" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "github.com/pokt-network/poktroll/pkg/observable/channel" "github.com/pokt-network/poktroll/pkg/relayer" "github.com/pokt-network/poktroll/pkg/relayer/miner" - "github.com/pokt-network/poktroll/testutil/mockclient" - prooftypes "github.com/pokt-network/poktroll/x/proof/types" + "github.com/pokt-network/poktroll/testutil/testclient/testqueryclients" servicetypes "github.com/pokt-network/poktroll/x/service/types" ) @@ -42,14 +40,7 @@ func TestMiner_MinedRelays(t *testing.T) { expectedMinedRelays = unmarshalHexMinedRelays(t, marshaledMinableRelaysHex) ) - // TODO_IN_THIS_COMMIT: move to shared testutil. - ctrl := gomock.NewController(t) - defaultProofParams := prooftypes.DefaultParams() - proofQueryClientMock := mockclient.NewMockProofQueryClient(ctrl) - proofQueryClientMock.EXPECT(). - GetParams(gomock.Any()). - Return(&defaultProofParams, nil). - AnyTimes() + proofQueryClientMock := testqueryclients.NewTestProofQueryClient(t) deps := depinject.Supply(proofQueryClientMock) mnr, err := miner.NewMiner(deps, miner.WithDifficulty(testDifficulty)) require.NoError(t, err) diff --git a/testutil/testclient/testqueryclients/proofquerier.go b/testutil/testclient/testqueryclients/proofquerier.go new file mode 100644 index 000000000..efcc11342 --- /dev/null +++ b/testutil/testclient/testqueryclients/proofquerier.go @@ -0,0 +1,24 @@ +package testqueryclients + +import ( + "testing" + + "github.com/golang/mock/gomock" + + "github.com/pokt-network/poktroll/testutil/mockclient" + prooftypes "github.com/pokt-network/poktroll/x/proof/types" +) + +// NewTestProofQueryClient creates a mock of the ProofQueryClient which uses the +// default proof module params for its GetParams() method implementation. +func NewTestProofQueryClient(t *testing.T) *mockclient.MockProofQueryClient { + ctrl := gomock.NewController(t) + defaultProofParams := prooftypes.DefaultParams() + proofQueryClientMock := mockclient.NewMockProofQueryClient(ctrl) + proofQueryClientMock.EXPECT(). + GetParams(gomock.Any()). + Return(&defaultProofParams, nil). + AnyTimes() + + return proofQueryClientMock +} From 41c72191677a7e5df0193a51daa889ea183af100 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 4 Jul 2024 12:24:15 +0200 Subject: [PATCH 06/17] chore: self-review improvements --- pkg/client/interface.go | 4 +++- pkg/client/query/proofquerier.go | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/client/interface.go b/pkg/client/interface.go index c4e732c34..1408c4c60 100644 --- a/pkg/client/interface.go +++ b/pkg/client/interface.go @@ -285,7 +285,7 @@ type SessionQueryClient interface { } // SharedQueryClient defines an interface that enables the querying of the -// on-chain shared module information. +// on-chain shared module params. type SharedQueryClient interface { // GetParams queries the chain for the current shared module parameters. GetParams(ctx context.Context) (*sharedtypes.Params, error) @@ -325,6 +325,8 @@ type ProofParams interface { GetProofMissingPenalty() *cosmostypes.Coin } +// ProofQueryClient defines an interface that enables the querying of the +// on-chain proof module params. type ProofQueryClient interface { // GetParams queries the chain for the current shared module parameters. GetParams(ctx context.Context) (ProofParams, error) diff --git a/pkg/client/query/proofquerier.go b/pkg/client/query/proofquerier.go index 6f871627b..30c2984cd 100644 --- a/pkg/client/query/proofquerier.go +++ b/pkg/client/query/proofquerier.go @@ -11,8 +11,7 @@ import ( ) // proofQuerier is a wrapper around the prooftypes.QueryClient that enables the -// querying of on-chain proof information through a single exposed method -// which returns an sharedtypes.Supplier struct +// querying of on-chain proof module params. type proofQuerier struct { clientConn grpc.ClientConn proofQuerier prooftypes.QueryClient From 3e574bd239c0f0e1f4ecf14f550ed772f59ea960 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 4 Jul 2024 12:27:24 +0200 Subject: [PATCH 07/17] chore: cleanup todo comments --- pkg/relayer/miner/miner.go | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/pkg/relayer/miner/miner.go b/pkg/relayer/miner/miner.go index 47bdb3d87..f91ec1871 100644 --- a/pkg/relayer/miner/miner.go +++ b/pkg/relayer/miner/miner.go @@ -16,20 +16,11 @@ import ( servicetypes "github.com/pokt-network/poktroll/x/service/types" ) -var ( - _ relayer.Miner = (*miner)(nil) - // TODO_BLOCKER(@Olshansk): query on-chain governance params once available. - // Setting this to 0 to effectively disables mining for now. - // I.e., all relays are added to the tree. - defaultRelayDifficultyBits = 0 -) +var _ relayer.Miner = (*miner)(nil) // Miner is responsible for observing servedRelayObs, hashing and checking the // difficulty of each, finally publishing those with sufficient difficulty to // minedRelayObs as they are applicable for relay volume. -// -// TODO_BLOCKER(@Olshansk): The relay hashing and relay difficulty mechanisms & values must come -// from on-chain. type miner struct { // proofQueryClient is ... proofQueryClient client.ProofQueryClient From 9b67108a655cae142ce9e50a80544fbb46306b35 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 4 Jul 2024 12:48:52 +0200 Subject: [PATCH 08/17] refactor: simplify protocol.CountHashDifficultyBits() --- pkg/relayer/miner/gen/gen_fixtures.go | 4 +- pkg/relayer/miner/miner.go | 7 ++- pkg/relayer/protocol/difficulty.go | 53 ++++--------------- pkg/relayer/protocol/difficulty_test.go | 23 ++++---- x/proof/keeper/msg_server_submit_proof.go | 9 +--- .../keeper/msg_server_submit_proof_test.go | 5 +- 6 files changed, 27 insertions(+), 74 deletions(-) diff --git a/pkg/relayer/miner/gen/gen_fixtures.go b/pkg/relayer/miner/gen/gen_fixtures.go index 358cd722e..1d993253e 100644 --- a/pkg/relayer/miner/gen/gen_fixtures.go +++ b/pkg/relayer/miner/gen/gen_fixtures.go @@ -200,13 +200,13 @@ func exitOnError(errCh <-chan error) { // difficultyGTE returns true if the given hash has a difficulty greater than or // equal to flagDifficultyBitsThreshold. func difficultyGTE(hash []byte) bool { - return protocol.MustCountDifficultyBits(hash) >= flagDifficultyBitsThreshold + return protocol.CountDifficultyBits(hash) >= flagDifficultyBitsThreshold } // difficultyLT returns true if the given hash has a difficulty less than // flagDifficultyBitsThreshold. func difficultyLT(hash []byte) bool { - return protocol.MustCountDifficultyBits(hash) < flagDifficultyBitsThreshold + return protocol.CountDifficultyBits(hash) < flagDifficultyBitsThreshold } // getMarshaledRelayFmtLines performs two map operations followed by a collect. diff --git a/pkg/relayer/miner/miner.go b/pkg/relayer/miner/miner.go index f91ec1871..fbc9cc9c0 100644 --- a/pkg/relayer/miner/miner.go +++ b/pkg/relayer/miner/miner.go @@ -112,11 +112,10 @@ func (mnr *miner) mapMineRelay( if err != nil { return either.Error[*relayer.MinedRelay](err), false } - relayHashArr := servicetypes.GetHashFromBytes(relayBz) - relayHash := relayHashArr[:] + relayHash := servicetypes.GetHashFromBytes(relayBz) // The relay IS NOT volume / reward applicable - if uint64(protocol.MustCountDifficultyBits(relayHash)) < mnr.relayDifficultyBits { + if uint64(protocol.CountHashDifficultyBits(relayHash)) < mnr.relayDifficultyBits { return either.Success[*relayer.MinedRelay](nil), true } @@ -124,6 +123,6 @@ func (mnr *miner) mapMineRelay( return either.Success(&relayer.MinedRelay{ Relay: *relay, Bytes: relayBz, - Hash: relayHash, + Hash: relayHash[:], }), false } diff --git a/pkg/relayer/protocol/difficulty.go b/pkg/relayer/protocol/difficulty.go index 4ab8b357c..a01b74df1 100644 --- a/pkg/relayer/protocol/difficulty.go +++ b/pkg/relayer/protocol/difficulty.go @@ -1,48 +1,17 @@ package protocol -import "math/bits" - -// MustCountDifficultyBits returns the number of leading zero bits in the given -// byte slice. It panics if an error is encountered. -func MustCountDifficultyBits(bz []byte) int { - diff, err := CountHashDifficultyBits(bz) - if err != nil { - panic(err) - } - - return diff -} +import ( + "encoding/binary" + "math/bits" +) // CountHashDifficultyBits returns the number of leading zero bits in the given byte // slice. It returns an error if the byte slice is all zero bits. -// -// TODO_BLOCKER(@Olshansk): Remove the forloop logic and replace with a simplified -// single method that accounts for the fact that block hashes/paths are always -// 32 bytes. We use Sha256 (32 bytes) and CosmosSDK defaults to 32 byte block -// hashes so specifying makes sense here. -// -// func CountHashDifficultyBits(bz [32]byte) int { -// return bits.LeadingZeros64(binary.LittleEndian.Uint64(bz)) -// } -// -// The above would mean we can replace MustCountDifficultyBits entirely. -func CountHashDifficultyBits(bz []byte) (int, error) { - bzLen := len(bz) - - var zeroBits int - for byteIdx, byteValue := range bz { - if byteValue != 0 { - zeroBits = bits.LeadingZeros8(byteValue) - if zeroBits == 8 { - // we already checked that byteValue != 0. - return 0, ErrDifficulty.Wrap("impossible code path") - } - - // We have byteIdx bytes that are all 0s and one byte that has - // zeroBits number of leading 0 bits. - return (byteIdx)*8 + zeroBits, nil - } - } - - return 0, ErrDifficulty.Wrapf("difficulty matches bytes length: %d; bytes (hex): % x", bzLen, bz) +func CountHashDifficultyBits(bz [32]byte) int { + // Using BigEndian for consistent bit/byte ordering such leading zeros + // accumulate across adjacent bytes. + // E.g.: 0x00, 0x255, 0x00, 0x00 has 8 leading zero bits. If LittleEndian + // were applied instead, it would have 16 leading zeros because it would + // look like 0x00, 0x00, 0x255, 0x00. + return bits.LeadingZeros64(binary.BigEndian.Uint64(bz[:])) } diff --git a/pkg/relayer/protocol/difficulty_test.go b/pkg/relayer/protocol/difficulty_test.go index b29e266be..7366992f3 100644 --- a/pkg/relayer/protocol/difficulty_test.go +++ b/pkg/relayer/protocol/difficulty_test.go @@ -15,42 +15,37 @@ func TestCountDifficultyBits(t *testing.T) { difficulty int }{ { - bz: []byte{0b11111111, 255, 255, 255}, + bz: []byte{0b11111111}, difficulty: 0, }, { - bz: []byte{0b01111111, 255, 255, 255}, + bz: []byte{0b01111111}, difficulty: 1, }, { - bz: []byte{0, 255, 255, 255}, + bz: []byte{0, 255}, difficulty: 8, }, { - bz: []byte{0, 0b01111111, 255, 255}, + bz: []byte{0, 0b01111111}, difficulty: 9, }, { - bz: []byte{0, 0b00111111, 255, 255}, + bz: []byte{0, 0b00111111}, difficulty: 10, }, { - bz: []byte{0, 0, 255, 255}, + bz: []byte{0, 0, 255}, difficulty: 16, }, } for _, test := range tests { t.Run(fmt.Sprintf("difficulty_%d_zero_bits", test.difficulty), func(t *testing.T) { - actualDifficulty, err := protocol.CountHashDifficultyBits(test.bz) - require.NoError(t, err) + var bz [32]byte + copy(bz[:], test.bz) + actualDifficulty := protocol.CountHashDifficultyBits(bz) require.Equal(t, test.difficulty, actualDifficulty) }) } } - -func TestCountDifficultyBits_Error(t *testing.T) { - _, err := protocol.CountHashDifficultyBits([]byte{0, 0, 0, 0}) - require.ErrorIs(t, err, protocol.ErrDifficulty) - require.ErrorContains(t, err, "difficulty matches bytes length") -} diff --git a/x/proof/keeper/msg_server_submit_proof.go b/x/proof/keeper/msg_server_submit_proof.go index 465aa9da7..316938df5 100644 --- a/x/proof/keeper/msg_server_submit_proof.go +++ b/x/proof/keeper/msg_server_submit_proof.go @@ -476,14 +476,7 @@ func verifyClosestProof( // function that can be used by both the proof and the miner packages. func validateMiningDifficulty(relayBz []byte, minRelayDifficultyBits uint64) error { relayHash := servicetypes.GetHashFromBytes(relayBz) - - relayDifficultyBits, err := protocol.CountHashDifficultyBits(relayHash[:]) - if err != nil { - return types.ErrProofInvalidRelay.Wrapf( - "error counting difficulty bits: %s", - err, - ) - } + relayDifficultyBits := protocol.CountHashDifficultyBits(relayHash) // TODO_MAINNET: Devise a test that tries to attack the network and ensure that there // is sufficient telemetry. diff --git a/x/proof/keeper/msg_server_submit_proof_test.go b/x/proof/keeper/msg_server_submit_proof_test.go index cd73c08c7..91e85f0ba 100644 --- a/x/proof/keeper/msg_server_submit_proof_test.go +++ b/x/proof/keeper/msg_server_submit_proof_test.go @@ -1394,10 +1394,7 @@ func getClosestRelayDifficultyBits( require.NoError(t, err) // Count the number of leading 0s in the relay hash to determine its difficulty. - relayDifficultyBits, err := protocol.CountHashDifficultyBits(relayHash[:]) - require.NoError(t, err) - - return uint64(relayDifficultyBits) + return uint64(protocol.CountHashDifficultyBits(relayHash)) } // resetBlockHeightFn returns a function that resets the block height of the From 5fd53f8651d9267b696d9d834616067901586cb5 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 4 Jul 2024 12:57:32 +0200 Subject: [PATCH 09/17] chore: improve comments --- pkg/relayer/protocol/difficulty.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/relayer/protocol/difficulty.go b/pkg/relayer/protocol/difficulty.go index a01b74df1..b70d5a358 100644 --- a/pkg/relayer/protocol/difficulty.go +++ b/pkg/relayer/protocol/difficulty.go @@ -8,10 +8,10 @@ import ( // CountHashDifficultyBits returns the number of leading zero bits in the given byte // slice. It returns an error if the byte slice is all zero bits. func CountHashDifficultyBits(bz [32]byte) int { - // Using BigEndian for consistent bit/byte ordering such leading zeros + // Using BigEndian for contiguous bit/byte ordering such leading zeros // accumulate across adjacent bytes. - // E.g.: 0x00, 0x255, 0x00, 0x00 has 8 leading zero bits. If LittleEndian - // were applied instead, it would have 16 leading zeros because it would - // look like 0x00, 0x00, 0x255, 0x00. + // E.g.: []byte{0, 0b00111111, 0x00, 0x00} has 10 leading zero bits. If + // LittleEndian were applied instead, it would have 18 leading zeros because it would + // look like []byte{0, 0, 0b00111111, 0}. return bits.LeadingZeros64(binary.BigEndian.Uint64(bz[:])) } From f82cafbff2222e1c867a5ceb20d7a480afd46f8f Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 4 Jul 2024 12:58:12 +0200 Subject: [PATCH 10/17] Empty commit From 2e9ad5710402656ee3bc0f7c77691d651f06c2ec Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 4 Jul 2024 13:00:35 +0200 Subject: [PATCH 11/17] chore: improve comments --- pkg/relayer/miner/miner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/relayer/miner/miner.go b/pkg/relayer/miner/miner.go index f91ec1871..d534bd9a5 100644 --- a/pkg/relayer/miner/miner.go +++ b/pkg/relayer/miner/miner.go @@ -22,7 +22,7 @@ var _ relayer.Miner = (*miner)(nil) // difficulty of each, finally publishing those with sufficient difficulty to // minedRelayObs as they are applicable for relay volume. type miner struct { - // proofQueryClient is ... + // proofQueryClient is used to query for the minimum relay difficulty. proofQueryClient client.ProofQueryClient // relayDifficultyBits is the minimum difficulty that a relay must have to be From 717995e009e5b60574ee363885d58e9f728911a7 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 4 Jul 2024 13:33:28 +0200 Subject: [PATCH 12/17] refactor: promote difficulty calc out of relayer to crypto pkg --- pkg/{relayer => crypto}/protocol/difficulty.go | 0 pkg/{relayer => crypto}/protocol/difficulty_test.go | 2 +- pkg/{relayer => crypto}/protocol/errors.go | 0 pkg/relayer/miner/miner.go | 2 +- x/proof/keeper/msg_server_submit_proof_test.go | 1 + 5 files changed, 3 insertions(+), 2 deletions(-) rename pkg/{relayer => crypto}/protocol/difficulty.go (100%) rename pkg/{relayer => crypto}/protocol/difficulty_test.go (93%) rename pkg/{relayer => crypto}/protocol/errors.go (100%) diff --git a/pkg/relayer/protocol/difficulty.go b/pkg/crypto/protocol/difficulty.go similarity index 100% rename from pkg/relayer/protocol/difficulty.go rename to pkg/crypto/protocol/difficulty.go diff --git a/pkg/relayer/protocol/difficulty_test.go b/pkg/crypto/protocol/difficulty_test.go similarity index 93% rename from pkg/relayer/protocol/difficulty_test.go rename to pkg/crypto/protocol/difficulty_test.go index 7366992f3..90a9a2367 100644 --- a/pkg/relayer/protocol/difficulty_test.go +++ b/pkg/crypto/protocol/difficulty_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/pokt-network/poktroll/pkg/relayer/protocol" + "github.com/pokt-network/poktroll/pkg/crypto/protocol" ) func TestCountDifficultyBits(t *testing.T) { diff --git a/pkg/relayer/protocol/errors.go b/pkg/crypto/protocol/errors.go similarity index 100% rename from pkg/relayer/protocol/errors.go rename to pkg/crypto/protocol/errors.go diff --git a/pkg/relayer/miner/miner.go b/pkg/relayer/miner/miner.go index fbc9cc9c0..e5500c880 100644 --- a/pkg/relayer/miner/miner.go +++ b/pkg/relayer/miner/miner.go @@ -6,13 +6,13 @@ import ( "cosmossdk.io/depinject" "github.com/pokt-network/poktroll/pkg/client" + "github.com/pokt-network/poktroll/pkg/crypto/protocol" "github.com/pokt-network/poktroll/pkg/either" "github.com/pokt-network/poktroll/pkg/observable" "github.com/pokt-network/poktroll/pkg/observable/channel" "github.com/pokt-network/poktroll/pkg/observable/filter" "github.com/pokt-network/poktroll/pkg/observable/logging" "github.com/pokt-network/poktroll/pkg/relayer" - "github.com/pokt-network/poktroll/pkg/relayer/protocol" servicetypes "github.com/pokt-network/poktroll/x/service/types" ) diff --git a/x/proof/keeper/msg_server_submit_proof_test.go b/x/proof/keeper/msg_server_submit_proof_test.go index 91e85f0ba..5c2e7092d 100644 --- a/x/proof/keeper/msg_server_submit_proof_test.go +++ b/x/proof/keeper/msg_server_submit_proof_test.go @@ -16,6 +16,7 @@ import ( "google.golang.org/grpc/status" "github.com/pokt-network/poktroll/pkg/crypto" + "github.com/pokt-network/poktroll/pkg/crypto/protocol" "github.com/pokt-network/poktroll/pkg/crypto/rings" "github.com/pokt-network/poktroll/pkg/polylog/polyzero" "github.com/pokt-network/poktroll/pkg/relayer" From 85251bf105814321929eadec9a2f1220bbd14531 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 4 Jul 2024 13:43:43 +0200 Subject: [PATCH 13/17] fixup: refactor: CountHashDifficultyBits() --- pkg/crypto/protocol/errors.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/crypto/protocol/errors.go b/pkg/crypto/protocol/errors.go index 9f3de5c29..187083002 100644 --- a/pkg/crypto/protocol/errors.go +++ b/pkg/crypto/protocol/errors.go @@ -1,8 +1,5 @@ package protocol -import sdkerrors "cosmossdk.io/errors" - var ( - ErrDifficulty = sdkerrors.New(codespace, 1, "difficulty error") - codespace = "relayer/protocol" + codespace = "relayer/protocol" ) From 7ce85585b6acdfc0a78eb7dfcc387211bda3be5d Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 4 Jul 2024 13:43:59 +0200 Subject: [PATCH 14/17] fixup: refactor: relayminer - fix: dep supply ordering --- pkg/relayer/cmd/cmd.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/relayer/cmd/cmd.go b/pkg/relayer/cmd/cmd.go index e498073c3..1f1fdd185 100644 --- a/pkg/relayer/cmd/cmd.go +++ b/pkg/relayer/cmd/cmd.go @@ -187,15 +187,15 @@ func setupRelayerDependencies( supplierFuncs := []config.SupplierFn{ config.NewSupplyLoggerFromCtx(ctx), - config.NewSupplyEventsQueryClientFn(queryNodeRPCUrl), // leaf - config.NewSupplyBlockQueryClientFn(queryNodeRPCUrl), // leaf - config.NewSupplyBlockClientFn(queryNodeRPCUrl), // leaf - config.NewSupplyQueryClientContextFn(queryNodeGRPCUrl), // leaf - supplyMiner, // leaf + config.NewSupplyEventsQueryClientFn(queryNodeRPCUrl), // leaf + config.NewSupplyBlockQueryClientFn(queryNodeRPCUrl), // leaf + config.NewSupplyBlockClientFn(queryNodeRPCUrl), // leaf + config.NewSupplyQueryClientContextFn(queryNodeGRPCUrl), // leaf config.NewSupplyTxClientContextFn(queryNodeGRPCUrl, txNodeRPCUrl), // leaf config.NewSupplyDelegationClientFn(), // leaf config.NewSupplySharedQueryClientFn(), // leaf config.NewSupplyProofQueryClientFn(), + supplyMiner, config.NewSupplyAccountQuerierFn(), config.NewSupplyApplicationQuerierFn(), config.NewSupplySupplierQuerierFn(), From c3ab4bca87cf2a308a5959a5312276326ff179cf Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 4 Jul 2024 13:53:21 +0200 Subject: [PATCH 15/17] fixup: refactor: promote CountHashDifficultyBits() to pkg/crypto/protocol --- pkg/crypto/protocol/errors.go | 2 +- pkg/relayer/miner/gen/gen_fixtures.go | 2 +- x/proof/keeper/msg_server_submit_proof.go | 2 +- x/proof/keeper/msg_server_submit_proof_test.go | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pkg/crypto/protocol/errors.go b/pkg/crypto/protocol/errors.go index 187083002..da3ba4e79 100644 --- a/pkg/crypto/protocol/errors.go +++ b/pkg/crypto/protocol/errors.go @@ -1,5 +1,5 @@ package protocol var ( - codespace = "relayer/protocol" + codespace = "crypto/protocol" ) diff --git a/pkg/relayer/miner/gen/gen_fixtures.go b/pkg/relayer/miner/gen/gen_fixtures.go index 1d993253e..0531e4266 100644 --- a/pkg/relayer/miner/gen/gen_fixtures.go +++ b/pkg/relayer/miner/gen/gen_fixtures.go @@ -17,11 +17,11 @@ import ( "sync" "time" + "github.com/pokt-network/poktroll/pkg/crypto/protocol" "github.com/pokt-network/poktroll/pkg/observable" "github.com/pokt-network/poktroll/pkg/observable/channel" "github.com/pokt-network/poktroll/pkg/relayer" "github.com/pokt-network/poktroll/pkg/relayer/miner" - "github.com/pokt-network/poktroll/pkg/relayer/protocol" servicetypes "github.com/pokt-network/poktroll/x/service/types" ) diff --git a/x/proof/keeper/msg_server_submit_proof.go b/x/proof/keeper/msg_server_submit_proof.go index 316938df5..e8633fed3 100644 --- a/x/proof/keeper/msg_server_submit_proof.go +++ b/x/proof/keeper/msg_server_submit_proof.go @@ -18,7 +18,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/pokt-network/poktroll/pkg/relayer/protocol" + "github.com/pokt-network/poktroll/pkg/crypto/protocol" "github.com/pokt-network/poktroll/telemetry" "github.com/pokt-network/poktroll/x/proof/types" servicetypes "github.com/pokt-network/poktroll/x/service/types" diff --git a/x/proof/keeper/msg_server_submit_proof_test.go b/x/proof/keeper/msg_server_submit_proof_test.go index 5c2e7092d..236f87ff3 100644 --- a/x/proof/keeper/msg_server_submit_proof_test.go +++ b/x/proof/keeper/msg_server_submit_proof_test.go @@ -20,7 +20,6 @@ import ( "github.com/pokt-network/poktroll/pkg/crypto/rings" "github.com/pokt-network/poktroll/pkg/polylog/polyzero" "github.com/pokt-network/poktroll/pkg/relayer" - "github.com/pokt-network/poktroll/pkg/relayer/protocol" "github.com/pokt-network/poktroll/pkg/relayer/session" testutilevents "github.com/pokt-network/poktroll/testutil/events" keepertest "github.com/pokt-network/poktroll/testutil/keeper" From c1f5ae62a34f46dd969b1eb5abc1cc84c97054ab Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 5 Jul 2024 23:23:42 +0200 Subject: [PATCH 16/17] chore: update comment --- pkg/crypto/protocol/difficulty.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/crypto/protocol/difficulty.go b/pkg/crypto/protocol/difficulty.go index b70d5a358..f63ba6bc3 100644 --- a/pkg/crypto/protocol/difficulty.go +++ b/pkg/crypto/protocol/difficulty.go @@ -5,8 +5,7 @@ import ( "math/bits" ) -// CountHashDifficultyBits returns the number of leading zero bits in the given byte -// slice. It returns an error if the byte slice is all zero bits. +// CountHashDifficultyBits returns the number of leading zero bits in the given byte slice. func CountHashDifficultyBits(bz [32]byte) int { // Using BigEndian for contiguous bit/byte ordering such leading zeros // accumulate across adjacent bytes. From 00ab72b1568b7cb5fe413762c9d7af83af96bb8f Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 5 Jul 2024 23:32:01 +0200 Subject: [PATCH 17/17] chore: update comment Co-authored-by: Daniel Olshansky --- pkg/crypto/protocol/difficulty.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/crypto/protocol/difficulty.go b/pkg/crypto/protocol/difficulty.go index f63ba6bc3..8901f0758 100644 --- a/pkg/crypto/protocol/difficulty.go +++ b/pkg/crypto/protocol/difficulty.go @@ -6,6 +6,10 @@ import ( ) // CountHashDifficultyBits returns the number of leading zero bits in the given byte slice. +// TODO_MAINNET: Consider generalizing difficulty to a target hash. See: +// - https://bitcoin.stackexchange.com/questions/107976/bitcoin-difficulty-why-leading-0s +// - https://bitcoin.stackexchange.com/questions/121920/is-it-always-possible-to-find-a-number-whose-hash-starts-with-a-certain-number-o +// - https://github.com/pokt-network/poktroll/pull/656/files#r1666712528 func CountHashDifficultyBits(bz [32]byte) int { // Using BigEndian for contiguous bit/byte ordering such leading zeros // accumulate across adjacent bytes.