From 396bef4ab5af4e153061848cba9b358c59251baf Mon Sep 17 00:00:00 2001 From: battlmonstr <battlmonstr@users.noreply.github.com> Date: Tue, 10 May 2022 03:49:17 +0200 Subject: [PATCH] p2p: move v4_lookup_test to integration tests (#4107) The test is flaky when the reply timeout is too low. Increasing the timeout makes it slow. Move the test to the integration suite. Having a higher timeout is fine there. --- p2p/discover/lookup_util_test.go | 220 +++++++++++++++++++++++++++++++ p2p/discover/v4_lookup_test.go | 216 +----------------------------- 2 files changed, 225 insertions(+), 211 deletions(-) create mode 100644 p2p/discover/lookup_util_test.go diff --git a/p2p/discover/lookup_util_test.go b/p2p/discover/lookup_util_test.go new file mode 100644 index 0000000000..e12b1262e9 --- /dev/null +++ b/p2p/discover/lookup_util_test.go @@ -0,0 +1,220 @@ +package discover + +import ( + "crypto/ecdsa" + "fmt" + "net" + "sort" + "testing" + + "github.com/ledgerwatch/erigon/crypto" + "github.com/ledgerwatch/erigon/p2p/discover/v4wire" + "github.com/ledgerwatch/erigon/p2p/enode" + "github.com/ledgerwatch/erigon/p2p/enr" +) + +// This is the test network for the Lookup test. +// The nodes were obtained by running lookupTestnet.mine with a random NodeID as target. +var lookupTestnet = &preminedTestnet{ + target: hexEncPubkey("5d485bdcbe9bc89314a10ae9231e429d33853e3a8fa2af39f5f827370a2e4185e344ace5d16237491dad41f278f1d3785210d29ace76cd627b9147ee340b1125"), + dists: [257][]*ecdsa.PrivateKey{ + 251: { + hexEncPrivkey("29738ba0c1a4397d6a65f292eee07f02df8e58d41594ba2be3cf84ce0fc58169"), + hexEncPrivkey("511b1686e4e58a917f7f848e9bf5539d206a68f5ad6b54b552c2399fe7d174ae"), + hexEncPrivkey("d09e5eaeec0fd596236faed210e55ef45112409a5aa7f3276d26646080dcfaeb"), + hexEncPrivkey("c1e20dbbf0d530e50573bd0a260b32ec15eb9190032b4633d44834afc8afe578"), + hexEncPrivkey("ed5f38f5702d92d306143e5d9154fb21819777da39af325ea359f453d179e80b"), + }, + 252: { + hexEncPrivkey("1c9b1cafbec00848d2c174b858219914b42a7d5c9359b1ca03fd650e8239ae94"), + hexEncPrivkey("e0e1e8db4a6f13c1ffdd3e96b72fa7012293ced187c9dcdcb9ba2af37a46fa10"), + hexEncPrivkey("3d53823e0a0295cb09f3e11d16c1b44d07dd37cec6f739b8df3a590189fe9fb9"), + }, + 253: { + hexEncPrivkey("2d0511ae9bf590166597eeab86b6f27b1ab761761eaea8965487b162f8703847"), + hexEncPrivkey("6cfbd7b8503073fc3dbdb746a7c672571648d3bd15197ccf7f7fef3d904f53a2"), + hexEncPrivkey("a30599b12827b69120633f15b98a7f6bc9fc2e9a0fd6ae2ebb767c0e64d743ab"), + hexEncPrivkey("14a98db9b46a831d67eff29f3b85b1b485bb12ae9796aea98d91be3dc78d8a91"), + hexEncPrivkey("2369ff1fc1ff8ca7d20b17e2673adc3365c3674377f21c5d9dafaff21fe12e24"), + hexEncPrivkey("9ae91101d6b5048607f41ec0f690ef5d09507928aded2410aabd9237aa2727d7"), + hexEncPrivkey("05e3c59090a3fd1ae697c09c574a36fcf9bedd0afa8fe3946f21117319ca4973"), + hexEncPrivkey("06f31c5ea632658f718a91a1b1b9ae4b7549d7b3bc61cbc2be5f4a439039f3ad"), + }, + 254: { + hexEncPrivkey("dec742079ec00ff4ec1284d7905bc3de2366f67a0769431fd16f80fd68c58a7c"), + hexEncPrivkey("ff02c8861fa12fbd129d2a95ea663492ef9c1e51de19dcfbbfe1c59894a28d2b"), + hexEncPrivkey("4dded9e4eefcbce4262be4fd9e8a773670ab0b5f448f286ec97dfc8cf681444a"), + hexEncPrivkey("750d931e2a8baa2c9268cb46b7cd851f4198018bed22f4dceb09dd334a2395f6"), + hexEncPrivkey("ce1435a956a98ffec484cd11489c4f165cf1606819ab6b521cee440f0c677e9e"), + hexEncPrivkey("996e7f8d1638be92d7328b4770f47e5420fc4bafecb4324fd33b1f5d9f403a75"), + hexEncPrivkey("ebdc44e77a6cc0eb622e58cf3bb903c3da4c91ca75b447b0168505d8fc308b9c"), + hexEncPrivkey("46bd1eddcf6431bea66fc19ebc45df191c1c7d6ed552dcdc7392885009c322f0"), + }, + 255: { + hexEncPrivkey("da8645f90826e57228d9ea72aff84500060ad111a5d62e4af831ed8e4b5acfb8"), + hexEncPrivkey("3c944c5d9af51d4c1d43f5d0f3a1a7ef65d5e82744d669b58b5fed242941a566"), + hexEncPrivkey("5ebcde76f1d579eebf6e43b0ffe9157e65ffaa391175d5b9aa988f47df3e33da"), + hexEncPrivkey("97f78253a7d1d796e4eaabce721febcc4550dd68fb11cc818378ba807a2cb7de"), + hexEncPrivkey("a38cd7dc9b4079d1c0406afd0fdb1165c285f2c44f946eca96fc67772c988c7d"), + hexEncPrivkey("d64cbb3ffdf712c372b7a22a176308ef8f91861398d5dbaf326fd89c6eaeef1c"), + hexEncPrivkey("d269609743ef29d6446e3355ec647e38d919c82a4eb5837e442efd7f4218944f"), + hexEncPrivkey("d8f7bcc4a530efde1d143717007179e0d9ace405ddaaf151c4d863753b7fd64c"), + }, + 256: { + hexEncPrivkey("8c5b422155d33ea8e9d46f71d1ad3e7b24cb40051413ffa1a81cff613d243ba9"), + hexEncPrivkey("937b1af801def4e8f5a3a8bd225a8bcff1db764e41d3e177f2e9376e8dd87233"), + hexEncPrivkey("120260dce739b6f71f171da6f65bc361b5fad51db74cf02d3e973347819a6518"), + hexEncPrivkey("1fa56cf25d4b46c2bf94e82355aa631717b63190785ac6bae545a88aadc304a9"), + hexEncPrivkey("3c38c503c0376f9b4adcbe935d5f4b890391741c764f61b03cd4d0d42deae002"), + hexEncPrivkey("3a54af3e9fa162bc8623cdf3e5d9b70bf30ade1d54cc3abea8659aba6cff471f"), + hexEncPrivkey("6799a02ea1999aefdcbcc4d3ff9544478be7365a328d0d0f37c26bd95ade0cda"), + hexEncPrivkey("e24a7bc9051058f918646b0f6e3d16884b2a55a15553b89bab910d55ebc36116"), + }, + }, +} + +type preminedTestnet struct { + target enode.PubkeyEncoded + dists [hashBits + 1][]*ecdsa.PrivateKey +} + +func (tn *preminedTestnet) len() int { + n := 0 + for _, keys := range tn.dists { + n += len(keys) + } + return n +} + +func (tn *preminedTestnet) nodes() []*enode.Node { + result := make([]*enode.Node, 0, tn.len()) + for dist, keys := range tn.dists { + for index := range keys { + result = append(result, tn.node(dist, index)) + } + } + sortByID(result) + return result +} + +func (tn *preminedTestnet) node(dist, index int) *enode.Node { + key := tn.dists[dist][index] + rec := new(enr.Record) + rec.Set(enr.IP{127, byte(dist >> 8), byte(dist), byte(index)}) + rec.Set(enr.UDP(5000)) + enode.SignV4(rec, key) + n, _ := enode.New(enode.ValidSchemes, rec) + return n +} + +func (tn *preminedTestnet) nodeByAddr(addr *net.UDPAddr) (*enode.Node, *ecdsa.PrivateKey) { + dist := int(addr.IP[1])<<8 + int(addr.IP[2]) + index := int(addr.IP[3]) + key := tn.dists[dist][index] + return tn.node(dist, index), key +} + +func (tn *preminedTestnet) nodesAtDistance(dist int) []v4wire.Node { + result := make([]v4wire.Node, len(tn.dists[dist])) + for i := range result { + result[i] = nodeToRPC(wrapNode(tn.node(dist, i))) + } + return result +} + +func (tn *preminedTestnet) neighborsAtDistances(base *enode.Node, distances []uint, elems int) []*enode.Node { + var result []*enode.Node + for d := range lookupTestnet.dists { + for i := range lookupTestnet.dists[d] { + n := lookupTestnet.node(d, i) + d := enode.LogDist(base.ID(), n.ID()) + if containsUint(uint(d), distances) { + result = append(result, n) + if len(result) >= elems { + return result + } + } + } + } + return result +} + +func (tn *preminedTestnet) closest(n int) (nodes []*enode.Node) { + for d := range tn.dists { + for i := range tn.dists[d] { + nodes = append(nodes, tn.node(d, i)) + } + } + sort.Slice(nodes, func(i, j int) bool { + return enode.DistCmp(tn.target.ID(), nodes[i].ID(), nodes[j].ID()) < 0 + }) + return nodes[:n] +} + +func (tn *preminedTestnet) privateKeys() []*ecdsa.PrivateKey { + var keys []*ecdsa.PrivateKey + for d := range tn.dists { + for _, key := range tn.dists[d] { + keys = append(keys, key) + } + } + return keys +} + +var _ = (*preminedTestnet).mine // avoid linter warning about mine being dead code. + +// mine generates a testnet struct literal with nodes at +// various distances to the network's target. +func (tn *preminedTestnet) mine() { + // Clear existing slices first (useful when re-mining). + for i := range tn.dists { + tn.dists[i] = nil + } + + targetSha := tn.target.ID() + found, need := 0, 40 + for found < need { + k := newkey() + ld := enode.LogDist(targetSha, enode.PubkeyToIDV4(&k.PublicKey)) + if len(tn.dists[ld]) < 8 { + tn.dists[ld] = append(tn.dists[ld], k) + found++ + fmt.Printf("found ID with ld %d (%d/%d)\n", ld, found, need) + } + } + fmt.Printf("&preminedTestnet{\n") + fmt.Printf(" target: hexEncPubkey(\"%x\"),\n", tn.target[:]) + fmt.Printf(" dists: [%d][]*ecdsa.PrivateKey{\n", len(tn.dists)) + for ld, ns := range tn.dists { + if len(ns) == 0 { + continue + } + fmt.Printf(" %d: {\n", ld) + for _, key := range ns { + fmt.Printf(" hexEncPrivkey(\"%x\"),\n", crypto.FromECDSA(key)) + } + fmt.Printf(" },\n") + } + fmt.Printf(" },\n") + fmt.Printf("}\n") +} + +// checkLookupResults verifies that the results of a lookup are the closest nodes to +// the testnet's target. +func checkLookupResults(t *testing.T, tn *preminedTestnet, results []*enode.Node) { + t.Helper() + t.Logf("results:") + for _, e := range results { + t.Logf(" ld=%d, %x", enode.LogDist(tn.target.ID(), e.ID()), e.ID().Bytes()) + } + if hasDuplicates(wrapNodes(results)) { + t.Errorf("result set contains duplicate entries") + } + if !sortedByDistanceTo(tn.target.ID(), wrapNodes(results)) { + t.Errorf("result set not sorted by distance to target") + } + wantNodes := tn.closest(len(results)) + if err := checkNodesEqual(results, wantNodes); err != nil { + t.Error(err) + } +} diff --git a/p2p/discover/v4_lookup_test.go b/p2p/discover/v4_lookup_test.go index d39ad5bd19..65df058d61 100644 --- a/p2p/discover/v4_lookup_test.go +++ b/p2p/discover/v4_lookup_test.go @@ -14,22 +14,22 @@ // 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/>. +//go:build integration +// +build integration + package discover import ( "context" "crypto/ecdsa" - "fmt" "net" "runtime" - "sort" "testing" "time" "github.com/ledgerwatch/erigon/crypto" "github.com/ledgerwatch/erigon/p2p/discover/v4wire" "github.com/ledgerwatch/erigon/p2p/enode" - "github.com/ledgerwatch/erigon/p2p/enr" ) func TestUDPv4_Lookup(t *testing.T) { @@ -39,7 +39,7 @@ func TestUDPv4_Lookup(t *testing.T) { t.Parallel() ctx := context.Background() - ctx = contextWithReplyTimeout(ctx, 200*time.Millisecond) + ctx = contextWithReplyTimeout(ctx, time.Second) test := newUDPTestContext(ctx, t) defer test.close() @@ -84,7 +84,7 @@ func TestUDPv4_LookupIterator(t *testing.T) { return testNetPrivateKeys[testNetPrivateKeyIndex], nil } ctx := context.Background() - ctx = contextWithReplyTimeout(ctx, 200*time.Millisecond) + ctx = contextWithReplyTimeout(ctx, time.Second) ctx = contextWithPrivateKeyGenerator(ctx, privateKeyGenerator) test := newUDPTestContext(ctx, t) @@ -170,209 +170,3 @@ func serveTestnet(test *udpTest, testnet *preminedTestnet) { }) } } - -// checkLookupResults verifies that the results of a lookup are the closest nodes to -// the testnet's target. -func checkLookupResults(t *testing.T, tn *preminedTestnet, results []*enode.Node) { - t.Helper() - t.Logf("results:") - for _, e := range results { - t.Logf(" ld=%d, %x", enode.LogDist(tn.target.ID(), e.ID()), e.ID().Bytes()) - } - if hasDuplicates(wrapNodes(results)) { - t.Errorf("result set contains duplicate entries") - } - if !sortedByDistanceTo(tn.target.ID(), wrapNodes(results)) { - t.Errorf("result set not sorted by distance to target") - } - wantNodes := tn.closest(len(results)) - if err := checkNodesEqual(results, wantNodes); err != nil { - t.Error(err) - } -} - -// This is the test network for the Lookup test. -// The nodes were obtained by running lookupTestnet.mine with a random NodeID as target. -var lookupTestnet = &preminedTestnet{ - target: hexEncPubkey("5d485bdcbe9bc89314a10ae9231e429d33853e3a8fa2af39f5f827370a2e4185e344ace5d16237491dad41f278f1d3785210d29ace76cd627b9147ee340b1125"), - dists: [257][]*ecdsa.PrivateKey{ - 251: { - hexEncPrivkey("29738ba0c1a4397d6a65f292eee07f02df8e58d41594ba2be3cf84ce0fc58169"), - hexEncPrivkey("511b1686e4e58a917f7f848e9bf5539d206a68f5ad6b54b552c2399fe7d174ae"), - hexEncPrivkey("d09e5eaeec0fd596236faed210e55ef45112409a5aa7f3276d26646080dcfaeb"), - hexEncPrivkey("c1e20dbbf0d530e50573bd0a260b32ec15eb9190032b4633d44834afc8afe578"), - hexEncPrivkey("ed5f38f5702d92d306143e5d9154fb21819777da39af325ea359f453d179e80b"), - }, - 252: { - hexEncPrivkey("1c9b1cafbec00848d2c174b858219914b42a7d5c9359b1ca03fd650e8239ae94"), - hexEncPrivkey("e0e1e8db4a6f13c1ffdd3e96b72fa7012293ced187c9dcdcb9ba2af37a46fa10"), - hexEncPrivkey("3d53823e0a0295cb09f3e11d16c1b44d07dd37cec6f739b8df3a590189fe9fb9"), - }, - 253: { - hexEncPrivkey("2d0511ae9bf590166597eeab86b6f27b1ab761761eaea8965487b162f8703847"), - hexEncPrivkey("6cfbd7b8503073fc3dbdb746a7c672571648d3bd15197ccf7f7fef3d904f53a2"), - hexEncPrivkey("a30599b12827b69120633f15b98a7f6bc9fc2e9a0fd6ae2ebb767c0e64d743ab"), - hexEncPrivkey("14a98db9b46a831d67eff29f3b85b1b485bb12ae9796aea98d91be3dc78d8a91"), - hexEncPrivkey("2369ff1fc1ff8ca7d20b17e2673adc3365c3674377f21c5d9dafaff21fe12e24"), - hexEncPrivkey("9ae91101d6b5048607f41ec0f690ef5d09507928aded2410aabd9237aa2727d7"), - hexEncPrivkey("05e3c59090a3fd1ae697c09c574a36fcf9bedd0afa8fe3946f21117319ca4973"), - hexEncPrivkey("06f31c5ea632658f718a91a1b1b9ae4b7549d7b3bc61cbc2be5f4a439039f3ad"), - }, - 254: { - hexEncPrivkey("dec742079ec00ff4ec1284d7905bc3de2366f67a0769431fd16f80fd68c58a7c"), - hexEncPrivkey("ff02c8861fa12fbd129d2a95ea663492ef9c1e51de19dcfbbfe1c59894a28d2b"), - hexEncPrivkey("4dded9e4eefcbce4262be4fd9e8a773670ab0b5f448f286ec97dfc8cf681444a"), - hexEncPrivkey("750d931e2a8baa2c9268cb46b7cd851f4198018bed22f4dceb09dd334a2395f6"), - hexEncPrivkey("ce1435a956a98ffec484cd11489c4f165cf1606819ab6b521cee440f0c677e9e"), - hexEncPrivkey("996e7f8d1638be92d7328b4770f47e5420fc4bafecb4324fd33b1f5d9f403a75"), - hexEncPrivkey("ebdc44e77a6cc0eb622e58cf3bb903c3da4c91ca75b447b0168505d8fc308b9c"), - hexEncPrivkey("46bd1eddcf6431bea66fc19ebc45df191c1c7d6ed552dcdc7392885009c322f0"), - }, - 255: { - hexEncPrivkey("da8645f90826e57228d9ea72aff84500060ad111a5d62e4af831ed8e4b5acfb8"), - hexEncPrivkey("3c944c5d9af51d4c1d43f5d0f3a1a7ef65d5e82744d669b58b5fed242941a566"), - hexEncPrivkey("5ebcde76f1d579eebf6e43b0ffe9157e65ffaa391175d5b9aa988f47df3e33da"), - hexEncPrivkey("97f78253a7d1d796e4eaabce721febcc4550dd68fb11cc818378ba807a2cb7de"), - hexEncPrivkey("a38cd7dc9b4079d1c0406afd0fdb1165c285f2c44f946eca96fc67772c988c7d"), - hexEncPrivkey("d64cbb3ffdf712c372b7a22a176308ef8f91861398d5dbaf326fd89c6eaeef1c"), - hexEncPrivkey("d269609743ef29d6446e3355ec647e38d919c82a4eb5837e442efd7f4218944f"), - hexEncPrivkey("d8f7bcc4a530efde1d143717007179e0d9ace405ddaaf151c4d863753b7fd64c"), - }, - 256: { - hexEncPrivkey("8c5b422155d33ea8e9d46f71d1ad3e7b24cb40051413ffa1a81cff613d243ba9"), - hexEncPrivkey("937b1af801def4e8f5a3a8bd225a8bcff1db764e41d3e177f2e9376e8dd87233"), - hexEncPrivkey("120260dce739b6f71f171da6f65bc361b5fad51db74cf02d3e973347819a6518"), - hexEncPrivkey("1fa56cf25d4b46c2bf94e82355aa631717b63190785ac6bae545a88aadc304a9"), - hexEncPrivkey("3c38c503c0376f9b4adcbe935d5f4b890391741c764f61b03cd4d0d42deae002"), - hexEncPrivkey("3a54af3e9fa162bc8623cdf3e5d9b70bf30ade1d54cc3abea8659aba6cff471f"), - hexEncPrivkey("6799a02ea1999aefdcbcc4d3ff9544478be7365a328d0d0f37c26bd95ade0cda"), - hexEncPrivkey("e24a7bc9051058f918646b0f6e3d16884b2a55a15553b89bab910d55ebc36116"), - }, - }, -} - -type preminedTestnet struct { - target enode.PubkeyEncoded - dists [hashBits + 1][]*ecdsa.PrivateKey -} - -func (tn *preminedTestnet) len() int { - n := 0 - for _, keys := range tn.dists { - n += len(keys) - } - return n -} - -func (tn *preminedTestnet) nodes() []*enode.Node { - result := make([]*enode.Node, 0, tn.len()) - for dist, keys := range tn.dists { - for index := range keys { - result = append(result, tn.node(dist, index)) - } - } - sortByID(result) - return result -} - -func (tn *preminedTestnet) node(dist, index int) *enode.Node { - key := tn.dists[dist][index] - rec := new(enr.Record) - rec.Set(enr.IP{127, byte(dist >> 8), byte(dist), byte(index)}) - rec.Set(enr.UDP(5000)) - enode.SignV4(rec, key) - n, _ := enode.New(enode.ValidSchemes, rec) - return n -} - -func (tn *preminedTestnet) nodeByAddr(addr *net.UDPAddr) (*enode.Node, *ecdsa.PrivateKey) { - dist := int(addr.IP[1])<<8 + int(addr.IP[2]) - index := int(addr.IP[3]) - key := tn.dists[dist][index] - return tn.node(dist, index), key -} - -func (tn *preminedTestnet) nodesAtDistance(dist int) []v4wire.Node { - result := make([]v4wire.Node, len(tn.dists[dist])) - for i := range result { - result[i] = nodeToRPC(wrapNode(tn.node(dist, i))) - } - return result -} - -func (tn *preminedTestnet) neighborsAtDistances(base *enode.Node, distances []uint, elems int) []*enode.Node { - var result []*enode.Node - for d := range lookupTestnet.dists { - for i := range lookupTestnet.dists[d] { - n := lookupTestnet.node(d, i) - d := enode.LogDist(base.ID(), n.ID()) - if containsUint(uint(d), distances) { - result = append(result, n) - if len(result) >= elems { - return result - } - } - } - } - return result -} - -func (tn *preminedTestnet) closest(n int) (nodes []*enode.Node) { - for d := range tn.dists { - for i := range tn.dists[d] { - nodes = append(nodes, tn.node(d, i)) - } - } - sort.Slice(nodes, func(i, j int) bool { - return enode.DistCmp(tn.target.ID(), nodes[i].ID(), nodes[j].ID()) < 0 - }) - return nodes[:n] -} - -func (tn *preminedTestnet) privateKeys() []*ecdsa.PrivateKey { - var keys []*ecdsa.PrivateKey - for d := range tn.dists { - for _, key := range tn.dists[d] { - keys = append(keys, key) - } - } - return keys -} - -var _ = (*preminedTestnet).mine // avoid linter warning about mine being dead code. - -// mine generates a testnet struct literal with nodes at -// various distances to the network's target. -func (tn *preminedTestnet) mine() { - // Clear existing slices first (useful when re-mining). - for i := range tn.dists { - tn.dists[i] = nil - } - - targetSha := tn.target.ID() - found, need := 0, 40 - for found < need { - k := newkey() - ld := enode.LogDist(targetSha, enode.PubkeyToIDV4(&k.PublicKey)) - if len(tn.dists[ld]) < 8 { - tn.dists[ld] = append(tn.dists[ld], k) - found++ - fmt.Printf("found ID with ld %d (%d/%d)\n", ld, found, need) - } - } - fmt.Printf("&preminedTestnet{\n") - fmt.Printf(" target: hexEncPubkey(\"%x\"),\n", tn.target[:]) - fmt.Printf(" dists: [%d][]*ecdsa.PrivateKey{\n", len(tn.dists)) - for ld, ns := range tn.dists { - if len(ns) == 0 { - continue - } - fmt.Printf(" %d: {\n", ld) - for _, key := range ns { - fmt.Printf(" hexEncPrivkey(\"%x\"),\n", crypto.FromECDSA(key)) - } - fmt.Printf(" },\n") - } - fmt.Printf(" },\n") - fmt.Printf("}\n") -} -- GitLab