From 32513b835866168e9d77f21569f4e36b554c1781 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Sat, 18 Nov 2023 10:15:07 +0100 Subject: [PATCH] [Off-chain, Testing] test: protocol pkg (part 1) (#192) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: `MapFn`s receive context arg * chore: add `ForEach` map shorthand operator * chore: add `/pkg/observable/filter` * chore: add `/pkg/observable/logging` * chore: add `/pkg/relayer/protocol` * chore: add `Miner` interface * feat: add `Miner` implementation * test: `Miner` implementation * chore: fix comment * chore: add godoc comments * feat: Add Relayer struct * chore: Rename to RelayMiner * chore: Rename relay miner file * chore: Remove unused RelayerOption parameter * [Test] First step for automated E2E Relay test (#167) - Fixed helpers for localnet regenesis - Added an application & supplier to the genesis file - Initializing appMap & supplierMap in E2E tests - Add support for the app's codec (for unmarshaling responses) in E2E tests - Adding a placeholder for `e2e/tests/relay.feature` --- Co-authored-by: harry <53987565+h5law@users.noreply.github.com> * [Relayer] refactor: simplify `RelayerSessionsManager` (#169) * refactor: `MapFn`s receive context arg * feat: add `MapExpand` observable operator * refactor: `RelayerSessionsManager` to be more reactive * chore: add godoc comment * chore: review feedback improvements * trigger CI * chore: review feedback improvements Co-authored-by: Daniel Olshansky * chore: review feedback improvements * chore: update start mining comment * fix: Update Miner interface * fix: import cycle & goimports * chore: review feedback improvements * chore: cleanup TODO_THIS_COMMIT comments * chore: improve var & func names for clarity and consistency * refactor: move claim/proof lifecycle concerns to `relayerSessionsManager`. * chore: review feedback improvements * chore: review feedback improvements * refactor: `miner#hash()` method * chore: tidy up * chore: simplify * wip: relayer CLI * chore: finish first pass * chore: review feedback improvements Co-authored-by: Daniel Olshansky * chore: review feedback improvements Co-authored-by: Daniel Olshansky * chore: review feedback improvements Co-authored-by: Daniel Olshansky * chore: review feedback improvements * chore: review feedback improvements * chore: tidy up cmd creation * fix: incomplete refactor * chore: simplify * chore: add log lines * wip: react to miner, refactor, construct miner, refactor * chore: cleanup * chore: Reflect responsibility changes of session manager * feat: Use relay miner to start * [WIP] Updating relay.feature to run curl command * chore: Improve comment about startig relayer proxy * wip: debugging * Continued implementation but still failing * Getting an invalid request right now but figuring it out... * wip: debugging * Added service and switched to AppGate * wip: debugging * chore: Rename falg variables * wip: debugging * revertme: disable tilt relayer service * chore: use arg not flag * chore: rename command * Debugging checkpoint * wip: debugging - improvments * wip: debugging * wip: debugging * wip: debugging * revert-or-fixme: add error log lines * revert-or-fixme: add debug log lines * fix: set relay server handle function * revert-or-fixme: add debug log lines * chore: rename some chan vars * feat: fix all bugs, e2e relay works * chore: add some todo comments * wip: debugging * fix: use remote helm charts again * fix: put adequate proxied services endpoitns, prevent session republishing * chore: Refactor JSONRPCServer and server builder * Upate a couple small comments in the maketfile * revert: comment relayers out of tiltfile * chore: fix subcmd name `relayerminer` -> `relayminer` * chore: improve logging * chore: cleanup error messaging & logging in appgate server * refactor: rename misnamed `jsonRPCServer` receiver var * chore: remove appgate server debug log * chore: unexport `relayMiner` struct * refactor: interrupt signal handling * chore: improve comments * chore: improve comments * revert: tiltfile hot-reload dirs * refactor: re-consolidate client contexts * fix: typo * chore: remove todo * chore: add todo comment * revert: comment change * fix: error format strings * chore: remove comment * fix: error format strings * chore: add `-features-path` flag to cucumber tests * fix: set the relayminer URL in the curl cmd * chore: remove redundant `-X` curl arg (says curl) * squash: fix relayminer url: reword: s/relayminer/appgateserver/ * chore: improve error messaging * fix: curl invocation * test: implement step definition to assert agains relay response * chore: improve error name & messaging * Self review * fixup: merge upstream * chore: review feedback improvements * chore: update anvil service port in make targets * chore: review feedback improvements Co-authored-by: Daniel Olshansky * refactor: relayminer depinject helpers & godoc comments on all constructors * refactor: separate tx and query client contexts 🙄 * fix: sessiontree store path check * fix: sessiontree store path check * chore: review feedback improvements Co-authored-by: Daniel Olshansky * chore: review feedback improvements * chore: add long command description * fix: supplier client test * chore: cleanup flags and dependencies for appgateserver cmd * chore: move shared dependency setup logic to shared pkg * chore: update comment * Update .gitignore * Update OpenAPI spec * Updated comments for post 177+179 work for okdas * Update pkg/relayer/cmd/cmd.go * Update the names and references to queryNode/sequencerNode/fullNode etc * Update some comments and TODOs * Added a couple more comments * More tiny comment updates * chore: review feedback improvements Co-authored-by: Daniel Olshansky * chore: add silent w/ error flag to curl * refactor: count difficulty; bit resolution * test: count difficulty * chore: review feedback improvements Co-authored-by: Daniel Olshansky --------- Co-authored-by: Redouane Lakrache Co-authored-by: Daniel Olshansky Co-authored-by: harry <53987565+h5law@users.noreply.github.com> --- pkg/relayer/miner/miner.go | 4 +- pkg/relayer/protocol/difficulty.go | 41 ++++++++++++++---- pkg/relayer/protocol/difficulty_test.go | 56 +++++++++++++++++++++++++ pkg/relayer/protocol/errors.go | 8 ++++ 4 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 pkg/relayer/protocol/difficulty_test.go create mode 100644 pkg/relayer/protocol/errors.go diff --git a/pkg/relayer/miner/miner.go b/pkg/relayer/miner/miner.go index 3537128c5..21d706f2f 100644 --- a/pkg/relayer/miner/miner.go +++ b/pkg/relayer/miner/miner.go @@ -21,7 +21,7 @@ var ( // TODO_BLOCKER: 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. - defaultRelayDifficulty = 0 + defaultRelayDifficultyBits = 0 ) // Miner is responsible for observing servedRelayObs, hashing and checking the @@ -107,7 +107,7 @@ func (mnr *miner) mapMineRelay( relayHash := mnr.hash(relayBz) // The relay IS NOT volume / reward applicable - if !protocol.BytesDifficultyGreaterThan(relayHash, defaultRelayDifficulty) { + if protocol.MustCountDifficultyBits(relayHash) < defaultRelayDifficultyBits { return either.Success[*relayer.MinedRelay](nil), true } diff --git a/pkg/relayer/protocol/difficulty.go b/pkg/relayer/protocol/difficulty.go index 4743d546d..a33c4bac6 100644 --- a/pkg/relayer/protocol/difficulty.go +++ b/pkg/relayer/protocol/difficulty.go @@ -1,17 +1,42 @@ package protocol import ( - "encoding/hex" - "strings" + "math/bits" ) // TODO_BLOCKER: Revisit this part of the algorithm after initial TestNet Launch. // TODO_TEST: Add extensive tests for the core relay mining business logic. -// BytesDifficultyGreaterThan determines if the bytes exceed a certain difficulty, and it -// is used to determine if a relay is volume applicable. See the spec for more details: https://github.com/pokt-network/pocket-network-protocol -func BytesDifficultyGreaterThan(bz []byte, compDifficultyBytes int) bool { - hexZerosPrefix := strings.Repeat("0", compDifficultyBytes*2) // 2 hex chars per byte. - hexBz := hex.EncodeToString(bz) - return strings.HasPrefix(hexBz, hexZerosPrefix) +// 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 := CountDifficultyBits(bz) + if err != nil { + panic(err) + } + + return diff +} + +// CountDifficultyBits 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 CountDifficultyBits(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) } diff --git a/pkg/relayer/protocol/difficulty_test.go b/pkg/relayer/protocol/difficulty_test.go new file mode 100644 index 000000000..ae5548634 --- /dev/null +++ b/pkg/relayer/protocol/difficulty_test.go @@ -0,0 +1,56 @@ +package protocol_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/pokt-network/poktroll/pkg/relayer/protocol" +) + +func TestCountDifficultyBits(t *testing.T) { + tests := []struct { + bz []byte + difficulty int + }{ + { + bz: []byte{0b11111111, 255, 255, 255}, + difficulty: 0, + }, + { + bz: []byte{0b01111111, 255, 255, 255}, + difficulty: 1, + }, + { + bz: []byte{0, 255, 255, 255}, + difficulty: 8, + }, + { + bz: []byte{0, 0b01111111, 255, 255}, + difficulty: 9, + }, + { + bz: []byte{0, 0b00111111, 255, 255}, + difficulty: 10, + }, + { + bz: []byte{0, 0, 255, 255}, + difficulty: 16, + }, + } + + for _, tt := range tests { + t.Run(fmt.Sprintf("difficulty_%d_zero_bits", tt.difficulty), func(t *testing.T) { + actualDifficulty, err := protocol.CountDifficultyBits(tt.bz) + require.NoError(t, err) + require.Equal(t, tt.difficulty, actualDifficulty) + }) + } +} + +func TestCountDifficultyBits_Error(t *testing.T) { + _, err := protocol.CountDifficultyBits([]byte{0, 0, 0, 0}) + require.ErrorIs(t, err, protocol.ErrDifficulty) + require.ErrorContains(t, err, "difficulty matches bytes length") +} diff --git a/pkg/relayer/protocol/errors.go b/pkg/relayer/protocol/errors.go new file mode 100644 index 000000000..f578bf8e0 --- /dev/null +++ b/pkg/relayer/protocol/errors.go @@ -0,0 +1,8 @@ +package protocol + +import errorsmod "cosmossdk.io/errors" + +var ( + ErrDifficulty = errorsmod.New(codespace, 1, "difficulty error") + codespace = "relayer/protocol" +)