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:
Arpit Temani 2023-08-28 18:42:21 +05:30 committed by GitHub
parent b38412dd9b
commit b48b89f852
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
58 changed files with 5639 additions and 612 deletions

View file

@ -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 {

View file

@ -0,0 +1,3 @@
package flags
const Milestone = true

5
common/gererics/empty.go Normal file
View file

@ -0,0 +1,5 @@
package gererics
func Empty[T any]() (t T) {
return
}

View file

@ -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 {

View file

@ -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()
} }

View file

@ -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 {

View file

@ -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) {

View file

@ -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),
},
} }
) )

View 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"`
}

View file

@ -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(),

View file

@ -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()})
}

View 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,
}
}

View file

@ -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
} }

View 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
}

View file

@ -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.

View file

@ -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 {

View file

@ -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 {

View file

@ -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
View 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
View 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
}

View file

@ -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")
}

View file

@ -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()
} }

View file

@ -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

View file

@ -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)

View file

@ -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 { var (
verify func(ctx context.Context, handler *ethHandler, checkpoint *checkpoint.Checkpoint) (string, error) // errMissingBlocks is returned when we don't have the blocks locally, yet.
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)
)
type borVerifier struct {
verify func(ctx context.Context, eth *Ethereum, handler *ethHandler, start uint64, end uint64, hash string, isCheckpoint bool) (string, error)
} }
func newCheckpointVerifier(verifyFn func(ctx context.Context, handler *ethHandler, checkpoint *checkpoint.Checkpoint) (string, error)) *checkpointVerifier { func newBorVerifier() *borVerifier {
if verifyFn != nil { return &borVerifier{borVerify}
return &checkpointVerifier{verifyFn} }
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"
} }
verifyFn = func(ctx context.Context, handler *ethHandler, checkpoint *checkpoint.Checkpoint) (string, error) { // 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 {
log.Debug("Failed to get root hash of given block range while whitelisting checkpoint", "start", start, "end", end, "err", err)
return hash, errRootHash
}
} else {
// in case of milestone(isCheckpoint==false) get the hash of endBlock
block, err := handler.ethAPI.GetBlockByNumber(ctx, rpc.BlockNumber(end), false)
if err != nil {
log.Debug("Failed to get end block hash while whitelisting milestone", "number", end, "err", err)
return hash, errEndBlock
}
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 ( var (
startBlock = checkpoint.StartBlock.Uint64() rewindTo uint64
endBlock = checkpoint.EndBlock.Uint64() doExist bool
) )
// check if we have the checkpoint blocks if doExist, rewindTo, _ = ethHandler.downloader.GetWhitelistedMilestone(); doExist {
//nolint:contextcheck
head := handler.ethAPI.BlockNumber() } else if doExist, rewindTo, _ = ethHandler.downloader.GetWhitelistedCheckpoint(); doExist {
if head < hexutil.Uint64(endBlock) {
log.Debug("Head block behind checkpoint block", "head", head, "checkpoint end block", endBlock) } else {
return "", errMissingCheckpoint if start <= 0 {
rewindTo = 0
} else {
rewindTo = start - 1
}
} }
// verify the root hash of checkpoint if head-rewindTo > 255 {
roothash, err := handler.ethAPI.GetRootHash(ctx, startBlock, endBlock) 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 { if err != nil {
log.Debug("Failed to get root hash of checkpoint while whitelisting", "err", err) log.Debug("Failed to get end block hash while whitelisting", "err", err)
return "", errRootHash return hash, errEndBlock
} }
if roothash != checkpoint.RootHash.String()[2:] { hash = fmt.Sprintf("%v", block["hash"])
log.Warn("Checkpoint root hash mismatch while whitelisting", "expected", checkpoint.RootHash.String()[2:], "got", roothash)
return "", errCheckpointRootHashMismatch
}
// fetch the end checkpoint block hash
block, err := handler.ethAPI.GetBlockByNumber(ctx, rpc.BlockNumber(endBlock), false)
if err != nil {
log.Debug("Failed to get end block hash of checkpoint while whitelisting", "err", err)
return "", errEndBlock
}
hash := fmt.Sprintf("%v", block["hash"])
return hash, nil return hash, nil
}
// 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))
} }
return &checkpointVerifier{verifyFn}
} }

View file

@ -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.

View file

@ -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

View 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))
}

View 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
}

View 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)
}
}

View file

@ -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
lastCheckpointBlockNum := w.checkpointOrder[len(w.checkpointOrder)-1]
lastCheckpointBlockHash := w.checkpointWhitelist[lastCheckpointBlockNum]
// 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 {
return false, fmt.Errorf("%w: last checkpoint %d, err %v", ErrNoRemoteCheckpoint, lastCheckpointBlockNum, err)
}
if len(headers) == 0 {
return false, fmt.Errorf("%w: last checkpoint %d", ErrNoRemoteCheckpoint, lastCheckpointBlockNum)
}
reqBlockNum := headers[0].Number.Uint64()
reqBlockHash := hashes[0]
// Check against the checkpointed blocks
if reqBlockNum == lastCheckpointBlockNum && reqBlockHash == lastCheckpointBlockHash {
return true, nil
}
return false, ErrCheckpointMismatch
} }
// IsValidChain checks the validity of chain by comparing it func NewService(db ethdb.Database) *Service {
// against the local checkpoint entries var checkpointDoExist = true
func (w *Service) IsValidChain(currentHeader *types.Header, chain []*types.Header) (bool, error) {
// Check if we have checkpoints to validate incoming chain in memory checkpointNumber, checkpointHash, err := rawdb.ReadFinality[*rawdb.Checkpoint](db)
if len(w.checkpointWhitelist) == 0 {
// We don't have any entries, no additional validation will be possible if err != nil {
return true, nil checkpointDoExist = false
} }
// Return if we've received empty chain var milestoneDoExist = true
if len(chain) == 0 {
return false, nil milestoneNumber, milestoneHash, err := rawdb.ReadFinality[*rawdb.Milestone](db)
if err != nil {
milestoneDoExist = false
} }
var ( locked, lockedMilestoneNumber, lockedMilestoneHash, lockedMilestoneIDs, err := rawdb.ReadLockField(db)
oldestCheckpointNumber uint64 = w.checkpointOrder[0] if err != nil || !locked {
current uint64 = currentHeader.Number.Uint64() locked = false
) lockedMilestoneIDs = make(map[string]struct{})
// 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 order, list, err := rawdb.ReadFutureMilestoneList(db)
pastChain, _ := splitChain(current, chain) if err != nil {
order = make([]uint64, 0)
// Note: Do not act on future chain and allow importing all kinds of future chains. list = make(map[uint64]common.Hash)
// 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 &Service{
&checkpoint{
finality[*rawdb.Checkpoint]{
doExist: checkpointDoExist,
Number: checkpointNumber,
Hash: checkpointHash,
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,
},
}
}
// 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 checkpoint submitted to mainchain and last milestone voted in the heimdall
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
}
milestoneBool, err := s.milestoneService.IsValidPeer(fetchHeadersByNumber)
if !milestoneBool {
return milestoneBool, err
} }
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 {
w.enqueueCheckpointWhitelist(endBlockNum, endBlockHash) // We don't have any entry, no additional validation will be possible
// If size of checkpoint whitelist map is greater than 10, remove the oldest entry. return true, nil
if w.length() > int(w.maxCapacity) {
w.dequeueCheckpointWhitelist()
} }
}
// GetCheckpointWhitelist returns the existing whitelisted current := currentHeader.Number.Uint64()
// entries of checkpoint of the form block number -> block hash.
func (w *Service) GetCheckpointWhitelist() map[uint64]common.Hash {
w.m.Lock()
defer w.m.Unlock()
return w.checkpointWhitelist // Check if imported chain is less than whitelisted number
} 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
// PurgeCheckpointWhitelist purges data from checkpoint whitelist map return false, nil
func (w *Service) PurgeCheckpointWhitelist() { } else {
w.m.Lock() return true, nil
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
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
} }
// Split the chain into past and future chain
pastChain, _ := splitChain(current, chain)
// 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
return res, nil
}
}
return true, nil
} }
// 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
} }

View file

@ -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)),

View file

@ -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()

View file

@ -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)

View file

@ -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 blockNums, blockHashes, nil return blockNum, blockHash, 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
} }

View file

@ -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,78 +38,112 @@ 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 := &ethHandler{} handler := &ethHandler{}
// 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) {
@ -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
}

View file

@ -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
View file

@ -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
View file

@ -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=

View file

@ -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
} }

View file

@ -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)

View file

@ -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 {

View file

@ -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
// //

View file

@ -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() {}

View file

@ -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,
}),
] ]
}); });
` `

View file

@ -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({

View file

@ -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() {
} }

View file

@ -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
} }

View file

@ -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() {

View file

@ -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)
} }

View file

@ -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{}

View file

@ -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()

File diff suppressed because it is too large Load diff

View file

@ -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")

View 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)
}
}

View file

@ -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)

View file

@ -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()