diff --git a/.github/workflows/docker-network.yml b/.github/workflows/docker-network.yml new file mode 100644 index 0000000000..4f8a82ba5e --- /dev/null +++ b/.github/workflows/docker-network.yml @@ -0,0 +1,38 @@ +on: + pull_request: + # Commented paths to avoid skipping required workflow + # See https://github.community/t/feature-request-conditional-required-checks/16761 + # paths: + # - .github/workflows/docker-grandpa.yml + # - "**/*.go" + # - "chain/**" + # - "cmd/**" + # - "dot/**" + # - "internal/**" + # - "lib/**" + # - "pkg/**" + # - "tests/stress/**" + # - go.mod + # - go.sum +name: docker-network + +jobs: + docker-network-tests: + runs-on: ubuntu-latest + env: + DOCKER_BUILDKIT: "1" + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.12.1 + with: + all_but_latest: true + + - uses: docker/build-push-action@v5 + with: + load: true + target: builder + tags: chainsafe/gossamer:test + + - name: Run grandpa + run: | + docker run chainsafe/gossamer:test sh -c "make it-network" diff --git a/.releaserc b/.releaserc index 3d9da34cf2..e2e17e0bf7 100644 --- a/.releaserc +++ b/.releaserc @@ -25,7 +25,8 @@ { "path": "dist/**" } - ] + ], + "successComment": false } ] ] diff --git a/Makefile b/Makefile index 02bf0e06a9..c25f80ba7d 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,10 @@ it-rpc: build @echo " > \033[32mRunning Integration Tests RPC Specs mode...\033[0m " MODE=rpc go test ./tests/rpc/... -timeout=10m -v +it-network: build + @echo " > \033[32mRunning Integration Tests Kademlia...\033[0m " + MODE=network go test ./tests/network/... -timeout=10m -v + it-sync: build @echo " > \033[32mRunning Integration Tests sync mode...\033[0m " MODE=sync go test ./tests/sync/... -timeout=5m -v diff --git a/docs/docs/testing-and-debugging/test-suite.md b/docs/docs/testing-and-debugging/test-suite.md index ca6a3fb6e6..f4c5c86d21 100644 --- a/docs/docs/testing-and-debugging/test-suite.md +++ b/docs/docs/testing-and-debugging/test-suite.md @@ -44,6 +44,13 @@ To run Gossamer **RPC** integration tests run the following command: make it-rpc ``` + +To run Gossamer **Network** integration tests run the following command: + +``` +make it-network +``` + To run Gossamer **Sync** integration tests run the following command: ``` diff --git a/dot/network/discovery.go b/dot/network/discovery.go index 8bedf3e812..a4e047f450 100644 --- a/dot/network/discovery.go +++ b/dot/network/discovery.go @@ -94,13 +94,14 @@ func (d *discovery) waitForPeers() (peers []peer.AddrInfo, err error) { func (d *discovery) start() error { // this basically only works with enabled mDNS which is used only for local test setups. Without bootnodes kademilia // would not bee able to connect to any peers and mDNS is used to find peers in local network. - // TODO: should be refactored because this if is basically used for local integration test purpose + // TODO: should be refactored because this if is basically used for local integration test purpose. + // Instead of waiting for peers to connect to start kad we can upgrade the kad routing table on every connection, + // I think that using d.dht.{LAN/WAN}.RoutingTable().UsefulNewPeer(peerID) should be a good option if len(d.bootnodes) == 0 { peers, err := d.waitForPeers() if err != nil { return fmt.Errorf("failed while waiting for peers: %w", err) } - d.bootnodes = peers } logger.Debugf("starting DHT with bootnodes %v...", d.bootnodes) @@ -133,17 +134,6 @@ func (d *discovery) start() error { return d.discoverAndAdvertise() } -func (d *discovery) stop() error { - if d.dht == nil { - return nil - } - - ethmetrics.Unregister(checkPeerCountMetrics) - ethmetrics.Unregister(peersStoreMetrics) - - return d.dht.Close() -} - func (d *discovery) discoverAndAdvertise() error { d.rd = routing.NewRoutingDiscovery(d.dht) @@ -233,6 +223,13 @@ func (d *discovery) findPeers() { } } -func (d *discovery) findPeer(peerID peer.ID) (peer.AddrInfo, error) { - return d.dht.FindPeer(d.ctx, peerID) +func (d *discovery) stop() error { + if d.dht == nil { + return nil + } + + ethmetrics.Unregister(checkPeerCountMetrics) + ethmetrics.Unregister(peersStoreMetrics) + + return d.dht.Close() } diff --git a/dot/network/service.go b/dot/network/service.go index af995315c1..984eeaddb2 100644 --- a/dot/network/service.go +++ b/dot/network/service.go @@ -36,7 +36,8 @@ const ( blockAnnounceID = "/block-announces/1" transactionsID = "/transactions/1" - maxMessageSize = 1024 * 64 // 64kb for now + maxMessageSize = 1024 * 64 // 64kb for now + findPeerQueryTimeout = 10 * time.Second ) var ( @@ -292,12 +293,11 @@ func (s *Service) Start() error { // this handles all new connections (incoming and outgoing) // it creates a per-protocol mutex for sending outbound handshakes to the peer // connectHandler is a part of libp2p.Notifiee interface implementation and getting called in the very end - //after or Incoming or Outgoing node is connected + // after or Incoming or Outgoing node is connected. s.host.cm.connectHandler = func(peerID peer.ID) { for _, prtl := range s.notificationsProtocols { prtl.peersData.setMutex(peerID) } - // TODO: currently we only have one set so setID is 0, change this once we have more set in peerSet const setID = 0 s.host.cm.peerSetHandler.Incoming(setID, peerID) } @@ -711,7 +711,9 @@ func (s *Service) processMessage(msg peerset.Message) { addrInfo := s.host.p2pHost.Peerstore().PeerInfo(peerID) if len(addrInfo.Addrs) == 0 { var err error - addrInfo, err = s.host.discovery.findPeer(peerID) + ctx, cancel := context.WithTimeout(s.host.discovery.ctx, findPeerQueryTimeout) + defer cancel() + addrInfo, err = s.host.discovery.dht.FindPeer(ctx, peerID) if err != nil { logger.Warnf("failed to find peer id %s: %s", peerID, err) return diff --git a/dot/state/epoch.go b/dot/state/epoch.go index 6d1d0880d5..70fc31316b 100644 --- a/dot/state/epoch.go +++ b/dot/state/epoch.go @@ -22,7 +22,6 @@ var ( errHashNotInMemory = errors.New("hash not found in memory map") errEpochNotInDatabase = errors.New("epoch data not found in the database") errHashNotPersisted = errors.New("hash with next epoch not found in database") - errNoPreRuntimeDigest = errors.New("header does not contain pre-runtime digest") ) var ( @@ -197,39 +196,12 @@ func (s *EpochState) GetEpochForBlock(header *types.Header) (uint64, error) { return 0, err } - for _, d := range header.Digest { - digestValue, err := d.Value() - if err != nil { - continue - } - predigest, ok := digestValue.(types.PreRuntimeDigest) - if !ok { - continue - } - - digest, err := types.DecodeBabePreDigest(predigest.Data) - if err != nil { - return 0, fmt.Errorf("failed to decode babe header: %w", err) - } - - var slotNumber uint64 - switch d := digest.(type) { - case types.BabePrimaryPreDigest: - slotNumber = d.SlotNumber - case types.BabeSecondaryVRFPreDigest: - slotNumber = d.SlotNumber - case types.BabeSecondaryPlainPreDigest: - slotNumber = d.SlotNumber - } - - if slotNumber < firstSlot { - return 0, nil - } - - return (slotNumber - firstSlot) / s.epochLength, nil + slotNumber, err := header.SlotNumber() + if err != nil { + return 0, fmt.Errorf("getting slot number: %w", err) } - return 0, errNoPreRuntimeDigest + return (slotNumber - firstSlot) / s.epochLength, nil } // SetEpochDataRaw sets the epoch data raw for a given epoch diff --git a/dot/sync/syncer.go b/dot/sync/syncer.go index ac74579163..bec64dfc7e 100644 --- a/dot/sync/syncer.go +++ b/dot/sync/syncer.go @@ -89,7 +89,7 @@ func (s *Service) Stop() error { // HandleBlockAnnounceHandshake notifies the `chainSync` module that // we have received a BlockAnnounceHandshake from the given peer. func (s *Service) HandleBlockAnnounceHandshake(from peer.ID, msg *network.BlockAnnounceHandshake) error { - logger.Infof("received block announce handshake from: %s, #%d (%s)", + logger.Debugf("received block announce handshake from: %s, #%d (%s)", from, msg.BestBlockNumber, msg.BestBlockHash.Short()) return s.chainSync.onBlockAnnounceHandshake(from, msg.BestBlockHash, uint(msg.BestBlockNumber)) } @@ -98,7 +98,7 @@ func (s *Service) HandleBlockAnnounceHandshake(from peer.ID, msg *network.BlockA func (s *Service) HandleBlockAnnounce(from peer.ID, msg *network.BlockAnnounceMessage) error { blockAnnounceHeader := types.NewHeader(msg.ParentHash, msg.StateRoot, msg.ExtrinsicsRoot, msg.Number, msg.Digest) blockAnnounceHeaderHash := blockAnnounceHeader.Hash() - logger.Infof("received block announce from: %s, #%d (%s)", from, + logger.Debugf("received block announce from: %s, #%d (%s)", from, blockAnnounceHeader.Number, blockAnnounceHeaderHash.Short()) // if the peer reports a lower or equal best block number than us, diff --git a/dot/types/header.go b/dot/types/header.go index 59344641e5..b59dc6a57c 100644 --- a/dot/types/header.go +++ b/dot/types/header.go @@ -4,12 +4,15 @@ package types import ( + "errors" "fmt" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/pkg/scale" ) +var ErrNoPreRuntimeDigest = errors.New("header does not contain pre-runtime digest") + // Header is a state block header type Header struct { ParentHash common.Hash `json:"parentHash"` @@ -96,3 +99,32 @@ func (bh *Header) Hash() common.Hash { return bh.hash } + +func (bh *Header) SlotNumber() (uint64, error) { + for _, d := range bh.Digest { + digestValue, err := d.Value() + if err != nil { + continue + } + predigest, ok := digestValue.(PreRuntimeDigest) + if !ok { + continue + } + + digest, err := DecodeBabePreDigest(predigest.Data) + if err != nil { + return 0, fmt.Errorf("failed to decode babe header: %w", err) + } + + switch d := digest.(type) { + case BabePrimaryPreDigest: + return d.SlotNumber, nil + case BabeSecondaryVRFPreDigest: + return d.SlotNumber, nil + case BabeSecondaryPlainPreDigest: + return d.SlotNumber, nil + } + } + + return 0, ErrNoPreRuntimeDigest +} diff --git a/go.mod b/go.mod index 7eb9365407..a04f930774 100644 --- a/go.mod +++ b/go.mod @@ -45,12 +45,12 @@ require ( ) require ( - github.com/DataDog/zstd v1.5.2 // indirect + github.com/DataDog/zstd v1.4.5 // indirect github.com/Jorropo/jsync v1.0.1 // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.2.1 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cockroachdb/errors v1.11.1 // indirect @@ -65,9 +65,9 @@ require ( github.com/decred/base58 v1.0.5 // indirect github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect - github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect + github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect + github.com/dustin/go-humanize v1.0.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect github.com/flynn/noise v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect @@ -82,7 +82,7 @@ require ( github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.0.0 // indirect + github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect @@ -91,7 +91,7 @@ require ( github.com/gtank/ristretto255 v0.1.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/holiman/uint256 v1.2.4 // indirect github.com/huin/goupnp v1.3.0 // indirect @@ -157,7 +157,7 @@ require ( github.com/prometheus/procfs v0.12.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.3.3 // indirect - github.com/quic-go/quic-go v0.38.2 // indirect + github.com/quic-go/quic-go v0.38.1 // indirect github.com/quic-go/webtransport-go v0.5.3 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect @@ -165,7 +165,6 @@ require ( github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect - github.com/smartystreets/assertions v1.13.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.11.0 // indirect diff --git a/go.sum b/go.sum index a704c912d8..791b3acac0 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,8 @@ github.com/ChainSafe/go-schnorrkel v1.1.0/go.mod h1:ABkENxiP+cvjFiByMIZ9LYbRoNNL github.com/ChainSafe/wazero v0.0.0-20231114190045-1d874d099362 h1:hbvvSSB436JJalwq/2fRZwJpptvq9HMOLYVZX9oVHKM= github.com/ChainSafe/wazero v0.0.0-20231114190045-1d874d099362/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= -github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Jorropo/jsync v1.0.1 h1:6HgRolFZnsdfzRUj+ImB9og1JYOxQoReSywkHOGSaUU= github.com/Jorropo/jsync v1.0.1/go.mod h1:jCOZj3vrBCri3bSU3ErUYvevKlnbssrXeCivybS5ABQ= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= @@ -43,8 +43,8 @@ github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd h1:js1gPwhcFflTZ7 github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= -github.com/btcsuite/btcd/btcec/v2 v2.2.1 h1:xP60mv8fvp+0khmrN0zTdPC3cNm24rfeE6lh2R/Yv3E= -github.com/btcsuite/btcd/btcec/v2 v2.2.1/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8= +github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= +github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= @@ -129,17 +129,15 @@ github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/disiqueira/gotree v1.0.0 h1:en5wk87n7/Jyk6gVME3cx3xN9KmUCstJ1IjHr4Se4To= github.com/disiqueira/gotree v1.0.0/go.mod h1:7CwL+VWsWAU95DovkdRZAtA7YbtHwGk+tLV/kNi8niU= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= @@ -198,9 +196,8 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= 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= @@ -277,8 +274,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= -github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= @@ -514,8 +511,8 @@ github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM= github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= -github.com/quic-go/quic-go v0.38.2 h1:VWv/6gxIoB8hROQJhx1JEyiegsUQ+zMN3em3kynTGdg= -github.com/quic-go/quic-go v0.38.2/go.mod h1:ijnZM7JsFIkp4cRyjxJNIzdSfCLmUMg9wdyhGmg+SN4= +github.com/quic-go/quic-go v0.38.1 h1:M36YWA5dEhEeT+slOu/SwMEucbYd0YFidxG3KlGPZaE= +github.com/quic-go/quic-go v0.38.1/go.mod h1:ijnZM7JsFIkp4cRyjxJNIzdSfCLmUMg9wdyhGmg+SN4= github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2EptUrfOPWU= github.com/quic-go/webtransport-go v0.5.3/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= @@ -560,9 +557,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= -github.com/smartystreets/assertions v1.13.0 h1:Dx1kYM01xsSqKPno3aqLnrwac2LetPvN23diwyr69Qs= -github.com/smartystreets/assertions v1.13.0/go.mod h1:wDmR7qL282YbGsPy6H/yAsesrxfxaaSlJazyFLYVFx8= github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= diff --git a/tests/network/network_integration_test.go b/tests/network/network_integration_test.go new file mode 100644 index 0000000000..3345810d34 --- /dev/null +++ b/tests/network/network_integration_test.go @@ -0,0 +1,105 @@ +// Copyright 2021 ChainSafe Systems (ON) +// SPDX-License-Identifier: LGPL-3.0-only + +package network + +import ( + cfg "github.com/ChainSafe/gossamer/config" + "github.com/ChainSafe/gossamer/dot/rpc/modules" + "github.com/ChainSafe/gossamer/lib/common" + libutils "github.com/ChainSafe/gossamer/lib/utils" + "github.com/ChainSafe/gossamer/tests/utils" + "github.com/ChainSafe/gossamer/tests/utils/config" + "github.com/ChainSafe/gossamer/tests/utils/node" + "github.com/ChainSafe/gossamer/tests/utils/retry" + "github.com/ChainSafe/gossamer/tests/utils/rpc" + "github.com/stretchr/testify/require" + + "context" + "os" + "testing" + "time" +) + +func TestKadDHTNetworkDiscovery(t *testing.T) { + if utils.MODE != "network" { + t.Skip("RPC tests are disabled, going to skip.") + } + + genesisPath := libutils.GetWestendDevRawGenesisPath(t) + con := config.Default() + con.ChainSpec = genesisPath + con.Core.Role = common.FullNodeRole + con.RPC.Modules = []string{"system", "author", "chain"} + con.Network.MinPeers = 1 + con.Network.MaxPeers = 20 + con.Network.NoMDNS = true // Turning off mDNS, purpose of this test is purly use only kadDHT discovery + con.Core.BabeAuthority = true + con.Log.Sync = "trace" + con.Network.Port = 7001 + + peerConfigBoB := cfg.Copy(&con) + peerConfigBoB.Network.Bootnodes = []string{ + "/ip4/127.0.0.1/tcp/7001/p2p/12D3KooWARREmJv5sDF3TFsnUsRrwPUQaXC5BaGGACHLGutNSGeV", + } + peerConfigBoB.Core.BabeAuthority = false + peerConfigBoB.Network.Port = 7002 + + peerConfigCharlie := cfg.Copy(&peerConfigBoB) + peerConfigCharlie.Network.Port = 7003 + + alice := node.New(t, con, node.SetIndex(0), node.SetWriter(os.Stdout)) + charlie := node.New(t, peerConfigCharlie, node.SetIndex(1), node.SetWriter(os.Stdout)) + bob := node.New(t, peerConfigBoB, node.SetIndex(2), node.SetWriter(os.Stdout)) + nodes := []*node.Node{&alice, &charlie, &bob} + nodeKeyMap := map[string]*node.Node{ + "5260036532755806706566077008373229892172734656718221275791488860": &alice, + "5260036532755806706566077008373229892172734656718221275791488861": &bob, + "5260036532755806706566077008373229892172734656718221275791488862": &charlie, + } + + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + for key, node := range nodeKeyMap { + node.InitAndStartTest(ctx, t, cancel, "--node-key", key) + const timeBetweenStart = 0 * time.Second + timer := time.NewTimer(timeBetweenStart) + select { + case <-timer.C: + case <-ctx.Done(): + timer.Stop() + return + } + } + + t.Log("waiting for all nodes to be connected") + peerTimeout, peerCancel := context.WithTimeout(context.Background(), 120*time.Second) + defer peerCancel() + err := retry.UntilOK(peerTimeout, 10*time.Second, func() (bool, error) { + for _, node := range nodes { + endpoint := rpc.NewEndpoint(node.RPCPort()) + t.Logf("requesting node %s with port %s", node.String(), endpoint) + var response modules.SystemHealthResponse + fetchWithTimeoutFromEndpoint(t, endpoint, "system_health", &response) + t.Logf("Response: %+v", response) + if response.Peers != len(nodes)-1 { + return false, nil + } + } + return true, nil + }) + require.NoError(t, err) +} + +func fetchWithTimeoutFromEndpoint(t *testing.T, endpoint, method string, target interface{}) { + t.Helper() + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + body, err := rpc.Post(ctx, endpoint, method, "{}") + require.NoError(t, err) + + err = rpc.Decode(body, target) + require.NoError(t, err) +} diff --git a/tests/utils/node/node.go b/tests/utils/node/node.go index 2dee8d9497..0d97eba40e 100644 --- a/tests/utils/node/node.go +++ b/tests/utils/node/node.go @@ -142,12 +142,14 @@ func (n *Node) Init() (err error) { // be started, and runs the node until the context gets canceled. // When the node crashes or is stopped, an error (nil or not) is sent // in the waitErrCh. -func (n *Node) Start(ctx context.Context) (runtimeError <-chan error, startErr error) { - cmd := exec.CommandContext(ctx, n.binPath, //nolint:gosec +func (n *Node) Start(ctx context.Context, optArgs ...string) (runtimeError <-chan error, startErr error) { + args := []string{ "--base-path", n.tomlConfig.BasePath, "--chain", n.tomlConfig.ChainSpec, "--role", config.ParseNetworkRole(n.tomlConfig.Core.Role), - "--no-telemetry") + "--no-telemetry"} + args = append(args, optArgs...) + cmd := exec.CommandContext(ctx, n.binPath, args...) //nolint:gosec if n.logsBuffer != nil { n.logsBuffer.Reset() @@ -177,9 +179,9 @@ func (n *Node) Start(ctx context.Context) (runtimeError <-chan error, startErr e // When the node crashes or is stopped, an error (nil or not) is sent // in the waitErrCh. // It waits for the node to respond to an RPC health call before returning. -func (n *Node) StartAndWait(ctx context.Context) ( +func (n *Node) StartAndWait(ctx context.Context, args ...string) ( runtimeError <-chan error, startErr error) { - runtimeError, startErr = n.Start(ctx) + runtimeError, startErr = n.Start(ctx, args...) if startErr != nil { return nil, startErr } @@ -198,7 +200,7 @@ func (n *Node) StartAndWait(ctx context.Context) ( // If the node crashes during runtime, the passed `signalTestToStop` argument is // called since the test cannot be failed from outside the main test goroutine. func (n Node) InitAndStartTest(ctx context.Context, t *testing.T, - signalTestToStop context.CancelFunc) { + signalTestToStop context.CancelFunc, args ...string) { t.Helper() err := n.Init() @@ -206,7 +208,7 @@ func (n Node) InitAndStartTest(ctx context.Context, t *testing.T, nodeCtx, nodeCancel := context.WithCancel(ctx) - waitErr, err := n.StartAndWait(nodeCtx) + waitErr, err := n.StartAndWait(nodeCtx, args...) if err != nil { t.Errorf("failed to start node %s: %s", n, err) // Release resources and fail the test