github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/beacon/blsync/block_sync_test.go (about) 1 // Copyright 2023 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 blsync 18 19 import ( 20 "testing" 21 22 "github.com/ethereum/go-ethereum/beacon/light/request" 23 "github.com/ethereum/go-ethereum/beacon/light/sync" 24 "github.com/ethereum/go-ethereum/beacon/types" 25 "github.com/ethereum/go-ethereum/common" 26 zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common" 27 "github.com/protolambda/zrnt/eth2/beacon/deneb" 28 ) 29 30 var ( 31 testServer1 = testServer("testServer1") 32 testServer2 = testServer("testServer2") 33 34 testBlock1 = types.NewBeaconBlock(&deneb.BeaconBlock{ 35 Slot: 123, 36 Body: deneb.BeaconBlockBody{ 37 ExecutionPayload: deneb.ExecutionPayload{ 38 BlockNumber: 456, 39 BlockHash: zrntcommon.Hash32(common.HexToHash("905ac721c4058d9ed40b27b6b9c1bdd10d4333e4f3d9769100bf9dfb80e5d1f6")), 40 }, 41 }, 42 }) 43 testBlock2 = types.NewBeaconBlock(&deneb.BeaconBlock{ 44 Slot: 124, 45 Body: deneb.BeaconBlockBody{ 46 ExecutionPayload: deneb.ExecutionPayload{ 47 BlockNumber: 457, 48 BlockHash: zrntcommon.Hash32(common.HexToHash("011703f39c664efc1c6cf5f49ca09b595581eec572d4dfddd3d6179a9e63e655")), 49 }, 50 }, 51 }) 52 ) 53 54 type testServer string 55 56 func (t testServer) Name() string { 57 return string(t) 58 } 59 60 func TestBlockSync(t *testing.T) { 61 ht := &testHeadTracker{} 62 blockSync := newBeaconBlockSync(ht) 63 headCh := make(chan types.ChainHeadEvent, 16) 64 blockSync.SubscribeChainHead(headCh) 65 ts := sync.NewTestScheduler(t, blockSync) 66 ts.AddServer(testServer1, 1) 67 ts.AddServer(testServer2, 1) 68 69 expHeadBlock := func(expHead *types.BeaconBlock) { 70 t.Helper() 71 var expNumber, headNumber uint64 72 if expHead != nil { 73 p, _ := expHead.ExecutionPayload() 74 expNumber = p.NumberU64() 75 } 76 select { 77 case event := <-headCh: 78 headNumber = event.Block.NumberU64() 79 default: 80 } 81 if headNumber != expNumber { 82 t.Errorf("Wrong head block, expected block number %d, got %d)", expNumber, headNumber) 83 } 84 } 85 86 // no block requests expected until head tracker knows about a head 87 ts.Run(1) 88 expHeadBlock(nil) 89 90 // set block 1 as prefetch head, announced by server 2 91 head1 := blockHeadInfo(testBlock1) 92 ht.prefetch = head1 93 ts.ServerEvent(sync.EvNewHead, testServer2, head1) 94 95 // expect request to server 2 which has announced the head 96 ts.Run(2, testServer2, sync.ReqBeaconBlock(head1.BlockRoot)) 97 98 // valid response 99 ts.RequestEvent(request.EvResponse, ts.Request(2, 1), testBlock1) 100 ts.AddAllowance(testServer2, 1) 101 ts.Run(3) 102 // head block still not expected as the fetched block is not the validated head yet 103 expHeadBlock(nil) 104 105 // set as validated head, expect no further requests but block 1 set as head block 106 ht.validated.Header = testBlock1.Header() 107 ts.Run(4) 108 expHeadBlock(testBlock1) 109 110 // set block 2 as prefetch head, announced by server 1 111 head2 := blockHeadInfo(testBlock2) 112 ht.prefetch = head2 113 ts.ServerEvent(sync.EvNewHead, testServer1, head2) 114 // expect request to server 1 115 ts.Run(5, testServer1, sync.ReqBeaconBlock(head2.BlockRoot)) 116 117 // req2 fails, no further requests expected because server 2 has not announced it 118 ts.RequestEvent(request.EvFail, ts.Request(5, 1), nil) 119 ts.Run(6) 120 121 // set as validated head before retrieving block; now it's assumed to be available from server 2 too 122 ht.validated.Header = testBlock2.Header() 123 // expect req2 retry to server 2 124 ts.Run(7, testServer2, sync.ReqBeaconBlock(head2.BlockRoot)) 125 // now head block should be unavailable again 126 expHeadBlock(nil) 127 128 // valid response, now head block should be block 2 immediately as it is already validated 129 ts.RequestEvent(request.EvResponse, ts.Request(7, 1), testBlock2) 130 ts.Run(8) 131 expHeadBlock(testBlock2) 132 } 133 134 type testHeadTracker struct { 135 prefetch types.HeadInfo 136 validated types.SignedHeader 137 } 138 139 func (h *testHeadTracker) PrefetchHead() types.HeadInfo { 140 return h.prefetch 141 } 142 143 func (h *testHeadTracker) ValidatedOptimistic() (types.OptimisticUpdate, bool) { 144 return types.OptimisticUpdate{ 145 Attested: types.HeaderWithExecProof{Header: h.validated.Header}, 146 Signature: h.validated.Signature, 147 SignatureSlot: h.validated.SignatureSlot, 148 }, h.validated.Header != (types.Header{}) 149 } 150 151 // TODO add test case for finality 152 func (h *testHeadTracker) ValidatedFinality() (types.FinalityUpdate, bool) { 153 finalized := types.NewExecutionHeader(new(deneb.ExecutionPayloadHeader)) 154 return types.FinalityUpdate{ 155 Attested: types.HeaderWithExecProof{Header: h.validated.Header}, 156 Finalized: types.HeaderWithExecProof{PayloadHeader: finalized}, 157 Signature: h.validated.Signature, 158 SignatureSlot: h.validated.SignatureSlot, 159 }, h.validated.Header != (types.Header{}) 160 }