@@ -193,6 +193,9 @@ type BlockChainConfig struct {
193
193
// If the value is zero, all transactions of the entire chain will be indexed.
194
194
// If the value is -1, indexing is disabled.
195
195
TxLookupLimit int64
196
+
197
+ // EnableBAL enables block access list creation and verification (TODO better wording here)
198
+ EnableBAL bool
196
199
}
197
200
198
201
// DefaultConfig returns the default config.
@@ -325,11 +328,12 @@ type BlockChain struct {
325
328
stopping atomic.Bool // false if chain is running, true when stopped
326
329
procInterrupt atomic.Bool // interrupt signaler for block processing
327
330
328
- engine consensus.Engine
329
- validator Validator // Block and state validator interface
330
- prefetcher Prefetcher
331
- processor Processor // Block transaction processor interface
332
- logger * tracing.Hooks
331
+ engine consensus.Engine
332
+ validator Validator // Block and state validator interface
333
+ prefetcher Prefetcher
334
+ balPrefetcher balPrefetcher
335
+ processor Processor // Block transaction processor interface
336
+ logger * tracing.Hooks
333
337
334
338
lastForkReadyAlert time.Time // Last time there was a fork readiness print out
335
339
}
@@ -388,6 +392,7 @@ func NewBlockChain(db ethdb.Database, genesis *Genesis, engine consensus.Engine,
388
392
bc .statedb = state .NewDatabase (bc .triedb , nil )
389
393
bc .validator = NewBlockValidator (chainConfig , bc )
390
394
bc .prefetcher = newStatePrefetcher (chainConfig , bc .hc )
395
+ bc .balPrefetcher = balPrefetcher {}
391
396
bc .processor = NewStateProcessor (chainConfig , bc .hc )
392
397
393
398
genesisHeader := bc .GetHeaderByNumber (0 )
@@ -1881,12 +1886,18 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
1881
1886
}
1882
1887
// The traced section of block import.
1883
1888
start := time .Now ()
1884
- res , err := bc .processBlock (parent .Root , block , setHead , makeWitness && len (chain ) == 1 )
1889
+
1890
+ blockHasAccessList := block .Body ().AccessList != nil
1891
+ // BAL generation/verification not enabled pre-selfdestruct removal
1892
+ forkSupportsBAL := bc .chainConfig .IsCancun (block .Number (), block .Time ())
1893
+ makeBAL := forkSupportsBAL && ! blockHasAccessList
1894
+ validateBAL := forkSupportsBAL && blockHasAccessList
1895
+
1896
+ res , err := bc .processBlock (parent .Root , block , setHead , makeWitness && len (chain ) == 1 , makeBAL , validateBAL )
1885
1897
if err != nil {
1886
1898
return nil , it .index , err
1887
1899
}
1888
1900
// Report the import stats before returning the various results
1889
- stats .processed ++
1890
1901
stats .usedGas += res .usedGas
1891
1902
witness = res .witness
1892
1903
@@ -1949,7 +1960,7 @@ type blockProcessingResult struct {
1949
1960
1950
1961
// processBlock executes and validates the given block. If there was no error
1951
1962
// it writes the block and associated state to database.
1952
- func (bc * BlockChain ) processBlock (parentRoot common.Hash , block * types.Block , setHead bool , makeWitness bool ) (_ * blockProcessingResult , blockEndErr error ) {
1963
+ func (bc * BlockChain ) processBlock (parentRoot common.Hash , block * types.Block , setHead bool , makeWitness bool , constructBAL bool , validateBALTesting bool ) (bpr * blockProcessingResult , blockEndErr error ) {
1953
1964
var (
1954
1965
err error
1955
1966
startTime = time .Now ()
@@ -1960,6 +1971,9 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s
1960
1971
1961
1972
if bc .cfg .NoPrefetch {
1962
1973
statedb , err = state .New (parentRoot , bc .statedb )
1974
+ if constructBAL || validateBALTesting {
1975
+ statedb .EnableStateDiffRecording ()
1976
+ }
1963
1977
if err != nil {
1964
1978
return nil , err
1965
1979
}
@@ -1981,6 +1995,9 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s
1981
1995
if err != nil {
1982
1996
return nil , err
1983
1997
}
1998
+ if constructBAL || validateBALTesting {
1999
+ statedb .EnableStateDiffRecording ()
2000
+ }
1984
2001
// Upload the statistics of reader at the end
1985
2002
defer func () {
1986
2003
stats := prefetch .GetStats ()
@@ -1999,7 +2016,11 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s
1999
2016
// Disable tracing for prefetcher executions.
2000
2017
vmCfg := bc .cfg .VmConfig
2001
2018
vmCfg .Tracer = nil
2002
- bc .prefetcher .Prefetch (block , throwaway , vmCfg , & interrupt )
2019
+ if block .Body ().AccessList != nil {
2020
+ bc .balPrefetcher .Prefetch (block , throwaway , & interrupt )
2021
+ } else {
2022
+ bc .prefetcher .Prefetch (block , throwaway , vmCfg , & interrupt )
2023
+ }
2003
2024
2004
2025
blockPrefetchExecuteTimer .Update (time .Since (start ))
2005
2026
if interrupt .Load () {
@@ -2008,6 +2029,10 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s
2008
2029
}(time .Now (), throwaway , block )
2009
2030
}
2010
2031
2032
+ if constructBAL {
2033
+ statedb .EnableBALConstruction ()
2034
+ }
2035
+
2011
2036
// If we are past Byzantium, enable prefetching to pull in trie node paths
2012
2037
// while processing transactions. Before Byzantium the prefetcher is mostly
2013
2038
// useless due to the intermediate root hashing after each transaction.
@@ -2022,8 +2047,15 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s
2022
2047
return nil , err
2023
2048
}
2024
2049
}
2025
- statedb .StartPrefetcher ("chain" , witness )
2026
- defer statedb .StopPrefetcher ()
2050
+
2051
+ // access-list containing blocks don't use the prefetcher because
2052
+ // state root computation proceeds concurrently with transaction
2053
+ // execution, meaning the prefetcher doesn't have any time to run
2054
+ // before the trie nodes are needed for state root computation.
2055
+ if block .Body ().AccessList == nil {
2056
+ statedb .StartPrefetcher ("chain" , witness )
2057
+ defer statedb .StopPrefetcher ()
2058
+ }
2027
2059
}
2028
2060
2029
2061
if bc .logger != nil && bc .logger .OnBlockStart != nil {
@@ -2039,21 +2071,65 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s
2039
2071
}()
2040
2072
}
2041
2073
2042
- // Process block using the parent state as reference point
2043
- pstart := time .Now ()
2044
- res , err := bc .processor .Process (block , statedb , bc .cfg .VmConfig )
2045
- if err != nil {
2046
- bc .reportBlock (block , res , err )
2047
- return nil , err
2074
+ var res * ProcessResult
2075
+ var ptime , vtime time.Duration
2076
+ if block .Body ().AccessList != nil {
2077
+ if block .NumberU64 () == 0 {
2078
+ return nil , fmt .Errorf ("genesis block cannot have a block access list" )
2079
+ }
2080
+ if ! validateBALTesting && ! bc .chainConfig .IsGlamsterdam (block .Number (), block .Time ()) {
2081
+ bc .reportBlock (block , res , fmt .Errorf ("received block containing access list before glamsterdam activated" ))
2082
+ return nil , err
2083
+ }
2084
+ // Process block using the parent state as reference point
2085
+ pstart := time .Now ()
2086
+ var resCh chan * ProcessResult
2087
+ resCh , err = bc .processor .ProcessWithAccessList (block , statedb , bc .cfg .VmConfig )
2088
+ if err != nil {
2089
+ // TODO: okay to pass nil here as execution result?
2090
+ bc .reportBlock (block , nil , err )
2091
+ return nil , err
2092
+ }
2093
+ ptime = time .Since (pstart )
2094
+
2095
+ vstart := time .Now ()
2096
+ var err error
2097
+ res , err = bc .validator .ValidateProcessResult (block , resCh , false )
2098
+ if err != nil {
2099
+ // TODO: okay to pass nil here as execution result?
2100
+ bc .reportBlock (block , nil , err )
2101
+ return nil , err
2102
+ }
2103
+ vtime = time .Since (vstart )
2104
+
2105
+ } else {
2106
+ // Process block using the parent state as reference point
2107
+ pstart := time .Now ()
2108
+ res , err = bc .processor .Process (block , statedb , bc .cfg .VmConfig )
2109
+ if err != nil {
2110
+ bc .reportBlock (block , res , err )
2111
+ return nil , err
2112
+ }
2113
+ ptime = time .Since (pstart )
2114
+
2115
+ vstart := time .Now ()
2116
+ if err := bc .validator .ValidateState (block , statedb , res , false ); err != nil {
2117
+ bc .reportBlock (block , res , err )
2118
+ return nil , err
2119
+ }
2120
+ vtime = time .Since (vstart )
2121
+
2048
2122
}
2049
- ptime := time .Since (pstart )
2050
2123
2051
- vstart := time .Now ()
2052
- if err := bc .validator .ValidateState (block , statedb , res , false ); err != nil {
2053
- bc .reportBlock (block , res , err )
2054
- return nil , err
2124
+ if constructBAL {
2125
+ // very ugly... deep-copy the block body before setting the block access
2126
+ // list on it to prevent mutating the block instance passed by the caller.
2127
+ existingBody := block .Body ()
2128
+ block = block .WithBody (* existingBody )
2129
+ existingBody = block .Body ()
2130
+ existingBody .AccessList = statedb .BlockAccessList ().ToEncodingObj ()
2131
+ block = block .WithBody (* existingBody )
2055
2132
}
2056
- vtime := time .Since (vstart )
2057
2133
2058
2134
// If witnesses was generated and stateless self-validation requested, do
2059
2135
// that now. Self validation should *never* run in production, it's more of
0 commit comments