-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Miner] feat: add Miner
component
#168
Merged
Merged
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
29b9bdf
refactor: `MapFn`s receive context arg
bryanchriswhite b6c9c71
chore: add `ForEach` map shorthand operator
bryanchriswhite f257b46
chore: add `/pkg/observable/filter`
bryanchriswhite 194cee5
chore: add `/pkg/observable/logging`
bryanchriswhite cca55c2
chore: add `/pkg/relayer/protocol`
bryanchriswhite c666542
chore: add `Miner` interface
bryanchriswhite ea8d848
feat: add `Miner` implementation
bryanchriswhite 38329bb
test: `Miner` implementation
bryanchriswhite d2f9cb4
chore: fix comment
bryanchriswhite d502b75
chore: add godoc comments
bryanchriswhite f85a381
Merge remote-tracking branch 'pokt/main' into issues/13/feat/miner
bryanchriswhite f9e1cbc
[Test] First step for automated E2E Relay test (#167)
Olshansk 0e72490
[Relayer] refactor: simplify `RelayerSessionsManager` (#169)
bryanchriswhite 107f6dd
chore: review feedback improvements
bryanchriswhite ccad087
chore: review feedback improvements
bryanchriswhite 8737024
Merge remote-tracking branch 'pokt/main' into issues/13/feat/miner
bryanchriswhite 85a49b7
fix: import cycle & goimports
bryanchriswhite 0788e1d
chore: review feedback improvements
bryanchriswhite e6a558b
chore: cleanup TODO_THIS_COMMIT comments
bryanchriswhite d04ea2a
Merge branch 'main' into issues/13/feat/miner
bryanchriswhite 9c75b2c
chore: improve var & func names for clarity and consistency
bryanchriswhite 286e1b2
Merge remote-tracking branch 'pokt/main' into issues/13/feat/miner
bryanchriswhite a0ffe9d
refactor: move claim/proof lifecycle concerns to `relayerSessionsMana…
bryanchriswhite 2019637
chore: review feedback improvements
bryanchriswhite 709f661
chore: review feedback improvements
bryanchriswhite 394575b
refactor: `miner#hash()` method
bryanchriswhite 1eae9d2
chore: tidy up
bryanchriswhite efb8a4e
chore: simplify
bryanchriswhite 3b2022a
chore: review feedback improvements
bryanchriswhite 967dddc
chore: review feedback improvements
bryanchriswhite f9a6fb2
chore: review feedback improvements
bryanchriswhite 7d23bd4
chore: review feedback improvements
bryanchriswhite 916c0dd
chore: review feedback improvements
bryanchriswhite 55c8118
fix: incomplete refactor
bryanchriswhite c1784f5
chore: simplify
bryanchriswhite File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,12 @@ | ||
package either | ||
|
||
import "github.com/pokt-network/poktroll/pkg/relayer" | ||
|
||
type ( | ||
// AsyncError represents a value which could either be a synchronous error or | ||
// an asynchronous error (sent through a channel). It wraps the more generic | ||
// `Either` type specific for error channels. | ||
AsyncError Either[chan error] | ||
Bytes = Either[[]byte] | ||
AsyncError Either[chan error] | ||
Bytes = Either[[]byte] | ||
SessionTree = Either[relayer.SessionTree] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package observable | ||
|
||
type ( | ||
Error = Observable[error] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package miner | ||
|
||
import ( | ||
"context" | ||
"crypto/sha256" | ||
"hash" | ||
|
||
"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" | ||
) | ||
|
||
var ( | ||
_ relayer.Miner = (*miner)(nil) | ||
defaultRelayHasher = sha256.New | ||
// 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 | ||
) | ||
|
||
// 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: The relay hashing and relay difficulty mechanisms & values must come | ||
type miner struct { | ||
// relayHasher is a function which returns a hash.Hash interfact type. It is | ||
// used to hash serialized relays to measure their mining difficulty. | ||
relayHasher func() hash.Hash | ||
// relayDifficulty is the minimum difficulty that a relay must have to be | ||
// volume / reward applicable. | ||
relayDifficulty int | ||
} | ||
Olshansk marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// NewMiner creates a new miner from the given dependencies and options. It | ||
// returns an error if it has not been sufficiently configured or supplied. | ||
func NewMiner( | ||
opts ...relayer.MinerOption, | ||
) (*miner, error) { | ||
mnr := &miner{} | ||
|
||
for _, opt := range opts { | ||
opt(mnr) | ||
} | ||
|
||
mnr.setDefaults() | ||
|
||
return mnr, nil | ||
} | ||
|
||
// MinedRelays maps servedRelaysObs through a pipeline which: | ||
// 1. Hashes the relay | ||
// 2. Checks if it's above the mining difficulty | ||
// 3. Adds it to the session tree if so | ||
// It DOES NOT BLOCK as map operations run in their own goroutines. | ||
func (mnr *miner) MinedRelays( | ||
ctx context.Context, | ||
servedRelaysObs observable.Observable[*servicetypes.Relay], | ||
) observable.Observable[*relayer.MinedRelay] { | ||
// Map servedRelaysObs to a new observable of an either type, populated with | ||
// the minedRelay or an error. It is notified after the relay has been mined | ||
// or an error has been encountered, respectively. | ||
eitherMinedRelaysObs := channel.Map(ctx, servedRelaysObs, mnr.mapMineRelay) | ||
logging.LogErrors(ctx, filter.EitherError(ctx, eitherMinedRelaysObs)) | ||
|
||
return filter.EitherSuccess(ctx, eitherMinedRelaysObs) | ||
} | ||
|
||
// setDefaults ensures that the miner has been configured with a hasherConstructor and uses | ||
// the default hasherConstructor if not. | ||
func (mnr *miner) setDefaults() { | ||
if mnr.relayHasher == nil { | ||
mnr.relayHasher = defaultRelayHasher | ||
} | ||
} | ||
|
||
// mapMineRelay is intended to be used as a MapFn. | ||
// 1. It hashes the relay and compares its difficult to the minimum threshold. | ||
// 2. If the relay difficulty is sufficient -> return an Either[MineRelay Value] | ||
// 3. If an error is encountered -> return an Either[error] | ||
// 4. Otherwise, skip the relay. | ||
func (mnr *miner) mapMineRelay( | ||
_ context.Context, | ||
relay *servicetypes.Relay, | ||
) (_ either.Either[*relayer.MinedRelay], skip bool) { | ||
relayBz, err := relay.Marshal() | ||
if err != nil { | ||
return either.Error[*relayer.MinedRelay](err), false | ||
} | ||
|
||
// TODO_BLOCKER: Centralize the logic of hashing a relay. It should live | ||
// alongside signing & verification. | ||
// | ||
// TODO_IMPROVE: We need to hash the key; it would be nice if smst.Update() could do it | ||
// since smst has a reference to the hasherConstructor | ||
relayHash := mnr.hash(relayBz) | ||
|
||
// The relay IS NOT volume / reward applicable | ||
if !protocol.BytesDifficultyGreaterThan(relayHash, defaultRelayDifficulty) { | ||
bryanchriswhite marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return either.Success[*relayer.MinedRelay](nil), true | ||
} | ||
|
||
// The relay IS volume / reward applicable | ||
return either.Success(&relayer.MinedRelay{ | ||
bryanchriswhite marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Relay: *relay, | ||
Bytes: relayBz, | ||
Hash: relayHash, | ||
}), false | ||
} | ||
|
||
// hash constructs a new hasher and hashes the given input bytes. | ||
func (mnr *miner) hash(inputBz []byte) []byte { | ||
hasher := mnr.relayHasher() | ||
hasher.Write(inputBz) | ||
return hasher.Sum(nil) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package miner_test | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
// TODO_TECHDEBT(@bryanchriswhite): add all the test coverage... | ||
func TestNewMiner(t *testing.T) { | ||
bryanchriswhite marked this conversation as resolved.
Show resolved
Hide resolved
|
||
t.Skip("TODO_TECHDEBT(@bryanchriswhite): add all the test coverage...") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package protocol | ||
|
||
import ( | ||
"encoding/binary" | ||
"log" | ||
"math/rand" | ||
|
||
"github.com/pokt-network/poktroll/pkg/client" | ||
) | ||
|
||
// GetEarliestCreateClaimHeight returns the earliest block height at which a claim | ||
// for a session with the given createClaimWindowStartHeight can be created. | ||
// | ||
// TODO_TEST(@bryanchriswhite): Add test coverage and more logs | ||
func GetEarliestCreateClaimHeight(createClaimWindowStartBlock client.Block) int64 { | ||
createClaimWindowStartBlockHash := createClaimWindowStartBlock.Hash() | ||
log.Printf("using createClaimWindowStartBlock %d's hash %x as randomness", createClaimWindowStartBlock.Height(), createClaimWindowStartBlockHash) | ||
rngSeed, _ := binary.Varint(createClaimWindowStartBlockHash) | ||
randomNumber := rand.NewSource(rngSeed).Int63() | ||
|
||
// TODO_TECHDEBT: query the on-chain governance parameter once available. | ||
// randCreateClaimHeightOffset := randomNumber % (claimproofparams.GovCreateClaimIntervalBlocks - claimproofparams.GovCreateClaimWindowBlocks - 1) | ||
_ = randomNumber | ||
randCreateClaimHeightOffset := int64(0) | ||
|
||
return createClaimWindowStartBlock.Height() + randCreateClaimHeightOffset | ||
} | ||
|
||
// GetEarliestSubmitProofHeight returns the earliest block height at which a proof | ||
// for a session with the given submitProofWindowStartHeight can be submitted. | ||
// | ||
// TODO_TEST(@bryanchriswhite): Add test coverage and more logs | ||
func GetEarliestSubmitProofHeight(submitProofWindowStartBlock client.Block) int64 { | ||
earliestSubmitProofBlockHash := submitProofWindowStartBlock.Hash() | ||
log.Printf("using submitProofWindowStartBlock %d's hash %x as randomness", submitProofWindowStartBlock.Height(), earliestSubmitProofBlockHash) | ||
rngSeed, _ := binary.Varint(earliestSubmitProofBlockHash) | ||
randomNumber := rand.NewSource(rngSeed).Int63() | ||
|
||
// TODO_TECHDEBT: query the on-chain governance parameter once available. | ||
// randSubmitProofHeightOffset := randomNumber % (claimproofparams.GovSubmitProofIntervalBlocks - claimproofparams.GovSubmitProofWindowBlocks - 1) | ||
_ = randomNumber | ||
randSubmitProofHeightOffset := int64(0) | ||
|
||
return submitProofWindowStartBlock.Height() + randSubmitProofHeightOffset | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package protocol | ||
|
||
import ( | ||
"encoding/hex" | ||
"strings" | ||
) | ||
|
||
// 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 { | ||
bryanchriswhite marked this conversation as resolved.
Show resolved
Hide resolved
|
||
hexZerosPrefix := strings.Repeat("0", compDifficultyBytes*2) // 2 hex chars per byte. | ||
hexBz := hex.EncodeToString(bz) | ||
|
||
return strings.HasPrefix(hexBz, hexZerosPrefix) | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UNRELATED OPTION NIT: Thoughts on adding a
TODO_TECHDEBT: Add the Obs suffix to all Observables in the codebase
.Might be worthing putting it in
observable.go
if you also agree that it's the right pattern to follow.