ulc_test.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // Copyright 2019 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package les
  17. import (
  18. "crypto/ecdsa"
  19. "fmt"
  20. "math/big"
  21. "net"
  22. "reflect"
  23. "testing"
  24. "time"
  25. "github.com/ethereum/go-ethereum/common/mclock"
  26. "github.com/ethereum/go-ethereum/core"
  27. "github.com/ethereum/go-ethereum/core/rawdb"
  28. "github.com/ethereum/go-ethereum/crypto"
  29. "github.com/ethereum/go-ethereum/eth"
  30. "github.com/ethereum/go-ethereum/light"
  31. "github.com/ethereum/go-ethereum/p2p"
  32. "github.com/ethereum/go-ethereum/p2p/enode"
  33. )
  34. func TestULCSyncWithOnePeer(t *testing.T) {
  35. f := newFullPeerPair(t, 1, 4, testChainGen)
  36. ulcConfig := &eth.ULCConfig{
  37. MinTrustedFraction: 100,
  38. TrustedServers: []string{f.Node.String()},
  39. }
  40. l := newLightPeer(t, ulcConfig)
  41. if reflect.DeepEqual(f.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) {
  42. t.Fatal("blocks are equal")
  43. }
  44. _, _, err := connectPeers(f, l, 2)
  45. if err != nil {
  46. t.Fatal(err)
  47. }
  48. l.PM.fetcher.lock.Lock()
  49. l.PM.fetcher.nextRequest()
  50. l.PM.fetcher.lock.Unlock()
  51. if !reflect.DeepEqual(f.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) {
  52. t.Fatal("sync doesn't work")
  53. }
  54. }
  55. func TestULCReceiveAnnounce(t *testing.T) {
  56. f := newFullPeerPair(t, 1, 4, testChainGen)
  57. ulcConfig := &eth.ULCConfig{
  58. MinTrustedFraction: 100,
  59. TrustedServers: []string{f.Node.String()},
  60. }
  61. l := newLightPeer(t, ulcConfig)
  62. fPeer, lPeer, err := connectPeers(f, l, 2)
  63. if err != nil {
  64. t.Fatal(err)
  65. }
  66. l.PM.synchronise(fPeer)
  67. //check that the sync is finished correctly
  68. if !reflect.DeepEqual(f.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) {
  69. t.Fatal("sync doesn't work")
  70. }
  71. l.PM.peers.lock.Lock()
  72. if len(l.PM.peers.peers) == 0 {
  73. t.Fatal("peer list should not be empty")
  74. }
  75. l.PM.peers.lock.Unlock()
  76. time.Sleep(time.Second)
  77. //send a signed announce message(payload doesn't matter)
  78. td := f.PM.blockchain.GetTd(l.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Number.Uint64())
  79. announce := announceData{
  80. Number: l.PM.blockchain.CurrentHeader().Number.Uint64() + 1,
  81. Td: td.Add(td, big.NewInt(1)),
  82. }
  83. announce.sign(f.Key)
  84. lPeer.SendAnnounce(announce)
  85. }
  86. func TestULCShouldNotSyncWithTwoPeersOneHaveEmptyChain(t *testing.T) {
  87. f1 := newFullPeerPair(t, 1, 4, testChainGen)
  88. f2 := newFullPeerPair(t, 2, 0, nil)
  89. ulcConf := &ulc{minTrustedFraction: 100, trustedKeys: make(map[string]struct{})}
  90. ulcConf.trustedKeys[f1.Node.ID().String()] = struct{}{}
  91. ulcConf.trustedKeys[f2.Node.ID().String()] = struct{}{}
  92. ulcConfig := &eth.ULCConfig{
  93. MinTrustedFraction: 100,
  94. TrustedServers: []string{f1.Node.String(), f2.Node.String()},
  95. }
  96. l := newLightPeer(t, ulcConfig)
  97. l.PM.ulc.minTrustedFraction = 100
  98. _, _, err := connectPeers(f1, l, 2)
  99. if err != nil {
  100. t.Fatal(err)
  101. }
  102. _, _, err = connectPeers(f2, l, 2)
  103. if err != nil {
  104. t.Fatal(err)
  105. }
  106. l.PM.fetcher.lock.Lock()
  107. l.PM.fetcher.nextRequest()
  108. l.PM.fetcher.lock.Unlock()
  109. if reflect.DeepEqual(f2.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) {
  110. t.Fatal("Incorrect hash: second peer has empty chain")
  111. }
  112. }
  113. func TestULCShouldNotSyncWithThreePeersOneHaveEmptyChain(t *testing.T) {
  114. f1 := newFullPeerPair(t, 1, 3, testChainGen)
  115. f2 := newFullPeerPair(t, 2, 4, testChainGen)
  116. f3 := newFullPeerPair(t, 3, 0, nil)
  117. ulcConfig := &eth.ULCConfig{
  118. MinTrustedFraction: 60,
  119. TrustedServers: []string{f1.Node.String(), f2.Node.String(), f3.Node.String()},
  120. }
  121. l := newLightPeer(t, ulcConfig)
  122. _, _, err := connectPeers(f1, l, 2)
  123. if err != nil {
  124. t.Fatal(err)
  125. }
  126. _, _, err = connectPeers(f2, l, 2)
  127. if err != nil {
  128. t.Fatal(err)
  129. }
  130. _, _, err = connectPeers(f3, l, 2)
  131. if err != nil {
  132. t.Fatal(err)
  133. }
  134. l.PM.fetcher.lock.Lock()
  135. l.PM.fetcher.nextRequest()
  136. l.PM.fetcher.lock.Unlock()
  137. if !reflect.DeepEqual(f1.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) {
  138. t.Fatal("Incorrect hash")
  139. }
  140. }
  141. type pairPeer struct {
  142. Name string
  143. Node *enode.Node
  144. PM *ProtocolManager
  145. Key *ecdsa.PrivateKey
  146. }
  147. func connectPeers(full, light pairPeer, version int) (*peer, *peer, error) {
  148. // Create a message pipe to communicate through
  149. app, net := p2p.MsgPipe()
  150. peerLight := full.PM.newPeer(version, NetworkId, p2p.NewPeer(light.Node.ID(), light.Name, nil), net)
  151. peerFull := light.PM.newPeer(version, NetworkId, p2p.NewPeer(full.Node.ID(), full.Name, nil), app)
  152. // Start the peerLight on a new thread
  153. errc1 := make(chan error, 1)
  154. errc2 := make(chan error, 1)
  155. go func() {
  156. select {
  157. case light.PM.newPeerCh <- peerFull:
  158. errc1 <- light.PM.handle(peerFull)
  159. case <-light.PM.quitSync:
  160. errc1 <- p2p.DiscQuitting
  161. }
  162. }()
  163. go func() {
  164. select {
  165. case full.PM.newPeerCh <- peerLight:
  166. errc2 <- full.PM.handle(peerLight)
  167. case <-full.PM.quitSync:
  168. errc2 <- p2p.DiscQuitting
  169. }
  170. }()
  171. select {
  172. case <-time.After(time.Millisecond * 100):
  173. case err := <-errc1:
  174. return nil, nil, fmt.Errorf("peerLight handshake error: %v", err)
  175. case err := <-errc2:
  176. return nil, nil, fmt.Errorf("peerFull handshake error: %v", err)
  177. }
  178. return peerFull, peerLight, nil
  179. }
  180. // newFullPeerPair creates node with full sync mode
  181. func newFullPeerPair(t *testing.T, index int, numberOfblocks int, chainGen func(int, *core.BlockGen)) pairPeer {
  182. db := rawdb.NewMemoryDatabase()
  183. pmFull := newTestProtocolManagerMust(t, false, numberOfblocks, chainGen, nil, nil, db, nil)
  184. peerPairFull := pairPeer{
  185. Name: "full node",
  186. PM: pmFull,
  187. }
  188. key, err := crypto.GenerateKey()
  189. if err != nil {
  190. t.Fatal("generate key err:", err)
  191. }
  192. peerPairFull.Key = key
  193. peerPairFull.Node = enode.NewV4(&key.PublicKey, net.ParseIP("127.0.0.1"), 35000, 35000)
  194. return peerPairFull
  195. }
  196. // newLightPeer creates node with light sync mode
  197. func newLightPeer(t *testing.T, ulcConfig *eth.ULCConfig) pairPeer {
  198. peers := newPeerSet()
  199. dist := newRequestDistributor(peers, make(chan struct{}), &mclock.System{})
  200. rm := newRetrieveManager(peers, dist, nil)
  201. ldb := rawdb.NewMemoryDatabase()
  202. odr := NewLesOdr(ldb, light.DefaultClientIndexerConfig, rm)
  203. pmLight := newTestProtocolManagerMust(t, true, 0, nil, odr, peers, ldb, ulcConfig)
  204. peerPairLight := pairPeer{
  205. Name: "ulc node",
  206. PM: pmLight,
  207. }
  208. key, err := crypto.GenerateKey()
  209. if err != nil {
  210. t.Fatal("generate key err:", err)
  211. }
  212. peerPairLight.Key = key
  213. peerPairLight.Node = enode.NewV4(&key.PublicKey, net.IP{}, 35000, 35000)
  214. return peerPairLight
  215. }