github.com/ethereum/go-ethereum@v1.16.1/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, err := expHead.ExecutionPayload() 74 if err != nil { 75 t.Fatalf("expHead.ExecutionPayload() failed: %v", err) 76 } 77 expNumber = p.NumberU64() 78 } 79 select { 80 case event := <-headCh: 81 headNumber = event.Block.NumberU64() 82 default: 83 } 84 if headNumber != expNumber { 85 t.Errorf("Wrong head block, expected block number %d, got %d)", expNumber, headNumber) 86 } 87 } 88 89 // no block requests expected until head tracker knows about a head 90 ts.Run(1) 91 expHeadBlock(nil) 92 93 // set block 1 as prefetch head, announced by server 2 94 head1 := blockHeadInfo(testBlock1) 95 ht.prefetch = head1 96 ts.ServerEvent(sync.EvNewHead, testServer2, head1) 97 98 // expect request to server 2 which has announced the head 99 ts.Run(2, testServer2, sync.ReqBeaconBlock(head1.BlockRoot)) 100 101 // valid response 102 ts.RequestEvent(request.EvResponse, ts.Request(2, 1), testBlock1) 103 ts.AddAllowance(testServer2, 1) 104 ts.Run(3) 105 // head block still not expected as the fetched block is not the validated head yet 106 expHeadBlock(nil) 107 108 // set as validated head, expect no further requests but block 1 set as head block 109 ht.validated.Header = testBlock1.Header() 110 ts.Run(4) 111 expHeadBlock(testBlock1) 112 113 // set block 2 as prefetch head, announced by server 1 114 head2 := blockHeadInfo(testBlock2) 115 ht.prefetch = head2 116 ts.ServerEvent(sync.EvNewHead, testServer1, head2) 117 // expect request to server 1 118 ts.Run(5, testServer1, sync.ReqBeaconBlock(head2.BlockRoot)) 119 120 // req2 fails, no further requests expected because server 2 has not announced it 121 ts.RequestEvent(request.EvFail, ts.Request(5, 1), nil) 122 ts.Run(6) 123 124 // set as validated head before retrieving block; now it's assumed to be available from server 2 too 125 ht.validated.Header = testBlock2.Header() 126 // expect req2 retry to server 2 127 ts.Run(7, testServer2, sync.ReqBeaconBlock(head2.BlockRoot)) 128 // now head block should be unavailable again 129 expHeadBlock(nil) 130 131 // valid response, now head block should be block 2 immediately as it is already validated 132 ts.RequestEvent(request.EvResponse, ts.Request(7, 1), testBlock2) 133 ts.Run(8) 134 expHeadBlock(testBlock2) 135 } 136 137 type testHeadTracker struct { 138 prefetch types.HeadInfo 139 validated types.SignedHeader 140 } 141 142 func (h *testHeadTracker) PrefetchHead() types.HeadInfo { 143 return h.prefetch 144 } 145 146 func (h *testHeadTracker) ValidatedOptimistic() (types.OptimisticUpdate, bool) { 147 return types.OptimisticUpdate{ 148 Attested: types.HeaderWithExecProof{Header: h.validated.Header}, 149 Signature: h.validated.Signature, 150 SignatureSlot: h.validated.SignatureSlot, 151 }, h.validated.Header != (types.Header{}) 152 } 153 154 // TODO add test case for finality 155 func (h *testHeadTracker) ValidatedFinality() (types.FinalityUpdate, bool) { 156 finalized := types.NewExecutionHeader(new(deneb.ExecutionPayloadHeader)) 157 return types.FinalityUpdate{ 158 Attested: types.HeaderWithExecProof{Header: h.validated.Header}, 159 Finalized: types.HeaderWithExecProof{PayloadHeader: finalized}, 160 Signature: h.validated.Signature, 161 SignatureSlot: h.validated.SignatureSlot, 162 }, h.validated.Header != (types.Header{}) 163 }