@@ -19,14 +19,12 @@ package dbft
1919
2020import (
2121 "bytes"
22- "context"
2322 "encoding/binary"
2423 "encoding/hex"
2524 "errors"
2625 "fmt"
2726 "io"
2827 "math/big"
29- "sort"
3028 "sync"
3129 "sync/atomic"
3230 "time"
@@ -35,15 +33,12 @@ import (
3533 "github.com/ethereum/go-ethereum/accounts/abi"
3634 "github.com/ethereum/go-ethereum/antimev"
3735 "github.com/ethereum/go-ethereum/common"
38- "github.com/ethereum/go-ethereum/common/hexutil"
39- "github.com/ethereum/go-ethereum/common/lru"
4036 "github.com/ethereum/go-ethereum/consensus"
4137 "github.com/ethereum/go-ethereum/consensus/dbft/dbftutil"
4238 "github.com/ethereum/go-ethereum/consensus/misc"
4339 "github.com/ethereum/go-ethereum/consensus/misc/eip1559"
4440 "github.com/ethereum/go-ethereum/core"
4541 "github.com/ethereum/go-ethereum/core/state"
46- "github.com/ethereum/go-ethereum/core/systemcontracts"
4742 "github.com/ethereum/go-ethereum/core/txpool"
4843 "github.com/ethereum/go-ethereum/core/txpool/legacypool"
4944 "github.com/ethereum/go-ethereum/core/types"
@@ -52,6 +47,7 @@ import (
5247 "github.com/ethereum/go-ethereum/crypto/tpke"
5348 "github.com/ethereum/go-ethereum/eth/downloader"
5449 dbftproto "github.com/ethereum/go-ethereum/eth/protocols/dbft"
50+ "github.com/ethereum/go-ethereum/eth/verifier"
5551 "github.com/ethereum/go-ethereum/ethdb"
5652 "github.com/ethereum/go-ethereum/event"
5753 "github.com/ethereum/go-ethereum/internal/ethapi"
@@ -87,11 +83,6 @@ const (
8783 // msgsChCap is a capacity of channel that accepts consensus messages from
8884 // dBFT protocol.
8985 msgsChCap = 100
90- // validatorsCacheCap is a capacity of validators cache. It's enough to store
91- // validators for only three potentially subsequent heights, i.e. three latest
92- // blocks to effectivaly verify dBFT payloads travelling through the network and
93- // properly initialize dBFT at the latest height.
94- validatorsCacheCap = 3
9586 // crossEpochDecryptionStartRound is the number of DKG round (as denoted in KeyManagement
9687 // system contract) starting from which continuous cross-epoch Envelopes decryption is supported.
9788 // First DKG round setups sharing key, second DKG round setups resharing key, hence resharing
@@ -218,11 +209,9 @@ type DBFT struct {
218209 finished chan struct {}
219210
220211 // various native contract APIs that dBFT uses.
221- backend * ethapi.Backend
222- txAPI * ethapi.TransactionAPI
223- validatorsCache * lru.Cache [uint64 , []common.Address ]
224- // dkgIndexCache is a cache for storing the index array of the ordered validators
225- dkgIndexCache * lru.Cache [uint64 , []int ]
212+ backend * ethapi.Backend
213+ txAPI * ethapi.TransactionAPI
214+ extensibleVerifier * verifier.ExtensibleVerifier
226215
227216 // The fields below are for testing only
228217 fakeDiff bool // Skip difficulty verifications
@@ -309,9 +298,6 @@ func New(chainCfg *params.ChainConfig, _ ethdb.Database, statisticsCfg Statistic
309298 quit : make (chan struct {}),
310299 finished : make (chan struct {}),
311300
312- validatorsCache : lru.NewCache [uint64 , []common.Address ](validatorsCacheCap ),
313- dkgIndexCache : lru.NewCache [uint64 , []int ](validatorsCacheCap ),
314-
315301 dkgSnapshot : NewSnapshot (),
316302 executeProofTaskChan : make (chan * taskList , 2 ), // The maximum number of task lists per epoch is 3
317303 loopWatchTaskChan : make (chan struct {}),
@@ -438,7 +424,7 @@ func (c *DBFT) getValidatorsCb(txs ...dbft.Transaction[common.Hash]) []dbft.Publ
438424 // getValidatorsSorted with empty args is used by dbft to fill the list of
439425 // block's validators, thus should return validators from the current
440426 // epoch without recalculation.
441- pKeys , err = c .getValidatorsSorted (& c .lastIndex , nil , nil )
427+ pKeys , err = c .extensibleVerifier . GetValidatorsSorted (& c .lastIndex , nil , nil )
442428 }
443429 // getValidatorsSorted with non-empty args is used by dbft to fill block's
444430 // NextConsensus field, but DBFT doesn't provide WithGetConsensusAddress
@@ -1058,7 +1044,7 @@ func (c *DBFT) processPreBlockCb(b dbft.PreBlock[common.Hash]) error {
10581044 )
10591045 for _ , preC := range ctx .PreCommitPayloads {
10601046 if preC != nil && preC .ViewNumber () == ctx .ViewNumber {
1061- dkgIndex , err := c .getDKGIndex (int (preC .ValidatorIndex ()), blockNum )
1047+ dkgIndex , err := c .extensibleVerifier . GetDKGIndex (int (preC .ValidatorIndex ()), blockNum )
10621048 if err != nil {
10631049 return fmt .Errorf ("get DKG index failed: ValidatorIndex %d, block height %d" , int (preC .ValidatorIndex ()), blockNum )
10641050 }
@@ -1400,7 +1386,7 @@ func (c *DBFT) getBlockWitness(pub *tpke.PublicKey, block *Block) ([]byte, error
14001386 if p := dctx .CommitPayloads [i ]; p != nil && p .ViewNumber () == dctx .ViewNumber {
14011387 var err error
14021388 blockNum := block .header .Number .Uint64 () - 1
1403- dkgIndex , err := c .getDKGIndex (i , blockNum )
1389+ dkgIndex , err := c .extensibleVerifier . GetDKGIndex (i , blockNum )
14041390 if err != nil {
14051391 return nil , fmt .Errorf ("get DKG index failed: ValidatorIndex %d, block height %d" , i , blockNum )
14061392 }
@@ -1473,47 +1459,11 @@ func (c *DBFT) WithRequestTxs(f func(hashed []common.Hash)) {
14731459func (c * DBFT ) WithMux (mux * event.TypeMux ) {
14741460 c .mux = mux
14751461 c .blockQueue .SetMux (mux )
1476-
1477- go c .syncWatcher ()
14781462}
14791463
1480- // syncWatcher is a standalone loop aimed to be active irrespectively of dBFT engine
1481- // activity. It tracks the first chain sync attempt till its end.
1482- func (c * DBFT ) syncWatcher () {
1483- downloaderEvents := c .mux .Subscribe (downloader.StartEvent {}, downloader.DoneEvent {}, downloader.FailedEvent {})
1484- defer func () {
1485- if ! downloaderEvents .Closed () {
1486- downloaderEvents .Unsubscribe ()
1487- }
1488- }()
1489- dlEventCh := downloaderEvents .Chan ()
1490-
1491- events:
1492- for {
1493- select {
1494- case <- c .quit :
1495- break events
1496- case ev := <- dlEventCh :
1497- if ev == nil {
1498- // Unsubscription done, stop listening.
1499- dlEventCh = nil
1500- break events
1501- }
1502- switch ev .Data .(type ) {
1503- case downloader.StartEvent :
1504- c .syncing .Store (true )
1505-
1506- case downloader.FailedEvent :
1507- c .syncing .Store (false )
1508-
1509- case downloader.DoneEvent :
1510- c .syncing .Store (false )
1511-
1512- // Stop reacting to downloader events.
1513- downloaderEvents .Unsubscribe ()
1514- }
1515- }
1516- }
1464+ // WithExtensibleVerifier initializes ExtensibleVerifier for extensible payloads verification.
1465+ func (c * DBFT ) WithExtensibleVerifier (ev * verifier.ExtensibleVerifier ) {
1466+ c .extensibleVerifier = ev
15171467}
15181468
15191469// WithTxPool initializes transaction pool API for DBFT interactions with memory pool
@@ -2202,7 +2152,7 @@ func (c *DBFT) eventLoop() {
22022152 // been broadcasted the events are unregistered and the loop is exited. This to
22032153 // prevent a major security vuln where external parties can DOS you with blocks
22042154 // and halt your dBFT operation for as long as the DOS continues.
2205- downloaderEvents := c .mux .Subscribe (downloader.DoneEvent {}, downloader.FailedEvent {})
2155+ downloaderEvents := c .mux .Subscribe (downloader.StartEvent {}, downloader. DoneEvent {}, downloader.FailedEvent {})
22062156 defer func () {
22072157 if ! downloaderEvents .Closed () {
22082158 downloaderEvents .Unsubscribe ()
@@ -2276,7 +2226,11 @@ events:
22762226 continue
22772227 }
22782228 switch ev .Data .(type ) {
2229+ case downloader.StartEvent :
2230+ c .syncing .Store (true )
22792231 case downloader.FailedEvent :
2232+ c .syncing .Store (false )
2233+
22802234 latest := c .chain .CurrentHeader ()
22812235 err := c .handleChainBlock (latest , false )
22822236 if err != nil {
@@ -2287,6 +2241,8 @@ events:
22872241 }
22882242
22892243 case downloader.DoneEvent :
2244+ c .syncing .Store (false )
2245+
22902246 // Stop reacting to downloader events.
22912247 downloaderEvents .Unsubscribe ()
22922248
@@ -2425,7 +2381,7 @@ func payloadFromMessage(ep *dbftproto.Message, getBlockExtraVersion func(*big.In
24252381
24262382func (c * DBFT ) validatePayload (p * Payload ) error {
24272383 h := c .chain .CurrentBlock ().Number .Uint64 ()
2428- validators , err := c .getValidatorsSorted (& h , nil , nil )
2384+ validators , err := c .extensibleVerifier . GetValidatorsSorted (& h , nil , nil )
24292385 if err != nil {
24302386 return fmt .Errorf ("failed to get next block validators: %w" , err )
24312387 }
@@ -2441,25 +2397,6 @@ func (c *DBFT) validatePayload(p *Payload) error {
24412397 return nil
24422398}
24432399
2444- // IsExtensibleAllowed determines if address is allowed to send extensible payloads
2445- // (only consensus payloads for now) at the specified height.
2446- func (c * DBFT ) IsExtensibleAllowed (h uint64 , u common.Address ) error {
2447- // Can't verify extensible sender if the node has an outdated state.
2448- if c .syncing .Load () {
2449- return dbftproto .ErrSyncing
2450- }
2451- // Only validators are included into extensible whitelist for now.
2452- validators , err := c .getValidatorsSorted (& h , nil , nil )
2453- if err != nil {
2454- return fmt .Errorf ("failed to get validators: %w" , err )
2455- }
2456- _ , found := slices .BinarySearchFunc (validators , u , common .Address .Cmp )
2457- if ! found {
2458- return fmt .Errorf ("address is not a validator" )
2459- }
2460- return nil
2461- }
2462-
24632400func (c * DBFT ) newConsensusPayloadCb (ctx * dbft.Context [common.Hash ], t dbft.MessageType , msg any ) dbft.ConsensusPayload [common.Hash ] {
24642401 var cp = new (Payload )
24652402 cp .BlockIndex = uint64 (ctx .BlockIndex )
@@ -2527,7 +2464,7 @@ func (c *DBFT) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, pa
25272464
25282465func (c * DBFT ) calcDifficulty (signer common.Address , parent * types.Header ) * big.Int {
25292466 h := parent .Number .Uint64 ()
2530- vals , err := c .getValidatorsSorted (& h , nil , nil )
2467+ vals , err := c .extensibleVerifier . GetValidatorsSorted (& h , nil , nil )
25312468 if err != nil {
25322469 return nil
25332470 }
@@ -2712,111 +2649,6 @@ func (c *DBFT) APIs(chain consensus.ChainHeaderReader) []rpc.API {
27122649 }}
27132650}
27142651
2715- // getValidatorsSorted returns validators chosen in the result of the latest
2716- // finalized voting epoch. It calls Governance contract under the hood. The call
2717- // is based on the provided state or (if not provided) on the state of the block
2718- // with the specified height. Validators returned from this method are always
2719- // sorted by bytes order (even if the list returned from governance contract is
2720- // sorted in another way). This method uses cached values in case of validators
2721- // requested by block height.
2722- func (c * DBFT ) getValidatorsSorted (blockNum * uint64 , state * state.StateDB , header * types.Header ) ([]common.Address , error ) {
2723- res , err := c .getValidators (blockNum , state , header )
2724- if err != nil {
2725- return nil , err
2726- }
2727-
2728- sortedList := slices .Clone (res )
2729- slices .SortFunc (sortedList , common .Address .Cmp )
2730- return sortedList , err
2731- }
2732-
2733- // getValidators returns validators chosen in the result of the latest finalized
2734- // voting epoch. It calls Governance contract under the hood. The call is based
2735- // on the provided state or (if not provided) on the state of the block with the
2736- // specified height. Validators returned from this method are sorted in the original
2737- // order used by Governance contract. This method uses cached values in case of
2738- // validators requested by block height.
2739- func (c * DBFT ) getValidators (blockNum * uint64 , state * state.StateDB , header * types.Header ) ([]common.Address , error ) {
2740- if c .backend == nil {
2741- return nil , errors .New ("eth API backend is not initialized, dBFT can't function properly" )
2742- }
2743-
2744- if state == nil && blockNum != nil {
2745- vals , ok := c .validatorsCache .Get (* blockNum )
2746- if ok {
2747- return vals , nil
2748- }
2749- }
2750-
2751- // Perform smart contract call.
2752- method := "getCurrentConsensus" // latest finalized epoch validators.
2753- data , err := systemcontracts .GovernanceABI .Pack (method )
2754- if err != nil {
2755- return nil , fmt .Errorf ("failed to pack '%s': %w" , method , err )
2756- }
2757- msgData := hexutil .Bytes (data )
2758- gas := hexutil .Uint64 (50_000_000 ) // more than enough for validators call processing.
2759- args := ethapi.TransactionArgs {
2760- Gas : & gas ,
2761- To : & systemcontracts .GovernanceProxyHash ,
2762- Data : & msgData ,
2763- }
2764-
2765- ctx , cancel := context .WithCancel (context .Background ())
2766- // Cancel when we are finished consuming integers.
2767- defer cancel ()
2768- var result * core.ExecutionResult
2769- if state != nil {
2770- result , err = ethapi .DoCallAtState (ctx , * c .backend , args , state , header , nil , nil , 0 , 0 )
2771- } else if blockNum != nil {
2772- blockNr := rpc .BlockNumberOrHashWithNumber (rpc .BlockNumber (* blockNum ))
2773- result , err = ethapi .DoCall (ctx , * c .backend , args , blockNr , nil , nil , 0 , 0 )
2774- } else {
2775- return nil , fmt .Errorf ("failed to compute validators: both block number and state are nil" )
2776- }
2777- if err != nil {
2778- return nil , fmt .Errorf ("failed to perform '%s' call: %w" , method , err )
2779- }
2780- var res []common.Address
2781- err = unpackContractExecutionResult (& res , result , systemcontracts .GovernanceABI , method )
2782- if err != nil {
2783- return nil , err
2784- }
2785-
2786- // Update cache in case if existing state was used for validators retrieval.
2787- if state == nil && blockNum != nil {
2788- _ = c .validatorsCache .Add (* blockNum , res )
2789- }
2790-
2791- return res , err
2792- }
2793-
2794- // getDKGIndex returns validator dkg index (original validator index +1) by validatorIndex (ordered validator index).
2795- func (c * DBFT ) getDKGIndex (validatorIndex int , blockNum uint64 ) (int , error ) {
2796- indices , ok := c .dkgIndexCache .Get (blockNum )
2797- if ! ok {
2798- originValidators , err := c .getValidators (& blockNum , nil , nil )
2799- if err != nil {
2800- return - 1 , err
2801- }
2802-
2803- indices = make ([]int , len (originValidators ))
2804- for i := range indices {
2805- indices [i ] = i
2806- }
2807- sort .Slice (indices , func (i , j int ) bool {
2808- return originValidators [indices [i ]].Cmp (originValidators [indices [j ]]) < 0
2809- })
2810- _ = c .dkgIndexCache .Add (blockNum , indices )
2811- }
2812-
2813- if validatorIndex < 0 || validatorIndex >= len (indices ) {
2814- return - 1 , fmt .Errorf ("invalid validator index: validators count is %d, requested %d" , len (indices ), validatorIndex )
2815- }
2816- dkgIndex := indices [validatorIndex ] + 1
2817- return dkgIndex , nil
2818- }
2819-
28202652// getGlobalPublicKey returns TPKE global public key. If state is provided, then this state
28212653// is used to recalculate local key based on the KeyManagement contract state. If state is
28222654// not provided, then the node's local keystore is used to retrieve global public key.
@@ -2850,7 +2682,7 @@ func (c *DBFT) getGlobalPublicKey(h *types.Header, s *state.StateDB) (*tpke.Publ
28502682func (c * DBFT ) getNextConsensus (h * types.Header , s * state.StateDB ) (common.Hash , common.Hash ) {
28512683 var multisig , threshold common.Hash
28522684
2853- nextVals , err := c .getValidatorsSorted (nil , s .Copy (), h )
2685+ nextVals , err := c .extensibleVerifier . GetValidatorsSorted (nil , s .Copy (), h )
28542686 if err != nil {
28552687 log .Crit ("Failed to compute next block validators" ,
28562688 "err" , err )
0 commit comments