@@ -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 // staticPool is a legacy pool instance for decrypted transaction verification,
227216 // which is initialized once per height at postBlock callback. It should be reset
228217 // before any reusage at the same height.
@@ -313,9 +302,6 @@ func New(chainCfg *params.ChainConfig, _ ethdb.Database, statisticsCfg Statistic
313302 quit : make (chan struct {}),
314303 finished : make (chan struct {}),
315304
316- validatorsCache : lru.NewCache [uint64 , []common.Address ](validatorsCacheCap ),
317- dkgIndexCache : lru.NewCache [uint64 , []int ](validatorsCacheCap ),
318-
319305 dkgSnapshot : NewSnapshot (),
320306 executeProofTaskChan : make (chan * taskList , 2 ), // The maximum number of task lists per epoch is 3
321307 loopWatchTaskChan : make (chan struct {}),
@@ -442,7 +428,7 @@ func (c *DBFT) getValidatorsCb(txs ...dbft.Transaction[common.Hash]) []dbft.Publ
442428 // getValidatorsSorted with empty args is used by dbft to fill the list of
443429 // block's validators, thus should return validators from the current
444430 // epoch without recalculation.
445- pKeys , err = c .getValidatorsSorted (& c .lastIndex , nil , nil )
431+ pKeys , err = c .extensibleVerifier . GetValidatorsSorted (& c .lastIndex , nil , nil )
446432 }
447433 // getValidatorsSorted with non-empty args is used by dbft to fill block's
448434 // NextConsensus field, but DBFT doesn't provide WithGetConsensusAddress
@@ -1065,7 +1051,7 @@ func (c *DBFT) processPreBlockCb(b dbft.PreBlock[common.Hash]) error {
10651051 )
10661052 for _ , preC := range ctx .PreCommitPayloads {
10671053 if preC != nil && preC .ViewNumber () == ctx .ViewNumber {
1068- dkgIndex , err := c .getDKGIndex (int (preC .ValidatorIndex ()), blockNum )
1054+ dkgIndex , err := c .extensibleVerifier . GetDKGIndex (int (preC .ValidatorIndex ()), blockNum )
10691055 if err != nil {
10701056 return fmt .Errorf ("get DKG index failed: ValidatorIndex %d, block height %d" , int (preC .ValidatorIndex ()), blockNum )
10711057 }
@@ -1409,7 +1395,7 @@ func (c *DBFT) getBlockWitness(pub *tpke.PublicKey, block *Block) ([]byte, error
14091395 if p := dctx .CommitPayloads [i ]; p != nil && p .ViewNumber () == dctx .ViewNumber {
14101396 var err error
14111397 blockNum := block .header .Number .Uint64 () - 1
1412- dkgIndex , err := c .getDKGIndex (i , blockNum )
1398+ dkgIndex , err := c .extensibleVerifier . GetDKGIndex (i , blockNum )
14131399 if err != nil {
14141400 return nil , fmt .Errorf ("get DKG index failed: ValidatorIndex %d, block height %d" , i , blockNum )
14151401 }
@@ -1482,47 +1468,11 @@ func (c *DBFT) WithRequestTxs(f func(hashed []common.Hash)) {
14821468func (c * DBFT ) WithMux (mux * event.TypeMux ) {
14831469 c .mux = mux
14841470 c .blockQueue .SetMux (mux )
1485-
1486- go c .syncWatcher ()
14871471}
14881472
1489- // syncWatcher is a standalone loop aimed to be active irrespectively of dBFT engine
1490- // activity. It tracks the first chain sync attempt till its end.
1491- func (c * DBFT ) syncWatcher () {
1492- downloaderEvents := c .mux .Subscribe (downloader.StartEvent {}, downloader.DoneEvent {}, downloader.FailedEvent {})
1493- defer func () {
1494- if ! downloaderEvents .Closed () {
1495- downloaderEvents .Unsubscribe ()
1496- }
1497- }()
1498- dlEventCh := downloaderEvents .Chan ()
1499-
1500- events:
1501- for {
1502- select {
1503- case <- c .quit :
1504- break events
1505- case ev := <- dlEventCh :
1506- if ev == nil {
1507- // Unsubscription done, stop listening.
1508- dlEventCh = nil
1509- break events
1510- }
1511- switch ev .Data .(type ) {
1512- case downloader.StartEvent :
1513- c .syncing .Store (true )
1514-
1515- case downloader.FailedEvent :
1516- c .syncing .Store (false )
1517-
1518- case downloader.DoneEvent :
1519- c .syncing .Store (false )
1520-
1521- // Stop reacting to downloader events.
1522- downloaderEvents .Unsubscribe ()
1523- }
1524- }
1525- }
1473+ // WithExtensibleVerifier initializes ExtensibleVerifier for extensible payloads verification.
1474+ func (c * DBFT ) WithExtensibleVerifier (ev * verifier.ExtensibleVerifier ) {
1475+ c .extensibleVerifier = ev
15261476}
15271477
15281478// WithTxPool initializes transaction pool API for DBFT interactions with memory pool
@@ -2212,7 +2162,7 @@ func (c *DBFT) eventLoop() {
22122162 // been broadcasted the events are unregistered and the loop is exited. This to
22132163 // prevent a major security vuln where external parties can DOS you with blocks
22142164 // and halt your dBFT operation for as long as the DOS continues.
2215- downloaderEvents := c .mux .Subscribe (downloader.DoneEvent {}, downloader.FailedEvent {})
2165+ downloaderEvents := c .mux .Subscribe (downloader.StartEvent {}, downloader. DoneEvent {}, downloader.FailedEvent {})
22162166 defer func () {
22172167 if ! downloaderEvents .Closed () {
22182168 downloaderEvents .Unsubscribe ()
@@ -2286,7 +2236,11 @@ events:
22862236 continue
22872237 }
22882238 switch ev .Data .(type ) {
2239+ case downloader.StartEvent :
2240+ c .syncing .Store (true )
22892241 case downloader.FailedEvent :
2242+ c .syncing .Store (false )
2243+
22902244 latest := c .chain .CurrentHeader ()
22912245 err := c .handleChainBlock (latest , false )
22922246 if err != nil {
@@ -2297,6 +2251,8 @@ events:
22972251 }
22982252
22992253 case downloader.DoneEvent :
2254+ c .syncing .Store (false )
2255+
23002256 // Stop reacting to downloader events.
23012257 downloaderEvents .Unsubscribe ()
23022258
@@ -2435,7 +2391,7 @@ func payloadFromMessage(ep *dbftproto.Message, getBlockExtraVersion func(*big.In
24352391
24362392func (c * DBFT ) validatePayload (p * Payload ) error {
24372393 h := c .chain .CurrentBlock ().Number .Uint64 ()
2438- validators , err := c .getValidatorsSorted (& h , nil , nil )
2394+ validators , err := c .extensibleVerifier . GetValidatorsSorted (& h , nil , nil )
24392395 if err != nil {
24402396 return fmt .Errorf ("failed to get next block validators: %w" , err )
24412397 }
@@ -2451,25 +2407,6 @@ func (c *DBFT) validatePayload(p *Payload) error {
24512407 return nil
24522408}
24532409
2454- // IsExtensibleAllowed determines if address is allowed to send extensible payloads
2455- // (only consensus payloads for now) at the specified height.
2456- func (c * DBFT ) IsExtensibleAllowed (h uint64 , u common.Address ) error {
2457- // Can't verify extensible sender if the node has an outdated state.
2458- if c .syncing .Load () {
2459- return dbftproto .ErrSyncing
2460- }
2461- // Only validators are included into extensible whitelist for now.
2462- validators , err := c .getValidatorsSorted (& h , nil , nil )
2463- if err != nil {
2464- return fmt .Errorf ("failed to get validators: %w" , err )
2465- }
2466- _ , found := slices .BinarySearchFunc (validators , u , common .Address .Cmp )
2467- if ! found {
2468- return fmt .Errorf ("address is not a validator" )
2469- }
2470- return nil
2471- }
2472-
24732410func (c * DBFT ) newConsensusPayloadCb (ctx * dbft.Context [common.Hash ], t dbft.MessageType , msg any ) dbft.ConsensusPayload [common.Hash ] {
24742411 var cp = new (Payload )
24752412 cp .BlockIndex = uint64 (ctx .BlockIndex )
@@ -2537,7 +2474,7 @@ func (c *DBFT) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, pa
25372474
25382475func (c * DBFT ) calcDifficulty (signer common.Address , parent * types.Header ) * big.Int {
25392476 h := parent .Number .Uint64 ()
2540- vals , err := c .getValidatorsSorted (& h , nil , nil )
2477+ vals , err := c .extensibleVerifier . GetValidatorsSorted (& h , nil , nil )
25412478 if err != nil {
25422479 return nil
25432480 }
@@ -2722,111 +2659,6 @@ func (c *DBFT) APIs(chain consensus.ChainHeaderReader) []rpc.API {
27222659 }}
27232660}
27242661
2725- // getValidatorsSorted returns validators chosen in the result of the latest
2726- // finalized voting epoch. It calls Governance contract under the hood. The call
2727- // is based on the provided state or (if not provided) on the state of the block
2728- // with the specified height. Validators returned from this method are always
2729- // sorted by bytes order (even if the list returned from governance contract is
2730- // sorted in another way). This method uses cached values in case of validators
2731- // requested by block height.
2732- func (c * DBFT ) getValidatorsSorted (blockNum * uint64 , state * state.StateDB , header * types.Header ) ([]common.Address , error ) {
2733- res , err := c .getValidators (blockNum , state , header )
2734- if err != nil {
2735- return nil , err
2736- }
2737-
2738- sortedList := slices .Clone (res )
2739- slices .SortFunc (sortedList , common .Address .Cmp )
2740- return sortedList , err
2741- }
2742-
2743- // getValidators returns validators chosen in the result of the latest finalized
2744- // voting epoch. It calls Governance contract under the hood. The call is based
2745- // on the provided state or (if not provided) on the state of the block with the
2746- // specified height. Validators returned from this method are sorted in the original
2747- // order used by Governance contract. This method uses cached values in case of
2748- // validators requested by block height.
2749- func (c * DBFT ) getValidators (blockNum * uint64 , state * state.StateDB , header * types.Header ) ([]common.Address , error ) {
2750- if c .backend == nil {
2751- return nil , errors .New ("eth API backend is not initialized, dBFT can't function properly" )
2752- }
2753-
2754- if state == nil && blockNum != nil {
2755- vals , ok := c .validatorsCache .Get (* blockNum )
2756- if ok {
2757- return vals , nil
2758- }
2759- }
2760-
2761- // Perform smart contract call.
2762- method := "getCurrentConsensus" // latest finalized epoch validators.
2763- data , err := systemcontracts .GovernanceABI .Pack (method )
2764- if err != nil {
2765- return nil , fmt .Errorf ("failed to pack '%s': %w" , method , err )
2766- }
2767- msgData := hexutil .Bytes (data )
2768- gas := hexutil .Uint64 (50_000_000 ) // more than enough for validators call processing.
2769- args := ethapi.TransactionArgs {
2770- Gas : & gas ,
2771- To : & systemcontracts .GovernanceProxyHash ,
2772- Data : & msgData ,
2773- }
2774-
2775- ctx , cancel := context .WithCancel (context .Background ())
2776- // Cancel when we are finished consuming integers.
2777- defer cancel ()
2778- var result * core.ExecutionResult
2779- if state != nil {
2780- result , err = ethapi .DoCallAtState (ctx , * c .backend , args , state , header , nil , nil , 0 , 0 )
2781- } else if blockNum != nil {
2782- blockNr := rpc .BlockNumberOrHashWithNumber (rpc .BlockNumber (* blockNum ))
2783- result , err = ethapi .DoCall (ctx , * c .backend , args , blockNr , nil , nil , 0 , 0 )
2784- } else {
2785- return nil , fmt .Errorf ("failed to compute validators: both block number and state are nil" )
2786- }
2787- if err != nil {
2788- return nil , fmt .Errorf ("failed to perform '%s' call: %w" , method , err )
2789- }
2790- var res []common.Address
2791- err = unpackContractExecutionResult (& res , result , systemcontracts .GovernanceABI , method )
2792- if err != nil {
2793- return nil , err
2794- }
2795-
2796- // Update cache in case if existing state was used for validators retrieval.
2797- if state == nil && blockNum != nil {
2798- _ = c .validatorsCache .Add (* blockNum , res )
2799- }
2800-
2801- return res , err
2802- }
2803-
2804- // getDKGIndex returns validator dkg index (original validator index +1) by validatorIndex (ordered validator index).
2805- func (c * DBFT ) getDKGIndex (validatorIndex int , blockNum uint64 ) (int , error ) {
2806- indices , ok := c .dkgIndexCache .Get (blockNum )
2807- if ! ok {
2808- originValidators , err := c .getValidators (& blockNum , nil , nil )
2809- if err != nil {
2810- return - 1 , err
2811- }
2812-
2813- indices = make ([]int , len (originValidators ))
2814- for i := range indices {
2815- indices [i ] = i
2816- }
2817- sort .Slice (indices , func (i , j int ) bool {
2818- return originValidators [indices [i ]].Cmp (originValidators [indices [j ]]) < 0
2819- })
2820- _ = c .dkgIndexCache .Add (blockNum , indices )
2821- }
2822-
2823- if validatorIndex < 0 || validatorIndex >= len (indices ) {
2824- return - 1 , fmt .Errorf ("invalid validator index: validators count is %d, requested %d" , len (indices ), validatorIndex )
2825- }
2826- dkgIndex := indices [validatorIndex ] + 1
2827- return dkgIndex , nil
2828- }
2829-
28302662// getGlobalPublicKey returns TPKE global public key. If state is provided, then this state
28312663// is used to recalculate local key based on the KeyManagement contract state. If state is
28322664// not provided, then the node's local keystore is used to retrieve global public key.
@@ -2860,7 +2692,7 @@ func (c *DBFT) getGlobalPublicKey(h *types.Header, s *state.StateDB) (*tpke.Publ
28602692func (c * DBFT ) getNextConsensus (h * types.Header , s * state.StateDB ) (common.Hash , common.Hash ) {
28612693 var multisig , threshold common.Hash
28622694
2863- nextVals , err := c .getValidatorsSorted (nil , s .Copy (), h )
2695+ nextVals , err := c .extensibleVerifier . GetValidatorsSorted (nil , s .Copy (), h )
28642696 if err != nil {
28652697 log .Crit ("Failed to compute next block validators" ,
28662698 "err" , err )
0 commit comments