github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/beacon/light/sync/head_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 sync 18 19 import ( 20 "testing" 21 22 "github.com/ethereum/go-ethereum/beacon/light/request" 23 "github.com/ethereum/go-ethereum/beacon/types" 24 "github.com/ethereum/go-ethereum/common" 25 ) 26 27 var ( 28 testServer1 = testServer("testServer1") 29 testServer2 = testServer("testServer2") 30 testServer3 = testServer("testServer3") 31 testServer4 = testServer("testServer4") 32 testServer5 = testServer("testServer5") 33 34 testHead0 = types.HeadInfo{} 35 testHead1 = types.HeadInfo{Slot: 123, BlockRoot: common.Hash{1}} 36 testHead2 = types.HeadInfo{Slot: 124, BlockRoot: common.Hash{2}} 37 testHead3 = types.HeadInfo{Slot: 124, BlockRoot: common.Hash{3}} 38 testHead4 = types.HeadInfo{Slot: 125, BlockRoot: common.Hash{4}} 39 40 testOptUpdate1 = types.OptimisticUpdate{SignatureSlot: 0x0124, Attested: types.HeaderWithExecProof{Header: types.Header{Slot: 0x0123, StateRoot: common.Hash{1}}}} 41 testOptUpdate2 = types.OptimisticUpdate{SignatureSlot: 0x2010, Attested: types.HeaderWithExecProof{Header: types.Header{Slot: 0x200e, StateRoot: common.Hash{2}}}} 42 // testOptUpdate3 is at the end of period 1 but signed in period 2 43 testOptUpdate3 = types.OptimisticUpdate{SignatureSlot: 0x4000, Attested: types.HeaderWithExecProof{Header: types.Header{Slot: 0x3fff, StateRoot: common.Hash{3}}}} 44 testOptUpdate4 = types.OptimisticUpdate{SignatureSlot: 0x6444, Attested: types.HeaderWithExecProof{Header: types.Header{Slot: 0x6443, StateRoot: common.Hash{4}}}} 45 ) 46 47 func finality(opt types.OptimisticUpdate) types.FinalityUpdate { 48 return types.FinalityUpdate{ 49 SignatureSlot: opt.SignatureSlot, 50 Attested: opt.Attested, 51 Finalized: types.HeaderWithExecProof{Header: types.Header{Slot: (opt.Attested.Header.Slot - 64) & uint64(0xffffffffffffffe0)}}, 52 } 53 } 54 55 type testServer string 56 57 func (t testServer) Name() string { 58 return string(t) 59 } 60 61 func TestValidatedHead(t *testing.T) { 62 chain := &TestCommitteeChain{} 63 ht := &TestHeadTracker{} 64 headSync := NewHeadSync(ht, chain) 65 ts := NewTestScheduler(t, headSync) 66 67 ht.ExpValidated(t, 0, nil) 68 69 ts.AddServer(testServer1, 1) 70 ts.ServerEvent(EvNewOptimisticUpdate, testServer1, testOptUpdate1) 71 ts.Run(1, testServer1, ReqFinality{}) 72 // announced head should be queued because of uninitialized chain 73 ht.ExpValidated(t, 1, nil) 74 75 chain.SetNextSyncPeriod(0) // initialize chain 76 ts.Run(2) 77 // expect previously queued head to be validated 78 ht.ExpValidated(t, 2, []types.OptimisticUpdate{testOptUpdate1}) 79 80 chain.SetNextSyncPeriod(1) 81 ts.ServerEvent(EvNewFinalityUpdate, testServer1, finality(testOptUpdate2)) 82 ts.ServerEvent(EvNewOptimisticUpdate, testServer1, testOptUpdate2) 83 ts.AddServer(testServer2, 1) 84 ts.ServerEvent(EvNewOptimisticUpdate, testServer2, testOptUpdate2) 85 ts.Run(3) 86 // expect both head announcements to be validated instantly 87 ht.ExpValidated(t, 3, []types.OptimisticUpdate{testOptUpdate2, testOptUpdate2}) 88 89 ts.ServerEvent(EvNewOptimisticUpdate, testServer1, testOptUpdate3) 90 ts.AddServer(testServer3, 1) 91 ts.ServerEvent(EvNewOptimisticUpdate, testServer3, testOptUpdate4) 92 // finality should be requested from both servers 93 ts.Run(4, testServer1, ReqFinality{}, testServer3, ReqFinality{}) 94 // future period annonced heads should be queued 95 ht.ExpValidated(t, 4, nil) 96 97 chain.SetNextSyncPeriod(2) 98 ts.Run(5) 99 // testOptUpdate3 can be validated now but not testOptUpdate4 100 ht.ExpValidated(t, 5, []types.OptimisticUpdate{testOptUpdate3}) 101 102 ts.AddServer(testServer4, 1) 103 ts.ServerEvent(EvNewOptimisticUpdate, testServer4, testOptUpdate3) 104 // new server joined with recent optimistic update but still no finality; should be requested 105 ts.Run(6, testServer4, ReqFinality{}) 106 ht.ExpValidated(t, 6, []types.OptimisticUpdate{testOptUpdate3}) 107 108 ts.AddServer(testServer5, 1) 109 ts.RequestEvent(request.EvResponse, ts.Request(6, 1), finality(testOptUpdate3)) 110 ts.ServerEvent(EvNewOptimisticUpdate, testServer5, testOptUpdate3) 111 // finality update request answered; new server should not be requested 112 ts.Run(7) 113 ht.ExpValidated(t, 7, []types.OptimisticUpdate{testOptUpdate3}) 114 115 // server 3 disconnected without proving period 3, its announced head should be dropped 116 ts.RemoveServer(testServer3) 117 ts.Run(8) 118 ht.ExpValidated(t, 8, nil) 119 120 chain.SetNextSyncPeriod(3) 121 ts.Run(9) 122 // testOptUpdate4 could be validated now but it's not queued by any registered server 123 ht.ExpValidated(t, 9, nil) 124 125 ts.ServerEvent(EvNewFinalityUpdate, testServer2, finality(testOptUpdate4)) 126 ts.ServerEvent(EvNewOptimisticUpdate, testServer2, testOptUpdate4) 127 ts.Run(10) 128 // now testOptUpdate4 should be validated 129 ht.ExpValidated(t, 10, []types.OptimisticUpdate{testOptUpdate4}) 130 } 131 132 func TestPrefetchHead(t *testing.T) { 133 chain := &TestCommitteeChain{} 134 ht := &TestHeadTracker{} 135 headSync := NewHeadSync(ht, chain) 136 ts := NewTestScheduler(t, headSync) 137 138 ht.ExpPrefetch(t, 0, testHead0) // no servers registered 139 140 ts.AddServer(testServer1, 1) 141 ts.ServerEvent(EvNewHead, testServer1, testHead1) 142 ts.Run(1) 143 ht.ExpPrefetch(t, 1, testHead1) // s1: h1 144 145 ts.AddServer(testServer2, 1) 146 ts.ServerEvent(EvNewHead, testServer2, testHead2) 147 ts.Run(2) 148 ht.ExpPrefetch(t, 2, testHead2) // s1: h1, s2: h2 149 150 ts.ServerEvent(EvNewHead, testServer1, testHead2) 151 ts.Run(3) 152 ht.ExpPrefetch(t, 3, testHead2) // s1: h2, s2: h2 153 154 ts.AddServer(testServer3, 1) 155 ts.ServerEvent(EvNewHead, testServer3, testHead3) 156 ts.Run(4) 157 ht.ExpPrefetch(t, 4, testHead2) // s1: h2, s2: h2, s3: h3 158 159 ts.AddServer(testServer4, 1) 160 ts.ServerEvent(EvNewHead, testServer4, testHead4) 161 ts.Run(5) 162 ht.ExpPrefetch(t, 5, testHead2) // s1: h2, s2: h2, s3: h3, s4: h4 163 164 ts.ServerEvent(EvNewHead, testServer2, testHead3) 165 ts.Run(6) 166 ht.ExpPrefetch(t, 6, testHead3) // s1: h2, s2: h3, s3: h3, s4: h4 167 168 ts.RemoveServer(testServer3) 169 ts.Run(7) 170 ht.ExpPrefetch(t, 7, testHead4) // s1: h2, s2: h3, s4: h4 171 172 ts.RemoveServer(testServer1) 173 ts.Run(8) 174 ht.ExpPrefetch(t, 8, testHead4) // s2: h3, s4: h4 175 176 ts.RemoveServer(testServer4) 177 ts.Run(9) 178 ht.ExpPrefetch(t, 9, testHead3) // s2: h3 179 180 ts.RemoveServer(testServer2) 181 ts.Run(10) 182 ht.ExpPrefetch(t, 10, testHead0) // no servers registered 183 }