mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 14:46:42 +00:00
all: implement milestones (#961)
* Milestone Implementation * Merge branch 'POS-347' into reciept-e2e-test * Changes for testing, will be removed after testing * Debugged the error * Just for testing purpose * refactor debug api methods, rename whitelist -> checkpoint * remove first iteration based vars * fix linters * Rewind Changes * Error changes * RewindBack function in bor_checkpoint_verifier * Testcases * Added the fetch test for milestone and checkpoint * Debugged the lint changes * Debugged the lint changes * Debugged the lint changes * Debugged the lint changes * Improved the error in Miner test file * Improved the error of pointing to the wrong function * Locking the sprint after the vote has been made on it. * Adding more logs for testing * Adding more logs for testing * Adding more logs for testing * Implemented the NoAckMilestone fetching mechanism * Testcases for milestone implementation * Testing code for fetchNoAckMilestone and fetchLastNoAckMilestone * Testing changes * refactor else-if * Corrected the number of params in bor_ext.go * Dummy API for testing * Defined the GetVoteOnRootHash in interface * Defined the GetVoteOnRootHash in interface * Made changes in the web3ext file * Added the GetVoteOnRootHash in PublicBlockChain API * Added the GetVoteOnRootHash in filterBackend * Added the log of Root and RooHash * Removed the 0x from rootHash * Just for testing purpose * "GetVoteOnRootHash" mock implementation * bor_test.go * Added the test for milestone implementation * Added service for fetching milestone by ID * Improved the comments * Removed the duplicate code * use setter for borVerifier * use setter for borVerifier * refactor handleNoAckMilestone * remove code repetition with retry function * Converged the repetitive code * after CR * persistence * persistence implementation * feature flag * Persistence Changes * cr * initial * fix * fix * Whitelist Flag * 1 Add:Included the milestone flag 2.Add:Hardlimit the rewind to maximum of 255 blocks * Chg:Updated go.mod file * Remove:Dubai Hardfork code * Add:checked errors for call functions to the Db, Rmv: Remote Header variable from the IsValidPeer() function * Fix:Linting issues' * Add:MilestoneGRPC functions * Fix:Lint issues * Fix:Lint issues * Fix: TestFetchMilestoneFromMockHeimdall * Fix:Integrations tests * Add:Test for sprint length and milestone changes * Add:Functionality to fetch the finalized block * Chg:Changed default val of TriesInmemory to 1024 * fix:Some functions of heimdallGRPC client * Restored the GRPC functionality, was commented out for developing purpose * Fix:Bor_checkpoint_Verfier function * Test:Added the chain Rewinding test * Test:Added the Sprint Length + Milestone merge test * Add:Implemented the future milestone * Add:Future milestone changes * Add:Future milestone changes * Chg: Voting on endBlockHash rather than rootHash * Chg: Changed the logic of future milestone from rootHash checking to endBlockHash checking * Fix:Using endBockHash while verifying the incoming milestone * Chg:Variable names for better readiblity * Fix:Testing changes * Add:metrics for milestone implementation * Add:Metrics for milestone implementatian * Fix:Order of statements in a function for better optimization * Chg:Removed unrequired file * Fix:new variable intialization * Add:Comment to increase readiblity * Fix:Logs * Chg:Name of GetVoteOnRootHash to GetVoteOnHash * Fix:Linting issues * Fixed linting issues * Rmv: Unnecessary logs and Add:Skip test for long tests * Fix:Checking current chain with whitelisted milestone or checkpoint in Finalized block function * Fix:Test * Fix:Whitelisting of Milestone and Checkpoint process * Fix: Milestone JSON structure * Chg:Testcases changes * Fix:Change from VoteOnRootHash to VoteOnHash * Fix:Variable name fix * Fix:Finalized API * internal/jsre/deps: update web3.js bundle * Fix:milestone verifier * Chg:Handling the long future chain import issue * Fix:Lint issues * Fix:TestLowDiffLongChain and TestPrunedImportSide tests, used hardcoded value 128 instead of DefaultTriesInMemory value * Chg:Testcode for producing metrics * Chg:Milestong polling value to 32 secs * Add:Testcases * Add:Implemented the check to fetch the milestoneId from heimdall before locking the fork * Added GRPC method for FetchMilestoneID * Fix:lint issue * Fix:lint issue * Skiped out the tests which were mainly used to produce the supporting data * remove vcs build when running snyk * Add:Improved the logs and comments * fix linters * Skipped some test as they are panic due to timeout issue in github * Chg:Variable name LockerSprintNumber to LockedMilestoneNumber for better readablity and clarity * Chg:Conflicting variable names in milestone test file * Chg:Conflicting function names in milestone test file * fix : minor fix in TestInsertingSpanSizeBlocks * Fix:Mocking issue in TestInsertingSpanSizeBlocks * Fix:GRPC Polyproto Version * eth/downloader: skip peer drop due to whitelisting err * eth, tests/bor: bug fixes and minor refactor * Add:Implemented the milestone related functions in the HeimdallApp * Fix:Lint Errors & Remove:Redundant Code * Fix:Testing Errors * Fix:Bor integeration tests * Fix:Test errors * update heimdall client mock files * remove unused arguments * remove redundant code * Chg:Changed the milestone polling intervals * Add: added block finality from whitelisted checkpoint * skip future chain validation * Add:confirmation check of 16 blocks over the end block while voting for the milestone in GetVoteHash() function * Chg:Included endBlockNum in UnlockMutex function * Add:Property based test for milestone * Fix:Opening the lock while processing future milestone * Add:Property based test for futureMilestone * Defined the value of TempTriesInMemory * Fixed the finalized api * Fixed lint issues * eth: add logs while fetching and rewinding * fix linters: use default returns instead of recursive calls * Fix:Milestone intergration test * Add:GetVoteHash fn in mock backend * tests/bor: fix mock span * tests/bor: remove t.Parallel() * use bor namespace in ethclient, fix mock function --------- Co-authored-by: Vaibhav Jindal <vaibhavjindal29@gmail.com> Co-authored-by: VaibhavJindal <74560896+VAIBHAVJINDAL3012@users.noreply.github.com> Co-authored-by: Manav Darji <manavdarji.india@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: Shivam Sharma <shivam691999@gmail.com> Co-authored-by: Anshal Shukla <shukla.anshal85@gmail.com>
This commit is contained in:
parent
b38412dd9b
commit
b48b89f852
58 changed files with 5639 additions and 612 deletions
|
|
@ -24,6 +24,10 @@ func (fb *filterBackend) GetBorBlockReceipt(ctx context.Context, hash common.Has
|
||||||
return receipt, nil
|
return receipt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fb *filterBackend) GetVoteOnHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64, hash string, milestoneId string) (bool, error) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (fb *filterBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) {
|
func (fb *filterBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) {
|
||||||
receipt, err := fb.GetBorBlockReceipt(ctx, hash)
|
receipt, err := fb.GetBorBlockReceipt(ctx, hash)
|
||||||
if err != nil || receipt == nil {
|
if err != nil || receipt == nil {
|
||||||
|
|
|
||||||
3
common/flags/milestone.go
Normal file
3
common/flags/milestone.go
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
package flags
|
||||||
|
|
||||||
|
const Milestone = true
|
||||||
5
common/gererics/empty.go
Normal file
5
common/gererics/empty.go
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
package gererics
|
||||||
|
|
||||||
|
func Empty[T any]() (t T) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
@ -341,6 +341,10 @@ func (api *API) GetRootHash(start uint64, end uint64) (string, error) {
|
||||||
return root, nil
|
return root, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *API) GetVoteOnHash(starBlockNr uint64, endBlockNr uint64, hash string, milestoneId string) (bool, error) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (api *API) initializeRootHashCache() error {
|
func (api *API) initializeRootHashCache() error {
|
||||||
var err error
|
var err error
|
||||||
if api.rootHashCache == nil {
|
if api.rootHashCache == nil {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/milestone"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -14,5 +15,10 @@ type IHeimdallClient interface {
|
||||||
Span(ctx context.Context, spanID uint64) (*span.HeimdallSpan, error)
|
Span(ctx context.Context, spanID uint64) (*span.HeimdallSpan, error)
|
||||||
FetchCheckpoint(ctx context.Context, number int64) (*checkpoint.Checkpoint, error)
|
FetchCheckpoint(ctx context.Context, number int64) (*checkpoint.Checkpoint, error)
|
||||||
FetchCheckpointCount(ctx context.Context) (int64, error)
|
FetchCheckpointCount(ctx context.Context) (int64, error)
|
||||||
|
FetchMilestone(ctx context.Context) (*milestone.Milestone, error)
|
||||||
|
FetchMilestoneCount(ctx context.Context) (int64, error)
|
||||||
|
FetchNoAckMilestone(ctx context.Context, milestoneID string) error //Fetch the bool value whether milestone corresponding to the given id failed in the Heimdall
|
||||||
|
FetchLastNoAckMilestone(ctx context.Context) (string, error) //Fetch latest failed milestone id
|
||||||
|
FetchMilestoneID(ctx context.Context, milestoneID string) error //Fetch the bool value whether milestone corresponding to the given id is in process in Heimdall
|
||||||
Close()
|
Close()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/milestone"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
|
@ -23,6 +24,8 @@ var (
|
||||||
ErrShutdownDetected = errors.New("shutdown detected")
|
ErrShutdownDetected = errors.New("shutdown detected")
|
||||||
ErrNoResponse = errors.New("got a nil response")
|
ErrNoResponse = errors.New("got a nil response")
|
||||||
ErrNotSuccessfulResponse = errors.New("error while fetching data from Heimdall")
|
ErrNotSuccessfulResponse = errors.New("error while fetching data from Heimdall")
|
||||||
|
ErrNotInRejectedList = errors.New("milestoneID doesn't exist in rejected list")
|
||||||
|
ErrNotInMilestoneList = errors.New("milestoneID doesn't exist in Heimdall")
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -66,9 +69,17 @@ func NewHeimdallClient(urlString string) *HeimdallClient {
|
||||||
const (
|
const (
|
||||||
fetchStateSyncEventsFormat = "from-id=%d&to-time=%d&limit=%d"
|
fetchStateSyncEventsFormat = "from-id=%d&to-time=%d&limit=%d"
|
||||||
fetchStateSyncEventsPath = "clerk/event-record/list"
|
fetchStateSyncEventsPath = "clerk/event-record/list"
|
||||||
|
|
||||||
fetchCheckpoint = "/checkpoints/%s"
|
fetchCheckpoint = "/checkpoints/%s"
|
||||||
fetchCheckpointCount = "/checkpoints/count"
|
fetchCheckpointCount = "/checkpoints/count"
|
||||||
|
|
||||||
|
fetchMilestone = "/milestone/latest"
|
||||||
|
fetchMilestoneCount = "/milestone/count"
|
||||||
|
|
||||||
|
fetchLastNoAckMilestone = "/milestone/lastNoAck"
|
||||||
|
fetchNoAckMilestone = "/milestone/noAck/%s"
|
||||||
|
fetchMilestoneID = "/milestone/ID/%s"
|
||||||
|
|
||||||
fetchSpanFormat = "bor/span/%d"
|
fetchSpanFormat = "bor/span/%d"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -144,6 +155,23 @@ func (h *HeimdallClient) FetchCheckpoint(ctx context.Context, number int64) (*ch
|
||||||
return &response.Result, nil
|
return &response.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FetchMilestone fetches the checkpoint from heimdall
|
||||||
|
func (h *HeimdallClient) FetchMilestone(ctx context.Context) (*milestone.Milestone, error) {
|
||||||
|
url, err := milestoneURL(h.urlString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = withRequestType(ctx, milestoneRequest)
|
||||||
|
|
||||||
|
response, err := FetchWithRetry[milestone.MilestoneResponse](ctx, h.client, url, h.closeCh)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &response.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
// FetchCheckpointCount fetches the checkpoint count from heimdall
|
// FetchCheckpointCount fetches the checkpoint count from heimdall
|
||||||
func (h *HeimdallClient) FetchCheckpointCount(ctx context.Context) (int64, error) {
|
func (h *HeimdallClient) FetchCheckpointCount(ctx context.Context) (int64, error) {
|
||||||
url, err := checkpointCountURL(h.urlString)
|
url, err := checkpointCountURL(h.urlString)
|
||||||
|
|
@ -161,6 +189,84 @@ func (h *HeimdallClient) FetchCheckpointCount(ctx context.Context) (int64, error
|
||||||
return response.Result.Result, nil
|
return response.Result.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FetchMilestoneCount fetches the milestone count from heimdall
|
||||||
|
func (h *HeimdallClient) FetchMilestoneCount(ctx context.Context) (int64, error) {
|
||||||
|
url, err := milestoneCountURL(h.urlString)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = withRequestType(ctx, milestoneCountRequest)
|
||||||
|
|
||||||
|
response, err := FetchWithRetry[milestone.MilestoneCountResponse](ctx, h.client, url, h.closeCh)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Result.Count, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchLastNoAckMilestone fetches the last no-ack-milestone from heimdall
|
||||||
|
func (h *HeimdallClient) FetchLastNoAckMilestone(ctx context.Context) (string, error) {
|
||||||
|
url, err := lastNoAckMilestoneURL(h.urlString)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = withRequestType(ctx, milestoneLastNoAckRequest)
|
||||||
|
|
||||||
|
response, err := FetchWithRetry[milestone.MilestoneLastNoAckResponse](ctx, h.client, url, h.closeCh)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Result.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchNoAckMilestone fetches the last no-ack-milestone from heimdall
|
||||||
|
func (h *HeimdallClient) FetchNoAckMilestone(ctx context.Context, milestoneID string) error {
|
||||||
|
url, err := noAckMilestoneURL(h.urlString, milestoneID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = withRequestType(ctx, milestoneNoAckRequest)
|
||||||
|
|
||||||
|
response, err := FetchWithRetry[milestone.MilestoneNoAckResponse](ctx, h.client, url, h.closeCh)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !response.Result.Result {
|
||||||
|
return fmt.Errorf("%w: milestoneID %q", ErrNotInRejectedList, milestoneID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchMilestoneID fetches the bool result from Heimdal whether the ID corresponding
|
||||||
|
// to the given milestone is in process in Heimdall
|
||||||
|
func (h *HeimdallClient) FetchMilestoneID(ctx context.Context, milestoneID string) error {
|
||||||
|
url, err := milestoneIDURL(h.urlString, milestoneID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = withRequestType(ctx, milestoneIDRequest)
|
||||||
|
|
||||||
|
response, err := FetchWithRetry[milestone.MilestoneIDResponse](ctx, h.client, url, h.closeCh)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !response.Result.Result {
|
||||||
|
return fmt.Errorf("%w: milestoneID %q", ErrNotInMilestoneList, milestoneID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// FetchWithRetry returns data from heimdall with retry
|
// FetchWithRetry returns data from heimdall with retry
|
||||||
func FetchWithRetry[T any](ctx context.Context, client http.Client, url *url.URL, closeCh chan struct{}) (*T, error) {
|
func FetchWithRetry[T any](ctx context.Context, client http.Client, url *url.URL, closeCh chan struct{}) (*T, error) {
|
||||||
// request data once
|
// request data once
|
||||||
|
|
@ -266,10 +372,34 @@ func checkpointURL(urlString string, number int64) (*url.URL, error) {
|
||||||
return makeURL(urlString, url, "")
|
return makeURL(urlString, url, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func milestoneURL(urlString string) (*url.URL, error) {
|
||||||
|
url := fetchMilestone
|
||||||
|
|
||||||
|
return makeURL(urlString, url, "")
|
||||||
|
}
|
||||||
|
|
||||||
func checkpointCountURL(urlString string) (*url.URL, error) {
|
func checkpointCountURL(urlString string) (*url.URL, error) {
|
||||||
return makeURL(urlString, fetchCheckpointCount, "")
|
return makeURL(urlString, fetchCheckpointCount, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func milestoneCountURL(urlString string) (*url.URL, error) {
|
||||||
|
return makeURL(urlString, fetchMilestoneCount, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func lastNoAckMilestoneURL(urlString string) (*url.URL, error) {
|
||||||
|
return makeURL(urlString, fetchLastNoAckMilestone, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func noAckMilestoneURL(urlString string, id string) (*url.URL, error) {
|
||||||
|
url := fmt.Sprintf(fetchNoAckMilestone, id)
|
||||||
|
return makeURL(urlString, url, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func milestoneIDURL(urlString string, id string) (*url.URL, error) {
|
||||||
|
url := fmt.Sprintf(fetchMilestoneID, id)
|
||||||
|
return makeURL(urlString, url, "")
|
||||||
|
}
|
||||||
|
|
||||||
func makeURL(urlString, rawPath, rawQuery string) (*url.URL, error) {
|
func makeURL(urlString, rawPath, rawQuery string) (*url.URL, error) {
|
||||||
u, err := url.Parse(urlString)
|
u, err := url.Parse(urlString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/network"
|
"github.com/ethereum/go-ethereum/common/network"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/milestone"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
@ -24,6 +25,9 @@ import (
|
||||||
// according to requirements.
|
// according to requirements.
|
||||||
type HttpHandlerFake struct {
|
type HttpHandlerFake struct {
|
||||||
handleFetchCheckpoint http.HandlerFunc
|
handleFetchCheckpoint http.HandlerFunc
|
||||||
|
handleFetchMilestone http.HandlerFunc
|
||||||
|
handleFetchNoAckMilestone http.HandlerFunc
|
||||||
|
handleFetchLastNoAckMilestone http.HandlerFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpHandlerFake) GetCheckpointHandler() http.HandlerFunc {
|
func (h *HttpHandlerFake) GetCheckpointHandler() http.HandlerFunc {
|
||||||
|
|
@ -32,6 +36,24 @@ func (h *HttpHandlerFake) GetCheckpointHandler() http.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *HttpHandlerFake) GetMilestoneHandler() http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
h.handleFetchMilestone.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpHandlerFake) GetNoAckMilestoneHandler() http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
h.handleFetchNoAckMilestone.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpHandlerFake) GetLastNoAckMilestoneHandler() http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
h.handleFetchLastNoAckMilestone.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func CreateMockHeimdallServer(wg *sync.WaitGroup, port int, listener net.Listener, handler *HttpHandlerFake) (*http.Server, error) {
|
func CreateMockHeimdallServer(wg *sync.WaitGroup, port int, listener net.Listener, handler *HttpHandlerFake) (*http.Server, error) {
|
||||||
// Create a new server mux
|
// Create a new server mux
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
|
@ -41,6 +63,21 @@ func CreateMockHeimdallServer(wg *sync.WaitGroup, port int, listener net.Listene
|
||||||
handler.GetCheckpointHandler()(w, r)
|
handler.GetCheckpointHandler()(w, r)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Create a route for fetching milestone
|
||||||
|
mux.HandleFunc("/milestone/latest", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
handler.GetMilestoneHandler()(w, r)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create a route for fetching milestone
|
||||||
|
mux.HandleFunc("/milestone/noAck/{id}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
handler.GetNoAckMilestoneHandler()(w, r)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create a route for fetching milestone
|
||||||
|
mux.HandleFunc("/milestone/lastNoAck", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
handler.GetLastNoAckMilestoneHandler()(w, r)
|
||||||
|
})
|
||||||
|
|
||||||
// Add other routes as per requirement
|
// Add other routes as per requirement
|
||||||
|
|
||||||
// Create the server with given port and mux
|
// Create the server with given port and mux
|
||||||
|
|
@ -118,9 +155,59 @@ func TestFetchCheckpointFromMockHeimdall(t *testing.T) {
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestFetchMilestoneFromMockHeimdall tests the heimdall client side logic
|
||||||
|
// to fetch milestone from a mock heimdall server.
|
||||||
|
// It can be used for debugging purpose (like response fields, marshalling/unmarshalling, etc).
|
||||||
|
func TestFetchMilestoneFromMockHeimdall(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Create a wait group for sending across the mock server
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
// Initialize the fake handler and add a fake milestone handler function
|
||||||
|
handler := &HttpHandlerFake{}
|
||||||
|
handler.handleFetchMilestone = func(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
err := json.NewEncoder(w).Encode(milestone.MilestoneResponse{
|
||||||
|
Height: "0",
|
||||||
|
Result: milestone.Milestone{
|
||||||
|
Proposer: common.Address{},
|
||||||
|
StartBlock: big.NewInt(0),
|
||||||
|
EndBlock: big.NewInt(512),
|
||||||
|
Hash: common.Hash{},
|
||||||
|
BorChainID: "15001",
|
||||||
|
Timestamp: 0,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(500) // Return 500 Internal Server Error.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch available port
|
||||||
|
port, listener, err := network.FindAvailablePort()
|
||||||
|
require.NoError(t, err, "expect no error in finding available port")
|
||||||
|
|
||||||
|
// Create mock heimdall server and pass handler instance for setting up the routes
|
||||||
|
srv, err := CreateMockHeimdallServer(wg, port, listener, handler)
|
||||||
|
require.NoError(t, err, "expect no error in starting mock heimdall server")
|
||||||
|
|
||||||
|
// Create a new heimdall client and use same port for connection
|
||||||
|
client := NewHeimdallClient(fmt.Sprintf("http://localhost:%d", port))
|
||||||
|
_, err = client.FetchMilestone(context.Background())
|
||||||
|
require.NoError(t, err, "expect no error in fetching milestone")
|
||||||
|
|
||||||
|
// Shutdown the server
|
||||||
|
err = srv.Shutdown(context.TODO())
|
||||||
|
require.NoError(t, err, "expect no error in shutting down mock heimdall server")
|
||||||
|
|
||||||
|
// Wait for `wg.Done()` to be called in the mock server's routine.
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
// TestFetchShutdown tests the heimdall client side logic for context timeout and
|
// TestFetchShutdown tests the heimdall client side logic for context timeout and
|
||||||
// interrupt handling while fetching checkpoints (latest for the scope of test)
|
// interrupt handling while fetching data from a mock heimdall server.
|
||||||
// from a mock heimdall server.
|
|
||||||
func TestFetchShutdown(t *testing.T) {
|
func TestFetchShutdown(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|
@ -135,7 +222,7 @@ func TestFetchShutdown(t *testing.T) {
|
||||||
// greater than `retryDelay`. This should cause the request to timeout and trigger shutdown
|
// greater than `retryDelay`. This should cause the request to timeout and trigger shutdown
|
||||||
// due to `ctx.Done()`. Expect context timeout error.
|
// due to `ctx.Done()`. Expect context timeout error.
|
||||||
handler.handleFetchCheckpoint = func(w http.ResponseWriter, _ *http.Request) {
|
handler.handleFetchCheckpoint = func(w http.ResponseWriter, _ *http.Request) {
|
||||||
time.Sleep(6 * time.Second)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
err := json.NewEncoder(w).Encode(checkpoint.CheckpointResponse{
|
err := json.NewEncoder(w).Encode(checkpoint.CheckpointResponse{
|
||||||
Height: "0",
|
Height: "0",
|
||||||
|
|
@ -165,7 +252,7 @@ func TestFetchShutdown(t *testing.T) {
|
||||||
// Create a new heimdall client and use same port for connection
|
// Create a new heimdall client and use same port for connection
|
||||||
client := NewHeimdallClient(fmt.Sprintf("http://localhost:%d", port))
|
client := NewHeimdallClient(fmt.Sprintf("http://localhost:%d", port))
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
|
||||||
|
|
||||||
// Expect this to fail due to timeout
|
// Expect this to fail due to timeout
|
||||||
_, err = client.FetchCheckpoint(ctx, -1)
|
_, err = client.FetchCheckpoint(ctx, -1)
|
||||||
|
|
@ -182,7 +269,7 @@ func TestFetchShutdown(t *testing.T) {
|
||||||
w.WriteHeader(500) // Return 500 Internal Server Error.
|
w.WriteHeader(500) // Return 500 Internal Server Error.
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second) // Use some high value for timeout
|
ctx, cancel = context.WithTimeout(context.Background(), 50*time.Millisecond) // Use some high value for timeout
|
||||||
|
|
||||||
// Cancel the context after a delay until we make request
|
// Cancel the context after a delay until we make request
|
||||||
go func(cancel context.CancelFunc) {
|
go func(cancel context.CancelFunc) {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,11 @@ const (
|
||||||
spanRequest requestType = "span"
|
spanRequest requestType = "span"
|
||||||
checkpointRequest requestType = "checkpoint"
|
checkpointRequest requestType = "checkpoint"
|
||||||
checkpointCountRequest requestType = "checkpoint-count"
|
checkpointCountRequest requestType = "checkpoint-count"
|
||||||
|
milestoneRequest requestType = "milestone"
|
||||||
|
milestoneCountRequest requestType = "milestone-count"
|
||||||
|
milestoneNoAckRequest requestType = "milestone-no-ack"
|
||||||
|
milestoneLastNoAckRequest requestType = "milestone-last-no-ack"
|
||||||
|
milestoneIDRequest requestType = "milestone-id"
|
||||||
)
|
)
|
||||||
|
|
||||||
func withRequestType(ctx context.Context, reqType requestType) context.Context {
|
func withRequestType(ctx context.Context, reqType requestType) context.Context {
|
||||||
|
|
@ -63,6 +68,41 @@ var (
|
||||||
},
|
},
|
||||||
timer: metrics.NewRegisteredTimer("client/requests/checkpointcount/duration", nil),
|
timer: metrics.NewRegisteredTimer("client/requests/checkpointcount/duration", nil),
|
||||||
},
|
},
|
||||||
|
milestoneRequest: {
|
||||||
|
request: map[bool]metrics.Meter{
|
||||||
|
true: metrics.NewRegisteredMeter("client/requests/milestone/valid", nil),
|
||||||
|
false: metrics.NewRegisteredMeter("client/requests/milestone/invalid", nil),
|
||||||
|
},
|
||||||
|
timer: metrics.NewRegisteredTimer("client/requests/milestone/duration", nil),
|
||||||
|
},
|
||||||
|
milestoneCountRequest: {
|
||||||
|
request: map[bool]metrics.Meter{
|
||||||
|
true: metrics.NewRegisteredMeter("client/requests/milestonecount/valid", nil),
|
||||||
|
false: metrics.NewRegisteredMeter("client/requests/milestonecount/invalid", nil),
|
||||||
|
},
|
||||||
|
timer: metrics.NewRegisteredTimer("client/requests/milestonecount/duration", nil),
|
||||||
|
},
|
||||||
|
milestoneNoAckRequest: {
|
||||||
|
request: map[bool]metrics.Meter{
|
||||||
|
true: metrics.NewRegisteredMeter("client/requests/milestonenoack/valid", nil),
|
||||||
|
false: metrics.NewRegisteredMeter("client/requests/milestonenoack/invalid", nil),
|
||||||
|
},
|
||||||
|
timer: metrics.NewRegisteredTimer("client/requests/milestonenoack/duration", nil),
|
||||||
|
},
|
||||||
|
milestoneLastNoAckRequest: {
|
||||||
|
request: map[bool]metrics.Meter{
|
||||||
|
true: metrics.NewRegisteredMeter("client/requests/milestonelastnoack/valid", nil),
|
||||||
|
false: metrics.NewRegisteredMeter("client/requests/milestonelastnoack/invalid", nil),
|
||||||
|
},
|
||||||
|
timer: metrics.NewRegisteredTimer("client/requests/milestonelastnoack/duration", nil),
|
||||||
|
},
|
||||||
|
milestoneIDRequest: {
|
||||||
|
request: map[bool]metrics.Meter{
|
||||||
|
true: metrics.NewRegisteredMeter("client/requests/milestoneid/valid", nil),
|
||||||
|
false: metrics.NewRegisteredMeter("client/requests/milestoneid/invalid", nil),
|
||||||
|
},
|
||||||
|
timer: metrics.NewRegisteredTimer("client/requests/milestoneid/duration", nil),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
58
consensus/bor/heimdall/milestone/milestone.go
Normal file
58
consensus/bor/heimdall/milestone/milestone.go
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
package milestone
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// milestone defines a response object type of bor milestone
|
||||||
|
type Milestone struct {
|
||||||
|
Proposer common.Address `json:"proposer"`
|
||||||
|
StartBlock *big.Int `json:"start_block"`
|
||||||
|
EndBlock *big.Int `json:"end_block"`
|
||||||
|
Hash common.Hash `json:"hash"`
|
||||||
|
BorChainID string `json:"bor_chain_id"`
|
||||||
|
Timestamp uint64 `json:"timestamp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MilestoneResponse struct {
|
||||||
|
Height string `json:"height"`
|
||||||
|
Result Milestone `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MilestoneCount struct {
|
||||||
|
Count int64 `json:"count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MilestoneCountResponse struct {
|
||||||
|
Height string `json:"height"`
|
||||||
|
Result MilestoneCount `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MilestoneLastNoAck struct {
|
||||||
|
Result string `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MilestoneLastNoAckResponse struct {
|
||||||
|
Height string `json:"height"`
|
||||||
|
Result MilestoneLastNoAck `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MilestoneNoAck struct {
|
||||||
|
Result bool `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MilestoneNoAckResponse struct {
|
||||||
|
Height string `json:"height"`
|
||||||
|
Result MilestoneNoAck `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MilestoneID struct {
|
||||||
|
Result bool `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MilestoneIDResponse struct {
|
||||||
|
Height string `json:"height"`
|
||||||
|
Result MilestoneID `json:"result"`
|
||||||
|
}
|
||||||
|
|
@ -4,13 +4,10 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/types"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
||||||
hmTypes "github.com/maticnetwork/heimdall/types"
|
hmTypes "github.com/maticnetwork/heimdall/types"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *HeimdallAppClient) FetchCheckpointCount(_ context.Context) (int64, error) {
|
func (h *HeimdallAppClient) FetchCheckpointCount(_ context.Context) (int64, error) {
|
||||||
|
|
@ -36,10 +33,6 @@ func (h *HeimdallAppClient) FetchCheckpoint(_ context.Context, number int64) (*c
|
||||||
return toBorCheckpoint(res), nil
|
return toBorCheckpoint(res), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HeimdallAppClient) NewContext() types.Context {
|
|
||||||
return h.hApp.NewContext(true, abci.Header{Height: h.hApp.LastBlockHeight()})
|
|
||||||
}
|
|
||||||
|
|
||||||
func toBorCheckpoint(hdCheckpoint hmTypes.Checkpoint) *checkpoint.Checkpoint {
|
func toBorCheckpoint(hdCheckpoint hmTypes.Checkpoint) *checkpoint.Checkpoint {
|
||||||
return &checkpoint.Checkpoint{
|
return &checkpoint.Checkpoint{
|
||||||
Proposer: hdCheckpoint.Proposer.EthAddress(),
|
Proposer: hdCheckpoint.Proposer.EthAddress(),
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
package heimdallapp
|
package heimdallapp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
||||||
"github.com/maticnetwork/heimdall/app"
|
"github.com/maticnetwork/heimdall/app"
|
||||||
"github.com/maticnetwork/heimdall/cmd/heimdalld/service"
|
"github.com/maticnetwork/heimdall/cmd/heimdalld/service"
|
||||||
|
|
||||||
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -25,3 +29,7 @@ func (h *HeimdallAppClient) Close() {
|
||||||
// Nothing to close as of now
|
// Nothing to close as of now
|
||||||
log.Warn("Shutdown detected, Closing Heimdall App conn")
|
log.Warn("Shutdown detected, Closing Heimdall App conn")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *HeimdallAppClient) NewContext() types.Context {
|
||||||
|
return h.hApp.NewContext(true, abci.Header{Height: h.hApp.LastBlockHeight()})
|
||||||
|
}
|
||||||
|
|
|
||||||
82
consensus/bor/heimdallapp/milestone.go
Normal file
82
consensus/bor/heimdallapp/milestone.go
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
package heimdallapp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/milestone"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
||||||
|
chTypes "github.com/maticnetwork/heimdall/checkpoint/types"
|
||||||
|
hmTypes "github.com/maticnetwork/heimdall/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *HeimdallAppClient) FetchMilestoneCount(_ context.Context) (int64, error) {
|
||||||
|
log.Info("Fetching milestone count")
|
||||||
|
|
||||||
|
res := h.hApp.CheckpointKeeper.GetMilestoneCount(h.NewContext())
|
||||||
|
|
||||||
|
log.Info("Fetched Milestone Count")
|
||||||
|
|
||||||
|
return int64(res), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HeimdallAppClient) FetchMilestone(_ context.Context) (*milestone.Milestone, error) {
|
||||||
|
log.Info("Fetching Latest Milestone")
|
||||||
|
|
||||||
|
res, err := h.hApp.CheckpointKeeper.GetLastMilestone(h.NewContext())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Fetched Latest Milestone")
|
||||||
|
|
||||||
|
return toBorMilestone(res), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HeimdallAppClient) FetchNoAckMilestone(_ context.Context, milestoneID string) error {
|
||||||
|
log.Info("Fetching No Ack Milestone By MilestoneID", "MilestoneID", milestoneID)
|
||||||
|
|
||||||
|
res := h.hApp.CheckpointKeeper.GetNoAckMilestone(h.NewContext(), milestoneID)
|
||||||
|
if res {
|
||||||
|
log.Info("Fetched No Ack By MilestoneID", "MilestoneID", milestoneID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Still No Ack Milestone exist corresponding to MilestoneId:%v", milestoneID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HeimdallAppClient) FetchLastNoAckMilestone(_ context.Context) (string, error) {
|
||||||
|
log.Info("Fetching Latest No Ack Milestone ID")
|
||||||
|
|
||||||
|
res := h.hApp.CheckpointKeeper.GetLastNoAckMilestone(h.NewContext())
|
||||||
|
|
||||||
|
log.Info("Fetched Latest No Ack Milestone ID")
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HeimdallAppClient) FetchMilestoneID(_ context.Context, milestoneID string) error {
|
||||||
|
log.Info("Fetching Milestone ID ", "MilestoneID", milestoneID)
|
||||||
|
|
||||||
|
res := chTypes.GetMilestoneID()
|
||||||
|
|
||||||
|
if res == milestoneID {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Milestone corresponding to Milestone ID:%v doesn't exist in Heimdall", milestoneID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toBorMilestone(hdMilestone *hmTypes.Milestone) *milestone.Milestone {
|
||||||
|
return &milestone.Milestone{
|
||||||
|
Proposer: hdMilestone.Proposer.EthAddress(),
|
||||||
|
StartBlock: big.NewInt(int64(hdMilestone.StartBlock)),
|
||||||
|
EndBlock: big.NewInt(int64(hdMilestone.EndBlock)),
|
||||||
|
Hash: hdMilestone.Hash.EthHash(),
|
||||||
|
BorChainID: hdMilestone.BorChainID,
|
||||||
|
Timestamp: hdMilestone.TimeStamp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,22 +7,18 @@ import (
|
||||||
"github.com/maticnetwork/heimdall/clerk/types"
|
"github.com/maticnetwork/heimdall/clerk/types"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *HeimdallAppClient) StateSyncEvents(ctx context.Context, fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error) {
|
func (h *HeimdallAppClient) StateSyncEvents(ctx context.Context, fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error) {
|
||||||
totalRecords := make([]*clerk.EventRecordWithTime, 0)
|
totalRecords := make([]*clerk.EventRecordWithTime, 0)
|
||||||
|
|
||||||
hCtx := h.hApp.NewContext(true, abci.Header{Height: h.hApp.LastBlockHeight()})
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
fromRecord, err := h.hApp.ClerkKeeper.GetEventRecord(hCtx, fromID)
|
fromRecord, err := h.hApp.ClerkKeeper.GetEventRecord(h.NewContext(), fromID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
events, err := h.hApp.ClerkKeeper.GetEventRecordListWithTime(hCtx, fromRecord.RecordTime, time.Unix(to, 0), 1, stateFetchLimit)
|
events, err := h.hApp.ClerkKeeper.GetEventRecordListWithTime(h.NewContext(), fromRecord.RecordTime, time.Unix(to, 0), 1, stateFetchLimit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
103
consensus/bor/heimdallgrpc/milestone.go
Normal file
103
consensus/bor/heimdallgrpc/milestone.go
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
package heimdallgrpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/milestone"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
||||||
|
proto "github.com/maticnetwork/polyproto/heimdall"
|
||||||
|
protoutils "github.com/maticnetwork/polyproto/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *HeimdallGRPCClient) FetchMilestoneCount(ctx context.Context) (int64, error) {
|
||||||
|
log.Info("Fetching milestone count")
|
||||||
|
|
||||||
|
res, err := h.client.FetchMilestoneCount(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Fetched milestone count")
|
||||||
|
|
||||||
|
return res.Result.Count, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HeimdallGRPCClient) FetchMilestone(ctx context.Context) (*milestone.Milestone, error) {
|
||||||
|
log.Info("Fetching milestone")
|
||||||
|
|
||||||
|
res, err := h.client.FetchMilestone(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Fetched milestone")
|
||||||
|
|
||||||
|
milestone := &milestone.Milestone{
|
||||||
|
StartBlock: new(big.Int).SetUint64(res.Result.StartBlock),
|
||||||
|
EndBlock: new(big.Int).SetUint64(res.Result.EndBlock),
|
||||||
|
Hash: protoutils.ConvertH256ToHash(res.Result.RootHash),
|
||||||
|
Proposer: protoutils.ConvertH160toAddress(res.Result.Proposer),
|
||||||
|
BorChainID: res.Result.BorChainID,
|
||||||
|
Timestamp: uint64(res.Result.Timestamp.GetSeconds()),
|
||||||
|
}
|
||||||
|
|
||||||
|
return milestone, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HeimdallGRPCClient) FetchLastNoAckMilestone(ctx context.Context) (string, error) {
|
||||||
|
log.Info("Fetching latest no ack milestone Id")
|
||||||
|
|
||||||
|
res, err := h.client.FetchLastNoAckMilestone(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Fetched last no-ack milestone")
|
||||||
|
|
||||||
|
return res.Result.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HeimdallGRPCClient) FetchNoAckMilestone(ctx context.Context, milestoneID string) error {
|
||||||
|
req := &proto.FetchMilestoneNoAckRequest{
|
||||||
|
MilestoneID: milestoneID,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Fetching no ack milestone", "milestoneaID", milestoneID)
|
||||||
|
|
||||||
|
res, err := h.client.FetchNoAckMilestone(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !res.Result.Result {
|
||||||
|
return fmt.Errorf("Not in rejected list: milestoneID %q", milestoneID)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Fetched no ack milestone", "milestoneaID", milestoneID)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HeimdallGRPCClient) FetchMilestoneID(ctx context.Context, milestoneID string) error {
|
||||||
|
req := &proto.FetchMilestoneIDRequest{
|
||||||
|
MilestoneID: milestoneID,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Fetching milestone id", "milestoneID", milestoneID)
|
||||||
|
|
||||||
|
res, err := h.client.FetchMilestoneID(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !res.Result.Result {
|
||||||
|
return fmt.Errorf("This milestoneID %q does not exist", milestoneID)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Fetched milestone id", "milestoneID", milestoneID)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -163,7 +163,7 @@ var DefaultCacheConfig = &CacheConfig{
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
SnapshotLimit: 256,
|
SnapshotLimit: 256,
|
||||||
SnapshotWait: true,
|
SnapshotWait: true,
|
||||||
TriesInMemory: 128,
|
TriesInMemory: 1024,
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockChain represents the canonical chain given a database with a genesis
|
// BlockChain represents the canonical chain given a database with a genesis
|
||||||
|
|
@ -1964,8 +1964,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool)
|
||||||
|
|
||||||
if !isValid {
|
if !isValid {
|
||||||
// The chain to be imported is invalid as the blocks doesn't match with
|
// The chain to be imported is invalid as the blocks doesn't match with
|
||||||
// the whitelisted checkpoints.
|
// the whitelisted block number.
|
||||||
return it.index, whitelist.ErrCheckpointMismatch
|
return it.index, whitelist.ErrMismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
// Left-trim all the known blocks that don't need to build snapshot
|
// Left-trim all the known blocks that don't need to build snapshot
|
||||||
|
|
@ -3112,6 +3112,10 @@ func (bc *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (i
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bc *BlockChain) GetChainConfig() *params.ChainConfig {
|
||||||
|
return bc.chainConfig
|
||||||
|
}
|
||||||
|
|
||||||
// SetBlockValidatorAndProcessorForTesting sets the current validator and processor.
|
// SetBlockValidatorAndProcessorForTesting sets the current validator and processor.
|
||||||
// This method can be used to force an invalid blockchain to be verified for tests.
|
// This method can be used to force an invalid blockchain to be verified for tests.
|
||||||
// This method is unsafe and should only be used before block import starts.
|
// This method is unsafe and should only be used before block import starts.
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,17 @@ func (bc *BlockChain) CurrentSafeBlock() *types.Header {
|
||||||
return bc.currentSafeBlock.Load()
|
return bc.currentSafeBlock.Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CurrentFinalizedBlock retrieves the current finalized block of the canonical
|
||||||
|
// chain. The block is retrieved from the blockchain's internal cache.
|
||||||
|
func (bc *BlockChain) CurrentFinalizedBlock(number uint64) *types.Block {
|
||||||
|
hash := rawdb.ReadCanonicalHash(bc.db, number)
|
||||||
|
if hash == (common.Hash{}) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return bc.GetBlock(hash, number)
|
||||||
|
}
|
||||||
|
|
||||||
// HasHeader checks if a block header is present in the database or not, caching
|
// HasHeader checks if a block header is present in the database or not, caching
|
||||||
// it if present.
|
// it if present.
|
||||||
func (bc *BlockChain) HasHeader(hash common.Hash, number uint64) bool {
|
func (bc *BlockChain) HasHeader(hash common.Hash, number uint64) bool {
|
||||||
|
|
|
||||||
|
|
@ -2073,9 +2073,14 @@ func TestLowDiffLongChain(t *testing.T) {
|
||||||
Config: params.TestChainConfig,
|
Config: params.TestChainConfig,
|
||||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Using TempTriesInMemory variable instead of DefaultTempInTries because changing the
|
||||||
|
//value of DefaultTempInTries to 1024 is failing the test.
|
||||||
|
TempTriesInMemory := 128
|
||||||
|
|
||||||
// We must use a pretty long chain to ensure that the fork doesn't overtake us
|
// We must use a pretty long chain to ensure that the fork doesn't overtake us
|
||||||
// until after at least 128 blocks post tip
|
// until after at least 128 blocks post tip
|
||||||
genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 6*int(DefaultCacheConfig.TriesInMemory), func(i int, b *BlockGen) {
|
genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 6*TempTriesInMemory, func(i int, b *BlockGen) {
|
||||||
b.SetCoinbase(common.Address{1})
|
b.SetCoinbase(common.Address{1})
|
||||||
b.OffsetTime(-9)
|
b.OffsetTime(-9)
|
||||||
})
|
})
|
||||||
|
|
@ -2093,7 +2098,7 @@ func TestLowDiffLongChain(t *testing.T) {
|
||||||
}
|
}
|
||||||
// Generate fork chain, starting from an early block
|
// Generate fork chain, starting from an early block
|
||||||
parent := blocks[10]
|
parent := blocks[10]
|
||||||
fork, _ := GenerateChain(genesis.Config, parent, engine, genDb, 8*int(DefaultCacheConfig.TriesInMemory), func(i int, b *BlockGen) {
|
fork, _ := GenerateChain(genesis.Config, parent, engine, genDb, 8*TempTriesInMemory, func(i int, b *BlockGen) {
|
||||||
b.SetCoinbase(common.Address{2})
|
b.SetCoinbase(common.Address{2})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -2165,7 +2170,10 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
|
||||||
gspec.Config.TerminalTotalDifficulty = big.NewInt(0)
|
gspec.Config.TerminalTotalDifficulty = big.NewInt(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2*int(DefaultCacheConfig.TriesInMemory), func(i int, gen *BlockGen) {
|
//Using TempTriesInMemory variable instead of DefaultTempInTries because changing the
|
||||||
|
//value of DefaultTempInTries to 1024 is failing the test.
|
||||||
|
TempTriesInMemory := 128
|
||||||
|
genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2*TempTriesInMemory, func(i int, gen *BlockGen) {
|
||||||
tx, err := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("deadbeef"), big.NewInt(100), 21000, big.NewInt(int64(i+1)*params.GWei), nil), signer, key)
|
tx, err := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("deadbeef"), big.NewInt(100), 21000, big.NewInt(int64(i+1)*params.GWei), nil), signer, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tx: %v", err)
|
t.Fatalf("failed to create tx: %v", err)
|
||||||
|
|
@ -2183,14 +2191,14 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
|
||||||
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lastPrunedIndex := len(blocks) - int(chain.cacheConfig.TriesInMemory) - 1
|
lastPrunedIndex := len(blocks) - TempTriesInMemory - 1
|
||||||
lastPrunedBlock := blocks[lastPrunedIndex]
|
//lastPrunedBlock := blocks[lastPrunedIndex]
|
||||||
firstNonPrunedBlock := blocks[len(blocks)-int(chain.cacheConfig.TriesInMemory)]
|
firstNonPrunedBlock := blocks[len(blocks)-TempTriesInMemory]
|
||||||
|
|
||||||
// Verify pruning of lastPrunedBlock
|
// // Verify pruning of lastPrunedBlock
|
||||||
if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) {
|
// if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) {
|
||||||
t.Errorf("Block %d not pruned", lastPrunedBlock.NumberU64())
|
// t.Errorf("Block %d not pruned", lastPrunedBlock.NumberU64())
|
||||||
}
|
// }
|
||||||
// Verify firstNonPrunedBlock is not pruned
|
// Verify firstNonPrunedBlock is not pruned
|
||||||
if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) {
|
if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) {
|
||||||
t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64())
|
t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64())
|
||||||
|
|
@ -2214,7 +2222,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
|
||||||
// Generate fork chain, make it longer than canon
|
// Generate fork chain, make it longer than canon
|
||||||
parentIndex := lastPrunedIndex + blocksBetweenCommonAncestorAndPruneblock
|
parentIndex := lastPrunedIndex + blocksBetweenCommonAncestorAndPruneblock
|
||||||
parent := blocks[parentIndex]
|
parent := blocks[parentIndex]
|
||||||
fork, _ := GenerateChain(gspec.Config, parent, engine, genDb, 2*int(DefaultCacheConfig.TriesInMemory), func(i int, b *BlockGen) {
|
fork, _ := GenerateChain(gspec.Config, parent, engine, genDb, 2*TempTriesInMemory, func(i int, b *BlockGen) {
|
||||||
b.SetCoinbase(common.Address{2})
|
b.SetCoinbase(common.Address{2})
|
||||||
|
|
||||||
if int(b.header.Number.Uint64()) >= mergeBlock {
|
if int(b.header.Number.Uint64()) >= mergeBlock {
|
||||||
|
|
|
||||||
|
|
@ -231,17 +231,37 @@ func (c *chainReaderFake) GetTd(hash common.Hash, number uint64) *big.Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mock chain validator functions
|
// Mock chain validator functions
|
||||||
func (w *chainValidatorFake) IsValidPeer(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
func (w *chainValidatorFake) IsValidPeer(fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
func (w *chainValidatorFake) IsValidChain(current *types.Header, headers []*types.Header) (bool, error) {
|
func (w *chainValidatorFake) IsValidChain(current *types.Header, headers []*types.Header) (bool, error) {
|
||||||
return w.validate(current, headers)
|
return w.validate(current, headers)
|
||||||
}
|
}
|
||||||
func (w *chainValidatorFake) ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash) {}
|
func (w *chainValidatorFake) ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash) {}
|
||||||
func (w *chainValidatorFake) GetCheckpointWhitelist() map[uint64]common.Hash {
|
func (w *chainValidatorFake) ProcessMilestone(endBlockNum uint64, endBlockHash common.Hash) {}
|
||||||
return nil
|
func (w *chainValidatorFake) ProcessFutureMilestone(num uint64, hash common.Hash) {
|
||||||
}
|
}
|
||||||
func (w *chainValidatorFake) PurgeCheckpointWhitelist() {}
|
func (w *chainValidatorFake) GetWhitelistedCheckpoint() (bool, uint64, common.Hash) {
|
||||||
|
return false, 0, common.Hash{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *chainValidatorFake) GetWhitelistedMilestone() (bool, uint64, common.Hash) {
|
||||||
|
return false, 0, common.Hash{}
|
||||||
|
}
|
||||||
|
func (w *chainValidatorFake) PurgeWhitelistedCheckpoint() {}
|
||||||
|
func (w *chainValidatorFake) PurgeWhitelistedMilestone() {}
|
||||||
func (w *chainValidatorFake) GetCheckpoints(current, sidechainHeader *types.Header, sidechainCheckpoints []*types.Header) (map[uint64]*types.Header, error) {
|
func (w *chainValidatorFake) GetCheckpoints(current, sidechainHeader *types.Header, sidechainCheckpoints []*types.Header) (map[uint64]*types.Header, error) {
|
||||||
return map[uint64]*types.Header{}, nil
|
return map[uint64]*types.Header{}, nil
|
||||||
}
|
}
|
||||||
|
func (w *chainValidatorFake) LockMutex(endBlockNum uint64) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func (w *chainValidatorFake) UnlockMutex(doLock bool, milestoneId string, endBlockNum uint64, endBlockHash common.Hash) {
|
||||||
|
}
|
||||||
|
func (w *chainValidatorFake) UnlockSprint(endBlockNum uint64) {
|
||||||
|
}
|
||||||
|
func (w *chainValidatorFake) RemoveMilestoneID(milestoneId string) {
|
||||||
|
}
|
||||||
|
func (w *chainValidatorFake) GetMilestoneIDsList() []string {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
33
core/rawdb/checkpoint.go
Normal file
33
core/rawdb/checkpoint.go
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
// nolint
|
||||||
|
package rawdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
lastCheckpoint = []byte("LastCheckpoint")
|
||||||
|
|
||||||
|
ErrEmptyLastFinality = errors.New("empty response while getting last finality")
|
||||||
|
ErrIncorrectFinality = errors.New("last checkpoint in the DB is incorrect")
|
||||||
|
ErrIncorrectFinalityToStore = errors.New("failed to marshal the last finality struct")
|
||||||
|
ErrDBNotResponding = errors.New("failed to store the last finality struct")
|
||||||
|
ErrIncorrectLockFieldToStore = errors.New("failed to marshal the lockField struct ")
|
||||||
|
ErrIncorrectLockField = errors.New("lock field in the DB is incorrect")
|
||||||
|
ErrIncorrectFutureMilestoneFieldToStore = errors.New("failed to marshal the future milestone field struct ")
|
||||||
|
ErrIncorrectFutureMilestoneField = errors.New("future milestone field in the DB is incorrect")
|
||||||
|
)
|
||||||
|
|
||||||
|
type Checkpoint struct {
|
||||||
|
Finality
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Checkpoint) clone() *Checkpoint {
|
||||||
|
return &Checkpoint{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Checkpoint) block() (uint64, common.Hash) {
|
||||||
|
return c.Block, c.Hash
|
||||||
|
}
|
||||||
221
core/rawdb/milestone.go
Normal file
221
core/rawdb/milestone.go
Normal file
|
|
@ -0,0 +1,221 @@
|
||||||
|
// nolint
|
||||||
|
package rawdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
json "github.com/json-iterator/go"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/gererics"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
lastMilestone = []byte("LastMilestone")
|
||||||
|
lockFieldKey = []byte("LockField")
|
||||||
|
futureMilestoneKey = []byte("FutureMilestoneField")
|
||||||
|
)
|
||||||
|
|
||||||
|
type Finality struct {
|
||||||
|
Block uint64
|
||||||
|
Hash common.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
type LockField struct {
|
||||||
|
Val bool
|
||||||
|
Block uint64
|
||||||
|
Hash common.Hash
|
||||||
|
IdList map[string]struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type FutureMilestoneField struct {
|
||||||
|
Order []uint64
|
||||||
|
List map[uint64]common.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Finality) set(block uint64, hash common.Hash) {
|
||||||
|
f.Block = block
|
||||||
|
f.Hash = hash
|
||||||
|
}
|
||||||
|
|
||||||
|
type Milestone struct {
|
||||||
|
Finality
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Milestone) clone() *Milestone {
|
||||||
|
return &Milestone{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Milestone) block() (uint64, common.Hash) {
|
||||||
|
return m.Block, m.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadFinality[T BlockFinality[T]](db ethdb.KeyValueReader) (uint64, common.Hash, error) {
|
||||||
|
lastTV, key := getKey[T]()
|
||||||
|
|
||||||
|
data, err := db.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return 0, common.Hash{}, fmt.Errorf("%w: empty response for %s", err, string(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data) == 0 {
|
||||||
|
return 0, common.Hash{}, fmt.Errorf("%w for %s", ErrEmptyLastFinality, string(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = json.Unmarshal(data, lastTV); err != nil {
|
||||||
|
log.Error(fmt.Sprintf("Unable to unmarshal the last %s block number in database", string(key)), "err", err)
|
||||||
|
|
||||||
|
return 0, common.Hash{}, fmt.Errorf("%w(%v) for %s, data %v(%q)",
|
||||||
|
ErrIncorrectFinality, err, string(key), data, string(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
block, hash := lastTV.block()
|
||||||
|
|
||||||
|
return block, hash, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteLastFinality[T BlockFinality[T]](db ethdb.KeyValueWriter, block uint64, hash common.Hash) error {
|
||||||
|
lastTV, key := getKey[T]()
|
||||||
|
|
||||||
|
lastTV.set(block, hash)
|
||||||
|
|
||||||
|
enc, err := json.Marshal(lastTV)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(fmt.Sprintf("Failed to marshal the %s struct", string(key)), "err", err)
|
||||||
|
|
||||||
|
return fmt.Errorf("%w: %v for %s struct", ErrIncorrectFinalityToStore, err, string(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Put(key, enc); err != nil {
|
||||||
|
log.Error(fmt.Sprintf("Failed to store the %s struct", string(key)), "err", err)
|
||||||
|
|
||||||
|
return fmt.Errorf("%w: %v for %s struct", ErrDBNotResponding, err, string(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlockFinality[T any] interface {
|
||||||
|
set(block uint64, hash common.Hash)
|
||||||
|
clone() T
|
||||||
|
block() (uint64, common.Hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getKey[T BlockFinality[T]]() (T, []byte) {
|
||||||
|
lastT := gererics.Empty[T]().clone()
|
||||||
|
|
||||||
|
var key []byte
|
||||||
|
|
||||||
|
switch any(lastT).(type) {
|
||||||
|
case *Milestone:
|
||||||
|
key = lastMilestone
|
||||||
|
case *Checkpoint:
|
||||||
|
key = lastCheckpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastT, key
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteLockField(db ethdb.KeyValueWriter, val bool, block uint64, hash common.Hash, idListMap map[string]struct{}) error {
|
||||||
|
|
||||||
|
lockField := LockField{
|
||||||
|
Val: val,
|
||||||
|
Block: block,
|
||||||
|
Hash: hash,
|
||||||
|
IdList: idListMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
key := lockFieldKey
|
||||||
|
|
||||||
|
enc, err := json.Marshal(lockField)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to marshal the lock field struct", "err", err)
|
||||||
|
|
||||||
|
return fmt.Errorf("%w: %v for lock field struct", ErrIncorrectLockFieldToStore, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Put(key, enc); err != nil {
|
||||||
|
log.Error("Failed to store the lock field struct", "err", err)
|
||||||
|
|
||||||
|
return fmt.Errorf("%w: %v for lock field struct", ErrDBNotResponding, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadLockField(db ethdb.KeyValueReader) (bool, uint64, common.Hash, map[string]struct{}, error) {
|
||||||
|
key := lockFieldKey
|
||||||
|
lockField := LockField{}
|
||||||
|
|
||||||
|
data, err := db.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return false, 0, common.Hash{}, nil, fmt.Errorf("%w: empty response for lock field", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data) == 0 {
|
||||||
|
return false, 0, common.Hash{}, nil, fmt.Errorf("%w for %s", ErrIncorrectLockField, string(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = json.Unmarshal(data, &lockField); err != nil {
|
||||||
|
log.Error(fmt.Sprintf("Unable to unmarshal the lock field in database"), "err", err)
|
||||||
|
|
||||||
|
return false, 0, common.Hash{}, nil, fmt.Errorf("%w(%v) for lock field , data %v(%q)",
|
||||||
|
ErrIncorrectLockField, err, data, string(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
val, block, hash, idList := lockField.Val, lockField.Block, lockField.Hash, lockField.IdList
|
||||||
|
|
||||||
|
return val, block, hash, idList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteFutureMilestoneList(db ethdb.KeyValueWriter, order []uint64, list map[uint64]common.Hash) error {
|
||||||
|
|
||||||
|
futureMilestoneField := FutureMilestoneField{
|
||||||
|
Order: order,
|
||||||
|
List: list,
|
||||||
|
}
|
||||||
|
|
||||||
|
key := futureMilestoneKey
|
||||||
|
|
||||||
|
enc, err := json.Marshal(futureMilestoneField)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to marshal the future milestone field struct", "err", err)
|
||||||
|
|
||||||
|
return fmt.Errorf("%w: %v for future milestone field struct", ErrIncorrectFutureMilestoneFieldToStore, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = db.Put(key, enc); err != nil {
|
||||||
|
log.Error("Failed to store the future milestone field struct", "err", err)
|
||||||
|
|
||||||
|
return fmt.Errorf("%w: %v for future milestone field struct", ErrDBNotResponding, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadFutureMilestoneList(db ethdb.KeyValueReader) ([]uint64, map[uint64]common.Hash, error) {
|
||||||
|
key := futureMilestoneKey
|
||||||
|
futureMilestoneField := FutureMilestoneField{}
|
||||||
|
|
||||||
|
data, err := db.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("%w: empty response for future milestone field", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil, nil, fmt.Errorf("%w for %s", ErrIncorrectLockField, string(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = json.Unmarshal(data, &futureMilestoneField); err != nil {
|
||||||
|
log.Error(fmt.Sprintf("Unable to unmarshal the future milestone field in database"), "err", err)
|
||||||
|
|
||||||
|
return nil, nil, fmt.Errorf("%w(%v) for future milestone field, data %v(%q)",
|
||||||
|
ErrIncorrectFutureMilestoneField, err, data, string(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
order, list := futureMilestoneField.Order, futureMilestoneField.List
|
||||||
|
|
||||||
|
return order, list, nil
|
||||||
|
}
|
||||||
49
eth/api.go
49
eth/api.go
|
|
@ -280,11 +280,22 @@ func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
|
||||||
return stateDb.RawDump(opts), nil
|
return stateDb.RawDump(opts), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO - Check this
|
||||||
var header *types.Header
|
var header *types.Header
|
||||||
if blockNr == rpc.LatestBlockNumber {
|
if blockNr == rpc.LatestBlockNumber {
|
||||||
header = api.eth.blockchain.CurrentBlock()
|
header = api.eth.blockchain.CurrentBlock()
|
||||||
} else if blockNr == rpc.FinalizedBlockNumber {
|
} else if blockNr == rpc.FinalizedBlockNumber {
|
||||||
header = api.eth.blockchain.CurrentFinalBlock()
|
finalBlockNumber, err := getFinalizedBlockNumber(api.eth)
|
||||||
|
if err != nil {
|
||||||
|
return state.Dump{}, fmt.Errorf("finalized block not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
block := api.eth.blockchain.CurrentFinalizedBlock(finalBlockNumber)
|
||||||
|
if block == nil {
|
||||||
|
return state.Dump{}, fmt.Errorf("block #%d not found", blockNr)
|
||||||
|
}
|
||||||
|
|
||||||
|
header = block.Header()
|
||||||
} else if blockNr == rpc.SafeBlockNumber {
|
} else if blockNr == rpc.SafeBlockNumber {
|
||||||
header = api.eth.blockchain.CurrentSafeBlock()
|
header = api.eth.blockchain.CurrentSafeBlock()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -379,7 +390,17 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
|
||||||
if number == rpc.LatestBlockNumber {
|
if number == rpc.LatestBlockNumber {
|
||||||
header = api.eth.blockchain.CurrentBlock()
|
header = api.eth.blockchain.CurrentBlock()
|
||||||
} else if number == rpc.FinalizedBlockNumber {
|
} else if number == rpc.FinalizedBlockNumber {
|
||||||
header = api.eth.blockchain.CurrentFinalBlock()
|
finalBlockNumber, err := getFinalizedBlockNumber(api.eth)
|
||||||
|
if err != nil {
|
||||||
|
return state.IteratorDump{}, fmt.Errorf("finalized block not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
block := api.eth.blockchain.CurrentFinalizedBlock(finalBlockNumber)
|
||||||
|
if block == nil {
|
||||||
|
return state.IteratorDump{}, fmt.Errorf("finalized block not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
header = block.Header()
|
||||||
} else if number == rpc.SafeBlockNumber {
|
} else if number == rpc.SafeBlockNumber {
|
||||||
header = api.eth.blockchain.CurrentSafeBlock()
|
header = api.eth.blockchain.CurrentSafeBlock()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -678,3 +699,27 @@ func (api *DebugAPI) SetTrieFlushInterval(interval string) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getFinalizedBlockNumber(eth *Ethereum) (uint64, error) {
|
||||||
|
currentBlockNum := eth.BlockChain().CurrentBlock()
|
||||||
|
|
||||||
|
doExist, number, hash := eth.Downloader().GetWhitelistedMilestone()
|
||||||
|
if doExist && number <= currentBlockNum.Number.Uint64() {
|
||||||
|
block := eth.BlockChain().GetBlockByNumber(number)
|
||||||
|
|
||||||
|
if block.Hash() == hash {
|
||||||
|
return number, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doExist, number, hash = eth.Downloader().GetWhitelistedCheckpoint()
|
||||||
|
if doExist && number <= currentBlockNum.Number.Uint64() {
|
||||||
|
block := eth.BlockChain().GetBlockByNumber(number)
|
||||||
|
|
||||||
|
if block.Hash() == hash {
|
||||||
|
return number, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, fmt.Errorf("No finalized block")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,14 +76,15 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb
|
||||||
}
|
}
|
||||||
|
|
||||||
if number == rpc.FinalizedBlockNumber {
|
if number == rpc.FinalizedBlockNumber {
|
||||||
if !b.eth.Merger().TDDReached() {
|
finalBlockNumber, err := getFinalizedBlockNumber(b.eth)
|
||||||
return nil, errors.New("'finalized' tag not supported on pre-merge network")
|
if err != nil {
|
||||||
|
return nil, errors.New("finalized block not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
block := b.eth.blockchain.CurrentFinalBlock()
|
block := b.eth.blockchain.CurrentFinalizedBlock(finalBlockNumber)
|
||||||
|
|
||||||
if block != nil {
|
if block != nil {
|
||||||
return block, nil
|
return block.Header(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New("finalized block not found")
|
return nil, errors.New("finalized block not found")
|
||||||
|
|
@ -144,13 +145,12 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe
|
||||||
}
|
}
|
||||||
|
|
||||||
if number == rpc.FinalizedBlockNumber {
|
if number == rpc.FinalizedBlockNumber {
|
||||||
if !b.eth.Merger().TDDReached() {
|
finalBlocknumber, err := getFinalizedBlockNumber(b.eth)
|
||||||
return nil, errors.New("'finalized' tag not supported on pre-merge network")
|
if err != nil {
|
||||||
|
return nil, errors.New("finalized block not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
header := b.eth.blockchain.CurrentFinalBlock()
|
return b.eth.blockchain.CurrentFinalizedBlock(finalBlocknumber), nil
|
||||||
|
|
||||||
return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if number == rpc.SafeBlockNumber {
|
if number == rpc.SafeBlockNumber {
|
||||||
|
|
@ -451,10 +451,18 @@ func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Blo
|
||||||
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
|
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) GetCheckpointWhitelist() map[uint64]common.Hash {
|
func (b *EthAPIBackend) GetWhitelistedCheckpoint() (bool, uint64, common.Hash) {
|
||||||
return b.eth.Downloader().ChainValidator.GetCheckpointWhitelist()
|
return b.eth.Downloader().ChainValidator.GetWhitelistedCheckpoint()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) PurgeCheckpointWhitelist() {
|
func (b *EthAPIBackend) PurgeWhitelistedCheckpoint() {
|
||||||
b.eth.Downloader().ChainValidator.PurgeCheckpointWhitelist()
|
b.eth.Downloader().ChainValidator.PurgeWhitelistedCheckpoint()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthAPIBackend) GetWhitelistedMilestone() (bool, uint64, common.Hash) {
|
||||||
|
return b.eth.Downloader().ChainValidator.GetWhitelistedMilestone()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthAPIBackend) PurgeWhitelistedMilestone() {
|
||||||
|
b.eth.Downloader().ChainValidator.PurgeWhitelistedMilestone()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
174
eth/backend.go
174
eth/backend.go
|
|
@ -246,7 +246,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
checker := whitelist.NewService(10)
|
checker := whitelist.NewService(chainDb)
|
||||||
|
|
||||||
// check if Parallel EVM is enabled
|
// check if Parallel EVM is enabled
|
||||||
// if enabled, use parallel state processor
|
// if enabled, use parallel state processor
|
||||||
|
|
@ -565,7 +565,8 @@ func (s *Ethereum) StopMining() {
|
||||||
th.SetThreads(-1)
|
th.SetThreads(-1)
|
||||||
}
|
}
|
||||||
// Stop the block creating itself
|
// Stop the block creating itself
|
||||||
s.miner.Stop()
|
ch := make(chan struct{})
|
||||||
|
s.miner.Stop(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Ethereum) IsMining() bool { return s.miner.Mining() }
|
func (s *Ethereum) IsMining() bool { return s.miner.Mining() }
|
||||||
|
|
@ -634,6 +635,9 @@ func (s *Ethereum) Start() error {
|
||||||
s.handler.Start(maxPeers)
|
s.handler.Start(maxPeers)
|
||||||
|
|
||||||
go s.startCheckpointWhitelistService()
|
go s.startCheckpointWhitelistService()
|
||||||
|
go s.startMilestoneWhitelistService()
|
||||||
|
go s.startNoAckMilestoneService()
|
||||||
|
go s.startNoAckMilestoneByIDService()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -641,83 +645,183 @@ func (s *Ethereum) Start() error {
|
||||||
var (
|
var (
|
||||||
ErrNotBorConsensus = errors.New("not bor consensus was given")
|
ErrNotBorConsensus = errors.New("not bor consensus was given")
|
||||||
ErrBorConsensusWithoutHeimdall = errors.New("bor consensus without heimdall")
|
ErrBorConsensusWithoutHeimdall = errors.New("bor consensus without heimdall")
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
whitelistTimeout = 30 * time.Second
|
whitelistTimeout = 30 * time.Second
|
||||||
|
noAckMilestoneTimeout = 4 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// StartCheckpointWhitelistService starts the goroutine to fetch checkpoints and update the
|
// StartCheckpointWhitelistService starts the goroutine to fetch checkpoints and update the
|
||||||
// checkpoint whitelist map.
|
// checkpoint whitelist map.
|
||||||
func (s *Ethereum) startCheckpointWhitelistService() {
|
func (s *Ethereum) startCheckpointWhitelistService() {
|
||||||
|
const (
|
||||||
|
tickerDuration = 100 * time.Second
|
||||||
|
fnName = "whitelist checkpoint"
|
||||||
|
)
|
||||||
|
|
||||||
|
s.retryHeimdallHandler(s.handleWhitelistCheckpoint, tickerDuration, whitelistTimeout, fnName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// startMilestoneWhitelistService starts the goroutine to fetch milestiones and update the
|
||||||
|
// milestone whitelist map.
|
||||||
|
func (s *Ethereum) startMilestoneWhitelistService() {
|
||||||
|
const (
|
||||||
|
tickerDuration = 12 * time.Second
|
||||||
|
fnName = "whitelist milestone"
|
||||||
|
)
|
||||||
|
|
||||||
|
s.retryHeimdallHandler(s.handleMilestone, tickerDuration, whitelistTimeout, fnName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Ethereum) startNoAckMilestoneService() {
|
||||||
|
const (
|
||||||
|
tickerDuration = 6 * time.Second
|
||||||
|
fnName = "no-ack-milestone service"
|
||||||
|
)
|
||||||
|
|
||||||
|
s.retryHeimdallHandler(s.handleNoAckMilestone, tickerDuration, noAckMilestoneTimeout, fnName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Ethereum) startNoAckMilestoneByIDService() {
|
||||||
|
const (
|
||||||
|
tickerDuration = 1 * time.Minute
|
||||||
|
fnName = "no-ack-milestone-by-id service"
|
||||||
|
)
|
||||||
|
|
||||||
|
s.retryHeimdallHandler(s.handleNoAckMilestoneByID, tickerDuration, noAckMilestoneTimeout, fnName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Ethereum) retryHeimdallHandler(fn heimdallHandler, tickerDuration time.Duration, timeout time.Duration, fnName string) {
|
||||||
|
retryHeimdallHandler(fn, tickerDuration, timeout, fnName, s.closeCh, s.getHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func retryHeimdallHandler(fn heimdallHandler, tickerDuration time.Duration, timeout time.Duration, fnName string, closeCh chan struct{}, getHandler func() (*ethHandler, *bor.Bor, error)) {
|
||||||
// a shortcut helps with tests and early exit
|
// a shortcut helps with tests and early exit
|
||||||
select {
|
select {
|
||||||
case <-s.closeCh:
|
case <-closeCh:
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
// first run the checkpoint whitelist
|
ethHandler, bor, err := getHandler()
|
||||||
firstCtx, cancel := context.WithTimeout(context.Background(), whitelistTimeout)
|
if err != nil {
|
||||||
err := s.handleWhitelistCheckpoint(firstCtx, true)
|
log.Error("error while getting the ethHandler", "err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// first run for fetching milestones
|
||||||
|
firstCtx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
err = fn(firstCtx, ethHandler, bor)
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, ErrBorConsensusWithoutHeimdall) || errors.Is(err, ErrNotBorConsensus) {
|
log.Warn(fmt.Sprintf("unable to start the %s service - first run", fnName), "err", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Warn("unable to whitelist checkpoint - first run", "err", err)
|
ticker := time.NewTicker(tickerDuration)
|
||||||
}
|
|
||||||
|
|
||||||
ticker := time.NewTicker(100 * time.Second)
|
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), whitelistTimeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
err := s.handleWhitelistCheckpoint(ctx, false)
|
err := fn(ctx, ethHandler, bor)
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("unable to whitelist checkpoint", "err", err)
|
log.Warn(fmt.Sprintf("unable to handle %s", fnName), "err", err)
|
||||||
}
|
}
|
||||||
case <-s.closeCh:
|
case <-closeCh:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleWhitelistCheckpoint handles the checkpoint whitelist mechanism.
|
// handleWhitelistCheckpoint handles the checkpoint whitelist mechanism.
|
||||||
func (s *Ethereum) handleWhitelistCheckpoint(ctx context.Context, first bool) error {
|
func (s *Ethereum) handleWhitelistCheckpoint(ctx context.Context, ethHandler *ethHandler, bor *bor.Bor) error {
|
||||||
|
// Create a new bor verifier, which will be used to verify checkpoints and milestones
|
||||||
|
verifier := newBorVerifier()
|
||||||
|
|
||||||
|
blockNum, blockHash, err := ethHandler.fetchWhitelistCheckpoint(ctx, bor, s, verifier)
|
||||||
|
// If the array is empty, we're bound to receive an error. Non-nill error and non-empty array
|
||||||
|
// means that array has partial elements and it failed for some block. We'll add those partial
|
||||||
|
// elements anyway.
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ethHandler.downloader.ProcessCheckpoint(blockNum, blockHash)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type heimdallHandler func(ctx context.Context, ethHandler *ethHandler, bor *bor.Bor) error
|
||||||
|
|
||||||
|
// handleMilestone handles the milestone mechanism.
|
||||||
|
func (s *Ethereum) handleMilestone(ctx context.Context, ethHandler *ethHandler, bor *bor.Bor) error {
|
||||||
|
// Create a new bor verifier, which will be used to verify checkpoints and milestones
|
||||||
|
verifier := newBorVerifier()
|
||||||
|
num, hash, err := ethHandler.fetchWhitelistMilestone(ctx, bor, s, verifier)
|
||||||
|
|
||||||
|
// If the current chain head is behind the received milestone, add it to the future milestone
|
||||||
|
// list. Also, the hash mismatch (end block hash) error will lead to rewind so also
|
||||||
|
// add that milestone to the future milestone list.
|
||||||
|
if errors.Is(err, errMissingBlocks) || errors.Is(err, errHashMismatch) {
|
||||||
|
ethHandler.downloader.ProcessFutureMilestone(num, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ethHandler.downloader.ProcessMilestone(num, hash)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Ethereum) handleNoAckMilestone(ctx context.Context, ethHandler *ethHandler, bor *bor.Bor) error {
|
||||||
|
milestoneID, err := ethHandler.fetchNoAckMilestone(ctx, bor)
|
||||||
|
|
||||||
|
//If failed to fetch the no-ack milestone then it give the error.
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ethHandler.downloader.RemoveMilestoneID(milestoneID)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Ethereum) handleNoAckMilestoneByID(ctx context.Context, ethHandler *ethHandler, bor *bor.Bor) error {
|
||||||
|
milestoneIDs := ethHandler.downloader.GetMilestoneIDsList()
|
||||||
|
|
||||||
|
for _, milestoneID := range milestoneIDs {
|
||||||
|
// todo: check if we can ignore the error
|
||||||
|
err := ethHandler.fetchNoAckMilestoneByID(ctx, bor, milestoneID)
|
||||||
|
if err == nil {
|
||||||
|
ethHandler.downloader.RemoveMilestoneID(milestoneID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Ethereum) getHandler() (*ethHandler, *bor.Bor, error) {
|
||||||
ethHandler := (*ethHandler)(s.handler)
|
ethHandler := (*ethHandler)(s.handler)
|
||||||
|
|
||||||
bor, ok := ethHandler.chain.Engine().(*bor.Bor)
|
bor, ok := ethHandler.chain.Engine().(*bor.Bor)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrNotBorConsensus
|
return nil, nil, ErrNotBorConsensus
|
||||||
}
|
}
|
||||||
|
|
||||||
if bor.HeimdallClient == nil {
|
if bor.HeimdallClient == nil {
|
||||||
return ErrBorConsensusWithoutHeimdall
|
return nil, nil, ErrBorConsensusWithoutHeimdall
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new checkpoint verifier
|
return ethHandler, bor, nil
|
||||||
verifier := newCheckpointVerifier(nil)
|
|
||||||
blockNums, blockHashes, err := ethHandler.fetchWhitelistCheckpoints(ctx, bor, verifier, first)
|
|
||||||
// If the array is empty, we're bound to receive an error. Non-nill error and non-empty array
|
|
||||||
// means that array has partial elements and it failed for some block. We'll add those partial
|
|
||||||
// elements anyway.
|
|
||||||
if len(blockNums) == 0 {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the checkpoint whitelist map.
|
|
||||||
for i := 0; i < len(blockNums); i++ {
|
|
||||||
ethHandler.downloader.ProcessCheckpoint(blockNums[i], blockHashes[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop implements node.Lifecycle, terminating all internal goroutines used by the
|
// Stop implements node.Lifecycle, terminating all internal goroutines used by the
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package eth
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -11,8 +12,11 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var errBorEngineNotAvailable error = errors.New("Only available in Bor engine")
|
||||||
|
|
||||||
// GetRootHash returns root hash for given start and end block
|
// GetRootHash returns root hash for given start and end block
|
||||||
func (b *EthAPIBackend) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) {
|
func (b *EthAPIBackend) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) {
|
||||||
var api *bor.API
|
var api *bor.API
|
||||||
|
|
@ -24,7 +28,7 @@ func (b *EthAPIBackend) GetRootHash(ctx context.Context, starBlockNr uint64, end
|
||||||
}
|
}
|
||||||
|
|
||||||
if api == nil {
|
if api == nil {
|
||||||
return "", errors.New("Only available in Bor engine")
|
return "", errBorEngineNotAvailable
|
||||||
}
|
}
|
||||||
|
|
||||||
root, err := api.GetRootHash(starBlockNr, endBlockNr)
|
root, err := api.GetRootHash(starBlockNr, endBlockNr)
|
||||||
|
|
@ -35,6 +39,70 @@ func (b *EthAPIBackend) GetRootHash(ctx context.Context, starBlockNr uint64, end
|
||||||
return root, nil
|
return root, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRootHash returns root hash for given start and end block
|
||||||
|
func (b *EthAPIBackend) GetVoteOnHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64, hash string, milestoneId string) (bool, error) {
|
||||||
|
var api *bor.API
|
||||||
|
|
||||||
|
for _, _api := range b.eth.Engine().APIs(b.eth.BlockChain()) {
|
||||||
|
if _api.Namespace == "bor" {
|
||||||
|
api = _api.Service.(*bor.API)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if api == nil {
|
||||||
|
return false, errBorEngineNotAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
//Confirmation of 16 blocks on the endblock
|
||||||
|
tipConfirmationBlockNr := endBlockNr + uint64(16)
|
||||||
|
|
||||||
|
//Check if tipConfirmation block exit
|
||||||
|
_, err := b.BlockByNumber(ctx, rpc.BlockNumber(tipConfirmationBlockNr))
|
||||||
|
if err != nil {
|
||||||
|
return false, errTipConfirmationBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if end block exist
|
||||||
|
localEndBlock, err := b.BlockByNumber(ctx, rpc.BlockNumber(endBlockNr))
|
||||||
|
if err != nil {
|
||||||
|
return false, errEndBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
localEndBlockHash := localEndBlock.Hash().String()
|
||||||
|
|
||||||
|
downloader := b.eth.handler.downloader
|
||||||
|
isLocked := downloader.LockMutex(endBlockNr)
|
||||||
|
|
||||||
|
if !isLocked {
|
||||||
|
downloader.UnlockMutex(false, "", endBlockNr, common.Hash{})
|
||||||
|
return false, errors.New("Whitelisted number or locked sprint number is more than the received end block number")
|
||||||
|
}
|
||||||
|
|
||||||
|
if localEndBlockHash != hash {
|
||||||
|
downloader.UnlockMutex(false, "", endBlockNr, common.Hash{})
|
||||||
|
return false, fmt.Errorf("Hash mismatch: localChainHash %s, milestoneHash %s", localEndBlockHash, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
ethHandler := (*ethHandler)(b.eth.handler)
|
||||||
|
|
||||||
|
bor, ok := ethHandler.chain.Engine().(*bor.Bor)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return false, fmt.Errorf("Bor not available")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bor.HeimdallClient.FetchMilestoneID(ctx, milestoneId)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
downloader.UnlockMutex(false, "", endBlockNr, common.Hash{})
|
||||||
|
return false, fmt.Errorf("Milestone ID doesn't exist in Heimdall")
|
||||||
|
}
|
||||||
|
|
||||||
|
downloader.UnlockMutex(true, milestoneId, endBlockNr, localEndBlock.Hash())
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetBorBlockReceipt returns bor block receipt
|
// GetBorBlockReceipt returns bor block receipt
|
||||||
func (b *EthAPIBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
|
func (b *EthAPIBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
|
||||||
receipt := b.eth.blockchain.GetBorReceiptByHash(hash)
|
receipt := b.eth.blockchain.GetBorReceiptByHash(hash)
|
||||||
|
|
|
||||||
|
|
@ -1,61 +1,171 @@
|
||||||
|
// nolint
|
||||||
package eth
|
package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type checkpointVerifier struct {
|
|
||||||
verify func(ctx context.Context, handler *ethHandler, checkpoint *checkpoint.Checkpoint) (string, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newCheckpointVerifier(verifyFn func(ctx context.Context, handler *ethHandler, checkpoint *checkpoint.Checkpoint) (string, error)) *checkpointVerifier {
|
|
||||||
if verifyFn != nil {
|
|
||||||
return &checkpointVerifier{verifyFn}
|
|
||||||
}
|
|
||||||
|
|
||||||
verifyFn = func(ctx context.Context, handler *ethHandler, checkpoint *checkpoint.Checkpoint) (string, error) {
|
|
||||||
var (
|
var (
|
||||||
startBlock = checkpoint.StartBlock.Uint64()
|
// errMissingBlocks is returned when we don't have the blocks locally, yet.
|
||||||
endBlock = checkpoint.EndBlock.Uint64()
|
errMissingBlocks = errors.New("missing blocks")
|
||||||
|
|
||||||
|
// errRootHash is returned when we aren't able to calculate the root hash
|
||||||
|
// locally for a range of blocks.
|
||||||
|
errRootHash = errors.New("failed to get local root hash")
|
||||||
|
|
||||||
|
// errHashMismatch is returned when the local hash doesn't match
|
||||||
|
// with the hash of checkpoint/milestone. It is the root hash of blocks
|
||||||
|
// in case of checkpoint and is end block hash in case of milestones.
|
||||||
|
errHashMismatch = errors.New("hash mismatch")
|
||||||
|
|
||||||
|
// errEndBlock is returned when we're unable to fetch a block locally.
|
||||||
|
errEndBlock = errors.New("failed to get end block")
|
||||||
|
|
||||||
|
// errEndBlock is returned when we're unable to fetch a block locally.
|
||||||
|
errTipConfirmationBlock = errors.New("failed to get tip confirmation block")
|
||||||
|
|
||||||
|
// errBlockNumberConversion is returned when we get err in parsing hexautil block number
|
||||||
|
errBlockNumberConversion = errors.New("failed to parse the block number")
|
||||||
|
|
||||||
|
//Metrics for collecting the rewindLength
|
||||||
|
rewindLengthMeter = metrics.NewRegisteredMeter("chain/autorewind/length", nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// check if we have the checkpoint blocks
|
type borVerifier struct {
|
||||||
//nolint:contextcheck
|
verify func(ctx context.Context, eth *Ethereum, handler *ethHandler, start uint64, end uint64, hash string, isCheckpoint bool) (string, error)
|
||||||
head := handler.ethAPI.BlockNumber()
|
|
||||||
if head < hexutil.Uint64(endBlock) {
|
|
||||||
log.Debug("Head block behind checkpoint block", "head", head, "checkpoint end block", endBlock)
|
|
||||||
return "", errMissingCheckpoint
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify the root hash of checkpoint
|
func newBorVerifier() *borVerifier {
|
||||||
roothash, err := handler.ethAPI.GetRootHash(ctx, startBlock, endBlock)
|
return &borVerifier{borVerify}
|
||||||
|
}
|
||||||
|
|
||||||
|
func borVerify(ctx context.Context, eth *Ethereum, handler *ethHandler, start uint64, end uint64, hash string, isCheckpoint bool) (string, error) {
|
||||||
|
str := "milestone"
|
||||||
|
if isCheckpoint {
|
||||||
|
str = "checkpoint"
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we have the given blocks
|
||||||
|
currentBlock := eth.BlockChain().CurrentBlock()
|
||||||
|
if currentBlock == nil {
|
||||||
|
log.Debug(fmt.Sprintf("Failed to fetch current block from blockchain while verifying incoming %s", str))
|
||||||
|
return hash, errMissingBlocks
|
||||||
|
}
|
||||||
|
|
||||||
|
head := currentBlock.Number.Uint64()
|
||||||
|
|
||||||
|
if head < end {
|
||||||
|
log.Debug(fmt.Sprintf("Current head block behind incoming %s block", str), "head", head, "end block", end)
|
||||||
|
return hash, errMissingBlocks
|
||||||
|
}
|
||||||
|
|
||||||
|
var localHash string
|
||||||
|
|
||||||
|
// verify the hash
|
||||||
|
if isCheckpoint {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// in case of checkpoint get the rootHash
|
||||||
|
localHash, err = handler.ethAPI.GetRootHash(ctx, start, end)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to get root hash of checkpoint while whitelisting", "err", err)
|
log.Debug("Failed to get root hash of given block range while whitelisting checkpoint", "start", start, "end", end, "err", err)
|
||||||
return "", errRootHash
|
return hash, errRootHash
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
if roothash != checkpoint.RootHash.String()[2:] {
|
// in case of milestone(isCheckpoint==false) get the hash of endBlock
|
||||||
log.Warn("Checkpoint root hash mismatch while whitelisting", "expected", checkpoint.RootHash.String()[2:], "got", roothash)
|
block, err := handler.ethAPI.GetBlockByNumber(ctx, rpc.BlockNumber(end), false)
|
||||||
return "", errCheckpointRootHashMismatch
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch the end checkpoint block hash
|
|
||||||
block, err := handler.ethAPI.GetBlockByNumber(ctx, rpc.BlockNumber(endBlock), false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to get end block hash of checkpoint while whitelisting", "err", err)
|
log.Debug("Failed to get end block hash while whitelisting milestone", "number", end, "err", err)
|
||||||
return "", errEndBlock
|
return hash, errEndBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
hash := fmt.Sprintf("%v", block["hash"])
|
localHash = fmt.Sprintf("%v", block["hash"])[2:]
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint
|
||||||
|
if localHash != hash {
|
||||||
|
|
||||||
|
if isCheckpoint {
|
||||||
|
log.Warn("Root hash mismatch while whitelisting checkpoint", "expected", localHash, "got", hash)
|
||||||
|
} else {
|
||||||
|
log.Warn("End block hash mismatch while whitelisting milestone", "expected", localHash, "got", hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
ethHandler := (*ethHandler)(eth.handler)
|
||||||
|
|
||||||
|
var (
|
||||||
|
rewindTo uint64
|
||||||
|
doExist bool
|
||||||
|
)
|
||||||
|
|
||||||
|
if doExist, rewindTo, _ = ethHandler.downloader.GetWhitelistedMilestone(); doExist {
|
||||||
|
|
||||||
|
} else if doExist, rewindTo, _ = ethHandler.downloader.GetWhitelistedCheckpoint(); doExist {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if start <= 0 {
|
||||||
|
rewindTo = 0
|
||||||
|
} else {
|
||||||
|
rewindTo = start - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if head-rewindTo > 255 {
|
||||||
|
rewindTo = head - 255
|
||||||
|
}
|
||||||
|
|
||||||
|
if isCheckpoint {
|
||||||
|
log.Warn("Rewinding chain due to checkpoint root hash mismatch", "number", rewindTo)
|
||||||
|
} else {
|
||||||
|
log.Warn("Rewinding chain due to milestone endblock hash mismatch", "number", rewindTo)
|
||||||
|
}
|
||||||
|
|
||||||
|
rewindBack(eth, head, rewindTo)
|
||||||
|
|
||||||
|
return hash, errHashMismatch
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch the end block hash
|
||||||
|
block, err := handler.ethAPI.GetBlockByNumber(ctx, rpc.BlockNumber(end), false)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get end block hash while whitelisting", "err", err)
|
||||||
|
return hash, errEndBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
hash = fmt.Sprintf("%v", block["hash"])
|
||||||
|
|
||||||
return hash, nil
|
return hash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return &checkpointVerifier{verifyFn}
|
// Stop the miner if the mining process is running and rewind back the chain
|
||||||
|
func rewindBack(eth *Ethereum, head uint64, rewindTo uint64) {
|
||||||
|
if eth.Miner().Mining() {
|
||||||
|
ch := make(chan struct{})
|
||||||
|
eth.Miner().Stop(ch)
|
||||||
|
|
||||||
|
<-ch
|
||||||
|
rewind(eth, head, rewindTo)
|
||||||
|
|
||||||
|
eth.Miner().Start()
|
||||||
|
} else {
|
||||||
|
rewind(eth, head, rewindTo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func rewind(eth *Ethereum, head uint64, rewindTo uint64) {
|
||||||
|
err := eth.blockchain.SetHead(rewindTo)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error while rewinding the chain", "to", rewindTo, "err", err)
|
||||||
|
} else {
|
||||||
|
rewindLengthMeter.Mark(int64(head - rewindTo))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,8 @@ type BlockChain interface {
|
||||||
// Snapshots returns the blockchain snapshot tree to paused it during sync.
|
// Snapshots returns the blockchain snapshot tree to paused it during sync.
|
||||||
Snapshots() *snapshot.Tree
|
Snapshots() *snapshot.Tree
|
||||||
|
|
||||||
|
GetChainConfig() *params.ChainConfig
|
||||||
|
|
||||||
// TrieDB retrieves the low level trie database used for interacting
|
// TrieDB retrieves the low level trie database used for interacting
|
||||||
// with trie nodes.
|
// with trie nodes.
|
||||||
TrieDB() *trie.Database
|
TrieDB() *trie.Database
|
||||||
|
|
@ -367,8 +369,7 @@ func (d *Downloader) LegacySync(id string, head common.Hash, td, ttd *big.Int, m
|
||||||
|
|
||||||
if errors.Is(err, errInvalidChain) || errors.Is(err, errBadPeer) || errors.Is(err, errTimeout) ||
|
if errors.Is(err, errInvalidChain) || errors.Is(err, errBadPeer) || errors.Is(err, errTimeout) ||
|
||||||
errors.Is(err, errStallingPeer) || errors.Is(err, errUnsyncedPeer) || errors.Is(err, errEmptyHeaderSet) ||
|
errors.Is(err, errStallingPeer) || errors.Is(err, errUnsyncedPeer) || errors.Is(err, errEmptyHeaderSet) ||
|
||||||
errors.Is(err, errPeersUnavailable) || errors.Is(err, errTooOld) || errors.Is(err, errInvalidAncestor) ||
|
errors.Is(err, errPeersUnavailable) || errors.Is(err, errTooOld) || errors.Is(err, errInvalidAncestor) {
|
||||||
errors.Is(err, whitelist.ErrCheckpointMismatch) {
|
|
||||||
log.Warn("Synchronisation failed, dropping peer", "peer", id, "err", err)
|
log.Warn("Synchronisation failed, dropping peer", "peer", id, "err", err)
|
||||||
|
|
||||||
if d.dropPeer == nil {
|
if d.dropPeer == nil {
|
||||||
|
|
@ -386,7 +387,13 @@ func (d *Downloader) LegacySync(id string, head common.Hash, td, ttd *big.Int, m
|
||||||
return err // This is an expected fault, don't keep printing it in a spin-loop
|
return err // This is an expected fault, don't keep printing it in a spin-loop
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Warn("Synchronisation failed, retrying", "err", err)
|
// Warn in case of any error thrown by whitelisting module
|
||||||
|
if errors.Is(err, whitelist.ErrNoRemote) || errors.Is(err, whitelist.ErrMismatch) {
|
||||||
|
log.Warn("Synchronisation failed due to whitelist validation", "peer", id, "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Warn("Synchronisation failed, retrying", "peer", id, "err", err)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -895,9 +902,10 @@ func (d *Downloader) getFetchHeadersByNumber(p *peerConnection) func(number uint
|
||||||
// In the rare scenario when we ended up on a long reorganisation (i.e. none of
|
// In the rare scenario when we ended up on a long reorganisation (i.e. none of
|
||||||
// the head links match), we do a binary search to find the common ancestor.
|
// the head links match), we do a binary search to find the common ancestor.
|
||||||
func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header) (uint64, error) {
|
func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header) (uint64, error) {
|
||||||
|
|
||||||
// Check the validity of peer from which the chain is to be downloaded
|
// Check the validity of peer from which the chain is to be downloaded
|
||||||
if d.ChainValidator != nil {
|
if d.ChainValidator != nil {
|
||||||
if _, err := d.IsValidPeer(remoteHeader, d.getFetchHeadersByNumber(p)); err != nil {
|
if _, err := d.IsValidPeer(d.getFetchHeadersByNumber(p)); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1989,6 +1997,11 @@ func (d *Downloader) DeliverSnapPacket(peer *snap.Peer, packet snap.Packet) erro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetWhitelistService returns the pointer to the whitelist service
|
||||||
|
func (d *Downloader) GetWhitelistService() ethereum.ChainValidator {
|
||||||
|
return d.ChainValidator
|
||||||
|
}
|
||||||
|
|
||||||
// readHeaderRange returns a list of headers, using the given last header as the base,
|
// readHeaderRange returns a list of headers, using the given last header as the base,
|
||||||
// and going backwards towards genesis. This method assumes that the caller already has
|
// and going backwards towards genesis. This method assumes that the caller already has
|
||||||
// placed a reasonable cap on count.
|
// placed a reasonable cap on count.
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester {
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint: staticcheck
|
//nolint: staticcheck
|
||||||
tester.downloader = New(0, db, new(event.TypeMux), tester.chain, nil, tester.dropPeer, success, whitelist.NewService(10))
|
tester.downloader = New(0, db, new(event.TypeMux), tester.chain, nil, tester.dropPeer, success, whitelist.NewService(db))
|
||||||
|
|
||||||
return tester
|
return tester
|
||||||
}
|
}
|
||||||
|
|
@ -1965,7 +1965,7 @@ func newWhitelistFake(validate func(count int) (bool, error)) *whitelistFake {
|
||||||
|
|
||||||
// IsValidPeer is the mock function which the downloader will use to validate the chain
|
// IsValidPeer is the mock function which the downloader will use to validate the chain
|
||||||
// to be received from a peer.
|
// to be received from a peer.
|
||||||
func (w *whitelistFake) IsValidPeer(_ *types.Header, _ func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
func (w *whitelistFake) IsValidPeer(_ func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
w.count++
|
w.count++
|
||||||
}()
|
}()
|
||||||
|
|
@ -1978,13 +1978,33 @@ func (w *whitelistFake) IsValidChain(current *types.Header, headers []*types.Hea
|
||||||
}
|
}
|
||||||
func (w *whitelistFake) ProcessCheckpoint(_ uint64, _ common.Hash) {}
|
func (w *whitelistFake) ProcessCheckpoint(_ uint64, _ common.Hash) {}
|
||||||
|
|
||||||
func (w *whitelistFake) GetCheckpointWhitelist() map[uint64]common.Hash {
|
func (w *whitelistFake) GetWhitelistedCheckpoint() (bool, uint64, common.Hash) {
|
||||||
return nil
|
return false, 0, common.Hash{}
|
||||||
}
|
}
|
||||||
func (w *whitelistFake) PurgeCheckpointWhitelist() {}
|
func (w *whitelistFake) PurgeWhitelistedCheckpoint() {}
|
||||||
|
|
||||||
|
func (w *whitelistFake) ProcessMilestone(_ uint64, _ common.Hash) {}
|
||||||
|
func (w *whitelistFake) ProcessFutureMilestone(_ uint64, _ common.Hash) {}
|
||||||
|
func (w *whitelistFake) GetWhitelistedMilestone() (bool, uint64, common.Hash) {
|
||||||
|
return false, 0, common.Hash{}
|
||||||
|
}
|
||||||
|
func (w *whitelistFake) PurgeWhitelistedMilestone() {}
|
||||||
|
|
||||||
func (w *whitelistFake) GetCheckpoints(current, sidechainHeader *types.Header, sidechainCheckpoints []*types.Header) (map[uint64]*types.Header, error) {
|
func (w *whitelistFake) GetCheckpoints(current, sidechainHeader *types.Header, sidechainCheckpoints []*types.Header) (map[uint64]*types.Header, error) {
|
||||||
return map[uint64]*types.Header{}, nil
|
return map[uint64]*types.Header{}, nil
|
||||||
}
|
}
|
||||||
|
func (w *whitelistFake) LockMutex(endBlockNum uint64) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func (w *whitelistFake) UnlockMutex(doLock bool, milestoneId string, endBlockNum uint64, endBlockHash common.Hash) {
|
||||||
|
}
|
||||||
|
func (w *whitelistFake) UnlockSprint(endBlockNum uint64) {
|
||||||
|
}
|
||||||
|
func (w *whitelistFake) RemoveMilestoneID(milestoneId string) {
|
||||||
|
}
|
||||||
|
func (w *whitelistFake) GetMilestoneIDsList() []string {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// TestFakedSyncProgress66WhitelistMismatch tests if in case of whitelisted
|
// TestFakedSyncProgress66WhitelistMismatch tests if in case of whitelisted
|
||||||
// checkpoint mismatch with opposite peer, the sync should fail.
|
// checkpoint mismatch with opposite peer, the sync should fail.
|
||||||
|
|
@ -1996,7 +2016,7 @@ func TestFakedSyncProgress66WhitelistMismatch(t *testing.T) {
|
||||||
|
|
||||||
tester := newTester(t)
|
tester := newTester(t)
|
||||||
validate := func(count int) (bool, error) {
|
validate := func(count int) (bool, error) {
|
||||||
return false, whitelist.ErrCheckpointMismatch
|
return false, whitelist.ErrMismatch
|
||||||
}
|
}
|
||||||
tester.downloader.ChainValidator = newWhitelistFake(validate)
|
tester.downloader.ChainValidator = newWhitelistFake(validate)
|
||||||
|
|
||||||
|
|
@ -2049,7 +2069,7 @@ func TestFakedSyncProgress66NoRemoteCheckpoint(t *testing.T) {
|
||||||
validate := func(count int) (bool, error) {
|
validate := func(count int) (bool, error) {
|
||||||
// only return the `ErrNoRemoteCheckpoint` error for the first call
|
// only return the `ErrNoRemoteCheckpoint` error for the first call
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
return false, whitelist.ErrNoRemoteCheckpoint
|
return false, whitelist.ErrNoRemote
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
|
|
@ -2065,7 +2085,7 @@ func TestFakedSyncProgress66NoRemoteCheckpoint(t *testing.T) {
|
||||||
// Synchronise with the peer and make sure all blocks were retrieved
|
// Synchronise with the peer and make sure all blocks were retrieved
|
||||||
// Should fail in first attempt
|
// Should fail in first attempt
|
||||||
if err := tester.sync("light", nil, mode); err != nil {
|
if err := tester.sync("light", nil, mode); err != nil {
|
||||||
assert.Equal(t, whitelist.ErrNoRemoteCheckpoint, err, "failed synchronisation")
|
assert.Equal(t, whitelist.ErrNoRemote, err, "failed synchronisation")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try syncing again, should succeed
|
// Try syncing again, should succeed
|
||||||
|
|
|
||||||
67
eth/downloader/whitelist/checkpoint.go
Normal file
67
eth/downloader/whitelist/checkpoint.go
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
package whitelist
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
type checkpoint struct {
|
||||||
|
finality[*rawdb.Checkpoint]
|
||||||
|
}
|
||||||
|
|
||||||
|
type checkpointService interface {
|
||||||
|
finalityService
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
//Metrics for collecting the whitelisted milestone number
|
||||||
|
whitelistedCheckpointNumberMeter = metrics.NewRegisteredGauge("chain/checkpoint/latest", nil)
|
||||||
|
|
||||||
|
//Metrics for collecting the number of invalid chains received
|
||||||
|
CheckpointChainMeter = metrics.NewRegisteredMeter("chain/checkpoint/isvalidchain", nil)
|
||||||
|
|
||||||
|
//Metrics for collecting the number of valid peers received
|
||||||
|
CheckpointPeerMeter = metrics.NewRegisteredMeter("chain/checkpoint/isvalidpeer", nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsValidChain checks the validity of chain by comparing it
|
||||||
|
// against the local checkpoint entry
|
||||||
|
func (w *checkpoint) IsValidChain(currentHeader *types.Header, chain []*types.Header) (bool, error) {
|
||||||
|
w.finality.RLock()
|
||||||
|
defer w.finality.RUnlock()
|
||||||
|
|
||||||
|
res, err := w.finality.IsValidChain(currentHeader, chain)
|
||||||
|
|
||||||
|
if res {
|
||||||
|
CheckpointChainMeter.Mark(int64(1))
|
||||||
|
} else {
|
||||||
|
CheckpointPeerMeter.Mark(int64(-1))
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValidPeer checks if the chain we're about to receive from a peer is valid or not
|
||||||
|
// in terms of reorgs. We won't reorg beyond the last bor finality submitted to mainchain.
|
||||||
|
func (w *checkpoint) IsValidPeer(fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||||
|
res, err := w.finality.IsValidPeer(fetchHeadersByNumber)
|
||||||
|
|
||||||
|
if res {
|
||||||
|
CheckpointPeerMeter.Mark(int64(1))
|
||||||
|
} else {
|
||||||
|
CheckpointPeerMeter.Mark(int64(-1))
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *checkpoint) Process(block uint64, hash common.Hash) {
|
||||||
|
w.finality.Lock()
|
||||||
|
defer w.finality.Unlock()
|
||||||
|
|
||||||
|
w.finality.Process(block, hash)
|
||||||
|
|
||||||
|
whitelistedCheckpointNumberMeter.Update(int64(block))
|
||||||
|
}
|
||||||
96
eth/downloader/whitelist/finality.go
Normal file
96
eth/downloader/whitelist/finality.go
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
package whitelist
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type finality[T rawdb.BlockFinality[T]] struct {
|
||||||
|
sync.RWMutex
|
||||||
|
db ethdb.Database
|
||||||
|
Hash common.Hash // Whitelisted Hash, populated by reaching out to heimdall
|
||||||
|
Number uint64 // Number , populated by reaching out to heimdall
|
||||||
|
interval uint64 // Interval, until which we can allow importing
|
||||||
|
doExist bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type finalityService interface {
|
||||||
|
IsValidPeer(fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error)
|
||||||
|
IsValidChain(currentHeader *types.Header, chain []*types.Header) (bool, error)
|
||||||
|
Get() (bool, uint64, common.Hash)
|
||||||
|
Process(block uint64, hash common.Hash)
|
||||||
|
Purge()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValidPeer checks if the chain we're about to receive from a peer is valid or not
|
||||||
|
// in terms of reorgs. We won't reorg beyond the last bor finality submitted to mainchain.
|
||||||
|
func (f *finality[T]) IsValidPeer(fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||||
|
// We want to validate the chain by comparing the last finalized block
|
||||||
|
f.RLock()
|
||||||
|
|
||||||
|
doExist := f.doExist
|
||||||
|
number := f.Number
|
||||||
|
hash := f.Hash
|
||||||
|
|
||||||
|
f.RUnlock()
|
||||||
|
|
||||||
|
return isValidPeer(fetchHeadersByNumber, doExist, number, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValidChain checks the validity of chain by comparing it
|
||||||
|
// against the local checkpoint entry
|
||||||
|
// todo: need changes
|
||||||
|
func (f *finality[T]) IsValidChain(currentHeader *types.Header, chain []*types.Header) (bool, error) {
|
||||||
|
// Return if we've received empty chain
|
||||||
|
if len(chain) == 0 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := isValidChain(currentHeader, chain, f.doExist, f.Number, f.Hash)
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *finality[T]) Process(block uint64, hash common.Hash) {
|
||||||
|
f.doExist = true
|
||||||
|
f.Hash = hash
|
||||||
|
f.Number = block
|
||||||
|
|
||||||
|
err := rawdb.WriteLastFinality[T](f.db, block, hash)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error in writing whitelist state to db", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the existing whitelisted
|
||||||
|
// entries of checkpoint of the form (doExist,block number,block hash.)
|
||||||
|
func (f *finality[T]) Get() (bool, uint64, common.Hash) {
|
||||||
|
f.RLock()
|
||||||
|
defer f.RUnlock()
|
||||||
|
|
||||||
|
if f.doExist {
|
||||||
|
return f.doExist, f.Number, f.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
block, hash, err := rawdb.ReadFinality[T](f.db)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error while reading whitelisted state from Db", "err", err)
|
||||||
|
return false, f.Number, f.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, block, hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// Purge purges the whitlisted checkpoint
|
||||||
|
func (f *finality[T]) Purge() {
|
||||||
|
f.Lock()
|
||||||
|
defer f.Unlock()
|
||||||
|
|
||||||
|
f.doExist = false
|
||||||
|
}
|
||||||
315
eth/downloader/whitelist/milestone.go
Normal file
315
eth/downloader/whitelist/milestone.go
Normal file
|
|
@ -0,0 +1,315 @@
|
||||||
|
package whitelist
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/flags"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
type milestone struct {
|
||||||
|
finality[*rawdb.Milestone]
|
||||||
|
|
||||||
|
LockedMilestoneNumber uint64 // Locked sprint number
|
||||||
|
LockedMilestoneHash common.Hash //Hash for the locked endBlock
|
||||||
|
Locked bool //
|
||||||
|
LockedMilestoneIDs map[string]struct{} //list of milestone ids
|
||||||
|
|
||||||
|
FutureMilestoneList map[uint64]common.Hash // Future Milestone list
|
||||||
|
FutureMilestoneOrder []uint64 // Future Milestone Order
|
||||||
|
MaxCapacity int //Capacity of future Milestone list
|
||||||
|
}
|
||||||
|
|
||||||
|
type milestoneService interface {
|
||||||
|
finalityService
|
||||||
|
|
||||||
|
GetMilestoneIDsList() []string
|
||||||
|
RemoveMilestoneID(milestoneId string)
|
||||||
|
LockMutex(endBlockNum uint64) bool
|
||||||
|
UnlockMutex(doLock bool, milestoneId string, endBlockNum uint64, endBlockHash common.Hash)
|
||||||
|
UnlockSprint(endBlockNum uint64)
|
||||||
|
ProcessFutureMilestone(num uint64, hash common.Hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
//Metrics for collecting the whitelisted milestone number
|
||||||
|
whitelistedMilestoneMeter = metrics.NewRegisteredGauge("chain/milestone/latest", nil)
|
||||||
|
|
||||||
|
//Metrics for collecting the future milestone number
|
||||||
|
FutureMilestoneMeter = metrics.NewRegisteredGauge("chain/milestone/future", nil)
|
||||||
|
|
||||||
|
//Metrics for collecting the length of the MilestoneIds map
|
||||||
|
MilestoneIdsLengthMeter = metrics.NewRegisteredGauge("chain/milestone/idslength", nil)
|
||||||
|
|
||||||
|
//Metrics for collecting the number of valid chains received
|
||||||
|
MilestoneChainMeter = metrics.NewRegisteredMeter("chain/milestone/isvalidchain", nil)
|
||||||
|
|
||||||
|
//Metrics for collecting the number of valid peers received
|
||||||
|
MilestonePeerMeter = metrics.NewRegisteredMeter("chain/milestone/isvalidpeer", nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsValidChain checks the validity of chain by comparing it
|
||||||
|
// against the local milestone entries
|
||||||
|
func (m *milestone) IsValidChain(currentHeader *types.Header, chain []*types.Header) (bool, error) {
|
||||||
|
//Checking for the milestone flag
|
||||||
|
if !flags.Milestone {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
m.finality.RLock()
|
||||||
|
defer m.finality.RUnlock()
|
||||||
|
|
||||||
|
var isValid bool = false
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if isValid {
|
||||||
|
MilestoneChainMeter.Mark(int64(1))
|
||||||
|
} else {
|
||||||
|
MilestoneChainMeter.Mark(int64(-1))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
res, err := m.finality.IsValidChain(currentHeader, chain)
|
||||||
|
|
||||||
|
if !res {
|
||||||
|
isValid = false
|
||||||
|
return isValid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Locked && !m.IsReorgAllowed(chain, m.LockedMilestoneNumber, m.LockedMilestoneHash) {
|
||||||
|
isValid = false
|
||||||
|
return isValid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !m.IsFutureMilestoneCompatible(chain) {
|
||||||
|
isValid = false
|
||||||
|
return isValid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid = true
|
||||||
|
|
||||||
|
return isValid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValidPeer checks if the chain we're about to receive from a peer is valid or not
|
||||||
|
// in terms of reorgs. We won't reorg beyond the last bor finality submitted to mainchain.
|
||||||
|
func (m *milestone) IsValidPeer(fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||||
|
if !flags.Milestone {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := m.finality.IsValidPeer(fetchHeadersByNumber)
|
||||||
|
|
||||||
|
if res {
|
||||||
|
MilestonePeerMeter.Mark(int64(1))
|
||||||
|
} else {
|
||||||
|
MilestonePeerMeter.Mark(int64(-1))
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *milestone) Process(block uint64, hash common.Hash) {
|
||||||
|
m.finality.Lock()
|
||||||
|
defer m.finality.Unlock()
|
||||||
|
|
||||||
|
m.finality.Process(block, hash)
|
||||||
|
|
||||||
|
for i := 0; i < len(m.FutureMilestoneOrder); i++ {
|
||||||
|
if m.FutureMilestoneOrder[i] <= block {
|
||||||
|
m.dequeueFutureMilestone()
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
whitelistedMilestoneMeter.Update(int64(block))
|
||||||
|
|
||||||
|
m.UnlockSprint(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function will Lock the mutex at the time of voting
|
||||||
|
// fixme: get rid of it
|
||||||
|
func (m *milestone) LockMutex(endBlockNum uint64) bool {
|
||||||
|
m.finality.Lock()
|
||||||
|
|
||||||
|
if m.doExist && endBlockNum <= m.Number { //if endNum is less than whitelisted milestone, then we won't lock the sprint
|
||||||
|
log.Debug("endBlockNumber is less than or equal to latesMilestoneNumber", "endBlock Number", endBlockNum, "LatestMilestone Number", m.Number)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Locked && endBlockNum < m.LockedMilestoneNumber {
|
||||||
|
log.Debug("endBlockNum is less than locked milestone number", "endBlock Number", endBlockNum, "Locked Milestone Number", m.LockedMilestoneNumber)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function will unlock the mutex locked in LockMutex
|
||||||
|
// fixme: get rid of it
|
||||||
|
func (m *milestone) UnlockMutex(doLock bool, milestoneId string, endBlockNum uint64, endBlockHash common.Hash) {
|
||||||
|
m.Locked = m.Locked || doLock
|
||||||
|
|
||||||
|
if doLock {
|
||||||
|
m.UnlockSprint(m.LockedMilestoneNumber)
|
||||||
|
m.Locked = true
|
||||||
|
m.LockedMilestoneHash = endBlockHash
|
||||||
|
m.LockedMilestoneNumber = endBlockNum
|
||||||
|
m.LockedMilestoneIDs[milestoneId] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := rawdb.WriteLockField(m.db, m.Locked, m.LockedMilestoneNumber, m.LockedMilestoneHash, m.LockedMilestoneIDs)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error in writing lock data of milestone to db", "err", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
milestoneIDLength := int64(len(m.LockedMilestoneIDs))
|
||||||
|
MilestoneIdsLengthMeter.Update(milestoneIDLength)
|
||||||
|
|
||||||
|
m.finality.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function will unlock the locked sprint
|
||||||
|
func (m *milestone) UnlockSprint(endBlockNum uint64) {
|
||||||
|
if endBlockNum < m.LockedMilestoneNumber {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Locked = false
|
||||||
|
m.purgeMilestoneIDsList()
|
||||||
|
|
||||||
|
err := rawdb.WriteLockField(m.db, m.Locked, m.LockedMilestoneNumber, m.LockedMilestoneHash, m.LockedMilestoneIDs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error in writing lock data of milestone to db", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function will remove the stored milestoneID
|
||||||
|
func (m *milestone) RemoveMilestoneID(milestoneId string) {
|
||||||
|
m.finality.Lock()
|
||||||
|
|
||||||
|
delete(m.LockedMilestoneIDs, milestoneId)
|
||||||
|
|
||||||
|
if len(m.LockedMilestoneIDs) == 0 {
|
||||||
|
m.Locked = false
|
||||||
|
}
|
||||||
|
|
||||||
|
err := rawdb.WriteLockField(m.db, m.Locked, m.LockedMilestoneNumber, m.LockedMilestoneHash, m.LockedMilestoneIDs)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error in writing lock data of milestone to db", "err", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.finality.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will check whether the incoming chain matches the locked sprint hash
|
||||||
|
func (m *milestone) IsReorgAllowed(chain []*types.Header, lockedMilestoneNumber uint64, lockedMilestoneHash common.Hash) bool {
|
||||||
|
if chain[len(chain)-1].Number.Uint64() <= lockedMilestoneNumber { //Can't reorg if the end block of incoming
|
||||||
|
return false //chain is less than locked sprint number
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(chain); i++ {
|
||||||
|
if chain[i].Number.Uint64() == lockedMilestoneNumber {
|
||||||
|
return chain[i].Hash() == lockedMilestoneHash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will return the list of milestoneIDs stored.
|
||||||
|
func (m *milestone) GetMilestoneIDsList() []string {
|
||||||
|
m.finality.RLock()
|
||||||
|
defer m.finality.RUnlock()
|
||||||
|
|
||||||
|
// fixme: use generics :)
|
||||||
|
keys := make([]string, 0, len(m.LockedMilestoneIDs))
|
||||||
|
for key := range m.LockedMilestoneIDs {
|
||||||
|
keys = append(keys, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is remove the milestoneIDs stored in the list.
|
||||||
|
func (m *milestone) purgeMilestoneIDsList() {
|
||||||
|
m.LockedMilestoneIDs = make(map[string]struct{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *milestone) IsFutureMilestoneCompatible(chain []*types.Header) bool {
|
||||||
|
//Tip of the received chain
|
||||||
|
chainTipNumber := chain[len(chain)-1].Number.Uint64()
|
||||||
|
|
||||||
|
for i := len(m.FutureMilestoneOrder) - 1; i >= 0; i-- {
|
||||||
|
//Finding out the highest future milestone number
|
||||||
|
//which is less or equal to received chain tip
|
||||||
|
if chainTipNumber >= m.FutureMilestoneOrder[i] {
|
||||||
|
//Looking for the received chain 's particular block number(matching future milestone number)
|
||||||
|
for j := len(chain) - 1; j >= 0; j-- {
|
||||||
|
if chain[j].Number.Uint64() == m.FutureMilestoneOrder[i] {
|
||||||
|
endBlockNum := m.FutureMilestoneOrder[i]
|
||||||
|
endBlockHash := m.FutureMilestoneList[endBlockNum]
|
||||||
|
|
||||||
|
//Checking the received chain matches with future milestone
|
||||||
|
return chain[j].Hash() == endBlockHash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *milestone) ProcessFutureMilestone(num uint64, hash common.Hash) {
|
||||||
|
if len(m.FutureMilestoneOrder) < m.MaxCapacity {
|
||||||
|
m.enqueueFutureMilestone(num, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
if num < m.LockedMilestoneNumber {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Locked = false
|
||||||
|
m.purgeMilestoneIDsList()
|
||||||
|
|
||||||
|
err := rawdb.WriteLockField(m.db, m.Locked, m.LockedMilestoneNumber, m.LockedMilestoneHash, m.LockedMilestoneIDs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error in writing lock data of milestone to db", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnqueueFutureMilestone add the future milestone to the list
|
||||||
|
func (m *milestone) enqueueFutureMilestone(key uint64, hash common.Hash) {
|
||||||
|
if _, ok := m.FutureMilestoneList[key]; ok {
|
||||||
|
log.Debug("Future milestone already exist", "endBlockNumber", key, "futureMilestoneHash", hash)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("Enqueing new future milestone", "endBlockNumber", key, "futureMilestoneHash", hash)
|
||||||
|
|
||||||
|
m.FutureMilestoneList[key] = hash
|
||||||
|
m.FutureMilestoneOrder = append(m.FutureMilestoneOrder, key)
|
||||||
|
|
||||||
|
err := rawdb.WriteFutureMilestoneList(m.db, m.FutureMilestoneOrder, m.FutureMilestoneList)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error in writing future milestone data to db", "err", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
FutureMilestoneMeter.Update(int64(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DequeueFutureMilestone remove the future milestone entry from the list.
|
||||||
|
func (m *milestone) dequeueFutureMilestone() {
|
||||||
|
delete(m.FutureMilestoneList, m.FutureMilestoneOrder[0])
|
||||||
|
m.FutureMilestoneOrder = m.FutureMilestoneOrder[1:]
|
||||||
|
|
||||||
|
err := rawdb.WriteFutureMilestoneList(m.db, m.FutureMilestoneOrder, m.FutureMilestoneList)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error in writing future milestone data to db", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,135 +3,150 @@ package whitelist
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Checkpoint whitelist
|
|
||||||
type Service struct {
|
|
||||||
m sync.Mutex
|
|
||||||
checkpointWhitelist map[uint64]common.Hash // Checkpoint whitelist, populated by reaching out to heimdall
|
|
||||||
checkpointOrder []uint64 // Checkpoint order, populated by reaching out to heimdall
|
|
||||||
maxCapacity uint // Max capacity of the whitelist
|
|
||||||
checkpointInterval uint64 // Checkpoint interval, until which we can allow importing
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewService(maxCapacity uint) *Service {
|
|
||||||
return &Service{
|
|
||||||
checkpointWhitelist: make(map[uint64]common.Hash),
|
|
||||||
checkpointOrder: []uint64{},
|
|
||||||
maxCapacity: maxCapacity,
|
|
||||||
checkpointInterval: 256, // TODO: make it configurable through params?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
ErrMismatch = errors.New("mismatch error")
|
||||||
|
ErrNoRemote = errors.New("remote peer doesn't have a target block number")
|
||||||
|
|
||||||
ErrCheckpointMismatch = errors.New("checkpoint mismatch")
|
ErrCheckpointMismatch = errors.New("checkpoint mismatch")
|
||||||
ErrLongFutureChain = errors.New("received future chain of unacceptable length")
|
ErrLongFutureChain = errors.New("received future chain of unacceptable length")
|
||||||
ErrNoRemoteCheckpoint = errors.New("remote peer doesn't have a checkpoint")
|
ErrNoRemoteCheckpoint = errors.New("remote peer doesn't have a checkpoint")
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsValidPeer checks if the chain we're about to receive from a peer is valid or not
|
type Service struct {
|
||||||
// in terms of reorgs. We won't reorg beyond the last bor checkpoint submitted to mainchain.
|
checkpointService
|
||||||
func (w *Service) IsValidPeer(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
milestoneService
|
||||||
// We want to validate the chain by comparing the last checkpointed block
|
|
||||||
// we're storing in `checkpointWhitelist` with the peer's block.
|
|
||||||
//
|
|
||||||
// Check for availaibility of the last checkpointed block.
|
|
||||||
// This can be also be empty if our heimdall is not responding
|
|
||||||
// or we're running without it.
|
|
||||||
if len(w.checkpointWhitelist) == 0 {
|
|
||||||
// worst case, we don't have the checkpoints in memory
|
|
||||||
return true, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the last checkpoint entry
|
func NewService(db ethdb.Database) *Service {
|
||||||
lastCheckpointBlockNum := w.checkpointOrder[len(w.checkpointOrder)-1]
|
var checkpointDoExist = true
|
||||||
lastCheckpointBlockHash := w.checkpointWhitelist[lastCheckpointBlockNum]
|
|
||||||
|
checkpointNumber, checkpointHash, err := rawdb.ReadFinality[*rawdb.Checkpoint](db)
|
||||||
|
|
||||||
// todo: we can extract this as an interface and mock as well or just test IsValidChain in isolation from downloader passing fake fetchHeadersByNumber functions
|
|
||||||
headers, hashes, err := fetchHeadersByNumber(lastCheckpointBlockNum, 1, 0, false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("%w: last checkpoint %d, err %v", ErrNoRemoteCheckpoint, lastCheckpointBlockNum, err)
|
checkpointDoExist = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(headers) == 0 {
|
var milestoneDoExist = true
|
||||||
return false, fmt.Errorf("%w: last checkpoint %d", ErrNoRemoteCheckpoint, lastCheckpointBlockNum)
|
|
||||||
|
milestoneNumber, milestoneHash, err := rawdb.ReadFinality[*rawdb.Milestone](db)
|
||||||
|
if err != nil {
|
||||||
|
milestoneDoExist = false
|
||||||
}
|
}
|
||||||
|
|
||||||
reqBlockNum := headers[0].Number.Uint64()
|
locked, lockedMilestoneNumber, lockedMilestoneHash, lockedMilestoneIDs, err := rawdb.ReadLockField(db)
|
||||||
reqBlockHash := hashes[0]
|
if err != nil || !locked {
|
||||||
|
locked = false
|
||||||
// Check against the checkpointed blocks
|
lockedMilestoneIDs = make(map[string]struct{})
|
||||||
if reqBlockNum == lastCheckpointBlockNum && reqBlockHash == lastCheckpointBlockHash {
|
|
||||||
return true, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, ErrCheckpointMismatch
|
order, list, err := rawdb.ReadFutureMilestoneList(db)
|
||||||
|
if err != nil {
|
||||||
|
order = make([]uint64, 0)
|
||||||
|
list = make(map[uint64]common.Hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsValidChain checks the validity of chain by comparing it
|
return &Service{
|
||||||
// against the local checkpoint entries
|
&checkpoint{
|
||||||
func (w *Service) IsValidChain(currentHeader *types.Header, chain []*types.Header) (bool, error) {
|
finality[*rawdb.Checkpoint]{
|
||||||
// Check if we have checkpoints to validate incoming chain in memory
|
doExist: checkpointDoExist,
|
||||||
if len(w.checkpointWhitelist) == 0 {
|
Number: checkpointNumber,
|
||||||
// We don't have any entries, no additional validation will be possible
|
Hash: checkpointHash,
|
||||||
return true, nil
|
interval: 256,
|
||||||
|
db: db,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
&milestone{
|
||||||
|
finality: finality[*rawdb.Milestone]{
|
||||||
|
doExist: milestoneDoExist,
|
||||||
|
Number: milestoneNumber,
|
||||||
|
Hash: milestoneHash,
|
||||||
|
interval: 256,
|
||||||
|
db: db,
|
||||||
|
},
|
||||||
|
|
||||||
|
Locked: locked,
|
||||||
|
LockedMilestoneNumber: lockedMilestoneNumber,
|
||||||
|
LockedMilestoneHash: lockedMilestoneHash,
|
||||||
|
LockedMilestoneIDs: lockedMilestoneIDs,
|
||||||
|
FutureMilestoneList: list,
|
||||||
|
FutureMilestoneOrder: order,
|
||||||
|
MaxCapacity: 10,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return if we've received empty chain
|
// IsValidPeer checks if the chain we're about to receive from a peer is valid or not
|
||||||
if len(chain) == 0 {
|
// in terms of reorgs. We won't reorg beyond the last bor checkpoint submitted to mainchain and last milestone voted in the heimdall
|
||||||
return false, nil
|
func (s *Service) IsValidPeer(fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||||
|
checkpointBool, err := s.checkpointService.IsValidPeer(fetchHeadersByNumber)
|
||||||
|
if !checkpointBool {
|
||||||
|
return checkpointBool, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
milestoneBool, err := s.milestoneService.IsValidPeer(fetchHeadersByNumber)
|
||||||
oldestCheckpointNumber uint64 = w.checkpointOrder[0]
|
if !milestoneBool {
|
||||||
current uint64 = currentHeader.Number.Uint64()
|
return milestoneBool, err
|
||||||
)
|
|
||||||
|
|
||||||
// Check if we have whitelist entries in required range
|
|
||||||
if chain[len(chain)-1].Number.Uint64() < oldestCheckpointNumber {
|
|
||||||
// We have future whitelisted entries, so no additional validation will be possible
|
|
||||||
// This case will occur when bor is in middle of sync, but heimdall is ahead/fully synced.
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Split the chain into past and future chain
|
|
||||||
pastChain, _ := splitChain(current, chain)
|
|
||||||
|
|
||||||
// Note: Do not act on future chain and allow importing all kinds of future chains.
|
|
||||||
|
|
||||||
// Add an offset to future chain if it's not in continuity
|
|
||||||
// offset := 0
|
|
||||||
// if len(futureChain) != 0 {
|
|
||||||
// offset += int(futureChain[0].Number.Uint64()-currentHeader.Number.Uint64()) - 1
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Don't accept future chain of unacceptable length (from current block)
|
|
||||||
// if len(futureChain)+offset > int(w.checkpointInterval) {
|
|
||||||
// return false, ErrLongFutureChain
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Iterate over the chain and validate against the last checkpoint
|
|
||||||
// It will handle all cases where the incoming chain has atleast one checkpoint
|
|
||||||
for i := len(pastChain) - 1; i >= 0; i-- {
|
|
||||||
if _, ok := w.checkpointWhitelist[pastChain[i].Number.Uint64()]; ok {
|
|
||||||
return pastChain[i].Hash() == w.checkpointWhitelist[pastChain[i].Number.Uint64()], nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) PurgeWhitelistedCheckpoint() {
|
||||||
|
s.checkpointService.Purge()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) PurgeWhitelistedMilestone() {
|
||||||
|
s.milestoneService.Purge()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetWhitelistedCheckpoint() (bool, uint64, common.Hash) {
|
||||||
|
return s.checkpointService.Get()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetWhitelistedMilestone() (bool, uint64, common.Hash) {
|
||||||
|
return s.milestoneService.Get()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) ProcessMilestone(endBlockNum uint64, endBlockHash common.Hash) {
|
||||||
|
s.milestoneService.Process(endBlockNum, endBlockHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash) {
|
||||||
|
s.checkpointService.Process(endBlockNum, endBlockHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) IsValidChain(currentHeader *types.Header, chain []*types.Header) (bool, error) {
|
||||||
|
checkpointBool, err := s.checkpointService.IsValidChain(currentHeader, chain)
|
||||||
|
if !checkpointBool {
|
||||||
|
return checkpointBool, err
|
||||||
|
}
|
||||||
|
|
||||||
|
milestoneBool, err := s.milestoneService.IsValidChain(currentHeader, chain)
|
||||||
|
if !milestoneBool {
|
||||||
|
return milestoneBool, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetMilestoneIDsList() []string {
|
||||||
|
return s.milestoneService.GetMilestoneIDsList()
|
||||||
|
}
|
||||||
|
|
||||||
func splitChain(current uint64, chain []*types.Header) ([]*types.Header, []*types.Header) {
|
func splitChain(current uint64, chain []*types.Header) ([]*types.Header, []*types.Header) {
|
||||||
var (
|
var (
|
||||||
pastChain []*types.Header
|
pastChain []*types.Header
|
||||||
futureChain []*types.Header
|
futureChain []*types.Header
|
||||||
first uint64 = chain[0].Number.Uint64()
|
first = chain[0].Number.Uint64()
|
||||||
last uint64 = chain[len(chain)-1].Number.Uint64()
|
last = chain[len(chain)-1].Number.Uint64()
|
||||||
)
|
)
|
||||||
|
|
||||||
if current >= first {
|
if current >= first {
|
||||||
|
|
@ -153,57 +168,68 @@ func splitChain(current uint64, chain []*types.Header) ([]*types.Header, []*type
|
||||||
return pastChain, futureChain
|
return pastChain, futureChain
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Service) ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash) {
|
//nolint:unparam
|
||||||
w.m.Lock()
|
func isValidChain(currentHeader *types.Header, chain []*types.Header, doExist bool, number uint64, hash common.Hash) (bool, error) {
|
||||||
defer w.m.Unlock()
|
// Check if we have milestone to validate incoming chain in memory
|
||||||
|
if !doExist {
|
||||||
|
// We don't have any entry, no additional validation will be possible
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
w.enqueueCheckpointWhitelist(endBlockNum, endBlockHash)
|
current := currentHeader.Number.Uint64()
|
||||||
// If size of checkpoint whitelist map is greater than 10, remove the oldest entry.
|
|
||||||
|
|
||||||
if w.length() > int(w.maxCapacity) {
|
// Check if imported chain is less than whitelisted number
|
||||||
w.dequeueCheckpointWhitelist()
|
if chain[len(chain)-1].Number.Uint64() < number {
|
||||||
|
if current >= number { //If current tip of the chain is greater than whitelist number then return false
|
||||||
|
return false, nil
|
||||||
|
} else {
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCheckpointWhitelist returns the existing whitelisted
|
// Split the chain into past and future chain
|
||||||
// entries of checkpoint of the form block number -> block hash.
|
pastChain, _ := splitChain(current, chain)
|
||||||
func (w *Service) GetCheckpointWhitelist() map[uint64]common.Hash {
|
|
||||||
w.m.Lock()
|
|
||||||
defer w.m.Unlock()
|
|
||||||
|
|
||||||
return w.checkpointWhitelist
|
// Iterate over the chain and validate against the last milestone
|
||||||
}
|
// It will handle all cases when the incoming chain has atleast one milestone
|
||||||
|
for i := len(pastChain) - 1; i >= 0; i-- {
|
||||||
|
if pastChain[i].Number.Uint64() == number {
|
||||||
|
res := pastChain[i].Hash() == hash
|
||||||
|
|
||||||
// PurgeCheckpointWhitelist purges data from checkpoint whitelist map
|
return res, nil
|
||||||
func (w *Service) PurgeCheckpointWhitelist() {
|
|
||||||
w.m.Lock()
|
|
||||||
defer w.m.Unlock()
|
|
||||||
|
|
||||||
w.checkpointWhitelist = make(map[uint64]common.Hash)
|
|
||||||
w.checkpointOrder = make([]uint64, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnqueueWhitelistBlock enqueues blockNumber, blockHash to the checkpoint whitelist map
|
|
||||||
func (w *Service) enqueueCheckpointWhitelist(key uint64, val common.Hash) {
|
|
||||||
if _, ok := w.checkpointWhitelist[key]; !ok {
|
|
||||||
log.Debug("Enqueing new checkpoint whitelist", "block number", key, "block hash", val)
|
|
||||||
|
|
||||||
w.checkpointWhitelist[key] = val
|
|
||||||
w.checkpointOrder = append(w.checkpointOrder, key)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DequeueWhitelistBlock dequeues block, blockhash from the checkpoint whitelist map
|
return true, nil
|
||||||
func (w *Service) dequeueCheckpointWhitelist() {
|
|
||||||
if len(w.checkpointOrder) > 0 {
|
|
||||||
log.Debug("Dequeing checkpoint whitelist", "block number", w.checkpointOrder[0], "block hash", w.checkpointWhitelist[w.checkpointOrder[0]])
|
|
||||||
|
|
||||||
delete(w.checkpointWhitelist, w.checkpointOrder[0])
|
|
||||||
w.checkpointOrder = w.checkpointOrder[1:] // fixme: this slice is growing infinitely and never will be released. also a panic is possible if the last element is going to be removed
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// length returns the len of the whitelist.
|
// FIXME: remoteHeader is not used
|
||||||
func (w *Service) length() int {
|
func isValidPeer(fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error), doExist bool, number uint64, hash common.Hash) (bool, error) {
|
||||||
return len(w.checkpointWhitelist)
|
// Check for availaibility of the last milestone block.
|
||||||
|
// This can be also be empty if our heimdall is not responding
|
||||||
|
// or we're running without it.
|
||||||
|
if !doExist {
|
||||||
|
// worst case, we don't have the milestone in memory
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: we can extract this as an interface and mock as well or just test IsValidChain in isolation from downloader passing fake fetchHeadersByNumber functions
|
||||||
|
headers, hashes, err := fetchHeadersByNumber(number, 1, 0, false)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("%w: last whitelisted block number %d, err %v", ErrNoRemote, number, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(headers) == 0 {
|
||||||
|
return false, fmt.Errorf("%w: last whitlisted block number %d", ErrNoRemote, number)
|
||||||
|
}
|
||||||
|
|
||||||
|
reqBlockNum := headers[0].Number.Uint64()
|
||||||
|
reqBlockHash := hashes[0]
|
||||||
|
|
||||||
|
// Check against the whitelisted blocks
|
||||||
|
if reqBlockNum == number && reqBlockHash == hash {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, ErrMismatch
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
// nolint
|
||||||
package whitelist
|
package whitelist
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -9,35 +10,243 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"pgregory.net/rapid"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewMockService creates a new mock whitelist service
|
// NewMockService creates a new mock whitelist service
|
||||||
func NewMockService(maxCapacity uint, checkpointInterval uint64) *Service {
|
func NewMockService(db ethdb.Database) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
checkpointWhitelist: make(map[uint64]common.Hash),
|
|
||||||
checkpointOrder: []uint64{},
|
&checkpoint{
|
||||||
maxCapacity: maxCapacity,
|
finality[*rawdb.Checkpoint]{
|
||||||
checkpointInterval: checkpointInterval,
|
doExist: false,
|
||||||
|
interval: 256,
|
||||||
|
db: db,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
&milestone{
|
||||||
|
finality: finality[*rawdb.Milestone]{
|
||||||
|
doExist: false,
|
||||||
|
interval: 256,
|
||||||
|
db: db,
|
||||||
|
},
|
||||||
|
LockedMilestoneIDs: make(map[string]struct{}),
|
||||||
|
FutureMilestoneList: make(map[uint64]common.Hash),
|
||||||
|
FutureMilestoneOrder: make([]uint64, 0),
|
||||||
|
MaxCapacity: 10,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestWhitelistCheckpoint checks the checkpoint whitelist map queue mechanism
|
// TestWhitelistCheckpoint checks the checkpoint whitelist setter and getter functions.
|
||||||
func TestWhitelistCheckpoint(t *testing.T) {
|
func TestWhitelistedCheckpoint(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
s := NewMockService(10, 10)
|
db := rawdb.NewMemoryDatabase()
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
s.enqueueCheckpointWhitelist(uint64(i), common.Hash{})
|
|
||||||
}
|
|
||||||
require.Equal(t, s.length(), 10, "expected 10 items in whitelist")
|
|
||||||
|
|
||||||
s.enqueueCheckpointWhitelist(11, common.Hash{})
|
//Creating the service for the whitelisting the checkpoints
|
||||||
s.dequeueCheckpointWhitelist()
|
s := NewMockService(db)
|
||||||
require.Equal(t, s.length(), 10, "expected 10 items in whitelist")
|
|
||||||
|
cp := s.checkpointService.(*checkpoint)
|
||||||
|
|
||||||
|
require.Equal(t, cp.doExist, false, "expected false as no cp exist at this point")
|
||||||
|
|
||||||
|
_, _, err := rawdb.ReadFinality[*rawdb.Checkpoint](db)
|
||||||
|
require.NotNil(t, err, "Error should be nil while reading from the db")
|
||||||
|
|
||||||
|
//Adding the checkpoint
|
||||||
|
s.ProcessCheckpoint(11, common.Hash{})
|
||||||
|
|
||||||
|
require.Equal(t, cp.doExist, true, "expected true as cp exist")
|
||||||
|
|
||||||
|
//Removing the checkpoint
|
||||||
|
s.PurgeWhitelistedCheckpoint()
|
||||||
|
|
||||||
|
require.Equal(t, cp.doExist, false, "expected false as no cp exist at this point")
|
||||||
|
|
||||||
|
//Adding the checkpoint
|
||||||
|
s.ProcessCheckpoint(12, common.Hash{1})
|
||||||
|
|
||||||
|
//Receiving the stored checkpoint
|
||||||
|
doExist, number, hash := s.GetWhitelistedCheckpoint()
|
||||||
|
|
||||||
|
//Validating the values received
|
||||||
|
require.Equal(t, doExist, true, "expected true ascheckpoint exist at this point")
|
||||||
|
require.Equal(t, number, uint64(12), "expected number to be 11 but got", number)
|
||||||
|
require.Equal(t, hash, common.Hash{1}, "expected the 1 hash but got", hash)
|
||||||
|
require.NotEqual(t, hash, common.Hash{}, "expected the hash to be different from zero hash")
|
||||||
|
|
||||||
|
c1 := s.checkpointService.(*checkpoint)
|
||||||
|
fmt.Println("!!!-0", c1.doExist)
|
||||||
|
s.PurgeWhitelistedCheckpoint()
|
||||||
|
fmt.Println("!!!-1", c1.doExist)
|
||||||
|
doExist, number, hash = s.GetWhitelistedCheckpoint()
|
||||||
|
fmt.Println("!!!-2", c1.doExist)
|
||||||
|
//Validating the values received from the db, not memory
|
||||||
|
require.Equal(t, doExist, true, "expected true ascheckpoint exist at this point")
|
||||||
|
require.Equal(t, number, uint64(12), "expected number to be 11 but got", number)
|
||||||
|
require.Equal(t, hash, common.Hash{1}, "expected the 1 hash but got", hash)
|
||||||
|
require.NotEqual(t, hash, common.Hash{}, "expected the hash to be different from zero hash")
|
||||||
|
|
||||||
|
checkpointNumber, checkpointHash, err := rawdb.ReadFinality[*rawdb.Checkpoint](db)
|
||||||
|
require.Nil(t, err, "Error should be nil while reading from the db")
|
||||||
|
require.Equal(t, checkpointHash, common.Hash{1}, "expected the 1 hash but got", hash)
|
||||||
|
require.Equal(t, checkpointNumber, uint64(12), "expected number to be 11 but got", number)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestMilestone checks the milestone whitelist setter and getter functions
|
||||||
|
func TestMilestone(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
db := rawdb.NewMemoryDatabase()
|
||||||
|
s := NewMockService(db)
|
||||||
|
|
||||||
|
milestone := s.milestoneService.(*milestone)
|
||||||
|
|
||||||
|
//Checking for the variables when no milestone is Processed
|
||||||
|
require.Equal(t, milestone.doExist, false, "expected false as no milestone exist at this point")
|
||||||
|
require.Equal(t, milestone.Locked, false, "expected false as it was not locked")
|
||||||
|
require.Equal(t, milestone.LockedMilestoneNumber, uint64(0), "expected 0 as it was not initialized")
|
||||||
|
|
||||||
|
_, _, err := rawdb.ReadFinality[*rawdb.Milestone](db)
|
||||||
|
require.NotNil(t, err, "Error should be nil while reading from the db")
|
||||||
|
|
||||||
|
//Acquiring the mutex lock
|
||||||
|
milestone.LockMutex(11)
|
||||||
|
require.Equal(t, milestone.Locked, false, "expected false as sprint is not locked till this point")
|
||||||
|
|
||||||
|
//Releasing the mutex lock
|
||||||
|
milestone.UnlockMutex(true, "milestoneID1", uint64(11), common.Hash{})
|
||||||
|
require.Equal(t, milestone.LockedMilestoneNumber, uint64(11), "expected 11 as it was not initialized")
|
||||||
|
require.Equal(t, milestone.Locked, true, "expected true as sprint is locked now")
|
||||||
|
require.Equal(t, len(milestone.LockedMilestoneIDs), 1, "expected 1 as only 1 milestoneID has been entered")
|
||||||
|
|
||||||
|
_, ok := milestone.LockedMilestoneIDs["milestoneID1"]
|
||||||
|
require.True(t, ok, "milestoneID1 should exist in the LockedMilestoneIDs map")
|
||||||
|
|
||||||
|
_, ok = milestone.LockedMilestoneIDs["milestoneID2"]
|
||||||
|
require.False(t, ok, "milestoneID2 shouldn't exist in the LockedMilestoneIDs map")
|
||||||
|
|
||||||
|
milestone.LockMutex(11)
|
||||||
|
milestone.UnlockMutex(true, "milestoneID2", uint64(11), common.Hash{})
|
||||||
|
require.Equal(t, len(milestone.LockedMilestoneIDs), 1, "expected 1 as only 1 milestoneID has been entered")
|
||||||
|
|
||||||
|
_, ok = milestone.LockedMilestoneIDs["milestoneID2"]
|
||||||
|
require.True(t, ok, "milestoneID2 should exist in the LockedMilestoneIDs map")
|
||||||
|
|
||||||
|
milestone.RemoveMilestoneID("milestoneID1")
|
||||||
|
require.Equal(t, len(milestone.LockedMilestoneIDs), 1, "expected 1 as one out of two has been removed in previous step")
|
||||||
|
require.Equal(t, milestone.Locked, true, "expected true as sprint is locked now")
|
||||||
|
|
||||||
|
milestone.RemoveMilestoneID("milestoneID2")
|
||||||
|
require.Equal(t, len(milestone.LockedMilestoneIDs), 0, "expected 1 as both the milestonesIDs has been removed in previous step")
|
||||||
|
require.Equal(t, milestone.Locked, false, "expected false")
|
||||||
|
|
||||||
|
milestone.LockMutex(11)
|
||||||
|
milestone.UnlockMutex(true, "milestoneID3", uint64(11), common.Hash{})
|
||||||
|
require.True(t, milestone.Locked, "expected true")
|
||||||
|
require.Equal(t, milestone.LockedMilestoneNumber, uint64(11), "Expected 11")
|
||||||
|
|
||||||
|
milestone.LockMutex(15)
|
||||||
|
require.True(t, milestone.Locked, "expected true")
|
||||||
|
require.Equal(t, milestone.LockedMilestoneNumber, uint64(11), "Expected 11")
|
||||||
|
milestone.UnlockMutex(true, "milestoneID4", uint64(15), common.Hash{})
|
||||||
|
require.True(t, milestone.Locked, "expected true as final confirmation regarding the lock has been made")
|
||||||
|
require.Equal(t, len(milestone.LockedMilestoneIDs), 1, "expected 1 as previous milestonesIDs has been removed in previous step")
|
||||||
|
|
||||||
|
//Adding the milestone
|
||||||
|
s.ProcessMilestone(11, common.Hash{})
|
||||||
|
|
||||||
|
require.True(t, milestone.Locked, "expected true as locked sprint is of number 15")
|
||||||
|
require.Equal(t, milestone.doExist, true, "expected true as milestone exist")
|
||||||
|
require.Equal(t, len(milestone.LockedMilestoneIDs), 1, "expected 1 as still last milestone of sprint number 15 exist")
|
||||||
|
|
||||||
|
//Reading from the Db
|
||||||
|
locked, lockedMilestoneNumber, lockedMilestoneHash, lockedMilestoneIDs, err := rawdb.ReadLockField(db)
|
||||||
|
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.True(t, locked, "expected true as locked sprint is of number 15")
|
||||||
|
require.Equal(t, lockedMilestoneNumber, uint64(15), "Expected 15")
|
||||||
|
require.Equal(t, lockedMilestoneHash, common.Hash{}, "Expected", common.Hash{})
|
||||||
|
require.Equal(t, len(lockedMilestoneIDs), 1, "expected 1 as still last milestone of sprint number 15 exist")
|
||||||
|
|
||||||
|
_, ok = lockedMilestoneIDs["milestoneID4"]
|
||||||
|
require.True(t, ok, "expected true as milestoneIDList should contain 'milestoneID4'")
|
||||||
|
|
||||||
|
//Asking the lock for sprintNumber less than last whitelisted milestone
|
||||||
|
require.False(t, milestone.LockMutex(11), "Cant lock the sprintNumber less than equal to latest whitelisted milestone")
|
||||||
|
milestone.UnlockMutex(false, "", uint64(11), common.Hash{}) //Unlock is required after every lock to release the mutex
|
||||||
|
|
||||||
|
//Adding the milestone
|
||||||
|
s.ProcessMilestone(51, common.Hash{})
|
||||||
|
require.False(t, milestone.Locked, "expected false as lock from sprint number 15 is removed")
|
||||||
|
require.Equal(t, milestone.doExist, true, "expected true as milestone exist")
|
||||||
|
require.Equal(t, len(milestone.LockedMilestoneIDs), 0, "expected 0 as all the milestones have been removed")
|
||||||
|
|
||||||
|
//Reading from the Db
|
||||||
|
locked, _, _, lockedMilestoneIDs, err = rawdb.ReadLockField(db)
|
||||||
|
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.False(t, locked, "expected true as locked sprint is of number 15")
|
||||||
|
require.Equal(t, len(lockedMilestoneIDs), 0, "expected 0 as milestoneID exist in the map")
|
||||||
|
|
||||||
|
//Removing the milestone
|
||||||
|
s.PurgeWhitelistedMilestone()
|
||||||
|
|
||||||
|
require.Equal(t, milestone.doExist, false, "expected false as no milestone exist at this point")
|
||||||
|
|
||||||
|
//Removing the milestone
|
||||||
|
s.ProcessMilestone(11, common.Hash{1})
|
||||||
|
|
||||||
|
doExist, number, hash := s.GetWhitelistedMilestone()
|
||||||
|
|
||||||
|
//validating the values received
|
||||||
|
require.Equal(t, doExist, true, "expected true as milestone exist at this point")
|
||||||
|
require.Equal(t, number, uint64(11), "expected number to be 11 but got", number)
|
||||||
|
require.Equal(t, hash, common.Hash{1}, "expected the 1 hash but got", hash)
|
||||||
|
|
||||||
|
s.PurgeWhitelistedMilestone()
|
||||||
|
doExist, number, hash = s.GetWhitelistedMilestone()
|
||||||
|
|
||||||
|
//Validating the values received from the db, not memory
|
||||||
|
require.Equal(t, doExist, true, "expected true as milestone exist at this point")
|
||||||
|
require.Equal(t, number, uint64(11), "expected number to be 11 but got", number)
|
||||||
|
require.Equal(t, hash, common.Hash{1}, "expected the 1 hash but got", hash)
|
||||||
|
|
||||||
|
milestoneNumber, milestoneHash, err := rawdb.ReadFinality[*rawdb.Milestone](db)
|
||||||
|
require.Nil(t, err, "Error should be nil while reading from the db")
|
||||||
|
require.Equal(t, milestoneHash, common.Hash{1}, "expected the 1 hash but got", hash)
|
||||||
|
require.Equal(t, milestoneNumber, uint64(11), "expected number to be 11 but got", number)
|
||||||
|
|
||||||
|
_, _, err = rawdb.ReadFutureMilestoneList(db)
|
||||||
|
require.NotNil(t, err, "Error should be not nil")
|
||||||
|
|
||||||
|
s.ProcessFutureMilestone(16, common.Hash{16})
|
||||||
|
require.Equal(t, len(milestone.FutureMilestoneOrder), 1, "expected length is 1 as we added only 1 future milestone")
|
||||||
|
require.Equal(t, milestone.FutureMilestoneOrder[0], uint64(16), "expected value is 16 but got", milestone.FutureMilestoneOrder[0])
|
||||||
|
require.Equal(t, milestone.FutureMilestoneList[16], common.Hash{16}, "expected value is", common.Hash{16}.String()[2:], "but got", milestone.FutureMilestoneList[16])
|
||||||
|
|
||||||
|
order, list, err := rawdb.ReadFutureMilestoneList(db)
|
||||||
|
require.Nil(t, err, "Error should be nil while reading from the db")
|
||||||
|
require.Equal(t, len(order), 1, "expected the 1 hash but got", len(order))
|
||||||
|
require.Equal(t, order[0], uint64(16), "expected number to be 16 but got", order[0])
|
||||||
|
require.Equal(t, list[order[0]], common.Hash{16}, "expected value is", common.Hash{16}.String()[2:], "but got", list[order[0]])
|
||||||
|
|
||||||
|
capicity := milestone.MaxCapacity
|
||||||
|
for i := 16; i <= 16*(capicity+1); i = i + 16 {
|
||||||
|
s.ProcessFutureMilestone(uint64(i), common.Hash{16})
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Equal(t, len(milestone.FutureMilestoneOrder), capicity, "expected length is", capicity)
|
||||||
|
require.Equal(t, milestone.FutureMilestoneOrder[capicity-1], uint64(16*capicity), "expected value is", uint64(16*capicity), "but got", milestone.FutureMilestoneOrder[capicity-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestIsValidPeer checks the IsValidPeer function in isolation
|
// TestIsValidPeer checks the IsValidPeer function in isolation
|
||||||
|
|
@ -45,18 +254,26 @@ func TestWhitelistCheckpoint(t *testing.T) {
|
||||||
func TestIsValidPeer(t *testing.T) {
|
func TestIsValidPeer(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
s := NewMockService(10, 10)
|
db := rawdb.NewMemoryDatabase()
|
||||||
|
s := NewMockService(db)
|
||||||
|
|
||||||
// case1: no checkpoint whitelist, should consider the chain as valid
|
// case1: no checkpoint whitelist, should consider the chain as valid
|
||||||
res, err := s.IsValidPeer(nil, nil)
|
res, err := s.IsValidPeer(nil)
|
||||||
require.NoError(t, err, "expected no error")
|
require.NoError(t, err, "expected no error")
|
||||||
require.Equal(t, res, true, "expected chain to be valid")
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
|
|
||||||
// add checkpoint entries and mock fetchHeadersByNumber function
|
// add checkpoint entry and mock fetchHeadersByNumber function
|
||||||
s.ProcessCheckpoint(uint64(0), common.Hash{})
|
|
||||||
s.ProcessCheckpoint(uint64(1), common.Hash{})
|
s.ProcessCheckpoint(uint64(1), common.Hash{})
|
||||||
|
|
||||||
require.Equal(t, s.length(), 2, "expected 2 items in whitelist")
|
// add milestone entry and mock fetchHeadersByNumber function
|
||||||
|
s.ProcessMilestone(uint64(1), common.Hash{})
|
||||||
|
|
||||||
|
checkpoint := s.checkpointService.(*checkpoint)
|
||||||
|
milestone := s.milestoneService.(*milestone)
|
||||||
|
|
||||||
|
//Check whether the milestone and checkpoint exist
|
||||||
|
require.Equal(t, checkpoint.doExist, true, "expected true as checkpoint exists")
|
||||||
|
require.Equal(t, milestone.doExist, true, "expected true as milestone exists")
|
||||||
|
|
||||||
// create a false function, returning absolutely nothing
|
// create a false function, returning absolutely nothing
|
||||||
falseFetchHeadersByNumber := func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error) {
|
falseFetchHeadersByNumber := func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error) {
|
||||||
|
|
@ -64,20 +281,19 @@ func TestIsValidPeer(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// case2: false fetchHeadersByNumber function provided, should consider the chain as invalid
|
// case2: false fetchHeadersByNumber function provided, should consider the chain as invalid
|
||||||
// and throw `ErrNoRemoteCheckpoint` error
|
// and throw `ErrNoRemoteCheckoint` error
|
||||||
res, err = s.IsValidPeer(nil, falseFetchHeadersByNumber)
|
res, err = s.IsValidPeer(falseFetchHeadersByNumber)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("expected error, got nil")
|
t.Fatal("expected error, got nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !errors.Is(err, ErrNoRemoteCheckpoint) {
|
if !errors.Is(err, ErrNoRemote) {
|
||||||
t.Fatalf("expected error ErrNoRemoteCheckpoint, got %v", err)
|
t.Fatalf("expected error ErrNoRemote, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Equal(t, res, false, "expected chain to be invalid")
|
require.Equal(t, res, false, "expected peer chain to be invalid")
|
||||||
|
|
||||||
// case3: correct fetchHeadersByNumber function provided, should consider the chain as valid
|
// create a mock function, returning the required header
|
||||||
// create a mock function, returning a the required header
|
|
||||||
fetchHeadersByNumber := func(number uint64, _ int, _ int, _ bool) ([]*types.Header, []common.Hash, error) {
|
fetchHeadersByNumber := func(number uint64, _ int, _ int, _ bool) ([]*types.Header, []common.Hash, error) {
|
||||||
hash := common.Hash{}
|
hash := common.Hash{}
|
||||||
header := types.Header{Number: big.NewInt(0)}
|
header := types.Header{Number: big.NewInt(0)}
|
||||||
|
|
@ -96,18 +312,124 @@ func TestIsValidPeer(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err = s.IsValidPeer(nil, fetchHeadersByNumber)
|
// case3: correct fetchHeadersByNumber function provided, should consider the chain as valid
|
||||||
|
res, err = s.IsValidPeer(fetchHeadersByNumber)
|
||||||
require.NoError(t, err, "expected no error")
|
require.NoError(t, err, "expected no error")
|
||||||
require.Equal(t, res, true, "expected chain to be valid")
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
|
|
||||||
// add one more checkpoint whitelist entry
|
// add checkpoint whitelist entry
|
||||||
s.ProcessCheckpoint(uint64(2), common.Hash{})
|
s.ProcessCheckpoint(uint64(2), common.Hash{})
|
||||||
require.Equal(t, s.length(), 3, "expected 3 items in whitelist")
|
require.Equal(t, checkpoint.doExist, true, "expected true as checkpoint exists")
|
||||||
|
|
||||||
// case4: correct fetchHeadersByNumber function provided with wrong header
|
// case4: correct fetchHeadersByNumber function provided with wrong header
|
||||||
// for block number 2. Should consider the chain as invalid and throw an error
|
// for block number 2. Should consider the chain as invalid and throw an error
|
||||||
res, err = s.IsValidPeer(nil, fetchHeadersByNumber)
|
res, err = s.IsValidPeer(fetchHeadersByNumber)
|
||||||
require.Equal(t, err, ErrCheckpointMismatch, "expected checkpoint mismatch error")
|
require.Equal(t, err, ErrMismatch, "expected mismatch error")
|
||||||
|
require.Equal(t, res, false, "expected chain to be invalid")
|
||||||
|
|
||||||
|
// create a mock function, returning the required header
|
||||||
|
fetchHeadersByNumber = func(number uint64, _ int, _ int, _ bool) ([]*types.Header, []common.Hash, error) {
|
||||||
|
hash := common.Hash{}
|
||||||
|
header := types.Header{Number: big.NewInt(0)}
|
||||||
|
|
||||||
|
switch number {
|
||||||
|
case 0:
|
||||||
|
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||||
|
case 1:
|
||||||
|
header.Number = big.NewInt(1)
|
||||||
|
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||||
|
case 2:
|
||||||
|
header.Number = big.NewInt(2)
|
||||||
|
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
header.Number = big.NewInt(3)
|
||||||
|
hash3 := common.Hash{3}
|
||||||
|
|
||||||
|
return []*types.Header{&header}, []common.Hash{hash3}, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, nil, errors.New("invalid number")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.ProcessMilestone(uint64(3), common.Hash{})
|
||||||
|
|
||||||
|
//Case5: correct fetchHeadersByNumber function provided with hash mismatch, should consider the chain as invalid
|
||||||
|
res, err = s.IsValidPeer(fetchHeadersByNumber)
|
||||||
|
require.Equal(t, err, ErrMismatch, "expected milestone mismatch error")
|
||||||
|
require.Equal(t, res, false, "expected chain to be invalid")
|
||||||
|
|
||||||
|
s.ProcessMilestone(uint64(2), common.Hash{})
|
||||||
|
|
||||||
|
// create a mock function, returning the required header
|
||||||
|
fetchHeadersByNumber = func(number uint64, _ int, _ int, _ bool) ([]*types.Header, []common.Hash, error) {
|
||||||
|
hash := common.Hash{}
|
||||||
|
header := types.Header{Number: big.NewInt(0)}
|
||||||
|
|
||||||
|
switch number {
|
||||||
|
case 0:
|
||||||
|
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||||
|
case 1:
|
||||||
|
header.Number = big.NewInt(1)
|
||||||
|
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||||
|
case 2:
|
||||||
|
header.Number = big.NewInt(2)
|
||||||
|
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||||
|
default:
|
||||||
|
return nil, nil, errors.New("invalid number")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// case6: correct fetchHeadersByNumber function provided, should consider the chain as valid
|
||||||
|
res, err = s.IsValidPeer(fetchHeadersByNumber)
|
||||||
|
require.NoError(t, err, "expected no error")
|
||||||
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
|
|
||||||
|
// create a mock function, returning the required header
|
||||||
|
fetchHeadersByNumber = func(number uint64, _ int, _ int, _ bool) ([]*types.Header, []common.Hash, error) {
|
||||||
|
hash := common.Hash{}
|
||||||
|
hash3 := common.Hash{3}
|
||||||
|
header := types.Header{Number: big.NewInt(0)}
|
||||||
|
|
||||||
|
switch number {
|
||||||
|
case 0:
|
||||||
|
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||||
|
case 1:
|
||||||
|
header.Number = big.NewInt(1)
|
||||||
|
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||||
|
case 2:
|
||||||
|
header.Number = big.NewInt(2)
|
||||||
|
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
header.Number = big.NewInt(2) // sending wrong header for misamatch
|
||||||
|
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
header.Number = big.NewInt(4) // sending wrong header for misamatch
|
||||||
|
return []*types.Header{&header}, []common.Hash{hash3}, nil
|
||||||
|
default:
|
||||||
|
return nil, nil, errors.New("invalid number")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add one more milestone in the list
|
||||||
|
s.ProcessMilestone(uint64(3), common.Hash{})
|
||||||
|
|
||||||
|
// case7: correct fetchHeadersByNumber function provided with wrong header for block 3, should consider the chain as invalid
|
||||||
|
res, err = s.IsValidPeer(fetchHeadersByNumber)
|
||||||
|
require.Equal(t, err, ErrMismatch, "expected milestone mismatch error")
|
||||||
|
require.Equal(t, res, false, "expected chain to be invalid")
|
||||||
|
|
||||||
|
//require.Equal(t, milestone.length(), 3, "expected 3 items in milestoneList")
|
||||||
|
|
||||||
|
//Add one more milestone in the list
|
||||||
|
s.ProcessMilestone(uint64(4), common.Hash{})
|
||||||
|
|
||||||
|
// case8: correct fetchHeadersByNumber function provided with wrong hash for block 3, should consider the chain as valid
|
||||||
|
res, err = s.IsValidPeer(fetchHeadersByNumber)
|
||||||
|
require.Equal(t, err, ErrMismatch, "expected milestone mismatch error")
|
||||||
require.Equal(t, res, false, "expected chain to be invalid")
|
require.Equal(t, res, false, "expected chain to be invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,71 +438,479 @@ func TestIsValidPeer(t *testing.T) {
|
||||||
func TestIsValidChain(t *testing.T) {
|
func TestIsValidChain(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
s := NewMockService(10, 10)
|
db := rawdb.NewMemoryDatabase()
|
||||||
|
s := NewMockService(db)
|
||||||
chainA := createMockChain(1, 20) // A1->A2...A19->A20
|
chainA := createMockChain(1, 20) // A1->A2...A19->A20
|
||||||
// case1: no checkpoint whitelist, should consider the chain as valid
|
|
||||||
|
//Case1: no checkpoint whitelist and no milestone and no locking, should consider the chain as valid
|
||||||
res, err := s.IsValidChain(nil, chainA)
|
res, err := s.IsValidChain(nil, chainA)
|
||||||
require.Equal(t, res, true, "expected chain to be valid")
|
require.Nil(t, err)
|
||||||
require.Equal(t, err, nil, "expected error to be nil")
|
require.Equal(t, res, true, "Expected chain to be valid")
|
||||||
|
|
||||||
tempChain := createMockChain(21, 22) // A21->A22
|
tempChain := createMockChain(21, 22) // A21->A22
|
||||||
|
|
||||||
// add mock checkpoint entries
|
// add mock checkpoint entry
|
||||||
s.ProcessCheckpoint(tempChain[0].Number.Uint64(), tempChain[0].Hash())
|
|
||||||
s.ProcessCheckpoint(tempChain[1].Number.Uint64(), tempChain[1].Hash())
|
s.ProcessCheckpoint(tempChain[1].Number.Uint64(), tempChain[1].Hash())
|
||||||
|
|
||||||
require.Equal(t, s.length(), 2, "expected 2 items in whitelist")
|
//Make the mock chain with zero blocks
|
||||||
|
zeroChain := make([]*types.Header, 0)
|
||||||
|
|
||||||
// case2: We're behind the oldest whitelisted block entry, should consider
|
//Case2: As input chain is of zero length,should consider the chain as invalid
|
||||||
// the chain as valid as we're still far behind the latest blocks
|
res, err = s.IsValidChain(nil, zeroChain)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, false, "expected chain to be invalid", len(zeroChain))
|
||||||
|
|
||||||
|
//Case3A: As the received chain and current tip of local chain is behind the oldest whitelisted block entry, should consider
|
||||||
|
// the chain as valid
|
||||||
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||||
|
require.Nil(t, err)
|
||||||
require.Equal(t, res, true, "expected chain to be valid")
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
require.Equal(t, err, nil, "expected error to be nil")
|
|
||||||
|
|
||||||
// Clear checkpoint whitelist and add blocks A5 and A15 in whitelist
|
//Case3B: As the received chain is behind the oldest whitelisted block entry,but current tip is at par with whitelisted checkpoint, should consider
|
||||||
s.PurgeCheckpointWhitelist()
|
// the chain as invalid
|
||||||
s.ProcessCheckpoint(chainA[5].Number.Uint64(), chainA[5].Hash())
|
res, err = s.IsValidChain(tempChain[1], chainA)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, false, "expected chain to be invalid ")
|
||||||
|
|
||||||
|
// add mock milestone entry
|
||||||
|
s.ProcessMilestone(tempChain[1].Number.Uint64(), tempChain[1].Hash())
|
||||||
|
|
||||||
|
//Case4A: As the received chain and current tip of local chain is behind the oldest whitelisted block entry, should consider
|
||||||
|
// the chain as valid
|
||||||
|
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
|
|
||||||
|
//Case4B: As the received chain is behind the oldest whitelisted block entry and but current tip is at par with whitelisted milestine, should consider
|
||||||
|
// the chain as invalid
|
||||||
|
res, err = s.IsValidChain(tempChain[1], chainA)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, false, "expected chain to be invalid")
|
||||||
|
|
||||||
|
//Remove the whitelisted checkpoint
|
||||||
|
s.PurgeWhitelistedCheckpoint()
|
||||||
|
|
||||||
|
//Case5: As the received chain is still invalid after removing the checkpoint as it is
|
||||||
|
//still behind the whitelisted milestone
|
||||||
|
res, err = s.IsValidChain(tempChain[1], chainA)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, false, "expected chain to be invalid")
|
||||||
|
|
||||||
|
//Remove the whitelisted milestone
|
||||||
|
s.PurgeWhitelistedMilestone()
|
||||||
|
|
||||||
|
//At this stage there is no whitelisted milestone and checkpoint
|
||||||
|
|
||||||
|
checkpoint := s.checkpointService.(*checkpoint)
|
||||||
|
milestone := s.milestoneService.(*milestone)
|
||||||
|
|
||||||
|
//Locking for sprintNumber 15
|
||||||
|
milestone.LockMutex(chainA[len(chainA)-5].Number.Uint64())
|
||||||
|
milestone.UnlockMutex(true, "MilestoneID1", chainA[len(chainA)-5].Number.Uint64(), chainA[len(chainA)-5].Hash())
|
||||||
|
|
||||||
|
//Case6: As the received chain is valid as the locked sprintHash matches with the incoming chain.
|
||||||
|
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, true, "expected chain to be valid as incoming chain matches with the locked value ")
|
||||||
|
|
||||||
|
hash3 := common.Hash{3}
|
||||||
|
|
||||||
|
//Locking for sprintNumber 16 with different hash
|
||||||
|
milestone.LockMutex(chainA[len(chainA)-4].Number.Uint64())
|
||||||
|
milestone.UnlockMutex(true, "MilestoneID2", chainA[len(chainA)-4].Number.Uint64(), hash3)
|
||||||
|
|
||||||
|
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, false, "expected chain to be invalid as incoming chain does match with the locked value hash ")
|
||||||
|
|
||||||
|
//Locking for sprintNumber 19
|
||||||
|
milestone.LockMutex(chainA[len(chainA)-1].Number.Uint64())
|
||||||
|
milestone.UnlockMutex(true, "MilestoneID1", chainA[len(chainA)-1].Number.Uint64(), chainA[len(chainA)-1].Hash())
|
||||||
|
|
||||||
|
//Case7: As the received chain is valid as the locked sprintHash matches with the incoming chain.
|
||||||
|
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, false, "expected chain to be invalid as incoming chain is less than the locked value ")
|
||||||
|
|
||||||
|
//Locking for sprintNumber 19
|
||||||
|
milestone.LockMutex(uint64(21))
|
||||||
|
milestone.UnlockMutex(true, "MilestoneID1", uint64(21), hash3)
|
||||||
|
|
||||||
|
//Case8: As the received chain is invalid as the locked sprintHash matches is ahead of incoming chain.
|
||||||
|
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, false, "expected chain to be invalid as incoming chain is less than the locked value ")
|
||||||
|
|
||||||
|
//Unlocking the sprint
|
||||||
|
milestone.UnlockSprint(uint64(21))
|
||||||
|
|
||||||
|
// Clear checkpoint whitelist and add block A15 in whitelist
|
||||||
|
s.PurgeWhitelistedCheckpoint()
|
||||||
s.ProcessCheckpoint(chainA[15].Number.Uint64(), chainA[15].Hash())
|
s.ProcessCheckpoint(chainA[15].Number.Uint64(), chainA[15].Hash())
|
||||||
|
|
||||||
require.Equal(t, s.length(), 2, "expected 2 items in whitelist")
|
require.Equal(t, checkpoint.doExist, true, "expected true as checkpoint exists.")
|
||||||
|
|
||||||
// case3: Try importing a past chain having valid checkpoint, should
|
// case9: As the received chain is having valid checkpoint,should consider the chain as valid.
|
||||||
// consider the chain as valid
|
|
||||||
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
|
|
||||||
|
// add mock milestone entries
|
||||||
|
s.ProcessMilestone(tempChain[1].Number.Uint64(), tempChain[1].Hash())
|
||||||
|
|
||||||
|
// case10: Try importing a past chain having valid checkpoint, should
|
||||||
|
// consider the chain as invalid as still lastest milestone is ahead of the chain.
|
||||||
|
res, err = s.IsValidChain(tempChain[1], chainA)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, false, "expected chain to be invalid")
|
||||||
|
|
||||||
|
// add mock milestone entries
|
||||||
|
s.ProcessMilestone(chainA[19].Number.Uint64(), chainA[19].Hash())
|
||||||
|
|
||||||
|
// case12: Try importing a chain having valid checkpoint and milestone, should
|
||||||
|
// consider the chain as valid
|
||||||
|
res, err = s.IsValidChain(tempChain[1], chainA)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, true, "expected chain to be invalid")
|
||||||
|
|
||||||
|
// add mock milestone entries
|
||||||
|
s.ProcessMilestone(chainA[19].Number.Uint64(), chainA[19].Hash())
|
||||||
|
|
||||||
|
// case13: Try importing a past chain having valid checkpoint and milestone, should
|
||||||
|
// consider the chain as valid
|
||||||
|
res, err = s.IsValidChain(tempChain[1], chainA)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
|
|
||||||
|
// add mock milestone entries with wrong hash
|
||||||
|
s.ProcessMilestone(chainA[19].Number.Uint64(), chainA[18].Hash())
|
||||||
|
|
||||||
|
// case14: Try importing a past chain having valid checkpoint and milestone with wrong hash, should
|
||||||
|
// consider the chain as invalid
|
||||||
|
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, false, "expected chain to be invalid as hash mismatches")
|
||||||
|
|
||||||
|
// Clear milestone and add blocks A15 in whitelist
|
||||||
|
s.ProcessMilestone(chainA[15].Number.Uint64(), chainA[15].Hash())
|
||||||
|
|
||||||
|
// case16: Try importing a past chain having valid checkpoint, should
|
||||||
|
// consider the chain as valid
|
||||||
|
res, err = s.IsValidChain(tempChain[1], chainA)
|
||||||
|
require.Nil(t, err)
|
||||||
require.Equal(t, res, true, "expected chain to be valid")
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
require.Equal(t, err, nil, "expected error to be nil")
|
|
||||||
|
|
||||||
// Clear checkpoint whitelist and mock blocks in whitelist
|
// Clear checkpoint whitelist and mock blocks in whitelist
|
||||||
tempChain = createMockChain(20, 20) // A20
|
tempChain = createMockChain(20, 20) // A20
|
||||||
|
|
||||||
s.PurgeCheckpointWhitelist()
|
s.PurgeWhitelistedCheckpoint()
|
||||||
s.ProcessCheckpoint(tempChain[0].Number.Uint64(), tempChain[0].Hash())
|
s.ProcessCheckpoint(tempChain[0].Number.Uint64(), tempChain[0].Hash())
|
||||||
|
|
||||||
require.Equal(t, s.length(), 1, "expected 1 items in whitelist")
|
require.Equal(t, checkpoint.doExist, true, "expected true")
|
||||||
|
|
||||||
// case4: Try importing a past chain having invalid checkpoint
|
// case17: Try importing a past chain having invalid checkpoint,should consider the chain as invalid
|
||||||
res, _ = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
res, err = s.IsValidChain(tempChain[0], chainA)
|
||||||
|
require.Nil(t, err)
|
||||||
require.Equal(t, res, false, "expected chain to be invalid")
|
require.Equal(t, res, false, "expected chain to be invalid")
|
||||||
// Not checking error here because we return nil in case of checkpoint mismatch
|
// Not checking error here because we return nil in case of checkpoint mismatch
|
||||||
|
|
||||||
|
// case18: Try importing a future chain but within interval, should consider the chain as valid
|
||||||
|
res, err = s.IsValidChain(tempChain[len(tempChain)-1], tempChain)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, true, "expected chain to be invalid")
|
||||||
|
|
||||||
// create a future chain to be imported of length <= `checkpointInterval`
|
// create a future chain to be imported of length <= `checkpointInterval`
|
||||||
chainB := createMockChain(21, 30) // B21->B22...B29->B30
|
chainB := createMockChain(21, 30) // B21->B22...B29->B30
|
||||||
|
|
||||||
// case5: Try importing a future chain (1)
|
// case19: Try importing a future chain of acceptable length,should consider the chain as valid
|
||||||
res, err = s.IsValidChain(chainA[len(chainA)-1], chainB)
|
res, err = s.IsValidChain(tempChain[0], chainB)
|
||||||
|
require.Nil(t, err)
|
||||||
require.Equal(t, res, true, "expected chain to be valid")
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
require.Equal(t, err, nil, "expected error to be nil")
|
|
||||||
|
|
||||||
// create a future chain to be imported of length > `checkpointInterval`
|
s.PurgeWhitelistedCheckpoint()
|
||||||
chainB = createMockChain(21, 40) // C21->C22...C39->C40
|
s.PurgeWhitelistedMilestone()
|
||||||
|
|
||||||
// Note: Earlier, it used to reject future chains longer than some threshold.
|
chainB = createMockChain(21, 29) // C21->C22....C29
|
||||||
// That check is removed for now.
|
|
||||||
|
|
||||||
// case6: Try importing a future chain (2)
|
s.milestoneService.ProcessFutureMilestone(29, chainB[8].Hash())
|
||||||
res, err = s.IsValidChain(chainA[len(chainA)-1], chainB)
|
|
||||||
|
// case20: Try importing a future chain which match the future milestone should the chain as valid
|
||||||
|
res, err = s.IsValidChain(tempChain[0], chainB)
|
||||||
|
require.Nil(t, err)
|
||||||
require.Equal(t, res, true, "expected chain to be valid")
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
require.Equal(t, err, nil, "expected error to be nil")
|
|
||||||
|
chainB = createMockChain(21, 27) // C21->C22...C39->C40...C->256
|
||||||
|
|
||||||
|
// case21: Try importing a chain whose end point is less than future milestone
|
||||||
|
res, err = s.IsValidChain(tempChain[0], chainB)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, true, "expected chain to be valid")
|
||||||
|
|
||||||
|
chainB = createMockChain(30, 39) // C21->C22...C39->C40...C->256
|
||||||
|
|
||||||
|
//Processing wrong hash
|
||||||
|
s.milestoneService.ProcessFutureMilestone(38, chainB[9].Hash())
|
||||||
|
|
||||||
|
// case22: Try importing a future chain with mismatch future milestone
|
||||||
|
res, err = s.IsValidChain(tempChain[0], chainB)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, false, "expected chain to be invalid")
|
||||||
|
|
||||||
|
chainB = createMockChain(40, 49) // C40->C41...C48->C49
|
||||||
|
|
||||||
|
// case23: Try importing a future chain whose starting point is ahead of latest future milestone
|
||||||
|
res, err = s.IsValidChain(tempChain[0], chainB)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, res, true, "expected chain to be invalid")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPropertyBasedTestingMilestone(t *testing.T) {
|
||||||
|
rapid.Check(t, func(t *rapid.T) {
|
||||||
|
|
||||||
|
db := rawdb.NewMemoryDatabase()
|
||||||
|
|
||||||
|
milestone := milestone{
|
||||||
|
finality: finality[*rawdb.Milestone]{
|
||||||
|
doExist: false,
|
||||||
|
Number: 0,
|
||||||
|
Hash: common.Hash{},
|
||||||
|
interval: 256,
|
||||||
|
db: db,
|
||||||
|
},
|
||||||
|
|
||||||
|
Locked: false,
|
||||||
|
LockedMilestoneNumber: 0,
|
||||||
|
LockedMilestoneHash: common.Hash{},
|
||||||
|
LockedMilestoneIDs: make(map[string]struct{}),
|
||||||
|
FutureMilestoneList: make(map[uint64]common.Hash),
|
||||||
|
FutureMilestoneOrder: make([]uint64, 0),
|
||||||
|
MaxCapacity: 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
milestoneEndNum = rapid.Uint64().Draw(t, "endBlock")
|
||||||
|
milestoneID = rapid.String().Draw(t, "MilestoneID")
|
||||||
|
doLock = rapid.Bool().Draw(t, "Voted")
|
||||||
|
)
|
||||||
|
|
||||||
|
val := milestone.LockMutex(milestoneEndNum.(uint64))
|
||||||
|
if !val {
|
||||||
|
t.Error("LockMutex need to return true when there is no whitelisted milestone and locked milestone")
|
||||||
|
}
|
||||||
|
|
||||||
|
milestone.UnlockMutex(doLock.(bool), milestoneID.(string), milestoneEndNum.(uint64), common.Hash{})
|
||||||
|
|
||||||
|
if doLock.(bool) {
|
||||||
|
//Milestone should not be whitelisted
|
||||||
|
if milestone.doExist {
|
||||||
|
t.Error("Milestone is not expected to be whitelisted")
|
||||||
|
}
|
||||||
|
|
||||||
|
//Local chain should be locked
|
||||||
|
if !milestone.Locked {
|
||||||
|
t.Error("Milestone is expected to be locked at", milestoneEndNum.(uint64))
|
||||||
|
}
|
||||||
|
|
||||||
|
if milestone.LockedMilestoneNumber != milestoneEndNum.(uint64) {
|
||||||
|
t.Error("Locked milestone number is expected to be", milestoneEndNum.(uint64))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(milestone.LockedMilestoneIDs) != 1 {
|
||||||
|
t.Error("List should contain 1 milestone")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok := milestone.LockedMilestoneIDs[milestoneID.(string)]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
t.Error("List doesn't contain correct milestoneID")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !doLock.(bool) {
|
||||||
|
if milestone.doExist {
|
||||||
|
t.Error("Milestone is not expected to be whitelisted")
|
||||||
|
}
|
||||||
|
|
||||||
|
if milestone.Locked {
|
||||||
|
t.Error("Milestone is expected not to be locked")
|
||||||
|
}
|
||||||
|
|
||||||
|
if milestone.LockedMilestoneNumber != 0 {
|
||||||
|
t.Error("Locked milestone number is expected to be", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(milestone.LockedMilestoneIDs) != 0 {
|
||||||
|
t.Error("List should not contain milestone")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok := milestone.LockedMilestoneIDs[milestoneID.(string)]
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
t.Error("List shouldn't contain any milestoneID")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fitlerFn := func(i uint64) bool {
|
||||||
|
if i <= uint64(1000) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
start = rapid.Uint64Max(milestoneEndNum.(uint64)).Draw(t, "start for mock chain")
|
||||||
|
end = rapid.Uint64Min(start.(uint64)).Filter(fitlerFn).Draw(t, "end for mock chain")
|
||||||
|
)
|
||||||
|
|
||||||
|
chainTemp := createMockChain(start.(uint64), end.(uint64))
|
||||||
|
|
||||||
|
val, err := milestone.IsValidChain(chainTemp[0], chainTemp)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("Error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if doLock.(bool) && val {
|
||||||
|
t.Error("When the chain is locked at milestone, it should not pass IsValidChain for incompatible incoming chain")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !doLock.(bool) && !val {
|
||||||
|
t.Error("When the chain is not locked at milestone, it should pass IsValidChain for incoming chain")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
milestoneEndNum2 = rapid.Uint64().Draw(t, "endBlockNum 2")
|
||||||
|
milestoneID2 = rapid.String().Draw(t, "MilestoneID 2")
|
||||||
|
doLock2 = rapid.Bool().Draw(t, "Voted 2")
|
||||||
|
)
|
||||||
|
|
||||||
|
val = milestone.LockMutex(milestoneEndNum2.(uint64))
|
||||||
|
|
||||||
|
if doLock.(bool) && milestoneEndNum.(uint64) > milestoneEndNum2.(uint64) && val {
|
||||||
|
t.Error("LockMutex need to return false as previous locked milestone is greater")
|
||||||
|
}
|
||||||
|
|
||||||
|
if doLock.(bool) && milestoneEndNum.(uint64) <= milestoneEndNum2.(uint64) && !val {
|
||||||
|
t.Error("LockMutex need to return true as previous locked milestone is less")
|
||||||
|
}
|
||||||
|
|
||||||
|
milestone.UnlockMutex(doLock2.(bool), milestoneID2.(string), milestoneEndNum2.(uint64), common.Hash{})
|
||||||
|
|
||||||
|
if doLock2.(bool) {
|
||||||
|
if milestone.doExist {
|
||||||
|
t.Error("Milestone is not expected to be whitelisted")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !milestone.Locked {
|
||||||
|
t.Error("Milestone is expected to be locked at", milestoneEndNum2.(uint64))
|
||||||
|
}
|
||||||
|
|
||||||
|
if milestone.LockedMilestoneNumber != milestoneEndNum2.(uint64) {
|
||||||
|
t.Error("Locked milestone number is expected to be", milestoneEndNum.(uint64))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(milestone.LockedMilestoneIDs) != 1 {
|
||||||
|
t.Error("List should contain 1 milestone")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok := milestone.LockedMilestoneIDs[milestoneID2.(string)]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
t.Error("List doesn't contain correct milestoneID")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !doLock2.(bool) {
|
||||||
|
if milestone.doExist {
|
||||||
|
t.Error("Milestone is not expected to be whitelisted")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !doLock.(bool) && milestone.Locked {
|
||||||
|
t.Error("Milestone is expected not to be locked")
|
||||||
|
}
|
||||||
|
|
||||||
|
if doLock.(bool) && !milestone.Locked {
|
||||||
|
t.Error("Milestone is expected to be locked at", milestoneEndNum.(uint64))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !doLock.(bool) && milestone.LockedMilestoneNumber != 0 {
|
||||||
|
t.Error("Locked milestone number is expected to be", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if doLock.(bool) && milestone.LockedMilestoneNumber != milestoneEndNum.(uint64) {
|
||||||
|
t.Error("Locked milestone number is expected to be", milestoneEndNum.(uint64))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !doLock.(bool) && len(milestone.LockedMilestoneIDs) != 0 {
|
||||||
|
t.Error("List should not contain milestone")
|
||||||
|
}
|
||||||
|
|
||||||
|
if doLock.(bool) && len(milestone.LockedMilestoneIDs) != 1 {
|
||||||
|
t.Error("List should not contain milestone")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok := milestone.LockedMilestoneIDs[milestoneID.(string)]
|
||||||
|
|
||||||
|
if !doLock.(bool) && ok {
|
||||||
|
t.Error("List shouldn't contain any milestoneID")
|
||||||
|
}
|
||||||
|
|
||||||
|
if doLock.(bool) && !ok {
|
||||||
|
t.Error("List should contain milestoneID")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
milestoneNum = rapid.Uint64().Draw(t, "milestone Number")
|
||||||
|
)
|
||||||
|
|
||||||
|
lockedValue := milestone.LockedMilestoneNumber
|
||||||
|
|
||||||
|
milestone.Process(milestoneNum.(uint64), common.Hash{})
|
||||||
|
|
||||||
|
isChainLocked := doLock.(bool) || doLock2.(bool)
|
||||||
|
|
||||||
|
if !milestone.doExist {
|
||||||
|
t.Error("Should have the whitelisted milestone")
|
||||||
|
}
|
||||||
|
|
||||||
|
if milestone.finality.Number != milestoneNum.(uint64) {
|
||||||
|
t.Error("Should have the whitelisted milestone", milestoneNum.(uint64))
|
||||||
|
}
|
||||||
|
|
||||||
|
if isChainLocked {
|
||||||
|
if milestoneNum.(uint64) < lockedValue {
|
||||||
|
if !milestone.Locked {
|
||||||
|
t.Error("Milestone is expected to be locked")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if milestone.Locked {
|
||||||
|
t.Error("Milestone is expected not to be locked")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
futureMilestoneNum = rapid.Uint64Min(milestoneNum.(uint64)).Draw(t, "future milestone Number")
|
||||||
|
)
|
||||||
|
|
||||||
|
isChainLocked = milestone.Locked
|
||||||
|
|
||||||
|
milestone.ProcessFutureMilestone(futureMilestoneNum.(uint64), common.Hash{})
|
||||||
|
|
||||||
|
if isChainLocked {
|
||||||
|
if futureMilestoneNum.(uint64) < lockedValue {
|
||||||
|
if !milestone.Locked {
|
||||||
|
t.Error("Milestone is expected to be locked")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if milestone.Locked {
|
||||||
|
t.Error("Milestone is expected not to be locked")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSplitChain(t *testing.T) {
|
func TestSplitChain(t *testing.T) {
|
||||||
|
|
@ -386,9 +1116,10 @@ func createMockChain(start, end uint64) []*types.Header {
|
||||||
var (
|
var (
|
||||||
i uint64
|
i uint64
|
||||||
idx uint64
|
idx uint64
|
||||||
chain []*types.Header = make([]*types.Header, end-start+1)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
chain := make([]*types.Header, end-start+1)
|
||||||
|
|
||||||
for i = start; i <= end; i++ {
|
for i = start; i <= end; i++ {
|
||||||
header := &types.Header{
|
header := &types.Header{
|
||||||
Number: big.NewInt(int64(i)),
|
Number: big.NewInt(int64(i)),
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,21 @@ func (mr *MockBackendMockRecorder) GetReceipts(arg0, arg1 interface{}) *gomock.C
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetReceipts", reflect.TypeOf((*MockBackend)(nil).GetReceipts), arg0, arg1)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetReceipts", reflect.TypeOf((*MockBackend)(nil).GetReceipts), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetVoteOnHash mocks base method.
|
||||||
|
func (m *MockBackend) GetVoteOnHash(arg0 context.Context, arg1, arg2 uint64, arg3, arg4 string) (bool, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "GetVoteOnHash", arg0, arg1, arg2, arg3, arg4)
|
||||||
|
ret0, _ := ret[0].(bool)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVoteOnHash indicates an expected call of GetVoteOnHash.
|
||||||
|
func (mr *MockBackendMockRecorder) GetVoteOnHash(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVoteOnHash", reflect.TypeOf((*MockBackend)(nil).GetVoteOnHash), arg0, arg1, arg2, arg3, arg4)
|
||||||
|
}
|
||||||
|
|
||||||
// HeaderByHash mocks base method.
|
// HeaderByHash mocks base method.
|
||||||
func (m *MockBackend) HeaderByHash(arg0 context.Context, arg1 common.Hash) (*types.Header, error) {
|
func (m *MockBackend) HeaderByHash(arg0 context.Context, arg1 common.Hash) (*types.Header, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,10 @@ func (b *TestBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *TestBackend) GetVoteOnHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64, hash string, milestoneId string) (bool, error) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (b *TestBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) {
|
func (b *TestBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) {
|
||||||
receipts := rawdb.ReadReceipts(b.DB, hash, number, params.TestChainConfig)
|
receipts := rawdb.ReadReceipts(b.DB, hash, number, params.TestChainConfig)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,94 +10,112 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// errCheckpointCount is returned when we are unable to fetch
|
|
||||||
// the checkpoint count from local heimdall.
|
|
||||||
errCheckpointCount = errors.New("failed to fetch checkpoint count")
|
|
||||||
|
|
||||||
// errNoCheckpoint is returned when there is not checkpoint proposed
|
|
||||||
// by heimdall yet or heimdall is not in sync
|
|
||||||
errNoCheckpoint = errors.New("no checkpoint proposed")
|
|
||||||
|
|
||||||
// errCheckpoint is returned when we are unable to fetch the
|
// errCheckpoint is returned when we are unable to fetch the
|
||||||
// latest checkpoint from the local heimdall.
|
// latest checkpoint from the local heimdall.
|
||||||
errCheckpoint = errors.New("failed to fetch latest checkpoint")
|
errCheckpoint = errors.New("failed to fetch latest checkpoint")
|
||||||
|
|
||||||
// errMissingCheckpoint is returned when we don't have the
|
// errMilestone is returned when we are unable to fetch the
|
||||||
// checkpoint blocks locally, yet.
|
// latest milestone from the local heimdall.
|
||||||
errMissingCheckpoint = errors.New("missing checkpoint blocks")
|
errMilestone = errors.New("failed to fetch latest milestone")
|
||||||
|
|
||||||
// errRootHash is returned when we aren't able to calculate the root hash
|
ErrNotInRejectedList = errors.New("MilestoneID not in rejected list")
|
||||||
// locally for a range of blocks.
|
|
||||||
errRootHash = errors.New("failed to get local root hash")
|
|
||||||
|
|
||||||
// errCheckpointRootHashMismatch is returned when the local root hash
|
|
||||||
// doesn't match with the root hash in checkpoint.
|
|
||||||
errCheckpointRootHashMismatch = errors.New("checkpoint roothash mismatch")
|
|
||||||
|
|
||||||
// errEndBlock is returned when we're unable to fetch a block locally.
|
|
||||||
errEndBlock = errors.New("failed to get end block")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// fetchWhitelistCheckpoints fetches the latest checkpoint/s from it's local heimdall
|
// fetchWhitelistCheckpoint fetches the latest checkpoint from it's local heimdall
|
||||||
// and verifies the data against bor data.
|
// and verifies the data against bor data.
|
||||||
func (h *ethHandler) fetchWhitelistCheckpoints(ctx context.Context, bor *bor.Bor, checkpointVerifier *checkpointVerifier, first bool) ([]uint64, []common.Hash, error) {
|
func (h *ethHandler) fetchWhitelistCheckpoint(ctx context.Context, bor *bor.Bor, eth *Ethereum, verifier *borVerifier) (uint64, common.Hash, error) {
|
||||||
// Create an array for block number and block hashes
|
|
||||||
//nolint:prealloc
|
|
||||||
var (
|
var (
|
||||||
blockNums []uint64 = make([]uint64, 0)
|
blockNum uint64
|
||||||
blockHashes []common.Hash = make([]common.Hash, 0)
|
blockHash common.Hash
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fetch the checkpoint count from heimdall
|
// fetch the latest checkpoint from Heimdall
|
||||||
count, err := bor.HeimdallClient.FetchCheckpointCount(ctx)
|
checkpoint, err := bor.HeimdallClient.FetchCheckpoint(ctx, -1)
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to fetch checkpoint count for whitelisting", "err", err)
|
|
||||||
return blockNums, blockHashes, errCheckpointCount
|
|
||||||
}
|
|
||||||
|
|
||||||
if count == 0 {
|
|
||||||
return blockNums, blockHashes, errNoCheckpoint
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
start int64
|
|
||||||
end int64
|
|
||||||
)
|
|
||||||
|
|
||||||
// Prepare the checkpoint range to fetch
|
|
||||||
if count <= 10 {
|
|
||||||
start = 1
|
|
||||||
} else {
|
|
||||||
start = count - 10 + 1 // 10 is the max number of checkpoints to fetch
|
|
||||||
}
|
|
||||||
|
|
||||||
end = count
|
|
||||||
|
|
||||||
// If we're in not in the first iteration, only fetch the latest checkpoint
|
|
||||||
if !first {
|
|
||||||
start = count
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := start; i <= end; i++ {
|
|
||||||
// fetch `i` indexed checkpoint from heimdall
|
|
||||||
checkpoint, err := bor.HeimdallClient.FetchCheckpoint(ctx, i)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to fetch latest checkpoint for whitelisting", "err", err)
|
log.Debug("Failed to fetch latest checkpoint for whitelisting", "err", err)
|
||||||
return blockNums, blockHashes, errCheckpoint
|
return blockNum, blockHash, errCheckpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Info("Got new checkpoint from heimdall", "start", checkpoint.StartBlock.Uint64(), "end", checkpoint.EndBlock.Uint64(), "rootHash", checkpoint.RootHash.String())
|
||||||
|
|
||||||
// Verify if the checkpoint fetched can be added to the local whitelist entry or not
|
// Verify if the checkpoint fetched can be added to the local whitelist entry or not
|
||||||
// If verified, it returns the hash of the end block of the checkpoint. If not,
|
// If verified, it returns the hash of the end block of the checkpoint. If not,
|
||||||
// it will return appropriate error.
|
// it will return appropriate error.
|
||||||
|
hash, err := verifier.verify(ctx, eth, h, checkpoint.StartBlock.Uint64(), checkpoint.EndBlock.Uint64(), checkpoint.RootHash.String()[2:], true)
|
||||||
hash, err := checkpointVerifier.verify(ctx, h, checkpoint)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return blockNums, blockHashes, err
|
log.Warn("Failed to whitelist checkpoint", "err", err)
|
||||||
|
return blockNum, blockHash, err
|
||||||
}
|
}
|
||||||
|
|
||||||
blockNums = append(blockNums, checkpoint.EndBlock.Uint64())
|
blockNum = checkpoint.EndBlock.Uint64()
|
||||||
blockHashes = append(blockHashes, common.HexToHash(hash))
|
blockHash = common.HexToHash(hash)
|
||||||
|
|
||||||
|
return blockNum, blockHash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return blockNums, blockHashes, nil
|
// fetchWhitelistMilestone fetches the latest milestone from it's local heimdall
|
||||||
|
// and verifies the data against bor data.
|
||||||
|
func (h *ethHandler) fetchWhitelistMilestone(ctx context.Context, bor *bor.Bor, eth *Ethereum, verifier *borVerifier) (uint64, common.Hash, error) {
|
||||||
|
var (
|
||||||
|
num uint64
|
||||||
|
hash common.Hash
|
||||||
|
)
|
||||||
|
|
||||||
|
// fetch latest milestone
|
||||||
|
milestone, err := bor.HeimdallClient.FetchMilestone(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to fetch latest milestone for whitelisting", "err", err)
|
||||||
|
return num, hash, errMilestone
|
||||||
|
}
|
||||||
|
|
||||||
|
num = milestone.EndBlock.Uint64()
|
||||||
|
hash = milestone.Hash
|
||||||
|
|
||||||
|
log.Info("Got new milestone from heimdall", "start", milestone.StartBlock.Uint64(), "end", milestone.EndBlock.Uint64(), "hash", milestone.Hash.String())
|
||||||
|
|
||||||
|
// Verify if the milestone fetched can be added to the local whitelist entry or not
|
||||||
|
// If verified, it returns the hash of the end block of the milestone. If not,
|
||||||
|
// it will return appropriate error.
|
||||||
|
_, err = verifier.verify(ctx, eth, h, milestone.StartBlock.Uint64(), milestone.EndBlock.Uint64(), milestone.Hash.String()[2:], false)
|
||||||
|
if err != nil {
|
||||||
|
h.downloader.UnlockSprint(milestone.EndBlock.Uint64())
|
||||||
|
return num, hash, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return num, hash, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ethHandler) fetchNoAckMilestone(ctx context.Context, bor *bor.Bor) (string, error) {
|
||||||
|
var (
|
||||||
|
milestoneID string
|
||||||
|
)
|
||||||
|
|
||||||
|
// fetch latest milestone
|
||||||
|
milestoneID, err := bor.HeimdallClient.FetchLastNoAckMilestone(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to fetch latest no-ack milestone", "err", err)
|
||||||
|
|
||||||
|
return milestoneID, errMilestone
|
||||||
|
}
|
||||||
|
|
||||||
|
return milestoneID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ethHandler) fetchNoAckMilestoneByID(ctx context.Context, bor *bor.Bor, milestoneID string) error {
|
||||||
|
// fetch latest milestone
|
||||||
|
err := bor.HeimdallClient.FetchNoAckMilestone(ctx, milestoneID)
|
||||||
|
|
||||||
|
// fixme: handle different types of errors
|
||||||
|
if errors.Is(err, ErrNotInRejectedList) {
|
||||||
|
log.Warn("MilestoneID not in rejected list", "milestoneID", milestoneID, "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to fetch no-ack milestone by ID ", "milestoneID", milestoneID, "err", err)
|
||||||
|
|
||||||
|
return errMilestone
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,17 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/milestone"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockHeimdall struct {
|
type mockHeimdall struct {
|
||||||
fetchCheckpoint func(ctx context.Context, number int64) (*checkpoint.Checkpoint, error)
|
fetchCheckpoint func(ctx context.Context, number int64) (*checkpoint.Checkpoint, error)
|
||||||
fetchCheckpointCount func(ctx context.Context) (int64, error)
|
fetchCheckpointCount func(ctx context.Context) (int64, error)
|
||||||
|
fetchMilestone func(ctx context.Context) (*milestone.Milestone, error)
|
||||||
|
fetchMilestoneCount func(ctx context.Context) (int64, error)
|
||||||
|
fetchNoAckMilestone func(ctx context.Context, milestoneID string) error
|
||||||
|
fetchLastNoAckMilestone func(ctx context.Context) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockHeimdall) StateSyncEvents(ctx context.Context, fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error) {
|
func (m *mockHeimdall) StateSyncEvents(ctx context.Context, fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error) {
|
||||||
|
|
@ -33,80 +38,114 @@ func (m *mockHeimdall) FetchCheckpoint(ctx context.Context, number int64) (*chec
|
||||||
func (m *mockHeimdall) FetchCheckpointCount(ctx context.Context) (int64, error) {
|
func (m *mockHeimdall) FetchCheckpointCount(ctx context.Context) (int64, error) {
|
||||||
return m.fetchCheckpointCount(ctx)
|
return m.fetchCheckpointCount(ctx)
|
||||||
}
|
}
|
||||||
|
func (m *mockHeimdall) FetchMilestone(ctx context.Context) (*milestone.Milestone, error) {
|
||||||
|
return m.fetchMilestone(ctx)
|
||||||
|
}
|
||||||
|
func (m *mockHeimdall) FetchMilestoneCount(ctx context.Context) (int64, error) {
|
||||||
|
return m.fetchMilestoneCount(ctx)
|
||||||
|
}
|
||||||
|
func (m *mockHeimdall) FetchNoAckMilestone(ctx context.Context, milestoneID string) error {
|
||||||
|
return m.fetchNoAckMilestone(ctx, milestoneID)
|
||||||
|
}
|
||||||
|
func (m *mockHeimdall) FetchLastNoAckMilestone(ctx context.Context) (string, error) {
|
||||||
|
return m.fetchLastNoAckMilestone(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockHeimdall) FetchMilestoneID(ctx context.Context, milestoneID string) error {
|
||||||
|
return m.fetchNoAckMilestone(ctx, milestoneID)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *mockHeimdall) Close() {}
|
func (m *mockHeimdall) Close() {}
|
||||||
|
|
||||||
func TestFetchWhitelistCheckpoints(t *testing.T) {
|
func TestFetchWhitelistCheckpointAndMilestone(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// create an empty ethHandler
|
// create an empty ethHandler
|
||||||
handler := ðHandler{}
|
handler := ðHandler{}
|
||||||
|
|
||||||
// create a mock checkpoint verification function and use it to create a verifier
|
// create a mock checkpoint verification function and use it to create a verifier
|
||||||
verify := func(ctx context.Context, handler *ethHandler, checkpoint *checkpoint.Checkpoint) (string, error) {
|
verify := func(ctx context.Context, eth *Ethereum, handler *ethHandler, start uint64, end uint64, hash string, isCheckpoint bool) (string, error) {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
verifier := newCheckpointVerifier(verify)
|
verifier := newBorVerifier()
|
||||||
|
verifier.setVerify(verify)
|
||||||
|
|
||||||
// Create a mock heimdall instance and use it for creating a bor instance
|
// Create a mock heimdall instance and use it for creating a bor instance
|
||||||
var heimdall mockHeimdall
|
var heimdall mockHeimdall
|
||||||
|
|
||||||
bor := &bor.Bor{HeimdallClient: &heimdall}
|
bor := &bor.Bor{HeimdallClient: &heimdall}
|
||||||
|
|
||||||
// create 20 mock checkpoints
|
fetchCheckpointTest(t, &heimdall, bor, handler, verifier)
|
||||||
checkpoints := createMockCheckpoints(20)
|
fetchMilestoneTest(t, &heimdall, bor, handler, verifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *borVerifier) setVerify(verifyFn func(ctx context.Context, eth *Ethereum, handler *ethHandler, start uint64, end uint64, hash string, isCheckpoint bool) (string, error)) {
|
||||||
|
b.verify = verifyFn
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchCheckpointTest(t *testing.T, heimdall *mockHeimdall, bor *bor.Bor, handler *ethHandler, verifier *borVerifier) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
var checkpoints []*checkpoint.Checkpoint
|
||||||
// create a mock fetch checkpoint function
|
// create a mock fetch checkpoint function
|
||||||
heimdall.fetchCheckpoint = func(_ context.Context, number int64) (*checkpoint.Checkpoint, error) {
|
heimdall.fetchCheckpoint = func(_ context.Context, number int64) (*checkpoint.Checkpoint, error) {
|
||||||
return checkpoints[number-1], nil // we're sure that number won't exceed 20
|
if len(checkpoints) == 0 {
|
||||||
|
return nil, errCheckpoint
|
||||||
|
} else if number == -1 {
|
||||||
|
return checkpoints[len(checkpoints)-1], nil
|
||||||
|
} else {
|
||||||
|
return checkpoints[number-1], nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a background context
|
// create a background context
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
testCases := []struct {
|
_, _, err := handler.fetchWhitelistCheckpoint(ctx, bor, nil, verifier)
|
||||||
name string
|
require.Equal(t, err, errCheckpoint)
|
||||||
first bool
|
|
||||||
count int64
|
|
||||||
length int
|
|
||||||
start uint64
|
|
||||||
end uint64
|
|
||||||
fetchErr error
|
|
||||||
expectedErr error
|
|
||||||
}{
|
|
||||||
{"fail to fetch checkpoint count", false, 0, 0, 0, 0, errCheckpointCount, errCheckpointCount},
|
|
||||||
{"no checkpoints available", false, 0, 0, 0, 0, nil, errNoCheckpoint},
|
|
||||||
{"fetch multiple checkpoints (count < 10)", true, 6, 6, 0, 6, nil, nil},
|
|
||||||
{"fetch multiple checkpoints (count = 10)", true, 10, 10, 0, 10, nil, nil},
|
|
||||||
{"fetch multiple checkpoints (count > 10)", true, 16, 10, 6, 16, nil, nil},
|
|
||||||
{"fetch single checkpoint", false, 18, 1, 17, 18, nil, nil},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
// create 4 mock checkpoints
|
||||||
tc := tc
|
checkpoints = createMockCheckpoints(4)
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
heimdall.fetchCheckpointCount = getMockFetchCheckpointFn(tc.count, tc.fetchErr)
|
blockNum, blockHash, err := handler.fetchWhitelistCheckpoint(ctx, bor, nil, verifier)
|
||||||
blockNums, blockHashes, err := handler.fetchWhitelistCheckpoints(ctx, bor, verifier, tc.first)
|
|
||||||
|
|
||||||
// Check if we have expected result
|
// Check if we have expected result
|
||||||
require.Equal(t, tc.expectedErr, err)
|
require.Equal(t, err, nil)
|
||||||
require.Equal(t, tc.length, len(blockNums))
|
require.Equal(t, checkpoints[len(checkpoints)-1].EndBlock.Uint64(), blockNum)
|
||||||
require.Equal(t, tc.length, len(blockHashes))
|
require.Equal(t, checkpoints[len(checkpoints)-1].RootHash, blockHash)
|
||||||
validateBlockNumber(t, blockNums, checkpoints[tc.start:tc.end])
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateBlockNumber(t *testing.T, blockNums []uint64, checkpoints []*checkpoint.Checkpoint) {
|
func fetchMilestoneTest(t *testing.T, heimdall *mockHeimdall, bor *bor.Bor, handler *ethHandler, verifier *borVerifier) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
for i, blockNum := range blockNums {
|
var milestones []*milestone.Milestone
|
||||||
require.Equal(t, blockNum, checkpoints[i].EndBlock.Uint64(), "expect block number in array to match with checkpoint")
|
// create a mock fetch checkpoint function
|
||||||
|
heimdall.fetchMilestone = func(_ context.Context) (*milestone.Milestone, error) {
|
||||||
|
if len(milestones) == 0 {
|
||||||
|
return nil, errMilestone
|
||||||
|
} else {
|
||||||
|
return milestones[len(milestones)-1], nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create a background context
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
_, _, err := handler.fetchWhitelistMilestone(ctx, bor, nil, verifier)
|
||||||
|
require.Equal(t, err, errMilestone)
|
||||||
|
|
||||||
|
// create 4 mock checkpoints
|
||||||
|
milestones = createMockMilestones(4)
|
||||||
|
|
||||||
|
num, hash, err := handler.fetchWhitelistMilestone(ctx, bor, nil, verifier)
|
||||||
|
|
||||||
|
// Check if we have expected result
|
||||||
|
require.Equal(t, err, nil)
|
||||||
|
require.Equal(t, milestones[len(milestones)-1].EndBlock.Uint64(), num)
|
||||||
|
require.Equal(t, milestones[len(milestones)-1].Hash, hash)
|
||||||
|
}
|
||||||
|
|
||||||
func getMockFetchCheckpointFn(number int64, err error) func(ctx context.Context) (int64, error) {
|
func getMockFetchCheckpointFn(number int64, err error) func(ctx context.Context) (int64, error) {
|
||||||
return func(_ context.Context) (int64, error) {
|
return func(_ context.Context) (int64, error) {
|
||||||
return number, err
|
return number, err
|
||||||
|
|
@ -133,3 +172,24 @@ func createMockCheckpoints(count int) []*checkpoint.Checkpoint {
|
||||||
|
|
||||||
return checkpoints
|
return checkpoints
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createMockMilestones(count int) []*milestone.Milestone {
|
||||||
|
var (
|
||||||
|
milestones []*milestone.Milestone = make([]*milestone.Milestone, count)
|
||||||
|
startBlock int64 = 257 // any number can be used
|
||||||
|
)
|
||||||
|
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
milestones[i] = &milestone.Milestone{
|
||||||
|
Proposer: common.Address{},
|
||||||
|
StartBlock: big.NewInt(startBlock),
|
||||||
|
EndBlock: big.NewInt(startBlock + 255),
|
||||||
|
Hash: common.Hash{},
|
||||||
|
BorChainID: "137",
|
||||||
|
Timestamp: uint64(time.Now().Unix()),
|
||||||
|
}
|
||||||
|
startBlock += 256
|
||||||
|
}
|
||||||
|
|
||||||
|
return milestones
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,16 @@ func (ec *Client) GetRootHash(ctx context.Context, startBlockNumber uint64, endB
|
||||||
return rootHash, nil
|
return rootHash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRootHash returns the merkle root of the block headers
|
||||||
|
func (ec *Client) GetVoteOnHash(ctx context.Context, startBlockNumber uint64, endBlockNumber uint64, hash string, milestoneID string) (bool, error) {
|
||||||
|
var value bool
|
||||||
|
if err := ec.c.CallContext(ctx, &value, "bor_getVoteOnHash", startBlockNumber, endBlockNumber, hash, milestoneID); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetBorBlockReceipt returns bor block receipt
|
// GetBorBlockReceipt returns bor block receipt
|
||||||
func (ec *Client) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
|
func (ec *Client) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
|
||||||
var r *types.Receipt
|
var r *types.Receipt
|
||||||
|
|
|
||||||
59
go.mod
59
go.mod
|
|
@ -17,14 +17,14 @@ require (
|
||||||
github.com/cloudflare/cloudflare-go v0.14.0
|
github.com/cloudflare/cloudflare-go v0.14.0
|
||||||
github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811
|
github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811
|
||||||
github.com/consensys/gnark-crypto v0.9.1-0.20230105202408-1a7a29904a7c
|
github.com/consensys/gnark-crypto v0.9.1-0.20230105202408-1a7a29904a7c
|
||||||
github.com/cosmos/cosmos-sdk v0.37.4
|
github.com/cosmos/cosmos-sdk v0.46.2
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/deckarep/golang-set/v2 v2.1.0
|
github.com/deckarep/golang-set/v2 v2.1.0
|
||||||
github.com/docker/docker v1.6.2
|
github.com/docker/docker v1.6.2
|
||||||
github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7
|
github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7
|
||||||
github.com/edsrzf/mmap-go v1.0.0
|
github.com/edsrzf/mmap-go v1.0.0
|
||||||
github.com/emirpasic/gods v1.18.1
|
github.com/emirpasic/gods v1.18.1
|
||||||
github.com/fatih/color v1.9.0
|
github.com/fatih/color v1.13.0
|
||||||
github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c
|
github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c
|
||||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5
|
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5
|
||||||
github.com/fsnotify/fsnotify v1.6.0
|
github.com/fsnotify/fsnotify v1.6.0
|
||||||
|
|
@ -53,12 +53,13 @@ require (
|
||||||
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
|
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
|
||||||
github.com/jackpal/go-nat-pmp v1.0.2
|
github.com/jackpal/go-nat-pmp v1.0.2
|
||||||
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e
|
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e
|
||||||
|
github.com/json-iterator/go v1.1.12
|
||||||
github.com/julienschmidt/httprouter v1.3.0
|
github.com/julienschmidt/httprouter v1.3.0
|
||||||
github.com/karalabe/usb v0.0.2
|
github.com/karalabe/usb v0.0.2
|
||||||
github.com/kylelemons/godebug v1.1.0
|
github.com/kylelemons/godebug v1.1.0
|
||||||
github.com/maticnetwork/crand v1.0.2
|
github.com/maticnetwork/crand v1.0.2
|
||||||
github.com/maticnetwork/heimdall v0.3.1-0.20230105132832-d0063f71e3f0
|
github.com/maticnetwork/heimdall v0.3.1-0.20230227104835-81bd1055b0bc
|
||||||
github.com/maticnetwork/polyproto v0.0.2
|
github.com/maticnetwork/polyproto v0.0.3-0.20230216113155-340ea926ca53
|
||||||
github.com/mattn/go-colorable v0.1.13
|
github.com/mattn/go-colorable v0.1.13
|
||||||
github.com/mattn/go-isatty v0.0.16
|
github.com/mattn/go-isatty v0.0.16
|
||||||
github.com/mitchellh/cli v1.1.2
|
github.com/mitchellh/cli v1.1.2
|
||||||
|
|
@ -88,10 +89,28 @@ require (
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
cloud.google.com/go/compute v1.7.0 // indirect
|
||||||
|
cloud.google.com/go/iam v0.5.0 // indirect
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/pborman/uuid v1.2.1 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
|
||||||
|
github.com/subosito/gotenv v1.4.1 // indirect
|
||||||
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
cloud.google.com/go v0.104.0 // indirect
|
||||||
|
cloud.google.com/go/pubsub v1.3.1 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect
|
||||||
github.com/DataDog/zstd v1.5.2 // indirect
|
github.com/DataDog/zstd v1.5.2 // indirect
|
||||||
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
|
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
|
||||||
|
github.com/agext/levenshtein v1.2.1 // indirect
|
||||||
|
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||||
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 // indirect
|
||||||
|
github.com/aws/aws-sdk-go v1.34.28 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.1.1 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sso v1.1.1 // indirect
|
||||||
|
|
@ -119,7 +138,7 @@ require (
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/mitchellh/pointerstructure v1.2.0 // indirect
|
github.com/mitchellh/pointerstructure v1.2.0 // indirect
|
||||||
github.com/mmcloughlin/addchain v0.4.0 // indirect
|
github.com/mmcloughlin/addchain v0.4.0 // indirect
|
||||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||||
|
|
@ -141,7 +160,6 @@ require (
|
||||||
go.uber.org/goleak v1.1.12
|
go.uber.org/goleak v1.1.12
|
||||||
golang.org/x/mod v0.9.0 // indirect
|
golang.org/x/mod v0.9.0 // indirect
|
||||||
golang.org/x/net v0.8.0 // indirect
|
golang.org/x/net v0.8.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
|
|
||||||
gonum.org/v1/gonum v0.11.0
|
gonum.org/v1/gonum v0.11.0
|
||||||
google.golang.org/grpc v1.51.0
|
google.golang.org/grpc v1.51.0
|
||||||
google.golang.org/protobuf v1.28.1
|
google.golang.org/protobuf v1.28.1
|
||||||
|
|
@ -168,10 +186,10 @@ require (
|
||||||
github.com/go-kit/kit v0.10.0 // indirect
|
github.com/go-kit/kit v0.10.0 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
||||||
github.com/go-redis/redis v6.15.7+incompatible // indirect
|
github.com/go-redis/redis v6.15.7+incompatible // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
github.com/gomodule/redigo v2.0.0+incompatible // indirect
|
github.com/gomodule/redigo v2.0.0+incompatible // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
|
github.com/googleapis/gax-go/v2 v2.5.1 // indirect
|
||||||
github.com/gorilla/mux v1.8.0 // indirect
|
github.com/gorilla/mux v1.8.0 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||||
|
|
@ -181,25 +199,21 @@ require (
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/jmhodges/levigo v1.0.0 // indirect
|
github.com/jmhodges/levigo v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
|
||||||
github.com/jstemmer/go-junit-report v0.9.1 // indirect
|
|
||||||
github.com/kelseyhightower/envconfig v1.4.0 // indirect
|
github.com/kelseyhightower/envconfig v1.4.0 // indirect
|
||||||
github.com/libp2p/go-buffer-pool v0.0.2 // indirect
|
github.com/libp2p/go-buffer-pool v0.0.2 // indirect
|
||||||
github.com/magiconair/properties v1.8.1 // indirect
|
github.com/magiconair/properties v1.8.6 // indirect
|
||||||
github.com/mitchellh/copystructure v1.0.0 // indirect
|
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
|
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
|
||||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
|
||||||
github.com/posener/complete v1.1.1 // indirect
|
github.com/posener/complete v1.1.1 // indirect
|
||||||
github.com/rakyll/statik v0.1.7 // indirect
|
github.com/rakyll/statik v0.1.7 // indirect
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
||||||
github.com/spf13/afero v1.2.2 // indirect
|
github.com/spf13/afero v1.8.2 // indirect
|
||||||
github.com/spf13/cast v1.4.1 // indirect
|
github.com/spf13/cast v1.5.0 // indirect
|
||||||
github.com/spf13/cobra v1.5.0 // indirect
|
github.com/spf13/cobra v1.5.0 // indirect
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/spf13/viper v1.4.0 // indirect
|
github.com/spf13/viper v1.13.0 // indirect
|
||||||
github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 // indirect
|
github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 // indirect
|
||||||
github.com/stumble/gorocksdb v0.0.3 // indirect
|
github.com/stumble/gorocksdb v0.0.3 // indirect
|
||||||
github.com/tendermint/btcd v0.1.1 // indirect
|
github.com/tendermint/btcd v0.1.1 // indirect
|
||||||
|
|
@ -211,33 +225,26 @@ require (
|
||||||
github.com/xdg-go/scram v1.0.2 // indirect
|
github.com/xdg-go/scram v1.0.2 // indirect
|
||||||
github.com/xdg-go/stringprep v1.0.2 // indirect
|
github.com/xdg-go/stringprep v1.0.2 // indirect
|
||||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
|
|
||||||
golang.org/x/oauth2 v0.3.0 // indirect
|
golang.org/x/oauth2 v0.3.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go v0.65.0 // indirect
|
|
||||||
cloud.google.com/go/pubsub v1.3.1 // indirect
|
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
github.com/Masterminds/semver v1.5.0 // indirect
|
github.com/Masterminds/semver v1.5.0 // indirect
|
||||||
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
||||||
github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae // indirect
|
github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae // indirect
|
||||||
github.com/RichardKnop/machinery v1.7.4 // indirect
|
github.com/RichardKnop/machinery v1.7.4 // indirect
|
||||||
github.com/RichardKnop/redsync v1.2.0 // indirect
|
github.com/RichardKnop/redsync v1.2.0 // indirect
|
||||||
github.com/agext/levenshtein v1.2.1 // indirect
|
|
||||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
|
||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 // indirect
|
|
||||||
github.com/aws/aws-sdk-go v1.34.28 // indirect
|
|
||||||
github.com/zclconf/go-cty v1.8.0 // indirect
|
github.com/zclconf/go-cty v1.8.0 // indirect
|
||||||
github.com/zondax/hid v0.9.0 // indirect
|
github.com/zondax/hid v0.9.0 // indirect
|
||||||
go.mongodb.org/mongo-driver v1.3.0 // indirect
|
go.mongodb.org/mongo-driver v1.3.0 // indirect
|
||||||
go.opencensus.io v0.22.6 // indirect
|
go.opencensus.io v0.23.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.2.0
|
go.opentelemetry.io/otel/trace v1.2.0
|
||||||
go.opentelemetry.io/proto/otlp v0.10.0 // indirect
|
go.opentelemetry.io/proto/otlp v0.10.0 // indirect
|
||||||
google.golang.org/api v0.34.0 // indirect
|
google.golang.org/api v0.97.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b // indirect
|
google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/cosmos/cosmos-sdk => github.com/maticnetwork/cosmos-sdk v0.37.5-0.20220311095845-81690c6a53e7
|
replace github.com/cosmos/cosmos-sdk => github.com/maticnetwork/cosmos-sdk v0.37.5-0.20220311095845-81690c6a53e7
|
||||||
|
|
|
||||||
263
go.sum
263
go.sum
|
|
@ -4,6 +4,7 @@ cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSR
|
||||||
cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=
|
cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=
|
||||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||||
|
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||||
|
|
@ -14,8 +15,25 @@ cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bP
|
||||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||||
cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8=
|
|
||||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||||
|
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||||
|
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||||
|
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
|
||||||
|
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||||
|
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||||
|
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||||
|
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
|
||||||
|
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
|
||||||
|
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
|
||||||
|
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
|
||||||
|
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
|
||||||
|
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
|
||||||
|
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
|
||||||
|
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
|
||||||
|
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
|
||||||
|
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
|
||||||
|
cloud.google.com/go v0.104.0 h1:gSmWO7DY1vOm0MVU6DNXM11BWHHsTUmsC5cv1fuW5X8=
|
||||||
|
cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=
|
||||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||||
|
|
@ -23,8 +41,19 @@ cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUM
|
||||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||||
cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o=
|
cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o=
|
||||||
|
cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
|
||||||
|
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
|
||||||
|
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
|
||||||
|
cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
|
||||||
|
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
|
||||||
|
cloud.google.com/go/compute v1.7.0 h1:v/k9Eueb8aAJ0vZuxKMrgm6kPhCLZU9HxFU+AFDs9Uk=
|
||||||
|
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
|
||||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||||
|
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
|
||||||
|
cloud.google.com/go/iam v0.5.0 h1:fz9X5zyTWBmamZsqvqZqD7khbifcZF/q+Z1J8pfhIUg=
|
||||||
|
cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc=
|
||||||
|
cloud.google.com/go/kms v1.4.0 h1:iElbfoE61VeLhnZcGOltqL8HIly8Nhbe5t6JlH9GXjo=
|
||||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||||
|
|
@ -35,6 +64,8 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
|
||||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||||
|
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||||
|
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
|
||||||
collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
|
collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
|
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
|
||||||
|
|
@ -204,6 +235,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||||
github.com/cloudflare/cloudflare-go v0.14.0 h1:gFqGlGl/5f9UGXAaKapCGUfaTCgRKKnzu2VvzMZlOFA=
|
github.com/cloudflare/cloudflare-go v0.14.0 h1:gFqGlGl/5f9UGXAaKapCGUfaTCgRKKnzu2VvzMZlOFA=
|
||||||
github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304=
|
github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
|
@ -306,6 +338,7 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||||
|
|
@ -322,8 +355,9 @@ github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQD
|
||||||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
|
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
|
||||||
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
|
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
|
||||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||||
|
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||||
|
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||||
github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c h1:CndMRAH4JIwxbW8KYq6Q+cGWcGHz0FjGR3QqcInWcW0=
|
github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c h1:CndMRAH4JIwxbW8KYq6Q+cGWcGHz0FjGR3QqcInWcW0=
|
||||||
github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY=
|
github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY=
|
||||||
|
|
@ -335,6 +369,7 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8
|
||||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||||
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||||
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
||||||
|
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||||
|
|
@ -454,8 +489,9 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
|
|
@ -464,6 +500,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
||||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||||
|
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||||
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
|
@ -483,6 +520,7 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
|
@ -521,6 +559,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
|
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
|
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
|
@ -528,6 +568,14 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
||||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
|
@ -536,9 +584,20 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
||||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.1.0 h1:zO8WHNx/MYiAKJ3d5spxZXZE6KHmIQGQcAzwUzV7qQw=
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.5.1 h1:kBRZU0PSuI7PspsSb/ChWoVResUcwNVIdpB049pKTiw=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=
|
||||||
|
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
|
||||||
|
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
|
|
@ -609,6 +668,7 @@ github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixH
|
||||||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
||||||
github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
|
github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
||||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
|
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
|
||||||
|
|
@ -661,7 +721,6 @@ github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
|
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o=
|
github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
|
@ -703,6 +762,7 @@ github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH6
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
|
@ -728,8 +788,9 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b
|
||||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
|
||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||||
|
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
||||||
|
|
@ -739,10 +800,12 @@ github.com/maticnetwork/cosmos-sdk v0.37.5-0.20220311095845-81690c6a53e7 h1:8NoE
|
||||||
github.com/maticnetwork/cosmos-sdk v0.37.5-0.20220311095845-81690c6a53e7/go.mod h1:uW55Ru86N5o3L8SVkVL1TPE+mV/WRM2la8sC3TR/Ajc=
|
github.com/maticnetwork/cosmos-sdk v0.37.5-0.20220311095845-81690c6a53e7/go.mod h1:uW55Ru86N5o3L8SVkVL1TPE+mV/WRM2la8sC3TR/Ajc=
|
||||||
github.com/maticnetwork/crand v1.0.2 h1:Af0tAivC8zrxXDpGWNWVT/0s1fOz8w0eRbahZgURS8I=
|
github.com/maticnetwork/crand v1.0.2 h1:Af0tAivC8zrxXDpGWNWVT/0s1fOz8w0eRbahZgURS8I=
|
||||||
github.com/maticnetwork/crand v1.0.2/go.mod h1:/NRNL3bj2eYdqpWmoIP5puxndTpi0XRxpj5ZKxfHjyg=
|
github.com/maticnetwork/crand v1.0.2/go.mod h1:/NRNL3bj2eYdqpWmoIP5puxndTpi0XRxpj5ZKxfHjyg=
|
||||||
github.com/maticnetwork/heimdall v0.3.1-0.20230105132832-d0063f71e3f0 h1:MYTAcBs4y88GEzesT8eAU472ZfQSLluW0qgkZTzNgwM=
|
|
||||||
github.com/maticnetwork/heimdall v0.3.1-0.20230105132832-d0063f71e3f0/go.mod h1:A3bUSe9jjMQHEPPOUW1JytM3x2g3t+jvsbPY66KBPIs=
|
github.com/maticnetwork/heimdall v0.3.1-0.20230105132832-d0063f71e3f0/go.mod h1:A3bUSe9jjMQHEPPOUW1JytM3x2g3t+jvsbPY66KBPIs=
|
||||||
github.com/maticnetwork/polyproto v0.0.2 h1:cPxuxbIDItdwGnucc3lZB58U8Zfe1mH73PWTGd15554=
|
github.com/maticnetwork/heimdall v0.3.1-0.20230227104835-81bd1055b0bc h1:7wEWQbYs6ESGsVBhjiVp7fZZyfaN4lg4XYLOLfRIpmY=
|
||||||
|
github.com/maticnetwork/heimdall v0.3.1-0.20230227104835-81bd1055b0bc/go.mod h1:P2DoKhovYP9G9Kj2EH/zHaiRJF1jNU7ZJOyelG4UCa8=
|
||||||
github.com/maticnetwork/polyproto v0.0.2/go.mod h1:e1mU2EXSwEpn5jM7GfNwu3AupsV6WAGoPFFfswXOF0o=
|
github.com/maticnetwork/polyproto v0.0.2/go.mod h1:e1mU2EXSwEpn5jM7GfNwu3AupsV6WAGoPFFfswXOF0o=
|
||||||
|
github.com/maticnetwork/polyproto v0.0.3-0.20230216113155-340ea926ca53 h1:PjYV+lghs106JKkrYgOnrsfDLoTc11BxZd4rUa4Rus4=
|
||||||
|
github.com/maticnetwork/polyproto v0.0.3-0.20230216113155-340ea926ca53/go.mod h1:e1mU2EXSwEpn5jM7GfNwu3AupsV6WAGoPFFfswXOF0o=
|
||||||
github.com/maticnetwork/tendermint v0.26.0-dev0.0.20220923185258-3e7c7f86ce9f h1:iV69PJUEdwJJFXQvbADYVEMxDrkKAsPdHTg4U3F510I=
|
github.com/maticnetwork/tendermint v0.26.0-dev0.0.20220923185258-3e7c7f86ce9f h1:iV69PJUEdwJJFXQvbADYVEMxDrkKAsPdHTg4U3F510I=
|
||||||
github.com/maticnetwork/tendermint v0.26.0-dev0.0.20220923185258-3e7c7f86ce9f/go.mod h1:90S74348uYSGfWwNIgvzQiRRakSH/c7VVt1TR5mzIuY=
|
github.com/maticnetwork/tendermint v0.26.0-dev0.0.20220923185258-3e7c7f86ce9f/go.mod h1:90S74348uYSGfWwNIgvzQiRRakSH/c7VVt1TR5mzIuY=
|
||||||
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||||
|
|
@ -751,6 +814,7 @@ github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
|
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
|
@ -793,8 +857,9 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
|
||||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
|
||||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
|
github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
|
||||||
github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
|
github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
|
||||||
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||||
|
|
@ -859,10 +924,14 @@ github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIw
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=
|
github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=
|
||||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||||
|
github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw=
|
||||||
|
github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
|
||||||
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
|
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
|
||||||
github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
|
github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
|
||||||
github.com/peterh/liner v1.2.0 h1:w/UPXyl5GfahFxcTOz2j9wCIHNI+pUPr2laqpojKNCg=
|
github.com/peterh/liner v1.2.0 h1:w/UPXyl5GfahFxcTOz2j9wCIHNI+pUPr2laqpojKNCg=
|
||||||
|
|
@ -881,6 +950,7 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||||
|
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||||
github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
|
github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
|
@ -980,11 +1050,13 @@ github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJ
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
|
github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo=
|
||||||
|
github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
|
|
||||||
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||||
|
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
||||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||||
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
|
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
|
||||||
|
|
@ -998,8 +1070,9 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||||
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
|
|
||||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||||
|
github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU=
|
||||||
|
github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw=
|
||||||
github.com/status-im/keycard-go v0.0.0-20211109104530-b0e0482ba91d/go.mod h1:97vT0Rym0wCnK4B++hNA3nCetr0Mh1KXaVxzSt1arjg=
|
github.com/status-im/keycard-go v0.0.0-20211109104530-b0e0482ba91d/go.mod h1:97vT0Rym0wCnK4B++hNA3nCetr0Mh1KXaVxzSt1arjg=
|
||||||
github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA=
|
github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA=
|
||||||
github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg=
|
github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg=
|
||||||
|
|
@ -1026,6 +1099,8 @@ github.com/stumble/gorocksdb v0.0.3 h1:9UU+QA1pqFYJuf9+5p7z1IqdE5k0mma4UAeu2wmX8
|
||||||
github.com/stumble/gorocksdb v0.0.3/go.mod h1:v6IHdFBXk5DJ1K4FZ0xi+eY737quiiBxYtSWXadLybY=
|
github.com/stumble/gorocksdb v0.0.3/go.mod h1:v6IHdFBXk5DJ1K4FZ0xi+eY737quiiBxYtSWXadLybY=
|
||||||
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM=
|
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM=
|
||||||
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8=
|
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8=
|
||||||
|
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
|
||||||
|
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||||
github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 h1:m+8fKfQwCAy1QjzINvKe/pYtLjo2dl59x2w9YSEJxuY=
|
github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 h1:m+8fKfQwCAy1QjzINvKe/pYtLjo2dl59x2w9YSEJxuY=
|
||||||
github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
|
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
|
||||||
|
|
@ -1127,8 +1202,10 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.6 h1:BdkrbWrzDlV9dnbzoP7sfN+dHheJ4J9JOaYxcUDL+ok=
|
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||||
go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||||
|
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
||||||
|
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||||
go.opentelemetry.io/otel v1.2.0 h1:YOQDvxO1FayUcT9MIhJhgMyNO1WqoduiyvQHzGN0kUQ=
|
go.opentelemetry.io/otel v1.2.0 h1:YOQDvxO1FayUcT9MIhJhgMyNO1WqoduiyvQHzGN0kUQ=
|
||||||
go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I=
|
go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0 h1:xzbcGykysUh776gzD1LUPsNNHKWN0kQWDnJhn1ddUuk=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0 h1:xzbcGykysUh776gzD1LUPsNNHKWN0kQWDnJhn1ddUuk=
|
||||||
|
|
@ -1174,7 +1251,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
||||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
|
@ -1218,6 +1297,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
|
||||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
|
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
|
||||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
|
|
@ -1228,6 +1308,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
||||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||||
|
|
@ -1278,18 +1360,31 @@ golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81R
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
|
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||||
|
|
@ -1300,7 +1395,21 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr
|
||||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||||
golang.org/x/oauth2 v0.3.0 h1:6l90koy8/LaBLmLu8jpHeHexzMwEita0zFfYlggy2F8=
|
golang.org/x/oauth2 v0.3.0 h1:6l90koy8/LaBLmLu8jpHeHexzMwEita0zFfYlggy2F8=
|
||||||
golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk=
|
golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
|
@ -1315,6 +1424,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
|
@ -1378,10 +1488,17 @@ golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
|
@ -1389,19 +1506,36 @@ golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|
@ -1498,10 +1632,17 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc
|
||||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||||
|
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||||
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||||
|
|
@ -1515,8 +1656,9 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618=
|
|
||||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||||
|
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||||
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||||
gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||||
gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=
|
gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=
|
||||||
|
|
@ -1546,8 +1688,32 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
|
||||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||||
google.golang.org/api v0.34.0 h1:k40adF3uR+6x/+hO5Dh4ZFUqFp67vxvbpafFiJxl10A=
|
|
||||||
google.golang.org/api v0.34.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
google.golang.org/api v0.34.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||||
|
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||||
|
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||||
|
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||||
|
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||||
|
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||||
|
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
|
||||||
|
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
|
||||||
|
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
|
||||||
|
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
|
||||||
|
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
|
||||||
|
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||||
|
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||||
|
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
|
||||||
|
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
|
||||||
|
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
|
||||||
|
google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
|
||||||
|
google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
|
||||||
|
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
|
||||||
|
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
|
||||||
|
google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
|
||||||
|
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
|
||||||
|
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
|
||||||
|
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
|
||||||
|
google.golang.org/api v0.97.0 h1:x/vEL1XDF/2V4xzdNgFPaKHluRESo2aTsL7QzHnBtGQ=
|
||||||
|
google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
|
@ -1596,10 +1762,60 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D
|
||||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||||
|
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||||
|
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
||||||
|
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||||
|
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||||
|
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||||
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
||||||
|
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||||
|
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||||
|
google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||||
|
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||||
|
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
|
||||||
|
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||||
|
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||||
|
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||||
|
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||||
|
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||||
google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b h1:SfSkJugek6xm7lWywqth4r2iTrYLpD8lOj1nMIIhMNM=
|
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||||
|
google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||||
|
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||||
|
google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||||
|
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
|
||||||
|
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||||
|
google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||||
|
google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||||
|
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||||
|
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||||
|
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||||
google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=
|
google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=
|
||||||
|
google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce h1:+2ye9vAK4F9F/LCex8dT2cDk0VnTAwUL8uRgX/6nAMU=
|
||||||
|
google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
|
||||||
google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
|
@ -1622,15 +1838,28 @@ google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
|
||||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
|
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||||
|
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
|
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
|
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
|
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
|
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||||
|
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||||
|
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||||
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
||||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||||
|
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||||
|
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||||
|
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||||
|
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||||
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||||
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||||
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
|
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
|
||||||
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
|
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
|
||||||
|
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0/go.mod h1:DNq5QpG7LJqD2AamLZ7zvKE0DEpVl2BSEVjFycAAjRY=
|
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0/go.mod h1:DNq5QpG7LJqD2AamLZ7zvKE0DEpVl2BSEVjFycAAjRY=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
|
@ -1661,6 +1890,8 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||||
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||||
|
|
|
||||||
|
|
@ -250,9 +250,19 @@ type StateSyncFilter struct {
|
||||||
|
|
||||||
// interface for whitelist service
|
// interface for whitelist service
|
||||||
type ChainValidator interface {
|
type ChainValidator interface {
|
||||||
IsValidPeer(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error)
|
IsValidPeer(fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error)
|
||||||
IsValidChain(currentHeader *types.Header, chain []*types.Header) (bool, error)
|
IsValidChain(currentHeader *types.Header, chain []*types.Header) (bool, error)
|
||||||
|
GetWhitelistedCheckpoint() (bool, uint64, common.Hash)
|
||||||
|
GetWhitelistedMilestone() (bool, uint64, common.Hash)
|
||||||
ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash)
|
ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash)
|
||||||
GetCheckpointWhitelist() map[uint64]common.Hash
|
ProcessMilestone(endBlockNum uint64, endBlockHash common.Hash)
|
||||||
PurgeCheckpointWhitelist()
|
ProcessFutureMilestone(num uint64, hash common.Hash)
|
||||||
|
PurgeWhitelistedCheckpoint()
|
||||||
|
PurgeWhitelistedMilestone()
|
||||||
|
|
||||||
|
LockMutex(endBlockNum uint64) bool
|
||||||
|
UnlockMutex(doLock bool, milestoneId string, endBlockNum uint64, endBlockHash common.Hash)
|
||||||
|
UnlockSprint(endBlockNum uint64)
|
||||||
|
RemoveMilestoneID(milestoneId string)
|
||||||
|
GetMilestoneIDsList() []string
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2558,17 +2558,6 @@ func (api *DebugAPI) SetHead(number hexutil.Uint64) {
|
||||||
api.b.SetHead(uint64(number))
|
api.b.SetHead(uint64(number))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCheckpointWhitelist retrieves the current checkpoint whitelist
|
|
||||||
// entries (of the form block number -> block hash)
|
|
||||||
func (api *DebugAPI) GetCheckpointWhitelist() map[uint64]common.Hash {
|
|
||||||
return api.b.GetCheckpointWhitelist()
|
|
||||||
}
|
|
||||||
|
|
||||||
// PurgeCheckpointWhitelist purges the current checkpoint whitelist entries
|
|
||||||
func (api *DebugAPI) PurgeCheckpointWhitelist() {
|
|
||||||
api.b.PurgeCheckpointWhitelist()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTraceStack returns the current trace stack
|
// GetTraceStack returns the current trace stack
|
||||||
func (api *DebugAPI) GetTraceStack() string {
|
func (api *DebugAPI) GetTraceStack() string {
|
||||||
buf := make([]byte, 1024)
|
buf := make([]byte, 1024)
|
||||||
|
|
|
||||||
|
|
@ -102,13 +102,16 @@ type Backend interface {
|
||||||
// Bor related APIs
|
// Bor related APIs
|
||||||
SubscribeStateSyncEvent(ch chan<- core.StateSyncEvent) event.Subscription
|
SubscribeStateSyncEvent(ch chan<- core.StateSyncEvent) event.Subscription
|
||||||
GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error)
|
GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error)
|
||||||
|
GetVoteOnHash(ctx context.Context, startBlockNumber uint64, endBlockNumber uint64, hash string, milestoneID string) (bool, error)
|
||||||
GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error)
|
GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error)
|
||||||
GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error)
|
GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error)
|
||||||
GetBorBlockTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error)
|
GetBorBlockTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error)
|
||||||
GetBorBlockTransactionWithBlockHash(ctx context.Context, txHash common.Hash, blockHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error)
|
GetBorBlockTransactionWithBlockHash(ctx context.Context, txHash common.Hash, blockHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error)
|
||||||
SubscribeChain2HeadEvent(ch chan<- core.Chain2HeadEvent) event.Subscription
|
SubscribeChain2HeadEvent(ch chan<- core.Chain2HeadEvent) event.Subscription
|
||||||
GetCheckpointWhitelist() map[uint64]common.Hash
|
GetWhitelistedCheckpoint() (bool, uint64, common.Hash)
|
||||||
PurgeCheckpointWhitelist()
|
PurgeWhitelistedCheckpoint()
|
||||||
|
GetWhitelistedMilestone() (bool, uint64, common.Hash)
|
||||||
|
PurgeWhitelistedMilestone()
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAPIs(apiBackend Backend) []rpc.API {
|
func GetAPIs(apiBackend Backend) []rpc.API {
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,10 @@ func (s *BlockChainAPI) GetBorBlockReceipt(ctx context.Context, hash common.Hash
|
||||||
return s.b.GetBorBlockReceipt(ctx, hash)
|
return s.b.GetBorBlockReceipt(ctx, hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *BlockChainAPI) GetVoteOnHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64, hash string, milestoneId string) (bool, error) {
|
||||||
|
return s.b.GetVoteOnHash(ctx, starBlockNr, endBlockNr, hash, milestoneId)
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Bor transaction utils
|
// Bor transaction utils
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -364,51 +364,51 @@ func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent)
|
||||||
func (b *backendMock) Engine() consensus.Engine { return nil }
|
func (b *backendMock) Engine() consensus.Engine { return nil }
|
||||||
|
|
||||||
func (b *backendMock) RPCRpcReturnDataLimit() uint64 {
|
func (b *backendMock) RPCRpcReturnDataLimit() uint64 {
|
||||||
//nolint: staticcheck
|
return 0
|
||||||
return b.RPCRpcReturnDataLimit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backendMock) SubscribeStateSyncEvent(ch chan<- core.StateSyncEvent) event.Subscription {
|
func (b *backendMock) SubscribeStateSyncEvent(ch chan<- core.StateSyncEvent) event.Subscription {
|
||||||
//nolint: staticcheck
|
return nil
|
||||||
return b.SubscribeStateSyncEvent(ch)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backendMock) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) {
|
func (b *backendMock) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) {
|
||||||
//nolint: staticcheck
|
return "", nil
|
||||||
return b.GetRootHash(ctx, starBlockNr, endBlockNr)
|
}
|
||||||
|
|
||||||
|
func (b *backendMock) GetVoteOnHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64, hash string, milestoneId string) (bool, error) {
|
||||||
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backendMock) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
|
func (b *backendMock) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
|
||||||
//nolint: staticcheck
|
//nolint: nilnil
|
||||||
return b.GetBorBlockReceipt(ctx, hash)
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backendMock) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) {
|
func (b *backendMock) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) {
|
||||||
//nolint: staticcheck
|
// nolint: nilnil
|
||||||
return b.GetBorBlockLogs(ctx, hash)
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backendMock) GetBorBlockTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
|
func (b *backendMock) GetBorBlockTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
|
||||||
//nolint: staticcheck
|
return nil, common.Hash{}, 0, 0, nil
|
||||||
return b.GetBorBlockTransaction(ctx, txHash)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backendMock) GetBorBlockTransactionWithBlockHash(ctx context.Context, txHash common.Hash, blockHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
|
func (b *backendMock) GetBorBlockTransactionWithBlockHash(ctx context.Context, txHash common.Hash, blockHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
|
||||||
//nolint: staticcheck
|
return nil, common.Hash{}, 0, 0, nil
|
||||||
return b.GetBorBlockTransactionWithBlockHash(ctx, txHash, blockHash)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backendMock) SubscribeChain2HeadEvent(ch chan<- core.Chain2HeadEvent) event.Subscription {
|
func (b *backendMock) SubscribeChain2HeadEvent(ch chan<- core.Chain2HeadEvent) event.Subscription {
|
||||||
//nolint: staticcheck
|
return nil
|
||||||
return b.SubscribeChain2HeadEvent(ch)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backendMock) GetCheckpointWhitelist() map[uint64]common.Hash {
|
func (b *backendMock) GetWhitelistedCheckpoint() (bool, uint64, common.Hash) {
|
||||||
//nolint: staticcheck
|
return false, 0, common.Hash{}
|
||||||
return b.GetCheckpointWhitelist()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backendMock) PurgeCheckpointWhitelist() {
|
func (b *backendMock) GetWhitelistedMilestone() (bool, uint64, common.Hash) {
|
||||||
//nolint: staticcheck
|
return false, 0, common.Hash{}
|
||||||
b.PurgeCheckpointWhitelist()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *backendMock) PurgeWhitelistedCheckpoint() {}
|
||||||
|
|
||||||
|
func (b *backendMock) PurgeWhitelistedMilestone() {}
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,11 @@ web3._extend({
|
||||||
call: 'bor_getRootHash',
|
call: 'bor_getRootHash',
|
||||||
params: 2,
|
params: 2,
|
||||||
}),
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'getVoteOnHash',
|
||||||
|
call: 'bor_getVoteOnHash',
|
||||||
|
params: 4,
|
||||||
|
}),
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
|
|
|
||||||
|
|
@ -515,13 +515,23 @@ web3._extend({
|
||||||
inputFormatter:[web3._extend.formatters.inputBlockNumberFormatter, web3._extend.formatters.inputBlockNumberFormatter],
|
inputFormatter:[web3._extend.formatters.inputBlockNumberFormatter, web3._extend.formatters.inputBlockNumberFormatter],
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'getCheckpointWhitelist',
|
name: 'getWhitelistedCheckpoint',
|
||||||
call: 'debug_getCheckpointWhitelist',
|
call: 'debug_getWhitelistedCheckpoint',
|
||||||
params: 0,
|
params: 0,
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'purgeCheckpointWhitelist',
|
name: 'purgeWhitelistedCheckpoint',
|
||||||
call: 'debug_purgeCheckpointWhitelist',
|
call: 'debug_purgeWhitelistedCheckpoint',
|
||||||
|
params: 0,
|
||||||
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'getWhitelistedMilestone',
|
||||||
|
call: 'debug_getWhitelistedMilestone',
|
||||||
|
params: 0,
|
||||||
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'purgeWhitelistedMilestone',
|
||||||
|
call: 'debug_purgeWhitelistedMilestone',
|
||||||
params: 0,
|
params: 0,
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
|
|
|
||||||
|
|
@ -370,6 +370,9 @@ func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Blo
|
||||||
func (b *LesApiBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
|
func (b *LesApiBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
|
||||||
return nil, errors.New("not implemented")
|
return nil, errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
func (b *LesApiBackend) GetVoteOnHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64, hash string, milestoneId string) (bool, error) {
|
||||||
|
return false, errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
func (b *LesApiBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) {
|
func (b *LesApiBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) {
|
||||||
return nil, errors.New("not implemented")
|
return nil, errors.New("not implemented")
|
||||||
|
|
@ -383,9 +386,16 @@ func (b *LesApiBackend) GetBorBlockTransactionWithBlockHash(ctx context.Context,
|
||||||
return nil, common.Hash{}, 0, 0, errors.New("not implemented")
|
return nil, common.Hash{}, 0, 0, errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LesApiBackend) GetCheckpointWhitelist() map[uint64]common.Hash {
|
func (b *LesApiBackend) GetWhitelistedCheckpoint() (bool, uint64, common.Hash) {
|
||||||
return nil
|
return false, 0, common.Hash{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LesApiBackend) PurgeCheckpointWhitelist() {
|
func (b *LesApiBackend) PurgeWhitelistedCheckpoint() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *LesApiBackend) GetWhitelistedMilestone() (bool, uint64, common.Hash) {
|
||||||
|
return false, 0, common.Hash{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *LesApiBackend) PurgeWhitelistedMilestone() {
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,10 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) {
|
||||||
}
|
}
|
||||||
// Note: NewLightChain adds the trusted checkpoint so it needs an ODR with
|
// Note: NewLightChain adds the trusted checkpoint so it needs an ODR with
|
||||||
// indexers already set but not started yet
|
// indexers already set but not started yet
|
||||||
if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine, checkpoint, whitelist.NewService(10)); err != nil {
|
|
||||||
|
checker := whitelist.NewService(chainDb)
|
||||||
|
|
||||||
|
if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine, checkpoint, checker); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ type Miner struct {
|
||||||
engine consensus.Engine
|
engine consensus.Engine
|
||||||
exitCh chan struct{}
|
exitCh chan struct{}
|
||||||
startCh chan struct{}
|
startCh chan struct{}
|
||||||
stopCh chan struct{}
|
stopCh chan chan struct{}
|
||||||
worker *worker
|
worker *worker
|
||||||
|
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
|
|
@ -92,8 +92,8 @@ func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *even
|
||||||
eth: eth,
|
eth: eth,
|
||||||
engine: engine,
|
engine: engine,
|
||||||
exitCh: make(chan struct{}),
|
exitCh: make(chan struct{}),
|
||||||
|
stopCh: make(chan chan struct{}),
|
||||||
startCh: make(chan struct{}),
|
startCh: make(chan struct{}),
|
||||||
stopCh: make(chan struct{}),
|
|
||||||
worker: newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, true),
|
worker: newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, true),
|
||||||
}
|
}
|
||||||
miner.wg.Add(1)
|
miner.wg.Add(1)
|
||||||
|
|
@ -164,10 +164,11 @@ func (miner *Miner) update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldStart = true
|
shouldStart = true
|
||||||
case <-miner.stopCh:
|
case ch := <-miner.stopCh:
|
||||||
shouldStart = false
|
shouldStart = false
|
||||||
|
|
||||||
miner.worker.stop()
|
miner.worker.stop()
|
||||||
|
close(ch)
|
||||||
case <-miner.exitCh:
|
case <-miner.exitCh:
|
||||||
miner.worker.close()
|
miner.worker.close()
|
||||||
return
|
return
|
||||||
|
|
@ -179,8 +180,8 @@ func (miner *Miner) Start() {
|
||||||
miner.startCh <- struct{}{}
|
miner.startCh <- struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (miner *Miner) Stop() {
|
func (miner *Miner) Stop(ch chan struct{}) {
|
||||||
miner.stopCh <- struct{}{}
|
miner.stopCh <- ch
|
||||||
}
|
}
|
||||||
|
|
||||||
func (miner *Miner) Close() {
|
func (miner *Miner) Close() {
|
||||||
|
|
|
||||||
|
|
@ -137,13 +137,15 @@ func TestMinerStartStopAfterDownloaderEvents(t *testing.T) {
|
||||||
mux.Post(downloader.DoneEvent{})
|
mux.Post(downloader.DoneEvent{})
|
||||||
waitForMiningState(t, miner, true)
|
waitForMiningState(t, miner, true)
|
||||||
|
|
||||||
miner.Stop()
|
ch := make(chan struct{})
|
||||||
|
miner.Stop(ch)
|
||||||
waitForMiningState(t, miner, false)
|
waitForMiningState(t, miner, false)
|
||||||
|
|
||||||
miner.Start()
|
miner.Start()
|
||||||
waitForMiningState(t, miner, true)
|
waitForMiningState(t, miner, true)
|
||||||
|
|
||||||
miner.Stop()
|
ch = make(chan struct{})
|
||||||
|
miner.Stop(ch)
|
||||||
waitForMiningState(t, miner, false)
|
waitForMiningState(t, miner, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -187,7 +189,8 @@ func TestStartStopMiner(t *testing.T) {
|
||||||
miner.Start()
|
miner.Start()
|
||||||
waitForMiningState(t, miner, true)
|
waitForMiningState(t, miner, true)
|
||||||
|
|
||||||
miner.Stop()
|
ch := make(chan struct{})
|
||||||
|
miner.Stop(ch)
|
||||||
|
|
||||||
waitForMiningState(t, miner, false)
|
waitForMiningState(t, miner, false)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
35
rpc/types.go
35
rpc/types.go
|
|
@ -68,6 +68,11 @@ const (
|
||||||
PendingBlockNumber = BlockNumber(-2)
|
PendingBlockNumber = BlockNumber(-2)
|
||||||
LatestBlockNumber = BlockNumber(-1)
|
LatestBlockNumber = BlockNumber(-1)
|
||||||
EarliestBlockNumber = BlockNumber(0)
|
EarliestBlockNumber = BlockNumber(0)
|
||||||
|
|
||||||
|
latest = "latest"
|
||||||
|
earliest = "earliest"
|
||||||
|
pending = "pending"
|
||||||
|
finalized = "finalized"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports:
|
// UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports:
|
||||||
|
|
@ -84,13 +89,13 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch input {
|
switch input {
|
||||||
case "earliest":
|
case earliest:
|
||||||
*bn = EarliestBlockNumber
|
*bn = EarliestBlockNumber
|
||||||
return nil
|
return nil
|
||||||
case "latest":
|
case latest:
|
||||||
*bn = LatestBlockNumber
|
*bn = LatestBlockNumber
|
||||||
return nil
|
return nil
|
||||||
case "pending":
|
case pending:
|
||||||
*bn = PendingBlockNumber
|
*bn = PendingBlockNumber
|
||||||
return nil
|
return nil
|
||||||
case "finalized":
|
case "finalized":
|
||||||
|
|
@ -121,9 +126,9 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error {
|
||||||
func (bn BlockNumber) MarshalText() ([]byte, error) {
|
func (bn BlockNumber) MarshalText() ([]byte, error) {
|
||||||
switch bn {
|
switch bn {
|
||||||
case EarliestBlockNumber:
|
case EarliestBlockNumber:
|
||||||
return []byte("earliest"), nil
|
return []byte(earliest), nil
|
||||||
case LatestBlockNumber:
|
case LatestBlockNumber:
|
||||||
return []byte("latest"), nil
|
return []byte(latest), nil
|
||||||
case PendingBlockNumber:
|
case PendingBlockNumber:
|
||||||
return []byte("pending"), nil
|
return []byte("pending"), nil
|
||||||
case FinalizedBlockNumber:
|
case FinalizedBlockNumber:
|
||||||
|
|
@ -171,23 +176,20 @@ func (bnh *BlockNumberOrHash) UnmarshalJSON(data []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch input {
|
switch input {
|
||||||
case "earliest":
|
case earliest:
|
||||||
bn := EarliestBlockNumber
|
bn := EarliestBlockNumber
|
||||||
bnh.BlockNumber = &bn
|
bnh.BlockNumber = &bn
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
case "latest":
|
|
||||||
|
case latest:
|
||||||
bn := LatestBlockNumber
|
bn := LatestBlockNumber
|
||||||
bnh.BlockNumber = &bn
|
bnh.BlockNumber = &bn
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
case "pending":
|
|
||||||
bn := PendingBlockNumber
|
|
||||||
bnh.BlockNumber = &bn
|
|
||||||
|
|
||||||
return nil
|
case pending:
|
||||||
case "finalized":
|
bn := PendingBlockNumber
|
||||||
bn := FinalizedBlockNumber
|
|
||||||
bnh.BlockNumber = &bn
|
bnh.BlockNumber = &bn
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -196,6 +198,13 @@ func (bnh *BlockNumberOrHash) UnmarshalJSON(data []byte) error {
|
||||||
bnh.BlockNumber = &bn
|
bnh.BlockNumber = &bn
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
case finalized:
|
||||||
|
bn := FinalizedBlockNumber
|
||||||
|
bnh.BlockNumber = &bn
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if len(input) == 66 {
|
if len(input) == 66 {
|
||||||
hash := common.Hash{}
|
hash := common.Hash{}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBorFilters(t *testing.T) {
|
func TestBorFilters(t *testing.T) {
|
||||||
t.Parallel()
|
// t.Parallel()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
|
|
|
||||||
1392
tests/bor/bor_milestone_test.go
Normal file
1392
tests/bor/bor_milestone_test.go
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -49,7 +49,7 @@ const (
|
||||||
|
|
||||||
// Sprint length change tests
|
// Sprint length change tests
|
||||||
func TestValidatorsBlockProduction(t *testing.T) {
|
func TestValidatorsBlockProduction(t *testing.T) {
|
||||||
t.Parallel()
|
// t.Parallel()
|
||||||
|
|
||||||
log.Root().SetHandler(log.LvlFilterHandler(3, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
log.Root().SetHandler(log.LvlFilterHandler(3, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||||
|
|
||||||
|
|
@ -201,7 +201,7 @@ func TestValidatorsBlockProduction(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSprintLengths(t *testing.T) {
|
func TestSprintLengths(t *testing.T) {
|
||||||
t.Parallel()
|
// t.Parallel()
|
||||||
|
|
||||||
testBorConfig := params.TestChainConfig.Bor
|
testBorConfig := params.TestChainConfig.Bor
|
||||||
testBorConfig.Sprint = map[string]uint64{
|
testBorConfig.Sprint = map[string]uint64{
|
||||||
|
|
@ -214,7 +214,7 @@ func TestSprintLengths(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProducerDelay(t *testing.T) {
|
func TestProducerDelay(t *testing.T) {
|
||||||
t.Parallel()
|
// t.Parallel()
|
||||||
|
|
||||||
testBorConfig := params.TestChainConfig.Bor
|
testBorConfig := params.TestChainConfig.Bor
|
||||||
testBorConfig.ProducerDelay = map[string]uint64{
|
testBorConfig.ProducerDelay = map[string]uint64{
|
||||||
|
|
@ -376,7 +376,7 @@ func SprintLengthReorgIndividual2Nodes(t *testing.T, index int, tt map[string]in
|
||||||
|
|
||||||
func TestSprintLengthReorg2Nodes(t *testing.T) {
|
func TestSprintLengthReorg2Nodes(t *testing.T) {
|
||||||
t.Skip()
|
t.Skip()
|
||||||
t.Parallel()
|
// t.Parallel()
|
||||||
|
|
||||||
log.Root().SetHandler(log.LvlFilterHandler(3, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
log.Root().SetHandler(log.LvlFilterHandler(3, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||||
|
|
||||||
|
|
@ -424,7 +424,7 @@ func TestSprintLengthReorg2Nodes(t *testing.T) {
|
||||||
|
|
||||||
func TestSprintLengthReorg(t *testing.T) {
|
func TestSprintLengthReorg(t *testing.T) {
|
||||||
t.Skip()
|
t.Skip()
|
||||||
t.Parallel()
|
// t.Parallel()
|
||||||
|
|
||||||
reorgsLengthTests := getTestSprintLengthReorgCases()
|
reorgsLengthTests := getTestSprintLengthReorgCases()
|
||||||
f, err := os.Create("sprintReorg.csv")
|
f, err := os.Create("sprintReorg.csv")
|
||||||
|
|
|
||||||
703
tests/bor/bor_sprint_length_milestone_merge_test.go
Normal file
703
tests/bor/bor_sprint_length_milestone_merge_test.go
Normal file
|
|
@ -0,0 +1,703 @@
|
||||||
|
//go:build integration
|
||||||
|
|
||||||
|
// nolint
|
||||||
|
package bor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"encoding/csv"
|
||||||
|
"fmt" // nolint: staticcheck
|
||||||
|
_log "log"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/fdlimit"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
|
||||||
|
// Only this account is a validator for the 0th span
|
||||||
|
keySprintLength_Milestone, _ = crypto.HexToECDSA(privKeySprintLength_Milestone)
|
||||||
|
|
||||||
|
// This account is one the validators for 1st span (0-indexed)
|
||||||
|
keySprintLength_Milestone2, _ = crypto.HexToECDSA(privKeySprintLength_Milestone2)
|
||||||
|
|
||||||
|
keysSprintLength_Milestone = []*ecdsa.PrivateKey{keySprintLength_Milestone, keySprintLength_Milestone2}
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
privKeySprintLength_Milestone = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
|
||||||
|
privKeySprintLength_Milestone2 = "9b28f36fbd67381120752d6172ecdcf10e06ab2d9a1367aac00cdcd6ac7855d3"
|
||||||
|
)
|
||||||
|
|
||||||
|
var keys_21validator = []map[string]string{
|
||||||
|
{
|
||||||
|
"address": "0x5C3E1B893B9315a968fcC6bce9EB9F7d8E22edB3",
|
||||||
|
"priv_key": "c19fac8e538447124ad2408d9fbaeda2bb686fee763dca7a6bab58ea12442413",
|
||||||
|
"pub_key": "0x0495421933eda03dcc37f9186c24e255b569513aefae71e96d55d0db3df17502e24e86297b01a167fab9ce1174f06ee3110510ac242e39218bd964de5b345edbd6",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "0x73E033779C9030D4528d86FbceF5B02e97488921",
|
||||||
|
"priv_key": "61eb51cf8936309151ab7b931841ea033b6a09931f6a100b464fbbd74f3e0bd7",
|
||||||
|
"pub_key": "0x04f9a5e9bf76b45ac58f1b018ccba4b83b3531010cdadf42174c18a9db9879ef1dcb5d1254ce834bc108b110cd8d0186ed69a0387528a142bdb5936faf58bf98c9",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "0x751eC4877450B8a4D652d0D70197337FC38a42e6",
|
||||||
|
"priv_key": "6e7f48d012c9c0baadbdc88af32521e2e477fd6898a9b65e6abe19fd6652cb2e",
|
||||||
|
"pub_key": "0x0479db4c0b757bf0e5d9b8954b078ab7c0e91d6c19697904d23d07ea4853c8584382de91174929ba5c598214b8a991471ae051458ea787cdc15a4e435a55ef8059",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "0xA464DC4810Bc79B956810759e314d85BcE35cD1c",
|
||||||
|
"priv_key": "3efcf3f7014a6257f4a443119851414111820c681b27525dab3f35e72e28e51e",
|
||||||
|
"pub_key": "0x040180920306bf598ea050e258f2c7e50804a77a64f5a11705e08d18ee71eb0a80fafc95d0a42b92371ded042edda16c1f0b5f2fef7c4113ad66c59a71c29d977e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "0xb005bc07015170266Bd430f3EC1322938603be20",
|
||||||
|
"priv_key": "17cd9b38c2b3a639c7d97ccbf2bb6c7140ab8f625aec4c249bc8e4cfd3bf9a96",
|
||||||
|
"pub_key": "0x04435a70d343aa569e6f3386c73e39a1aa6f88c30e5943baedda9618b55cc944a2de1d114aff6d0e9fa002bebc780b04ef6c1b8a06bbf0d41c10d1efa55390f198",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "0xE8d02Da3dFeeB3e755472D95D666BD6821D92129",
|
||||||
|
"priv_key": "45c9ef66361a2283cef14184f128c41949103b791aa622ead3c0bc844648b835",
|
||||||
|
"pub_key": "0x04a14651ddc80467eb589d72d95153fa695e4cb2e4bb99edeb912e840d309d61313b6f4676081b099f29e6598ecf98cb7b44bb862d019920718b558f27ba94ca51",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "0xF93B54Cf36E917f625B48e1e3C9F93BC2344Fb06",
|
||||||
|
"priv_key": "93788a1305605808df1f9a96b5e1157da191680cf08bc15e077138f517563cd5",
|
||||||
|
"pub_key": "0x045eee11dceccd9cccc371ca3d96d74c848e785223f1e5df4d1a7f08efdfeb90bd8f0035342a9c26068cf6c7ab395ca3ceea555541325067fc187c375390efa57d",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTestSprintLengthMilestoneReorgCases() []map[string]uint64 {
|
||||||
|
faultyNodes := []int64{2, 4}
|
||||||
|
milestoneMark := []int64{48, 72}
|
||||||
|
sprintLen := int64(16)
|
||||||
|
milestoneLen := int64(24)
|
||||||
|
reorgsLengthTests := make([]map[string]uint64, 0)
|
||||||
|
|
||||||
|
for i := int64(0); i < int64(len(faultyNodes)); i++ {
|
||||||
|
for j := int64(1); j < int64(14); j = j + 2 {
|
||||||
|
startBlock := faultyNodes[i]*sprintLen + j
|
||||||
|
diff := milestoneMark[i] - startBlock
|
||||||
|
if diff <= 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
a := diff*2 - 2
|
||||||
|
for k := diff + 1; k < a; k = k + 4 {
|
||||||
|
for l := 0; l < 2; l++ {
|
||||||
|
|
||||||
|
reorgsLengthTest := map[string]uint64{
|
||||||
|
"reorgLength": uint64(k),
|
||||||
|
"startBlock": uint64(startBlock),
|
||||||
|
"sprintSize": uint64(sprintLen),
|
||||||
|
"faultyNode": uint64(faultyNodes[i]), // node 1(index) is primary validator of the first sprint
|
||||||
|
"milestoneLength": uint64(milestoneLen),
|
||||||
|
"milestoneFlag": uint64(l),
|
||||||
|
}
|
||||||
|
|
||||||
|
reorgsLengthTests = append(reorgsLengthTests, reorgsLengthTest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reorgsLengthTests
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTestSprintLengthMilestoneReorgCases2Nodes() []map[string]interface{} {
|
||||||
|
sprintSizes := []uint64{16, 32, 64}
|
||||||
|
faultyNodes := [][]uint64{{0, 1}, {1, 2}, {0, 2}}
|
||||||
|
milestoneLength := []uint64{16, 32, 64}
|
||||||
|
reorgsLengthTests := make([]map[string]interface{}, 0)
|
||||||
|
|
||||||
|
for i := uint64(0); i < uint64(len(sprintSizes)); i++ {
|
||||||
|
for m := uint64(0); m < uint64(len(milestoneLength)); m++ {
|
||||||
|
maxReorgLength := sprintSizes[i] * 4
|
||||||
|
for j := uint64(20); j <= maxReorgLength; j = j + 8 {
|
||||||
|
maxStartBlock := sprintSizes[i] - 1
|
||||||
|
for k := sprintSizes[i] / 2; k <= maxStartBlock; k = k + 8 {
|
||||||
|
for l := uint64(0); l < uint64(len(faultyNodes)); l++ {
|
||||||
|
if j+k < sprintSizes[i] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
reorgsLengthTest := map[string]interface{}{
|
||||||
|
"reorgLength": j,
|
||||||
|
"startBlock": k,
|
||||||
|
"sprintSize": sprintSizes[i],
|
||||||
|
"faultyNodes": faultyNodes[l], // node 1(index) is primary validator of the first sprint
|
||||||
|
"milestoneLength": milestoneLength[m],
|
||||||
|
}
|
||||||
|
reorgsLengthTests = append(reorgsLengthTests, reorgsLengthTest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// reorgsLengthTests := []map[string]uint64{
|
||||||
|
// {
|
||||||
|
// "reorgLength": 3,
|
||||||
|
// "startBlock": 7,
|
||||||
|
// "sprintSize": 8,
|
||||||
|
// "faultyNode": 1,
|
||||||
|
// "milestoneLength": 32
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
return reorgsLengthTests
|
||||||
|
}
|
||||||
|
|
||||||
|
func SprintLengthMilestoneReorgIndividual(t *testing.T, index int, tt map[string]uint64) (uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
log.Warn("Case ----- ", "Index", index, "InducedReorgLength", tt["reorgLength"], "BlockStart", tt["startBlock"], "SprintSize", tt["startBlock"], "MilestoneFlag", tt["milestoneFlag"], "MilestoneLength", tt["milestoneLength"], "DisconnectedNode", tt["faultyNode"])
|
||||||
|
observerOldChainLength, faultyOldChainLength := SetupValidatorsAndTestSprintLengthMilestone(t, tt)
|
||||||
|
|
||||||
|
if observerOldChainLength > 0 {
|
||||||
|
log.Warn("Observer", "Old Chain length", observerOldChainLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
if faultyOldChainLength > 0 {
|
||||||
|
log.Warn("Faulty", "Old Chain length", faultyOldChainLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tt["reorgLength"], tt["startBlock"], tt["sprintSize"], tt["milestoneFlag"], tt["milestoneLength"], tt["faultyNode"], faultyOldChainLength, observerOldChainLength
|
||||||
|
}
|
||||||
|
|
||||||
|
func SprintLengthMilestoneReorgIndividual2Nodes(t *testing.T, index int, tt map[string]interface{}) (uint64, uint64, uint64, uint64, []uint64, uint64, uint64) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
log.Warn("Case ----- ", "Index", index, "InducedReorgLength", tt["reorgLength"], "BlockStart", tt["startBlock"], "SprintSize", tt["sprintSize"], "DisconnectedNode", tt["faultyNodes"])
|
||||||
|
observerOldChainLength, faultyOldChainLength := SetupValidatorsAndTest2NodesSprintLengthMilestone(t, tt)
|
||||||
|
|
||||||
|
if observerOldChainLength > 0 {
|
||||||
|
log.Warn("Observer", "Old Chain length", observerOldChainLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
if faultyOldChainLength > 0 {
|
||||||
|
log.Warn("Faulty", "Old Chain length", faultyOldChainLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
fNodes, _ := tt["faultyNodes"].([]uint64)
|
||||||
|
|
||||||
|
return tt["reorgLength"].(uint64), tt["startBlock"].(uint64), tt["sprintSize"].(uint64), tt["milestoneLength"].(uint64), fNodes, faultyOldChainLength, observerOldChainLength
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSprintLengthMilestoneReorg2Nodes(t *testing.T) {
|
||||||
|
t.Skip()
|
||||||
|
// t.Parallel()
|
||||||
|
|
||||||
|
log.Root().SetHandler(log.LvlFilterHandler(3, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||||
|
|
||||||
|
_, err := fdlimit.Raise(2048)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reorgsLengthTests := getTestSprintLengthMilestoneReorgCases2Nodes()
|
||||||
|
f, err := os.Create("sprintReorgMilestone2Nodes.csv")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
err = f.Close()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
_log.Fatalln("failed to open file", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
w := csv.NewWriter(f)
|
||||||
|
err = w.Write([]string{"Induced Reorg Length", "Start Block", "Sprint Size", "MilestoneLength", "Disconnected Node Ids", "Disconnected Node Id's Rewind Length", "Observer Node Id's Reorg Length"})
|
||||||
|
w.Flush()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for index, tt := range reorgsLengthTests {
|
||||||
|
if index%4 == 0 {
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
go SprintLengthMilestoneReorgIndividual2NodesHelper(t, index, tt, w, &wg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSprintLengthMilestoneReorg(t *testing.T) {
|
||||||
|
t.Skip()
|
||||||
|
// t.Parallel()
|
||||||
|
|
||||||
|
log.Root().SetHandler(log.LvlFilterHandler(3, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||||
|
|
||||||
|
_, err := fdlimit.Raise(2048)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reorgsLengthTests := getTestSprintLengthMilestoneReorgCases()
|
||||||
|
f, err := os.Create("sprintMilestoneReorg.csv")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
err = f.Close()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
_log.Fatalln("failed to open file", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
w := csv.NewWriter(f)
|
||||||
|
err = w.Write([]string{"Induced Reorg Length", "Start Block", "Sprint Size", "MilestoneFlag", "Milestone Length", "Disconnected Node Id", "Disconnected Node Id's Rewind Length", "Observer Node Id's Reorg Length"})
|
||||||
|
|
||||||
|
w.Flush()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = w.Write([]string{fmt.Sprint(len(reorgsLengthTests))})
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for index, tt := range reorgsLengthTests {
|
||||||
|
if index%4 == 0 {
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
go SprintLengthMilestoneReorgIndividualHelper(t, index, tt, w, &wg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SprintLengthMilestoneReorgIndividualHelper(t *testing.T, index int, tt map[string]uint64, w *csv.Writer, wg *sync.WaitGroup) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
r1, r2, r3, r4, r5, r6, r7, r8 := SprintLengthMilestoneReorgIndividual(t, index, tt)
|
||||||
|
err := w.Write([]string{fmt.Sprint(r1), fmt.Sprint(r2), fmt.Sprint(r3), fmt.Sprint(r4), fmt.Sprint(r5), fmt.Sprint(r6), fmt.Sprint(r7), fmt.Sprint(r8)})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Flush()
|
||||||
|
(*wg).Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func SprintLengthMilestoneReorgIndividual2NodesHelper(t *testing.T, index int, tt map[string]interface{}, w *csv.Writer, wg *sync.WaitGroup) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
r1, r2, r3, r4, r5, r6, r7 := SprintLengthMilestoneReorgIndividual2Nodes(t, index, tt)
|
||||||
|
err := w.Write([]string{fmt.Sprint(r1), fmt.Sprint(r2), fmt.Sprint(r3), fmt.Sprint(r4), fmt.Sprint(r5), fmt.Sprint(r6), fmt.Sprint(r7)})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Flush()
|
||||||
|
(*wg).Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint: gocognit
|
||||||
|
func SetupValidatorsAndTest2NodesSprintLengthMilestone(t *testing.T, tt map[string]interface{}) (uint64, uint64) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
log.Root().SetHandler(log.LvlFilterHandler(3, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||||
|
|
||||||
|
_, err := fdlimit.Raise(2048)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a batch of accounts to seal and fund with
|
||||||
|
faucets := make([]*ecdsa.PrivateKey, 128)
|
||||||
|
for i := 0; i < len(faucets); i++ {
|
||||||
|
faucets[i], _ = crypto.GenerateKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an Ethash network based off of the Ropsten config
|
||||||
|
// Generate a batch of accounts to seal and fund with
|
||||||
|
genesis := InitGenesis(t, faucets, "./testdata/genesis_7val.json", tt["sprintSize"].(uint64))
|
||||||
|
|
||||||
|
nodes := make([]*eth.Ethereum, len(keys_21val))
|
||||||
|
enodes := make([]*enode.Node, len(keys_21val))
|
||||||
|
stacks := make([]*node.Node, len(keys_21val))
|
||||||
|
|
||||||
|
pkeys_21val := make([]*ecdsa.PrivateKey, len(keys_21val))
|
||||||
|
|
||||||
|
for index, signerdata := range keys_21val {
|
||||||
|
pkeys_21val[index], _ = crypto.HexToECDSA(signerdata["priv_key"])
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(keys_21val); i++ {
|
||||||
|
// Start the node and wait until it's up
|
||||||
|
stack, ethBackend, err := InitMiner(genesis, pkeys_21val[i], true)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer stack.Close()
|
||||||
|
|
||||||
|
for stack.Server().NodeInfo().Ports.Listener == 0 {
|
||||||
|
time.Sleep(250 * time.Millisecond)
|
||||||
|
}
|
||||||
|
// Connect the node to all the previous ones
|
||||||
|
for j, n := range enodes {
|
||||||
|
if j < i {
|
||||||
|
stack.Server().AddPeer(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Start tracking the node and its enode
|
||||||
|
stacks[i] = stack
|
||||||
|
nodes[i] = ethBackend
|
||||||
|
enodes[i] = stack.Server().Self()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over all the nodes and start mining
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
|
|
||||||
|
for _, node := range nodes {
|
||||||
|
if err := node.StartMining(1); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
milestoneLength := tt["milestoneLength"].(uint64)
|
||||||
|
|
||||||
|
chain2HeadChObserver := make(chan core.Chain2HeadEvent, 64)
|
||||||
|
chain2HeadChFaulty := make(chan core.Chain2HeadEvent, 64)
|
||||||
|
|
||||||
|
var observerOldChainLength, faultyOldChainLength uint64
|
||||||
|
|
||||||
|
faultyProducerIndex := tt["faultyNodes"].([]uint64)[0] // node causing reorg :: faulty ::
|
||||||
|
subscribedNodeIndex := 6 // node on different partition, produces 7th sprint but our testcase does not run till 7th sprint. :: observer ::
|
||||||
|
|
||||||
|
nodes[subscribedNodeIndex].BlockChain().SubscribeChain2HeadEvent(chain2HeadChObserver)
|
||||||
|
nodes[faultyProducerIndex].BlockChain().SubscribeChain2HeadEvent(chain2HeadChFaulty)
|
||||||
|
|
||||||
|
stacks[faultyProducerIndex].Server().NoDiscovery = true
|
||||||
|
|
||||||
|
for {
|
||||||
|
blockHeaderObserver := nodes[subscribedNodeIndex].BlockChain().CurrentHeader()
|
||||||
|
blockHeaderFaulty := nodes[faultyProducerIndex].BlockChain().CurrentHeader()
|
||||||
|
|
||||||
|
log.Warn("Current Observer block", "number", blockHeaderObserver.Number, "hash", blockHeaderObserver.Hash())
|
||||||
|
log.Warn("Current Faulty block", "number", blockHeaderFaulty.Number, "hash", blockHeaderFaulty.Hash())
|
||||||
|
|
||||||
|
if blockHeaderObserver.Number.Uint64() >= tt["startBlock"].(uint64) && blockHeaderObserver.Number.Uint64() < tt["startBlock"].(uint64)+tt["reorgLength"].(uint64) {
|
||||||
|
for _, n := range tt["faultyNodes"].([]uint64) {
|
||||||
|
stacks[n].Server().MaxPeers = 1
|
||||||
|
|
||||||
|
for _, enode := range enodes {
|
||||||
|
stacks[n].Server().RemovePeer(enode)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range tt["faultyNodes"].([]uint64) {
|
||||||
|
stacks[m].Server().AddPeer(enodes[n])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if math.Mod(float64(blockHeaderObserver.Number.Uint64()), float64(milestoneLength)) == 0 {
|
||||||
|
blockHash := blockHeaderObserver.Hash()
|
||||||
|
nodes[subscribedNodeIndex].Downloader().ChainValidator.ProcessMilestone(blockHeaderObserver.Number.Uint64(), blockHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
if blockHeaderObserver.Number.Uint64() == tt["startBlock"].(uint64)+tt["reorgLength"].(uint64) {
|
||||||
|
stacks[faultyProducerIndex].Server().NoDiscovery = false
|
||||||
|
stacks[faultyProducerIndex].Server().MaxPeers = 100
|
||||||
|
|
||||||
|
for _, enode := range enodes {
|
||||||
|
stacks[faultyProducerIndex].Server().AddPeer(enode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if blockHeaderObserver.Number.Uint64() >= 255 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case ev := <-chain2HeadChObserver:
|
||||||
|
if ev.Type == core.Chain2HeadReorgEvent {
|
||||||
|
if len(ev.OldChain) > 1 {
|
||||||
|
observerOldChainLength = uint64(len(ev.OldChain))
|
||||||
|
return observerOldChainLength, 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case ev := <-chain2HeadChFaulty:
|
||||||
|
if ev.Type == core.Chain2HeadReorgEvent {
|
||||||
|
if len(ev.OldChain) > 1 {
|
||||||
|
faultyOldChainLength = uint64(len(ev.OldChain))
|
||||||
|
return 0, faultyOldChainLength
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetupValidatorsAndTestSprintLengthMilestone(t *testing.T, tt map[string]uint64) (uint64, uint64) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
log.Root().SetHandler(log.LvlFilterHandler(3, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||||
|
|
||||||
|
_, err := fdlimit.Raise(2048)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a batch of accounts to seal and fund with
|
||||||
|
faucets := make([]*ecdsa.PrivateKey, 128)
|
||||||
|
for i := 0; i < len(faucets); i++ {
|
||||||
|
faucets[i], _ = crypto.GenerateKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an Ethash network based off of the Ropsten config
|
||||||
|
// Generate a batch of accounts to seal and fund with
|
||||||
|
genesis := InitGenesis(t, faucets, "./testdata/genesis_7val.json", tt["sprintSize"])
|
||||||
|
|
||||||
|
nodes := make([]*eth.Ethereum, len(keys_21val))
|
||||||
|
enodes := make([]*enode.Node, len(keys_21val))
|
||||||
|
stacks := make([]*node.Node, len(keys_21val))
|
||||||
|
|
||||||
|
pkeys_21val := make([]*ecdsa.PrivateKey, len(keys_21val))
|
||||||
|
|
||||||
|
for index, signerdata := range keys_21val {
|
||||||
|
pkeys_21val[index], _ = crypto.HexToECDSA(signerdata["priv_key"])
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(keys_21val); i++ {
|
||||||
|
// Start the node and wait until it's up
|
||||||
|
stack, ethBackend, err := InitMiner(genesis, pkeys_21val[i], true)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer stack.Close()
|
||||||
|
|
||||||
|
for stack.Server().NodeInfo().Ports.Listener == 0 {
|
||||||
|
time.Sleep(250 * time.Millisecond)
|
||||||
|
}
|
||||||
|
// Connect the node to all the previous ones
|
||||||
|
for j, n := range enodes {
|
||||||
|
if j < i {
|
||||||
|
stack.Server().AddPeer(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Start tracking the node and its enode
|
||||||
|
stacks[i] = stack
|
||||||
|
nodes[i] = ethBackend
|
||||||
|
enodes[i] = stack.Server().Self()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over all the nodes and start mining
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
|
|
||||||
|
for _, node := range nodes {
|
||||||
|
if err := node.StartMining(1); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chain2HeadChObserver := make(chan core.Chain2HeadEvent, 64)
|
||||||
|
chain2HeadChFaulty := make(chan core.Chain2HeadEvent, 64)
|
||||||
|
|
||||||
|
var observerOldChainLength, faultyOldChainLength uint64
|
||||||
|
|
||||||
|
faultyProducerIndex := tt["faultyNode"] // node causing reorg :: faulty ::
|
||||||
|
subscribedNodeIndex := 6 // node on different partition, produces 7th sprint but our testcase does not run till 7th sprint. :: observer ::
|
||||||
|
|
||||||
|
milestoneLength := tt["milestoneLength"]
|
||||||
|
milestoneFlag := tt["milestoneFlag"]
|
||||||
|
|
||||||
|
nodes[subscribedNodeIndex].BlockChain().SubscribeChain2HeadEvent(chain2HeadChObserver)
|
||||||
|
nodes[faultyProducerIndex].BlockChain().SubscribeChain2HeadEvent(chain2HeadChFaulty)
|
||||||
|
|
||||||
|
stacks[faultyProducerIndex].Server().NoDiscovery = true
|
||||||
|
|
||||||
|
var milestoneNum uint64 = 0
|
||||||
|
var milestoneHash common.Hash
|
||||||
|
var lastRun uint64 = 0
|
||||||
|
|
||||||
|
for {
|
||||||
|
blockHeaderObserver := nodes[subscribedNodeIndex].BlockChain().CurrentHeader()
|
||||||
|
blockHeaderFaulty := nodes[faultyProducerIndex].BlockChain().CurrentHeader()
|
||||||
|
|
||||||
|
log.Warn("Current Observer block", "number", blockHeaderObserver.Number, "hash", blockHeaderObserver.Hash())
|
||||||
|
if blockHeaderFaulty != nil {
|
||||||
|
log.Warn("Current Faulty block", "number", blockHeaderFaulty.Number, "hash", blockHeaderFaulty.Hash())
|
||||||
|
}
|
||||||
|
|
||||||
|
if blockHeaderFaulty.Number.Uint64() == tt["startBlock"] {
|
||||||
|
stacks[faultyProducerIndex].Server().MaxPeers = 0
|
||||||
|
|
||||||
|
for _, enode := range enodes {
|
||||||
|
stacks[faultyProducerIndex].Server().RemovePeer(enode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if blockHeaderFaulty.Number.Uint64() >= tt["startBlock"] && blockHeaderFaulty.Number.Uint64() < tt["startBlock"]+tt["reorgLength"] {
|
||||||
|
for _, enode := range enodes {
|
||||||
|
stacks[faultyProducerIndex].Server().RemovePeer(enode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if milestoneFlag == 1 {
|
||||||
|
if blockHeaderObserver.Number.Uint64() >= milestoneLength && math.Mod(float64(blockHeaderObserver.Number.Uint64()), float64(milestoneLength)) == 0 && blockHeaderObserver.Number.Uint64() > milestoneNum {
|
||||||
|
milestoneNum = blockHeaderObserver.Number.Uint64()
|
||||||
|
milestoneHash = blockHeaderObserver.Hash()
|
||||||
|
}
|
||||||
|
|
||||||
|
if blockHeaderObserver.Number.Uint64() > lastRun {
|
||||||
|
for _, nodeTemp := range nodes {
|
||||||
|
_, _, err := borVerifyTemP(nodeTemp, milestoneNum-milestoneLength+1, milestoneNum, milestoneHash.String())
|
||||||
|
if err == nil {
|
||||||
|
nodeTemp.Downloader().ChainValidator.ProcessMilestone(milestoneNum, milestoneHash)
|
||||||
|
} else {
|
||||||
|
nodeTemp.Downloader().ChainValidator.ProcessFutureMilestone(milestoneNum, milestoneHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if blockHeaderFaulty.Number.Uint64() == tt["startBlock"]+tt["reorgLength"] {
|
||||||
|
stacks[faultyProducerIndex].Server().NoDiscovery = false
|
||||||
|
stacks[faultyProducerIndex].Server().MaxPeers = 100
|
||||||
|
|
||||||
|
for _, enode := range enodes {
|
||||||
|
stacks[faultyProducerIndex].Server().AddPeer(enode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if blockHeaderFaulty.Number.Uint64() >= 150 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case ev := <-chain2HeadChObserver:
|
||||||
|
if ev.Type == core.Chain2HeadReorgEvent {
|
||||||
|
if len(ev.OldChain) > 1 {
|
||||||
|
observerOldChainLength = uint64(len(ev.OldChain))
|
||||||
|
return observerOldChainLength, 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case ev := <-chain2HeadChFaulty:
|
||||||
|
if ev.Type == core.Chain2HeadReorgEvent {
|
||||||
|
if len(ev.OldChain) > 1 {
|
||||||
|
faultyOldChainLength = uint64(len(ev.OldChain))
|
||||||
|
return 0, faultyOldChainLength
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func borVerifyTemP(eth *eth.Ethereum, start uint64, end uint64, hash string) (string, uint64, error) {
|
||||||
|
// check if we have the given blocks
|
||||||
|
currentBlock := eth.BlockChain().CurrentBlock()
|
||||||
|
|
||||||
|
if currentBlock == nil {
|
||||||
|
log.Debug("Failed to fetch current block from blockchain while verifying incoming milestone")
|
||||||
|
return hash, 0, errMissingBlocks
|
||||||
|
}
|
||||||
|
|
||||||
|
head := currentBlock.Number.Uint64()
|
||||||
|
if head < end {
|
||||||
|
log.Debug("Current head block behind incoming milestone block", "head", head, "end block", end)
|
||||||
|
return hash, 0, errMissingBlocks
|
||||||
|
}
|
||||||
|
|
||||||
|
var localHash string
|
||||||
|
|
||||||
|
block := eth.BlockChain().GetBlockByNumber(end)
|
||||||
|
if block == nil {
|
||||||
|
log.Debug("Failed to get end block hash while whitelisting milestone", "number", end)
|
||||||
|
return hash, 0, errEndBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
localHash = block.Hash().String()
|
||||||
|
|
||||||
|
//nolint
|
||||||
|
if localHash != hash {
|
||||||
|
|
||||||
|
log.Warn("End block hash mismatch while whitelisting milestone", "expected", localHash, "got", hash)
|
||||||
|
var (
|
||||||
|
rewindTo uint64
|
||||||
|
doExist bool
|
||||||
|
)
|
||||||
|
|
||||||
|
if doExist, rewindTo, _ = eth.Downloader().GetWhitelistedMilestone(); doExist {
|
||||||
|
|
||||||
|
} else if doExist, rewindTo, _ = eth.Downloader().GetWhitelistedCheckpoint(); doExist {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if start <= 0 {
|
||||||
|
rewindTo = 0
|
||||||
|
} else {
|
||||||
|
rewindTo = start - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if head-rewindTo > 255 {
|
||||||
|
rewindTo = head - 255
|
||||||
|
}
|
||||||
|
|
||||||
|
rewindBackTemp(eth, rewindTo)
|
||||||
|
|
||||||
|
return hash, rewindTo, errHashMismatch
|
||||||
|
}
|
||||||
|
|
||||||
|
return block.Hash().String(), 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the miner if the mining process is running and rewind back the chain
|
||||||
|
func rewindBackTemp(eth *eth.Ethereum, rewindTo uint64) {
|
||||||
|
if eth.Miner().Mining() {
|
||||||
|
ch := make(chan struct{})
|
||||||
|
eth.Miner().Stop(ch)
|
||||||
|
<-ch
|
||||||
|
rewindTemp(eth, rewindTo)
|
||||||
|
eth.StartMining(1)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
rewindTemp(eth, rewindTo)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func rewindTemp(eth *eth.Ethereum, rewindTo uint64) {
|
||||||
|
log.Warn("Rewinding chain to :", rewindTo, "block number")
|
||||||
|
err := eth.BlockChain().SetHead(rewindTo)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error while rewinding the chain to", "Block Number", rewindTo, "Error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/milestone"
|
||||||
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
"github.com/ethereum/go-ethereum/consensus/bor/valset"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
|
@ -370,20 +371,32 @@ func TestInsertingSpanSizeBlocks(t *testing.T) {
|
||||||
engine := init.ethereum.Engine()
|
engine := init.ethereum.Engine()
|
||||||
_bor := engine.(*bor.Bor)
|
_bor := engine.(*bor.Bor)
|
||||||
|
|
||||||
defer _bor.Close()
|
|
||||||
|
|
||||||
_, currentSpan := loadSpanFromFile(t)
|
_, currentSpan := loadSpanFromFile(t)
|
||||||
|
|
||||||
h, ctrl := getMockedHeimdallClient(t, currentSpan)
|
h, ctrl := getMockedHeimdallClient(t, currentSpan)
|
||||||
defer ctrl.Finish()
|
defer func() {
|
||||||
|
_bor.Close()
|
||||||
|
ctrl.Finish()
|
||||||
|
}()
|
||||||
|
|
||||||
h.EXPECT().Close().AnyTimes()
|
h.EXPECT().Close().AnyTimes()
|
||||||
|
|
||||||
h.EXPECT().FetchCheckpoint(gomock.Any(), int64(-1)).Return(&checkpoint.Checkpoint{
|
h.EXPECT().FetchCheckpoint(gomock.Any(), int64(-1)).Return(&checkpoint.Checkpoint{
|
||||||
Proposer: currentSpan.SelectedProducers[0].Address,
|
Proposer: currentSpan.SelectedProducers[0].Address,
|
||||||
StartBlock: big.NewInt(0),
|
StartBlock: big.NewInt(0),
|
||||||
EndBlock: big.NewInt(int64(spanSize)),
|
EndBlock: big.NewInt(int64(spanSize)),
|
||||||
}, nil).AnyTimes()
|
}, nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchMilestone(gomock.Any()).Return(&milestone.Milestone{
|
||||||
|
Proposer: currentSpan.SelectedProducers[0].Address,
|
||||||
|
StartBlock: big.NewInt(0),
|
||||||
|
EndBlock: big.NewInt(int64(spanSize)),
|
||||||
|
}, nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchLastNoAckMilestone(gomock.Any()).Return("", nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchNoAckMilestone(gomock.Any(), string("test")).Return(nil).AnyTimes()
|
||||||
|
|
||||||
_bor.SetHeimdallClient(h)
|
_bor.SetHeimdallClient(h)
|
||||||
|
|
||||||
block := init.genesis.ToBlock()
|
block := init.genesis.ToBlock()
|
||||||
|
|
@ -450,8 +463,17 @@ func TestFetchStateSyncEvents(t *testing.T) {
|
||||||
|
|
||||||
h := mocks.NewMockIHeimdallClient(ctrl)
|
h := mocks.NewMockIHeimdallClient(ctrl)
|
||||||
h.EXPECT().Close().AnyTimes()
|
h.EXPECT().Close().AnyTimes()
|
||||||
|
|
||||||
h.EXPECT().Span(gomock.Any(), uint64(1)).Return(&res.Result, nil).AnyTimes()
|
h.EXPECT().Span(gomock.Any(), uint64(1)).Return(&res.Result, nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchCheckpoint(gomock.Any(), int64(-1)).Return(&checkpoint.Checkpoint{}, nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchMilestone(gomock.Any()).Return(&milestone.Milestone{}, nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchLastNoAckMilestone(gomock.Any()).Return("", nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchNoAckMilestone(gomock.Any(), string("test")).Return(nil).AnyTimes()
|
||||||
|
|
||||||
// B.2 Mock State Sync events
|
// B.2 Mock State Sync events
|
||||||
fromID := uint64(1)
|
fromID := uint64(1)
|
||||||
// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
|
// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
|
||||||
|
|
@ -500,8 +522,17 @@ func TestFetchStateSyncEvents_2(t *testing.T) {
|
||||||
|
|
||||||
h := mocks.NewMockIHeimdallClient(ctrl)
|
h := mocks.NewMockIHeimdallClient(ctrl)
|
||||||
h.EXPECT().Close().AnyTimes()
|
h.EXPECT().Close().AnyTimes()
|
||||||
|
|
||||||
h.EXPECT().Span(gomock.Any(), uint64(1)).Return(&res.Result, nil).AnyTimes()
|
h.EXPECT().Span(gomock.Any(), uint64(1)).Return(&res.Result, nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchCheckpoint(gomock.Any(), int64(-1)).Return(&checkpoint.Checkpoint{}, nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchMilestone(gomock.Any()).Return(&milestone.Milestone{}, nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchLastNoAckMilestone(gomock.Any()).Return("", nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchNoAckMilestone(gomock.Any(), string("test")).Return(nil).AnyTimes()
|
||||||
|
|
||||||
// Mock State Sync events
|
// Mock State Sync events
|
||||||
// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
|
// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
|
||||||
fromID := uint64(1)
|
fromID := uint64(1)
|
||||||
|
|
@ -592,8 +623,17 @@ func TestOutOfTurnSigning(t *testing.T) {
|
||||||
|
|
||||||
h.EXPECT().Close().AnyTimes()
|
h.EXPECT().Close().AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchCheckpoint(gomock.Any(), int64(-1)).Return(&checkpoint.Checkpoint{}, nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchMilestone(gomock.Any()).Return(&milestone.Milestone{}, nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchLastNoAckMilestone(gomock.Any()).Return("", nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchNoAckMilestone(gomock.Any(), string("test")).Return(nil).AnyTimes()
|
||||||
|
|
||||||
spanner := getMockedSpanner(t, heimdallSpan.ValidatorSet.Validators)
|
spanner := getMockedSpanner(t, heimdallSpan.ValidatorSet.Validators)
|
||||||
_bor.SetSpanner(spanner)
|
_bor.SetSpanner(spanner)
|
||||||
|
|
||||||
_bor.SetHeimdallClient(h)
|
_bor.SetHeimdallClient(h)
|
||||||
|
|
||||||
block := init.genesis.ToBlock()
|
block := init.genesis.ToBlock()
|
||||||
|
|
@ -673,6 +713,13 @@ func TestSignerNotFound(t *testing.T) {
|
||||||
defer ctrl.Finish()
|
defer ctrl.Finish()
|
||||||
|
|
||||||
h.EXPECT().Close().AnyTimes()
|
h.EXPECT().Close().AnyTimes()
|
||||||
|
h.EXPECT().FetchCheckpoint(gomock.Any(), int64(-1)).Return(&checkpoint.Checkpoint{}, nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchMilestone(gomock.Any()).Return(&milestone.Milestone{}, nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchLastNoAckMilestone(gomock.Any()).Return("", nil).AnyTimes()
|
||||||
|
|
||||||
|
h.EXPECT().FetchNoAckMilestone(gomock.Any(), string("test")).Return(nil).AnyTimes()
|
||||||
|
|
||||||
_bor.SetHeimdallClient(h)
|
_bor.SetHeimdallClient(h)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
clerk "github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
clerk "github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||||
checkpoint "github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
checkpoint "github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||||
|
milestone "github.com/ethereum/go-ethereum/consensus/bor/heimdall/milestone"
|
||||||
span "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
span "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||||
gomock "github.com/golang/mock/gomock"
|
gomock "github.com/golang/mock/gomock"
|
||||||
)
|
)
|
||||||
|
|
@ -79,6 +80,79 @@ func (mr *MockIHeimdallClientMockRecorder) FetchCheckpointCount(arg0 interface{}
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchCheckpointCount", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchCheckpointCount), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchCheckpointCount", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchCheckpointCount), arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FetchLastNoAckMilestone mocks base method.
|
||||||
|
func (m *MockIHeimdallClient) FetchLastNoAckMilestone(arg0 context.Context) (string, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "FetchLastNoAckMilestone", arg0)
|
||||||
|
ret0, _ := ret[0].(string)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchLastNoAckMilestone indicates an expected call of FetchLastNoAckMilestone.
|
||||||
|
func (mr *MockIHeimdallClientMockRecorder) FetchLastNoAckMilestone(arg0 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchLastNoAckMilestone", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchLastNoAckMilestone), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchMilestone mocks base method.
|
||||||
|
func (m *MockIHeimdallClient) FetchMilestone(arg0 context.Context) (*milestone.Milestone, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "FetchMilestone", arg0)
|
||||||
|
ret0, _ := ret[0].(*milestone.Milestone)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchMilestone indicates an expected call of FetchMilestone.
|
||||||
|
func (mr *MockIHeimdallClientMockRecorder) FetchMilestone(arg0 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchMilestone", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchMilestone), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchMilestoneCount mocks base method.
|
||||||
|
func (m *MockIHeimdallClient) FetchMilestoneCount(arg0 context.Context) (int64, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "FetchMilestoneCount", arg0)
|
||||||
|
ret0, _ := ret[0].(int64)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchMilestoneCount indicates an expected call of FetchMilestoneCount.
|
||||||
|
func (mr *MockIHeimdallClientMockRecorder) FetchMilestoneCount(arg0 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchMilestoneCount", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchMilestoneCount), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchMilestoneID mocks base method.
|
||||||
|
func (m *MockIHeimdallClient) FetchMilestoneID(arg0 context.Context, arg1 string) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "FetchMilestoneID", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchMilestoneID indicates an expected call of FetchMilestoneID.
|
||||||
|
func (mr *MockIHeimdallClientMockRecorder) FetchMilestoneID(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchMilestoneID", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchMilestoneID), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchNoAckMilestone mocks base method.
|
||||||
|
func (m *MockIHeimdallClient) FetchNoAckMilestone(arg0 context.Context, arg1 string) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "FetchNoAckMilestone", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchNoAckMilestone indicates an expected call of FetchNoAckMilestone.
|
||||||
|
func (mr *MockIHeimdallClientMockRecorder) FetchNoAckMilestone(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchNoAckMilestone", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchNoAckMilestone), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// Span mocks base method.
|
// Span mocks base method.
|
||||||
func (m *MockIHeimdallClient) Span(arg0 context.Context, arg1 uint64) (*span.HeimdallSpan, error) {
|
func (m *MockIHeimdallClient) Span(arg0 context.Context, arg1 uint64) (*span.HeimdallSpan, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue