github.com/c4dt/go-ethereum@v1.9.2/les/ulc_test.go (about) 1 // Copyright 2018 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 17 package les 18 19 import ( 20 "crypto/ecdsa" 21 "fmt" 22 "math/big" 23 "net" 24 "reflect" 25 "testing" 26 "time" 27 28 "github.com/ethereum/go-ethereum/common/mclock" 29 "github.com/ethereum/go-ethereum/core/rawdb" 30 "github.com/ethereum/go-ethereum/crypto" 31 "github.com/ethereum/go-ethereum/light" 32 "github.com/ethereum/go-ethereum/p2p" 33 "github.com/ethereum/go-ethereum/p2p/enode" 34 ) 35 36 func TestULCSyncWithOnePeer(t *testing.T) { 37 f := newFullPeerPair(t, 1, 4) 38 l := newLightPeer(t, []string{f.Node.String()}, 100) 39 40 if reflect.DeepEqual(f.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) { 41 t.Fatal("blocks are equal") 42 } 43 _, _, err := connectPeers(f, l, 2) 44 if err != nil { 45 t.Fatal(err) 46 } 47 l.PM.fetcher.lock.Lock() 48 l.PM.fetcher.nextRequest() 49 l.PM.fetcher.lock.Unlock() 50 51 if !reflect.DeepEqual(f.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) { 52 t.Fatal("sync doesn't work") 53 } 54 } 55 56 func TestULCReceiveAnnounce(t *testing.T) { 57 f := newFullPeerPair(t, 1, 4) 58 l := newLightPeer(t, []string{f.Node.String()}, 100) 59 fPeer, lPeer, err := connectPeers(f, l, 2) 60 if err != nil { 61 t.Fatal(err) 62 } 63 l.PM.synchronise(fPeer) 64 65 //check that the sync is finished correctly 66 if !reflect.DeepEqual(f.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) { 67 t.Fatal("sync doesn't work") 68 } 69 l.PM.peers.lock.Lock() 70 if len(l.PM.peers.peers) == 0 { 71 t.Fatal("peer list should not be empty") 72 } 73 l.PM.peers.lock.Unlock() 74 75 time.Sleep(time.Second) 76 //send a signed announce message(payload doesn't matter) 77 td := f.PM.blockchain.GetTd(l.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Number.Uint64()) 78 announce := announceData{ 79 Number: l.PM.blockchain.CurrentHeader().Number.Uint64() + 1, 80 Td: td.Add(td, big.NewInt(1)), 81 } 82 announce.sign(f.Key) 83 lPeer.SendAnnounce(announce) 84 } 85 86 func TestULCShouldNotSyncWithTwoPeersOneHaveEmptyChain(t *testing.T) { 87 f1 := newFullPeerPair(t, 1, 4) 88 f2 := newFullPeerPair(t, 2, 0) 89 l := newLightPeer(t, []string{f1.Node.String(), f2.Node.String()}, 100) 90 _, _, err := connectPeers(f1, l, 2) 91 if err != nil { 92 t.Fatal(err) 93 } 94 _, _, err = connectPeers(f2, l, 2) 95 if err != nil { 96 t.Fatal(err) 97 } 98 l.PM.fetcher.lock.Lock() 99 l.PM.fetcher.nextRequest() 100 l.PM.fetcher.lock.Unlock() 101 102 if reflect.DeepEqual(f2.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) { 103 t.Fatal("Incorrect hash: second peer has empty chain") 104 } 105 } 106 107 func TestULCShouldNotSyncWithThreePeersOneHaveEmptyChain(t *testing.T) { 108 f1 := newFullPeerPair(t, 1, 3) 109 f2 := newFullPeerPair(t, 2, 4) 110 f3 := newFullPeerPair(t, 3, 0) 111 112 l := newLightPeer(t, []string{f1.Node.String(), f2.Node.String(), f3.Node.String()}, 60) 113 _, _, err := connectPeers(f1, l, 2) 114 if err != nil { 115 t.Fatal(err) 116 } 117 _, _, err = connectPeers(f2, l, 2) 118 if err != nil { 119 t.Fatal(err) 120 } 121 _, _, err = connectPeers(f3, l, 2) 122 if err != nil { 123 t.Fatal(err) 124 } 125 l.PM.fetcher.lock.Lock() 126 l.PM.fetcher.nextRequest() 127 l.PM.fetcher.lock.Unlock() 128 129 if !reflect.DeepEqual(f1.PM.blockchain.CurrentHeader().Hash(), l.PM.blockchain.CurrentHeader().Hash()) { 130 t.Fatal("Incorrect hash") 131 } 132 } 133 134 type pairPeer struct { 135 Name string 136 Node *enode.Node 137 PM *ProtocolManager 138 Key *ecdsa.PrivateKey 139 } 140 141 func connectPeers(full, light pairPeer, version int) (*peer, *peer, error) { 142 // Create a message pipe to communicate through 143 app, net := p2p.MsgPipe() 144 145 peerLight := full.PM.newPeer(version, NetworkId, p2p.NewPeer(light.Node.ID(), light.Name, nil), net) 146 peerFull := light.PM.newPeer(version, NetworkId, p2p.NewPeer(full.Node.ID(), full.Name, nil), app) 147 148 // Start the peerLight on a new thread 149 errc1 := make(chan error, 1) 150 errc2 := make(chan error, 1) 151 go func() { 152 select { 153 case light.PM.newPeerCh <- peerFull: 154 errc1 <- light.PM.handle(peerFull) 155 case <-light.PM.quitSync: 156 errc1 <- p2p.DiscQuitting 157 } 158 }() 159 go func() { 160 select { 161 case full.PM.newPeerCh <- peerLight: 162 errc2 <- full.PM.handle(peerLight) 163 case <-full.PM.quitSync: 164 errc2 <- p2p.DiscQuitting 165 } 166 }() 167 168 select { 169 case <-time.After(time.Millisecond * 100): 170 case err := <-errc1: 171 return nil, nil, fmt.Errorf("peerLight handshake error: %v", err) 172 case err := <-errc2: 173 return nil, nil, fmt.Errorf("peerFull handshake error: %v", err) 174 } 175 176 return peerFull, peerLight, nil 177 } 178 179 // newFullPeerPair creates node with full sync mode 180 func newFullPeerPair(t *testing.T, index int, numberOfblocks int) pairPeer { 181 db := rawdb.NewMemoryDatabase() 182 183 pmFull, _ := newTestProtocolManagerMust(t, false, numberOfblocks, nil, nil, nil, db, nil, 0) 184 185 peerPairFull := pairPeer{ 186 Name: "full node", 187 PM: pmFull, 188 } 189 key, err := crypto.GenerateKey() 190 if err != nil { 191 t.Fatal("generate key err:", err) 192 } 193 peerPairFull.Key = key 194 peerPairFull.Node = enode.NewV4(&key.PublicKey, net.ParseIP("127.0.0.1"), 35000, 35000) 195 return peerPairFull 196 } 197 198 // newLightPeer creates node with light sync mode 199 func newLightPeer(t *testing.T, ulcServers []string, ulcFraction int) pairPeer { 200 peers := newPeerSet() 201 dist := newRequestDistributor(peers, make(chan struct{}), &mclock.System{}) 202 rm := newRetrieveManager(peers, dist, nil) 203 ldb := rawdb.NewMemoryDatabase() 204 205 odr := NewLesOdr(ldb, light.DefaultClientIndexerConfig, rm) 206 207 pmLight, _ := newTestProtocolManagerMust(t, true, 0, odr, nil, peers, ldb, ulcServers, ulcFraction) 208 peerPairLight := pairPeer{ 209 Name: "ulc node", 210 PM: pmLight, 211 } 212 key, err := crypto.GenerateKey() 213 if err != nil { 214 t.Fatal("generate key err:", err) 215 } 216 peerPairLight.Key = key 217 peerPairLight.Node = enode.NewV4(&key.PublicKey, net.IP{}, 35000, 35000) 218 return peerPairLight 219 }