github.com/core-coin/go-core/v2@v2.1.9/xcb/protocol_test.go (about) 1 // Copyright 2014 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package xcb 18 19 import ( 20 "fmt" 21 "math/big" 22 "sync" 23 "sync/atomic" 24 "testing" 25 "time" 26 27 "github.com/core-coin/go-core/v2/consensus/cryptore" 28 29 "github.com/core-coin/go-core/v2/common" 30 "github.com/core-coin/go-core/v2/core" 31 "github.com/core-coin/go-core/v2/core/forkid" 32 "github.com/core-coin/go-core/v2/core/rawdb" 33 "github.com/core-coin/go-core/v2/core/types" 34 "github.com/core-coin/go-core/v2/core/vm" 35 "github.com/core-coin/go-core/v2/crypto" 36 "github.com/core-coin/go-core/v2/event" 37 "github.com/core-coin/go-core/v2/p2p" 38 "github.com/core-coin/go-core/v2/p2p/enode" 39 "github.com/core-coin/go-core/v2/params" 40 "github.com/core-coin/go-core/v2/rlp" 41 "github.com/core-coin/go-core/v2/xcb/downloader" 42 ) 43 44 func init() { 45 // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) 46 } 47 48 var testAccount, _ = crypto.UnmarshalPrivateKeyHex("89bdfaa2b6f9c30b94ee98fec96c58ff8507fabf49d36a6267e6cb5516eaa2a9e854eccc041f9f67e109d0eb4f653586855355c5b2b87bb313") 49 50 // Tests that handshake failures are detected and reported correctly. 51 func TestStatusMsgErrors63(t *testing.T) { 52 pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 0, nil, nil) 53 var ( 54 genesis = pm.blockchain.Genesis() 55 head = pm.blockchain.CurrentHeader() 56 td = pm.blockchain.GetTd(head.Hash(), head.Number.Uint64()) 57 ) 58 defer pm.Stop() 59 60 tests := []struct { 61 code uint64 62 data interface{} 63 wantError error 64 }{ 65 { 66 code: TransactionMsg, data: []interface{}{}, 67 wantError: errResp(ErrNoStatusMsg, "first msg has code 2 (!= 0)"), 68 }, 69 { 70 code: StatusMsg, data: statusData63{10, DefaultConfig.NetworkId, td, head.Hash(), genesis.Hash()}, 71 wantError: errResp(ErrProtocolVersionMismatch, "10 (!= %d)", 63), 72 }, 73 { 74 code: StatusMsg, data: statusData63{63, 999, td, head.Hash(), genesis.Hash()}, 75 wantError: errResp(ErrNetworkIDMismatch, "999 (!= %d)", DefaultConfig.NetworkId), 76 }, 77 { 78 code: StatusMsg, data: statusData63{63, DefaultConfig.NetworkId, td, head.Hash(), common.Hash{3}}, 79 wantError: errResp(ErrGenesisMismatch, "0300000000000000 (!= %x)", genesis.Hash().Bytes()[:8]), 80 }, 81 } 82 for i, test := range tests { 83 p, errc := newTestPeer("peer", 63, pm, false) 84 // The send call might hang until reset because 85 // the protocol might not read the payload. 86 go p2p.Send(p.app, test.code, test.data) 87 88 select { 89 case err := <-errc: 90 if err == nil { 91 t.Errorf("test %d: protocol returned nil error, want %q", i, test.wantError) 92 } else if err.Error() != test.wantError.Error() { 93 t.Errorf("test %d: wrong error: got %q, want %q", i, err, test.wantError) 94 } 95 case <-time.After(2 * time.Second): 96 t.Errorf("protocol did not shut down within 2 seconds") 97 } 98 p.close() 99 } 100 } 101 102 func TestStatusMsgErrors64(t *testing.T) { 103 pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 0, nil, nil) 104 var ( 105 genesis = pm.blockchain.Genesis() 106 head = pm.blockchain.CurrentHeader() 107 td = pm.blockchain.GetTd(head.Hash(), head.Number.Uint64()) 108 forkID = forkid.NewID(pm.blockchain.Config(), pm.blockchain.Genesis().Hash(), pm.blockchain.CurrentHeader().Number.Uint64()) 109 ) 110 defer pm.Stop() 111 112 tests := []struct { 113 code uint64 114 data interface{} 115 wantError error 116 }{ 117 { 118 code: TransactionMsg, data: []interface{}{}, 119 wantError: errResp(ErrNoStatusMsg, "first msg has code 2 (!= 0)"), 120 }, 121 { 122 code: StatusMsg, data: statusData{10, DefaultConfig.NetworkId, td, head.Hash(), genesis.Hash(), forkID}, 123 wantError: errResp(ErrProtocolVersionMismatch, "10 (!= %d)", 64), 124 }, 125 { 126 code: StatusMsg, data: statusData{64, 999, td, head.Hash(), genesis.Hash(), forkID}, 127 wantError: errResp(ErrNetworkIDMismatch, "999 (!= %d)", DefaultConfig.NetworkId), 128 }, 129 { 130 code: StatusMsg, data: statusData{64, DefaultConfig.NetworkId, td, head.Hash(), common.Hash{3}, forkID}, 131 wantError: errResp(ErrGenesisMismatch, "0300000000000000000000000000000000000000000000000000000000000000 (!= %x)", genesis.Hash()), 132 }, 133 { 134 code: StatusMsg, data: statusData{64, DefaultConfig.NetworkId, td, head.Hash(), genesis.Hash(), forkid.ID{Hash: [4]byte{0x00, 0x01, 0x02, 0x03}}}, 135 wantError: errResp(ErrForkIDRejected, forkid.ErrLocalIncompatibleOrStale.Error()), 136 }, 137 } 138 for i, test := range tests { 139 p, errc := newTestPeer("peer", 64, pm, false) 140 // The send call might hang until reset because 141 // the protocol might not read the payload. 142 go p2p.Send(p.app, test.code, test.data) 143 144 select { 145 case err := <-errc: 146 if err == nil { 147 t.Errorf("test %d: protocol returned nil error, want %q", i, test.wantError) 148 } else if err.Error() != test.wantError.Error() { 149 t.Errorf("test %d: wrong error: got %q, want %q", i, err, test.wantError) 150 } 151 case <-time.After(2 * time.Second): 152 t.Errorf("protocol did not shut down within 2 seconds") 153 } 154 p.close() 155 } 156 } 157 158 func TestForkIDSplit(t *testing.T) { 159 var ( 160 engine = cryptore.NewFaker() 161 162 configNoFork = ¶ms.ChainConfig{NetworkID: big.NewInt(1)} 163 configProFork = ¶ms.ChainConfig{ 164 NetworkID: big.NewInt(1), 165 EWASMBlock: big.NewInt(2), 166 } 167 dbNoFork = rawdb.NewMemoryDatabase() 168 dbProFork = rawdb.NewMemoryDatabase() 169 170 gspecNoFork = &core.Genesis{Config: configNoFork} 171 gspecProFork = &core.Genesis{Config: configProFork} 172 173 genesisNoFork = gspecNoFork.MustCommit(dbNoFork) 174 genesisProFork = gspecProFork.MustCommit(dbProFork) 175 176 chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, configNoFork, engine, vm.Config{}, nil, nil) 177 chainProFork, _ = core.NewBlockChain(dbProFork, nil, configProFork, engine, vm.Config{}, nil, nil) 178 179 blocksNoFork, _ = core.GenerateChain(configNoFork, genesisNoFork, engine, dbNoFork, 2, nil) 180 blocksProFork, _ = core.GenerateChain(configProFork, genesisProFork, engine, dbProFork, 2, nil) 181 182 xcbNoFork, _ = NewProtocolManager(configNoFork, nil, downloader.FullSync, 1, new(event.TypeMux), &testTxPool{pool: make(map[common.Hash]*types.Transaction)}, engine, chainNoFork, dbNoFork, 1, nil, false) 183 xcbProFork, _ = NewProtocolManager(configProFork, nil, downloader.FullSync, 1, new(event.TypeMux), &testTxPool{pool: make(map[common.Hash]*types.Transaction)}, engine, chainProFork, dbProFork, 1, nil, false) 184 ) 185 xcbNoFork.Start(1000) 186 xcbProFork.Start(1000) 187 188 // Both nodes should allow the other to connect (same genesis, next fork is the same) 189 p2pNoFork, p2pProFork := p2p.MsgPipe() 190 peerNoFork := newPeer(64, p2p.NewPeer(enode.ID{1}, "", nil), p2pNoFork, nil) 191 peerProFork := newPeer(64, p2p.NewPeer(enode.ID{2}, "", nil), p2pProFork, nil) 192 193 errc := make(chan error, 2) 194 go func() { errc <- xcbNoFork.handle(peerProFork) }() 195 go func() { errc <- xcbProFork.handle(peerNoFork) }() 196 197 select { 198 case err := <-errc: 199 t.Fatalf("nofork <-> profork failed: %v", err) 200 case <-time.After(1 * time.Second): 201 p2pNoFork.Close() 202 p2pProFork.Close() 203 } 204 // Progress. Fork's match, so we don't care what the future holds 205 chainNoFork.InsertChain(blocksNoFork[:1]) 206 chainProFork.InsertChain(blocksProFork[:1]) 207 208 p2pNoFork, p2pProFork = p2p.MsgPipe() 209 peerNoFork = newPeer(64, p2p.NewPeer(enode.ID{1}, "", nil), p2pNoFork, nil) 210 peerProFork = newPeer(64, p2p.NewPeer(enode.ID{2}, "", nil), p2pProFork, nil) 211 212 errc = make(chan error, 2) 213 go func() { errc <- xcbNoFork.handle(peerProFork) }() 214 go func() { errc <- xcbProFork.handle(peerNoFork) }() 215 216 select { 217 case err := <-errc: 218 t.Fatalf("nofork <-> profork failed: %v", err) 219 case <-time.After(250 * time.Millisecond): 220 p2pNoFork.Close() 221 p2pProFork.Close() 222 } 223 // Progress into Spurious. Forks mismatch, signalling differing chains, reject 224 chainNoFork.InsertChain(blocksNoFork[1:2]) 225 chainProFork.InsertChain(blocksProFork[1:2]) 226 227 p2pNoFork, p2pProFork = p2p.MsgPipe() 228 peerNoFork = newPeer(64, p2p.NewPeer(enode.ID{1}, "", nil), p2pNoFork, nil) 229 peerProFork = newPeer(64, p2p.NewPeer(enode.ID{2}, "", nil), p2pProFork, nil) 230 231 errc = make(chan error, 2) 232 go func() { errc <- xcbNoFork.handle(peerProFork) }() 233 go func() { errc <- xcbProFork.handle(peerNoFork) }() 234 235 select { 236 case err := <-errc: 237 if want := errResp(ErrForkIDRejected, forkid.ErrLocalIncompatibleOrStale.Error()); err.Error() != want.Error() { 238 t.Fatalf("fork ID rejection error mismatch: have %v, want %v", err, want) 239 } 240 case <-time.After(250 * time.Millisecond): 241 t.Fatalf("split peers not rejected") 242 } 243 } 244 245 // This test checks that received transactions are added to the local pool. 246 func TestRecvTransactions63(t *testing.T) { testRecvTransactions(t, 63) } 247 func TestRecvTransactions64(t *testing.T) { testRecvTransactions(t, 64) } 248 func TestRecvTransactions65(t *testing.T) { testRecvTransactions(t, 65) } 249 250 func testRecvTransactions(t *testing.T, protocol int) { 251 txAdded := make(chan []*types.Transaction) 252 pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 0, nil, txAdded) 253 pm.acceptTxs = 1 // mark synced to accept transactions 254 p, _ := newTestPeer("peer", protocol, pm, true) 255 defer pm.Stop() 256 defer p.close() 257 258 tx := newTestTransaction(testAccount, 0, 0) 259 if err := p2p.Send(p.app, TransactionMsg, []interface{}{tx}); err != nil { 260 t.Fatalf("send error: %v", err) 261 } 262 select { 263 case added := <-txAdded: 264 if len(added) != 1 { 265 t.Errorf("wrong number of added transactions: got %d, want 1", len(added)) 266 } else if added[0].Hash() != tx.Hash() { 267 t.Errorf("added wrong tx hash: got %v, want %v", added[0].Hash(), tx.Hash()) 268 } 269 case <-time.After(2 * time.Second): 270 t.Errorf("no NewTxsEvent received within 2 seconds") 271 } 272 } 273 274 // This test checks that pending transactions are sent. 275 func TestSendTransactions63(t *testing.T) { testSendTransactions(t, 63) } 276 func TestSendTransactions64(t *testing.T) { testSendTransactions(t, 64) } 277 func TestSendTransactions65(t *testing.T) { testSendTransactions(t, 65) } 278 279 func testSendTransactions(t *testing.T, protocol int) { 280 pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 0, nil, nil) 281 defer pm.Stop() 282 283 // Fill the pool with big transactions (use a subscription to wait until all 284 // the transactions are announced to avoid spurious events causing extra 285 // broadcasts). 286 const txsize = txsyncPackSize / 10 287 alltxs := make([]*types.Transaction, 100) 288 for nonce := range alltxs { 289 alltxs[nonce] = newTestTransaction(testAccount, uint64(nonce), txsize) 290 } 291 pm.txpool.AddRemotes(alltxs) 292 time.Sleep(100 * time.Millisecond) // Wait until new tx even gets out of the system (lame) 293 294 // Connect several peers. They should all receive the pending transactions. 295 var wg sync.WaitGroup 296 checktxs := func(p *testPeer) { 297 defer wg.Done() 298 defer p.close() 299 seen := make(map[common.Hash]bool) 300 for _, tx := range alltxs { 301 seen[tx.Hash()] = false 302 } 303 for n := 0; n < len(alltxs) && !t.Failed(); { 304 var forAllHashes func(callback func(hash common.Hash)) 305 switch protocol { 306 case 63: 307 fallthrough 308 case 64: 309 msg, err := p.app.ReadMsg() 310 if err != nil { 311 t.Errorf("%v: read error: %v", p.Peer, err) 312 continue 313 } else if msg.Code != TransactionMsg { 314 t.Errorf("%v: got code %d, want TxMsg", p.Peer, msg.Code) 315 continue 316 } 317 var txs []*types.Transaction 318 if err := msg.Decode(&txs); err != nil { 319 t.Errorf("%v: %v", p.Peer, err) 320 continue 321 } 322 forAllHashes = func(callback func(hash common.Hash)) { 323 for _, tx := range txs { 324 callback(tx.Hash()) 325 } 326 } 327 case 65: 328 msg, err := p.app.ReadMsg() 329 if err != nil { 330 t.Errorf("%v: read error: %v", p.Peer, err) 331 continue 332 } else if msg.Code != NewPooledTransactionHashesMsg { 333 t.Errorf("%v: got code %d, want NewPooledTransactionHashesMsg", p.Peer, msg.Code) 334 continue 335 } 336 var hashes []common.Hash 337 if err := msg.Decode(&hashes); err != nil { 338 t.Errorf("%v: %v", p.Peer, err) 339 continue 340 } 341 forAllHashes = func(callback func(hash common.Hash)) { 342 for _, h := range hashes { 343 callback(h) 344 } 345 } 346 } 347 forAllHashes(func(hash common.Hash) { 348 seentx, want := seen[hash] 349 if seentx { 350 t.Errorf("%v: got tx more than once: %x", p.Peer, hash) 351 } 352 if !want { 353 t.Errorf("%v: got unexpected tx: %x", p.Peer, hash) 354 } 355 seen[hash] = true 356 n++ 357 }) 358 } 359 } 360 for i := 0; i < 3; i++ { 361 p, _ := newTestPeer(fmt.Sprintf("peer #%d", i), protocol, pm, true) 362 wg.Add(1) 363 go checktxs(p) 364 } 365 wg.Wait() 366 } 367 368 func TestTransactionPropagation(t *testing.T) { testSyncTransaction(t, true) } 369 func TestTransactionAnnouncement(t *testing.T) { testSyncTransaction(t, false) } 370 371 func testSyncTransaction(t *testing.T, propagtion bool) { 372 // Create a protocol manager for transaction fetcher and sender 373 pmFetcher, _ := newTestProtocolManagerMust(t, downloader.FastSync, 0, nil, nil) 374 defer pmFetcher.Stop() 375 pmSender, _ := newTestProtocolManagerMust(t, downloader.FastSync, 1024, nil, nil) 376 pmSender.broadcastTxAnnouncesOnly = !propagtion 377 defer pmSender.Stop() 378 379 // Sync up the two peers 380 io1, io2 := p2p.MsgPipe() 381 382 go pmSender.handle(pmSender.newPeer(65, p2p.NewPeer(enode.ID{}, "sender", nil), io2, pmSender.txpool.Get)) 383 go pmFetcher.handle(pmFetcher.newPeer(65, p2p.NewPeer(enode.ID{}, "fetcher", nil), io1, pmFetcher.txpool.Get)) 384 385 time.Sleep(250 * time.Millisecond) 386 pmFetcher.doSync(peerToSyncOp(downloader.FullSync, pmFetcher.peers.BestPeer())) 387 atomic.StoreUint32(&pmFetcher.acceptTxs, 1) 388 389 newTxs := make(chan core.NewTxsEvent, 1024) 390 sub := pmFetcher.txpool.SubscribeNewTxsEvent(newTxs) 391 defer sub.Unsubscribe() 392 393 // Fill the pool with new transactions 394 alltxs := make([]*types.Transaction, 1024) 395 for nonce := range alltxs { 396 alltxs[nonce] = newTestTransaction(testAccount, uint64(nonce), 0) 397 } 398 pmSender.txpool.AddRemotes(alltxs) 399 400 var got int 401 loop: 402 for { 403 select { 404 case ev := <-newTxs: 405 got += len(ev.Txs) 406 if got == 1024 { 407 break loop 408 } 409 case <-time.NewTimer(time.Second).C: 410 t.Fatal("Failed to retrieve all transaction") 411 } 412 } 413 } 414 415 // Tests that the custom union field encoder and decoder works correctly. 416 func TestGetBlockHeadersDataEncodeDecode(t *testing.T) { 417 // Create a "random" hash for testing 418 var hash common.Hash 419 for i := range hash { 420 hash[i] = byte(i) 421 } 422 // Assemble some table driven tests 423 tests := []struct { 424 packet *getBlockHeadersData 425 fail bool 426 }{ 427 // Providing the origin as either a hash or a number should both work 428 {fail: false, packet: &getBlockHeadersData{Origin: hashOrNumber{Number: 314}}}, 429 {fail: false, packet: &getBlockHeadersData{Origin: hashOrNumber{Hash: hash}}}, 430 431 // Providing arbitrary query field should also work 432 {fail: false, packet: &getBlockHeadersData{Origin: hashOrNumber{Number: 314}, Amount: 314, Skip: 1, Reverse: true}}, 433 {fail: false, packet: &getBlockHeadersData{Origin: hashOrNumber{Hash: hash}, Amount: 314, Skip: 1, Reverse: true}}, 434 435 // Providing both the origin hash and origin number must fail 436 {fail: true, packet: &getBlockHeadersData{Origin: hashOrNumber{Hash: hash, Number: 314}}}, 437 } 438 // Iterate over each of the tests and try to encode and then decode 439 for i, tt := range tests { 440 bytes, err := rlp.EncodeToBytes(tt.packet) 441 if err != nil && !tt.fail { 442 t.Fatalf("test %d: failed to encode packet: %v", i, err) 443 } else if err == nil && tt.fail { 444 t.Fatalf("test %d: encode should have failed", i) 445 } 446 if !tt.fail { 447 packet := new(getBlockHeadersData) 448 if err := rlp.DecodeBytes(bytes, packet); err != nil { 449 t.Fatalf("test %d: failed to decode packet: %v", i, err) 450 } 451 if packet.Origin.Hash != tt.packet.Origin.Hash || packet.Origin.Number != tt.packet.Origin.Number || packet.Amount != tt.packet.Amount || 452 packet.Skip != tt.packet.Skip || packet.Reverse != tt.packet.Reverse { 453 t.Fatalf("test %d: encode decode mismatch: have %+v, want %+v", i, packet, tt.packet) 454 } 455 } 456 } 457 }