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  }