mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-07 20:43:48 +00:00
* Merge qa to master (#750) * Added checks to RPC requests and introduced new flags to customise the parameters (#657) * added a check to reject rpc requests with batch size > the one set using a newly added flag (rpcbatchlimit) * added a check to reject rpc requests whose result size > the one set using a newly added flag (rpcreturndatalimit) * updated the config files and docs * chg : trieTimeout from 60 to 10 mins (#692) * chg : trieTimeout from 60 to 10 mins * chg : cache.timout to 10m from 1h in configs * internal/cli/server : fix : added triesInMemory in config (#691) * changed version from 0.3.0 to 0.3.4-beta (#693) * fix nil state-sync issue, increase grpc limit (#695) * Increase grpc message size limit in pprof * consensus/bor/bor.go : stateSyncs init fixed [Fix #686] * eth/filters: handle nil state-sync before notify * eth/filters: update check Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Daniil <daniil.melnik@chainstack.com> * core, tests/bor: add more tests for state-sync validation (#710) * core: add get state sync function for tests * tests/bor: add validation for state sync events post consensus * Arpit/temp bor sync (#701) * Increase grpc message size limit in pprof * ReadBorReceipts improvements * use internal function * fix tests * fetch geth upstread for ReadBorReceiptRLP * Only query bor receipt when the query index is equal to # tx in block body This change reduces the frequency of calling ReadBorReceipt and ReadBorTransaction, which are CPU and db intensive. * Revert "fetch geth upstread for ReadBorReceiptRLP" This reverts commit 2e838a6b1313d26674f3a8df4b044e35dcbf35a0. * Restore ReadBorReceiptRLP * fix bor receipts * remove unused * fix lints --------- Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Manav Darji <manavdarji.india@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> * Revert "chg : trieTimeout from 60 to 10 mins (#692)" (#720) This reverts commit241843c7e7. * Arpit/add execution pool 2 (#719) * initial * linters * linters * remove timeout * update pool * change pool size function * check nil * check nil * fix tests * Use execution pool from server in all handlers * simplify things * test fix * add support for cli, config * add to cli and config * merge base branch * debug statements * fix bug * atomic pointer timeout * add apis * update workerpool * fix issues * change params * fix issues * fix ipc issue * remove execution pool from IPC * revert * fix tests * mutex * refactor flag and value names * ordering fix * refactor flag and value names * update default ep size to 40 * fix bor start issues * revert file changes * debug statements * fix bug * update workerpool * atomic pointer timeout * add apis * Merge branch 'add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * fix issues * change params * fix issues * fix ipc issue * remove execution pool from IPC * revert * merge base branch * Merge branch 'add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * mutex * fix tests * Merge branch 'arpit/add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * Change default size of execution pool to 40 * refactor flag and value names * fix merge conflicts * ordering fix * refactor flag and value names * update default ep size to 40 * fix bor start issues * revert file changes * fix linters * fix go.mod * change sec to ms * change default value for ep timeout * fix node api calls * comment setter for ep timeout --------- Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Manav Darji <manavdarji.india@gmail.com> * version change (#721) * Event based pprof (#732) * feature * Save pprof to /tmp --------- Co-authored-by: Jerry <jerrycgh@gmail.com> * Cherry-pick changes from develop (#738) * Check if block is nil to prevent panic (#736) * miner: use env for tracing instead of block object (#728) --------- Co-authored-by: Dmitry <46797839+dkeysil@users.noreply.github.com> * add max code init size check in txpool (#739) * Revert "Event based pprof" and update version (#742) * Revert "Event based pprof (#732)" This reverts commit22fa4033e8. * params: update version to 0.3.4-beta3 * packaging/templates: update bor version * params, packaging/templates: update bor version --------- Co-authored-by: SHIVAM SHARMA <shivam691999@gmail.com> Co-authored-by: Pratik Patil <pratikspatil024@gmail.com> Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Daniil <daniil.melnik@chainstack.com> Co-authored-by: Arpit Temani <temaniarpit27@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: Dmitry <46797839+dkeysil@users.noreply.github.com> * core, miner: add sub-spans for tracing (#753) * core, miner: add sub-spans for tracing * fix linters * core: add logs for debugging * core: add more logs to print tdd while reorg * fix linters * core: minor fix * core: remove debug logs * core: use different span for write block and set head * core: use internal context for sending traces (#755) * core: add : impossible reorg block dump (#754) * add : impossible reorg block dump * chg : 3 seperate files for impossoble reorg dump * add : use exportBlocks method and RLP blocks before writing * chg : small changes * bump : go version from 1.19 to 1.20.1 (#761) * Revert "bump : go version from 1.19 to 1.20.1 (#761)" This reverts commit4561012af9. * core/vm: use optimized bigint (#26021) * Add holiman/big * Fix linter * Bump version to v0.3.5 * fix lints from develop (few lints decided to appear from code that was untouched, weird) * upgrade crypto lib version (#770) * bump dep : github.com/Masterminds/goutils to v1.1.1 (#769) * mardizzone/pos-1313: bump crypto dependency (#772) * dev: chg: bumd net dependency * dev: chg: bump crypto dependency * dev: chg: bump crypto dependency * bump dep : golang.org/x/net to v0.8.0 (#771) * Verify validator set against local contract on receiving an end-of-sprint block (#768) * Verify validator set against local contract on receiving an end-of-sprint block * Fix tests * Respect error returned by ParseValidators * Keep going back until a parent block presents * core/txpool: implement DoS defenses from geth (#778) * Hotfixes and deps bump (#776) * dev: chg: bump deps * internal/cli/server, rpc: lower down http readtimeout to 10s * dev: chg: get p2p adapter * dev: chg: lower down jsonrpc readtimeout to 10s * cherry-pick txpool optimisation changes * add check for empty lists in txpool (#704) * add check * linters * core, miner: add empty instrumentation name for tracing --------- Co-authored-by: Raneet Debnath <raneetdebnath10@gmail.com> Co-authored-by: SHIVAM SHARMA <shivam691999@gmail.com> Co-authored-by: Evgeny Danilenko <6655321@bk.ru> Co-authored-by: Manav Darji <manavdarji.india@gmail.com> * packaging,params: bump to v0.3.6 (#782) * v0.3.6 fix (#787) * Fix get validator set in header verifier * chg : commit tx logs from info to debug (#673) * chg : commit tx logs from info to debug * fix : minor changes * chg : miner : commitTransactions-stats moved from info to debug * lint : fix linters * refactor logging * miner : chg : UnauthorizedSignerError to debug * lint : fix lint * fix : log.Logger interface compatibility --------- Co-authored-by: Evgeny Danienko <6655321@bk.ru> * Remove unnecessary sorting of valset from header in verification * dev: chg: version bump --------- Co-authored-by: SHIVAM SHARMA <shivam691999@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: marcello33 <marcelloardizzone@hotmail.it> * core: improve locks in txpool (#807) * added a write lock to the txs.filter method and a read lock to the txs.reheap method - both of which are called by Filter during reorg adjustments to txpool * txpool reorg locks * more locks * locks * linters * params, packaging: update version for v0.3.8-beta release * core: add logs in reheap --------- Co-authored-by: Alex <dalexwatts@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> * Merge qa to master (#808) * Added checks to RPC requests and introduced new flags to customise the parameters (#657) * added a check to reject rpc requests with batch size > the one set using a newly added flag (rpcbatchlimit) * added a check to reject rpc requests whose result size > the one set using a newly added flag (rpcreturndatalimit) * updated the config files and docs * chg : trieTimeout from 60 to 10 mins (#692) * chg : trieTimeout from 60 to 10 mins * chg : cache.timout to 10m from 1h in configs * internal/cli/server : fix : added triesInMemory in config (#691) * changed version from 0.3.0 to 0.3.4-beta (#693) * fix nil state-sync issue, increase grpc limit (#695) * Increase grpc message size limit in pprof * consensus/bor/bor.go : stateSyncs init fixed [Fix #686] * eth/filters: handle nil state-sync before notify * eth/filters: update check Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Daniil <daniil.melnik@chainstack.com> * core, tests/bor: add more tests for state-sync validation (#710) * core: add get state sync function for tests * tests/bor: add validation for state sync events post consensus * Arpit/temp bor sync (#701) * Increase grpc message size limit in pprof * ReadBorReceipts improvements * use internal function * fix tests * fetch geth upstread for ReadBorReceiptRLP * Only query bor receipt when the query index is equal to # tx in block body This change reduces the frequency of calling ReadBorReceipt and ReadBorTransaction, which are CPU and db intensive. * Revert "fetch geth upstread for ReadBorReceiptRLP" This reverts commit 2e838a6b1313d26674f3a8df4b044e35dcbf35a0. * Restore ReadBorReceiptRLP * fix bor receipts * remove unused * fix lints --------- Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Manav Darji <manavdarji.india@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> * Revert "chg : trieTimeout from 60 to 10 mins (#692)" (#720) This reverts commit241843c7e7. * Arpit/add execution pool 2 (#719) * initial * linters * linters * remove timeout * update pool * change pool size function * check nil * check nil * fix tests * Use execution pool from server in all handlers * simplify things * test fix * add support for cli, config * add to cli and config * merge base branch * debug statements * fix bug * atomic pointer timeout * add apis * update workerpool * fix issues * change params * fix issues * fix ipc issue * remove execution pool from IPC * revert * fix tests * mutex * refactor flag and value names * ordering fix * refactor flag and value names * update default ep size to 40 * fix bor start issues * revert file changes * debug statements * fix bug * update workerpool * atomic pointer timeout * add apis * Merge branch 'add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * fix issues * change params * fix issues * fix ipc issue * remove execution pool from IPC * revert * merge base branch * Merge branch 'add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * mutex * fix tests * Merge branch 'arpit/add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * Change default size of execution pool to 40 * refactor flag and value names * fix merge conflicts * ordering fix * refactor flag and value names * update default ep size to 40 * fix bor start issues * revert file changes * fix linters * fix go.mod * change sec to ms * change default value for ep timeout * fix node api calls * comment setter for ep timeout --------- Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Manav Darji <manavdarji.india@gmail.com> * version change (#721) * Event based pprof (#732) * feature * Save pprof to /tmp --------- Co-authored-by: Jerry <jerrycgh@gmail.com> * Cherry-pick changes from develop (#738) * Check if block is nil to prevent panic (#736) * miner: use env for tracing instead of block object (#728) --------- Co-authored-by: Dmitry <46797839+dkeysil@users.noreply.github.com> * add max code init size check in txpool (#739) * Revert "Event based pprof" and update version (#742) * Revert "Event based pprof (#732)" This reverts commit22fa4033e8. * params: update version to 0.3.4-beta3 * packaging/templates: update bor version * internal/ethapi :: Fix : newRPCTransactionFromBlockIndex * fix: remove assignment for bor receipt --------- Co-authored-by: SHIVAM SHARMA <shivam691999@gmail.com> Co-authored-by: Pratik Patil <pratikspatil024@gmail.com> Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Daniil <daniil.melnik@chainstack.com> Co-authored-by: Arpit Temani <temaniarpit27@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: Dmitry <46797839+dkeysil@users.noreply.github.com> * Setting up bor to use hosted 18.04 runner as ubuntu provided 18.04 runner is end of life --------- Co-authored-by: SHIVAM SHARMA <shivam691999@gmail.com> Co-authored-by: Pratik Patil <pratikspatil024@gmail.com> Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Daniil <daniil.melnik@chainstack.com> Co-authored-by: Arpit Temani <temaniarpit27@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: Dmitry <46797839+dkeysil@users.noreply.github.com> Co-authored-by: Martin Holst Swende <martin@swende.se> Co-authored-by: marcello33 <marcelloardizzone@hotmail.it> Co-authored-by: Raneet Debnath <raneetdebnath10@gmail.com> Co-authored-by: Raneet Debnath <35629432+Raneet10@users.noreply.github.com> Co-authored-by: Alex <dalexwatts@gmail.com> Co-authored-by: Daniel Jones <djones@polygon.technology>
465 lines
13 KiB
Go
465 lines
13 KiB
Go
// Copyright 2018 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package dnsdisc
|
|
|
|
import (
|
|
"context"
|
|
"crypto/ecdsa"
|
|
"errors"
|
|
"math/rand"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/davecgh/go-spew/spew"
|
|
"github.com/ethereum/go-ethereum/common/mclock"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/ethereum/go-ethereum/internal/testlog"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
|
"github.com/ethereum/go-ethereum/p2p/enr"
|
|
)
|
|
|
|
const (
|
|
signingKeySeed = 0x111111
|
|
nodesSeed1 = 0x2945237
|
|
nodesSeed2 = 0x4567299
|
|
)
|
|
|
|
func TestClientSyncTree(t *testing.T) {
|
|
r := mapResolver{
|
|
"n": "enrtree-root:v1 e=JWXYDBPXYWG6FX3GMDIBFA6CJ4 l=C7HRFPF3BLGF3YR4DY5KX3SMBE seq=1 sig=o908WmNp7LibOfPsr4btQwatZJ5URBr2ZAuxvK4UWHlsB9sUOTJQaGAlLPVAhM__XJesCHxLISo94z5Z2a463gA",
|
|
"C7HRFPF3BLGF3YR4DY5KX3SMBE.n": "enrtree://AM5FCQLWIZX2QFPNJAP7VUERCCRNGRHWZG3YYHIUV7BVDQ5FDPRT2@morenodes.example.org",
|
|
"JWXYDBPXYWG6FX3GMDIBFA6CJ4.n": "enrtree-branch:2XS2367YHAXJFGLZHVAWLQD4ZY,H4FHT4B454P6UXFD7JCYQ5PWDY,MHTDO6TMUBRIA2XWG5LUDACK24",
|
|
"2XS2367YHAXJFGLZHVAWLQD4ZY.n": "enr:-HW4QOFzoVLaFJnNhbgMoDXPnOvcdVuj7pDpqRvh6BRDO68aVi5ZcjB3vzQRZH2IcLBGHzo8uUN3snqmgTiE56CH3AMBgmlkgnY0iXNlY3AyNTZrMaECC2_24YYkYHEgdzxlSNKQEnHhuNAbNlMlWJxrJxbAFvA",
|
|
"H4FHT4B454P6UXFD7JCYQ5PWDY.n": "enr:-HW4QAggRauloj2SDLtIHN1XBkvhFZ1vtf1raYQp9TBW2RD5EEawDzbtSmlXUfnaHcvwOizhVYLtr7e6vw7NAf6mTuoCgmlkgnY0iXNlY3AyNTZrMaECjrXI8TLNXU0f8cthpAMxEshUyQlK-AM0PW2wfrnacNI",
|
|
"MHTDO6TMUBRIA2XWG5LUDACK24.n": "enr:-HW4QLAYqmrwllBEnzWWs7I5Ev2IAs7x_dZlbYdRdMUx5EyKHDXp7AV5CkuPGUPdvbv1_Ms1CPfhcGCvSElSosZmyoqAgmlkgnY0iXNlY3AyNTZrMaECriawHKWdDRk2xeZkrOXBQ0dfMFLHY4eENZwdufn1S1o",
|
|
}
|
|
var (
|
|
wantNodes = testNodes(0x29452, 3)
|
|
wantLinks = []string{"enrtree://AM5FCQLWIZX2QFPNJAP7VUERCCRNGRHWZG3YYHIUV7BVDQ5FDPRT2@morenodes.example.org"}
|
|
wantSeq = uint(1)
|
|
)
|
|
|
|
c := NewClient(Config{Resolver: r, Logger: testlog.Logger(t, log.LvlTrace)})
|
|
stree, err := c.SyncTree("enrtree://AKPYQIUQIL7PSIACI32J7FGZW56E5FKHEFCCOFHILBIMW3M6LWXS2@n")
|
|
|
|
if err != nil {
|
|
t.Fatal("sync error:", err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(sortByID(stree.Nodes()), sortByID(wantNodes)) {
|
|
t.Errorf("wrong nodes in synced tree:\nhave %v\nwant %v", spew.Sdump(stree.Nodes()), spew.Sdump(wantNodes))
|
|
}
|
|
|
|
if !reflect.DeepEqual(stree.Links(), wantLinks) {
|
|
t.Errorf("wrong links in synced tree: %v", stree.Links())
|
|
}
|
|
|
|
if stree.Seq() != wantSeq {
|
|
t.Errorf("synced tree has wrong seq: %d", stree.Seq())
|
|
}
|
|
}
|
|
|
|
// In this test, syncing the tree fails because it contains an invalid ENR entry.
|
|
func TestClientSyncTreeBadNode(t *testing.T) {
|
|
// var b strings.Builder
|
|
// b.WriteString(enrPrefix)
|
|
// b.WriteString("-----")
|
|
// badHash := subdomain(&b)
|
|
// tree, _ := MakeTree(3, nil, []string{"enrtree://AM5FCQLWIZX2QFPNJAP7VUERCCRNGRHWZG3YYHIUV7BVDQ5FDPRT2@morenodes.example.org"})
|
|
// tree.entries[badHash] = &b
|
|
// tree.root.eroot = badHash
|
|
// url, _ := tree.Sign(testKey(signingKeySeed), "n")
|
|
// fmt.Println(url)
|
|
// fmt.Printf("%#v\n", tree.ToTXT("n"))
|
|
|
|
r := mapResolver{
|
|
"n": "enrtree-root:v1 e=INDMVBZEEQ4ESVYAKGIYU74EAA l=C7HRFPF3BLGF3YR4DY5KX3SMBE seq=3 sig=Vl3AmunLur0JZ3sIyJPSH6A3Vvdp4F40jWQeCmkIhmcgwE4VC5U9wpK8C_uL_CMY29fd6FAhspRvq2z_VysTLAA",
|
|
"C7HRFPF3BLGF3YR4DY5KX3SMBE.n": "enrtree://AM5FCQLWIZX2QFPNJAP7VUERCCRNGRHWZG3YYHIUV7BVDQ5FDPRT2@morenodes.example.org",
|
|
"INDMVBZEEQ4ESVYAKGIYU74EAA.n": "enr:-----",
|
|
}
|
|
c := NewClient(Config{Resolver: r, Logger: testlog.Logger(t, log.LvlTrace)})
|
|
_, err := c.SyncTree("enrtree://AKPYQIUQIL7PSIACI32J7FGZW56E5FKHEFCCOFHILBIMW3M6LWXS2@n")
|
|
wantErr := nameError{name: "INDMVBZEEQ4ESVYAKGIYU74EAA.n", err: entryError{typ: "enr", err: errInvalidENR}}
|
|
if err != wantErr {
|
|
t.Fatalf("expected sync error %q, got %q", wantErr, err)
|
|
}
|
|
}
|
|
|
|
// This test checks that randomIterator finds all entries.
|
|
func TestIterator(t *testing.T) {
|
|
nodes := testNodes(nodesSeed1, 30)
|
|
tree, url := makeTestTree("n", nodes, nil)
|
|
r := mapResolver(tree.ToTXT("n"))
|
|
c := NewClient(Config{
|
|
Resolver: r,
|
|
Logger: testlog.Logger(t, log.LvlTrace),
|
|
RateLimit: 500,
|
|
})
|
|
it, err := c.NewIterator(url)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkIterator(t, it, nodes)
|
|
}
|
|
|
|
func TestIteratorCloseWithoutNext(t *testing.T) {
|
|
tree1, url1 := makeTestTree("t1", nil, nil)
|
|
c := NewClient(Config{Resolver: newMapResolver(tree1.ToTXT("t1"))})
|
|
it, err := c.NewIterator(url1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
it.Close()
|
|
ok := it.Next()
|
|
if ok {
|
|
t.Fatal("Next returned true after Close")
|
|
}
|
|
}
|
|
|
|
// This test checks if closing randomIterator races.
|
|
func TestIteratorClose(t *testing.T) {
|
|
nodes := testNodes(nodesSeed1, 500)
|
|
tree1, url1 := makeTestTree("t1", nodes, nil)
|
|
c := NewClient(Config{Resolver: newMapResolver(tree1.ToTXT("t1"))})
|
|
it, err := c.NewIterator(url1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
done := make(chan struct{})
|
|
go func() {
|
|
for it.Next() {
|
|
_ = it.Node()
|
|
}
|
|
close(done)
|
|
}()
|
|
|
|
time.Sleep(50 * time.Millisecond)
|
|
it.Close()
|
|
<-done
|
|
}
|
|
|
|
// This test checks that randomIterator traverses linked trees as well as explicitly added trees.
|
|
func TestIteratorLinks(t *testing.T) {
|
|
nodes := testNodes(nodesSeed1, 40)
|
|
tree1, url1 := makeTestTree("t1", nodes[:10], nil)
|
|
tree2, url2 := makeTestTree("t2", nodes[10:], []string{url1})
|
|
c := NewClient(Config{
|
|
Resolver: newMapResolver(tree1.ToTXT("t1"), tree2.ToTXT("t2")),
|
|
Logger: testlog.Logger(t, log.LvlTrace),
|
|
RateLimit: 500,
|
|
})
|
|
it, err := c.NewIterator(url2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkIterator(t, it, nodes)
|
|
}
|
|
|
|
// This test verifies that randomIterator re-checks the root of the tree to catch
|
|
// updates to nodes.
|
|
func TestIteratorNodeUpdates(t *testing.T) {
|
|
var (
|
|
clock = new(mclock.Simulated)
|
|
nodes = testNodes(nodesSeed1, 30)
|
|
resolver = newMapResolver()
|
|
c = NewClient(Config{
|
|
Resolver: resolver,
|
|
Logger: testlog.Logger(t, log.LvlTrace),
|
|
RecheckInterval: 20 * time.Minute,
|
|
RateLimit: 500,
|
|
})
|
|
)
|
|
c.clock = clock
|
|
tree1, url := makeTestTree("n", nodes[:25], nil)
|
|
it, err := c.NewIterator(url)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Sync the original tree.
|
|
resolver.add(tree1.ToTXT("n"))
|
|
checkIterator(t, it, nodes[:25])
|
|
|
|
// Ensure RandomNode returns the new nodes after the tree is updated.
|
|
updateSomeNodes(nodesSeed1, nodes)
|
|
tree2, _ := makeTestTree("n", nodes, nil)
|
|
resolver.clear()
|
|
resolver.add(tree2.ToTXT("n"))
|
|
t.Log("tree updated")
|
|
|
|
clock.Run(c.cfg.RecheckInterval + 1*time.Second)
|
|
checkIterator(t, it, nodes)
|
|
}
|
|
|
|
// This test checks that the tree root is rechecked when a couple of leaf
|
|
// requests have failed. The test is just like TestIteratorNodeUpdates, but
|
|
// without advancing the clock by recheckInterval after the tree update.
|
|
func TestIteratorRootRecheckOnFail(t *testing.T) {
|
|
var (
|
|
clock = new(mclock.Simulated)
|
|
nodes = testNodes(nodesSeed1, 30)
|
|
resolver = newMapResolver()
|
|
c = NewClient(Config{
|
|
Resolver: resolver,
|
|
Logger: testlog.Logger(t, log.LvlTrace),
|
|
RecheckInterval: 20 * time.Minute,
|
|
RateLimit: 500,
|
|
// Disabling the cache is required for this test because the client doesn't
|
|
// notice leaf failures if all records are cached.
|
|
CacheLimit: 1,
|
|
})
|
|
)
|
|
c.clock = clock
|
|
tree1, url := makeTestTree("n", nodes[:25], nil)
|
|
it, err := c.NewIterator(url)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Sync the original tree.
|
|
resolver.add(tree1.ToTXT("n"))
|
|
checkIterator(t, it, nodes[:25])
|
|
|
|
// Ensure RandomNode returns the new nodes after the tree is updated.
|
|
updateSomeNodes(nodesSeed1, nodes)
|
|
tree2, _ := makeTestTree("n", nodes, nil)
|
|
resolver.clear()
|
|
resolver.add(tree2.ToTXT("n"))
|
|
t.Log("tree updated")
|
|
|
|
checkIterator(t, it, nodes)
|
|
}
|
|
|
|
// This test checks that the iterator works correctly when the tree is initially empty.
|
|
func TestIteratorEmptyTree(t *testing.T) {
|
|
var (
|
|
clock = new(mclock.Simulated)
|
|
nodes = testNodes(nodesSeed1, 1)
|
|
resolver = newMapResolver()
|
|
c = NewClient(Config{
|
|
Resolver: resolver,
|
|
Logger: testlog.Logger(t, log.LvlTrace),
|
|
RecheckInterval: 20 * time.Minute,
|
|
RateLimit: 500,
|
|
})
|
|
)
|
|
c.clock = clock
|
|
tree1, url := makeTestTree("n", nil, nil)
|
|
tree2, _ := makeTestTree("n", nodes, nil)
|
|
resolver.add(tree1.ToTXT("n"))
|
|
|
|
// Start the iterator.
|
|
node := make(chan *enode.Node)
|
|
it, err := c.NewIterator(url)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
go func() {
|
|
it.Next()
|
|
node <- it.Node()
|
|
}()
|
|
|
|
// Wait for the client to get stuck in waitForRootUpdates.
|
|
clock.WaitForTimers(1)
|
|
|
|
// Now update the root.
|
|
resolver.add(tree2.ToTXT("n"))
|
|
|
|
// Wait for it to pick up the root change.
|
|
clock.Run(c.cfg.RecheckInterval)
|
|
select {
|
|
case n := <-node:
|
|
if n.ID() != nodes[0].ID() {
|
|
t.Fatalf("wrong node returned")
|
|
}
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("it.Next() did not unblock within 5s of real time")
|
|
}
|
|
}
|
|
|
|
// updateSomeNodes applies ENR updates to some of the given nodes.
|
|
func updateSomeNodes(keySeed int64, nodes []*enode.Node) {
|
|
keys := testKeys(keySeed, len(nodes))
|
|
for i, n := range nodes[:len(nodes)/2] {
|
|
r := n.Record()
|
|
r.Set(enr.IP{127, 0, 0, 1})
|
|
r.SetSeq(55)
|
|
enode.SignV4(r, keys[i])
|
|
n2, _ := enode.New(enode.ValidSchemes, r)
|
|
nodes[i] = n2
|
|
}
|
|
}
|
|
|
|
// This test verifies that randomIterator re-checks the root of the tree to catch
|
|
// updates to links.
|
|
func TestIteratorLinkUpdates(t *testing.T) {
|
|
var (
|
|
clock = new(mclock.Simulated)
|
|
nodes = testNodes(nodesSeed1, 30)
|
|
resolver = newMapResolver()
|
|
c = NewClient(Config{
|
|
Resolver: resolver,
|
|
Logger: testlog.Logger(t, log.LvlTrace),
|
|
RecheckInterval: 20 * time.Minute,
|
|
RateLimit: 500,
|
|
})
|
|
)
|
|
c.clock = clock
|
|
tree3, url3 := makeTestTree("t3", nodes[20:30], nil)
|
|
tree2, url2 := makeTestTree("t2", nodes[10:20], nil)
|
|
tree1, url1 := makeTestTree("t1", nodes[0:10], []string{url2})
|
|
resolver.add(tree1.ToTXT("t1"))
|
|
resolver.add(tree2.ToTXT("t2"))
|
|
resolver.add(tree3.ToTXT("t3"))
|
|
|
|
it, err := c.NewIterator(url1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Sync tree1 using RandomNode.
|
|
checkIterator(t, it, nodes[:20])
|
|
|
|
// Add link to tree3, remove link to tree2.
|
|
tree1, _ = makeTestTree("t1", nodes[:10], []string{url3})
|
|
resolver.add(tree1.ToTXT("t1"))
|
|
t.Log("tree1 updated")
|
|
|
|
clock.Run(c.cfg.RecheckInterval + 1*time.Second)
|
|
|
|
var wantNodes []*enode.Node
|
|
wantNodes = append(wantNodes, tree1.Nodes()...)
|
|
wantNodes = append(wantNodes, tree3.Nodes()...)
|
|
checkIterator(t, it, wantNodes)
|
|
|
|
// Check that linked trees are GCed when they're no longer referenced.
|
|
knownTrees := it.(*randomIterator).trees
|
|
if len(knownTrees) != 2 {
|
|
t.Errorf("client knows %d trees, want 2", len(knownTrees))
|
|
}
|
|
}
|
|
|
|
func checkIterator(t *testing.T, it enode.Iterator, wantNodes []*enode.Node) {
|
|
t.Helper()
|
|
|
|
var (
|
|
want = make(map[enode.ID]*enode.Node)
|
|
maxCalls = len(wantNodes) * 3
|
|
calls = 0
|
|
)
|
|
for _, n := range wantNodes {
|
|
want[n.ID()] = n
|
|
}
|
|
for ; len(want) > 0 && calls < maxCalls; calls++ {
|
|
if !it.Next() {
|
|
t.Fatalf("Next returned false (call %d)", calls)
|
|
}
|
|
n := it.Node()
|
|
delete(want, n.ID())
|
|
}
|
|
t.Logf("checkIterator called Next %d times to find %d nodes", calls, len(wantNodes))
|
|
for _, n := range want {
|
|
t.Errorf("iterator didn't discover node %v", n.ID())
|
|
}
|
|
}
|
|
|
|
func makeTestTree(domain string, nodes []*enode.Node, links []string) (*Tree, string) {
|
|
tree, err := MakeTree(1, nodes, links)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
url, err := tree.Sign(testKey(signingKeySeed), domain)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return tree, url
|
|
}
|
|
|
|
// testKeys creates deterministic private keys for testing.
|
|
func testKeys(seed int64, n int) []*ecdsa.PrivateKey {
|
|
rand := rand.New(rand.NewSource(seed))
|
|
keys := make([]*ecdsa.PrivateKey, n)
|
|
for i := 0; i < n; i++ {
|
|
key, err := ecdsa.GenerateKey(crypto.S256(), rand)
|
|
if err != nil {
|
|
panic("can't generate key: " + err.Error())
|
|
}
|
|
keys[i] = key
|
|
}
|
|
return keys
|
|
}
|
|
|
|
func testKey(seed int64) *ecdsa.PrivateKey {
|
|
return testKeys(seed, 1)[0]
|
|
}
|
|
|
|
func testNodes(seed int64, n int) []*enode.Node {
|
|
keys := testKeys(seed, n)
|
|
nodes := make([]*enode.Node, n)
|
|
for i, key := range keys {
|
|
record := new(enr.Record)
|
|
record.SetSeq(uint64(i))
|
|
enode.SignV4(record, key)
|
|
n, err := enode.New(enode.ValidSchemes, record)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
nodes[i] = n
|
|
}
|
|
return nodes
|
|
}
|
|
|
|
func testNode(seed int64) *enode.Node {
|
|
return testNodes(seed, 1)[0]
|
|
}
|
|
|
|
type mapResolver map[string]string
|
|
|
|
func newMapResolver(maps ...map[string]string) mapResolver {
|
|
mr := make(mapResolver)
|
|
for _, m := range maps {
|
|
mr.add(m)
|
|
}
|
|
return mr
|
|
}
|
|
|
|
func (mr mapResolver) clear() {
|
|
for k := range mr {
|
|
delete(mr, k)
|
|
}
|
|
}
|
|
|
|
func (mr mapResolver) add(m map[string]string) {
|
|
for k, v := range m {
|
|
mr[k] = v
|
|
}
|
|
}
|
|
|
|
func (mr mapResolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
|
|
if record, ok := mr[name]; ok {
|
|
return []string{record}, nil
|
|
}
|
|
return nil, errors.New("not found")
|
|
}
|