load L1 fee hooks (#8)

This commit is contained in:
Simon Oswald 2023-12-19 13:06:49 +01:00 committed by GitHub
parent a1b6b2229a
commit 630a9f6f65
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 209 additions and 24 deletions

View file

@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/scwallet"
"github.com/ethereum/go-ethereum/accounts/usbwallet"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/eth/catalyst"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/ethconfig"
@ -43,6 +44,7 @@ import (
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
"github.com/naoina/toml"
"github.com/specularL2/specular/lib/el_golang_lib/hook"
"github.com/urfave/cli/v2"
)
@ -178,6 +180,17 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
}
backend, eth := utils.RegisterEthService(stack, &cfg.Eth)
// <specular modification>
log.Info("initializing specular hooks")
l2ChainId := ctx.Uint64(utils.NetworkIdFlag.Name)
l1FeeRecipient := backend.ChainConfig().L1FeeRecipient
if (l1FeeRecipient != common.Address{}) {
vm := eth.BlockChain().GetVMConfig()
vm.SpecularEVMPreTransferHook = hook.MakeSpecularEVMPreTransferHook(l2ChainId, l1FeeRecipient)
vm.SpecularL1FeeReader = hook.MakeSpecularL1FeeReader(l2ChainId)
}
// <specular modification/>
// Create gauge with geth system and build information
if eth != nil { // The 'eth' backend may be nil in light mode
var protos []string

View file

@ -71,6 +71,9 @@ var (
utils.TxPoolLocalsFlag,
utils.TxPoolNoLocalsFlag,
utils.TxPoolJournalFlag,
// <specular modification>
utils.TxPoolJournalRemotesFlag,
// <specular modification />
utils.TxPoolRejournalFlag,
utils.TxPoolPriceLimitFlag,
utils.TxPoolPriceBumpFlag,

View file

@ -387,6 +387,13 @@ var (
Value: ethconfig.Defaults.TxPool.Lifetime,
Category: flags.TxPoolCategory,
}
// <specular modification>
TxPoolJournalRemotesFlag = &cli.BoolFlag{
Name: "txpool.journalremotes",
Usage: "Includes remote transactions in the journal",
Category: flags.TxPoolCategory,
}
// <specular modification />
// Blob transaction pool settings
BlobPoolDataDirFlag = &cli.StringFlag{
Name: "blobpool.datadir",
@ -1532,6 +1539,11 @@ func setTxPool(ctx *cli.Context, cfg *legacypool.Config) {
if ctx.IsSet(TxPoolJournalFlag.Name) {
cfg.Journal = ctx.String(TxPoolJournalFlag.Name)
}
// <specular modification>
if ctx.IsSet(TxPoolJournalRemotesFlag.Name) {
cfg.JournalRemote = ctx.Bool(TxPoolJournalRemotesFlag.Name)
}
// <specular modification />
if ctx.IsSet(TxPoolRejournalFlag.Name) {
cfg.Rejournal = ctx.Duration(TxPoolRejournalFlag.Name)
}

View file

@ -450,7 +450,9 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
// <specular modification>
if st.evm.Config.SpecularEVMPreTransferHook != nil {
err = st.evm.Config.SpecularEVMPreTransferHook(st.msg, st.evm)
// <specular modification>
err = st.evm.Config.SpecularEVMPreTransferHook(st.msg, st.evm.StateDB)
// <specular modification />
if err != nil {
return nil, err
}

View file

@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
@ -120,6 +121,11 @@ type BlockChain interface {
// StateAt returns a state database for a given root hash (generally the head).
StateAt(root common.Hash) (*state.StateDB, error)
// <specular modification>
// GetVMConfig returns the vm config
GetVMConfig() *vm.Config
// <specular modification />
}
// Config are the configuration parameters of the transaction pool.
@ -129,6 +135,13 @@ type Config struct {
Journal string // Journal of local transactions to survive node restarts
Rejournal time.Duration // Time interval to regenerate the local transaction journal
// <specular modification>
// JournalRemote controls whether journaling includes remote transactions or not.
// When true, all transactions loaded from the journal are treated as remote.
JournalRemote bool
// <specular modification />
PriceLimit uint64 // Minimum gas price to enforce for acceptance into the pool
PriceBump uint64 // Minimum price bump percentage to replace an already existing transaction (nonce)
@ -195,6 +208,10 @@ func (config *Config) sanitize() Config {
return conf
}
// <specular modification>
type L1CostFn func(tx *types.Transaction) *big.Int //
// <specular modification/>
// LegacyPool contains all currently known transactions. Transactions
// enter the pool when they are received from the network or submitted
// locally. They exit the pool when they are included in the blockchain.
@ -235,6 +252,10 @@ type LegacyPool struct {
initDoneCh chan struct{} // is closed once the pool is initialized (for tests)
changesSinceReorg int // A counter for how many drops we've performed in-between reorg.
// <specular modification>
l1CostFn L1CostFn
// <specular modification />
}
type txpoolResetRequest struct {
@ -271,9 +292,19 @@ func New(config Config, chain BlockChain) *LegacyPool {
}
pool.priced = newPricedList(pool.all)
if !config.NoLocals && config.Journal != "" {
// <specular modification>
if (!config.NoLocals || config.JournalRemote) && config.Journal != "" {
pool.journal = newTxJournal(config.Journal)
}
if pool.chain.GetVMConfig().SpecularL1FeeReader != nil {
pool.l1CostFn = func (tx *types.Transaction) *big.Int {
l1Fee, _ := pool.chain.GetVMConfig().SpecularL1FeeReader(tx, pool.currentState)
return l1Fee
}
}
// <specular modification />
return pool
}
@ -307,12 +338,18 @@ func (pool *LegacyPool) Init(gasTip *big.Int, head *types.Header, reserve txpool
// If local transactions and journaling is enabled, load from disk
if pool.journal != nil {
if err := pool.journal.load(pool.addLocals); err != nil {
// <specular modification>
add := pool.addLocals
if pool.config.JournalRemote {
add = pool.addRemotesSync // Use sync version to match pool.AddLocals
}
if err := pool.journal.load(add); err != nil {
log.Warn("Failed to load transaction journal", "err", err)
}
if err := pool.journal.rotate(pool.local()); err != nil {
if err := pool.journal.rotate(pool.toJournal()); err != nil {
log.Warn("Failed to rotate transaction journal", "err", err)
}
// <specular modification />
}
pool.wg.Add(1)
go pool.loop()
@ -380,7 +417,7 @@ func (pool *LegacyPool) loop() {
case <-journal.C:
if pool.journal != nil {
pool.mu.Lock()
if err := pool.journal.rotate(pool.local()); err != nil {
if err := pool.journal.rotate(pool.toJournal()); err != nil {
log.Warn("Failed to rotate local tx journal", "err", err)
}
pool.mu.Unlock()
@ -555,6 +592,26 @@ func (pool *LegacyPool) Locals() []common.Address {
return pool.locals.flatten()
}
// <specular modification>
// toJournal retrieves all transactions that should be included in the journal,
// grouped by origin account and sorted by nonce.
// The returned transaction set is a copy and can be freely modified by calling code.
func (pool *LegacyPool) toJournal() map[common.Address]types.Transactions {
if !pool.config.JournalRemote {
return pool.local()
}
txs := make(map[common.Address]types.Transactions)
for addr, pending := range pool.pending {
txs[addr] = append(txs[addr], pending.Flatten()...)
}
for addr, queued := range pool.queue {
txs[addr] = append(txs[addr], queued.Flatten()...)
}
return txs
}
// <specular modification />
// local retrieves all currently known local transactions, grouped by origin
// account and sorted by nonce. The returned transaction set is a copy and can be
// freely modified by calling code.
@ -620,7 +677,13 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction, local bool) error {
ExistingCost: func(addr common.Address, nonce uint64) *big.Int {
if list := pool.pending[addr]; list != nil {
if tx := list.txs.Get(nonce); tx != nil {
return tx.Cost()
// <specular modification>
cost := tx.Cost()
if pool.chain.GetVMConfig().SpecularL1FeeReader != nil {
l1Fee, _ := pool.chain.GetVMConfig().SpecularL1FeeReader(tx, pool.currentState)
cost.Add(cost, l1Fee)
}
// <specular modification />
}
}
return nil
@ -747,7 +810,7 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e
// Try to replace an existing transaction in the pending pool
if list := pool.pending[from]; list != nil && list.Contains(tx.Nonce()) {
// Nonce already pending, check if required price bump is met
inserted, old := list.Add(tx, pool.config.PriceBump)
inserted, old := list.Add(tx, pool.config.PriceBump, pool.l1CostFn)
if !inserted {
pendingDiscardMeter.Mark(1)
return false, txpool.ErrReplaceUnderpriced
@ -821,7 +884,7 @@ func (pool *LegacyPool) enqueueTx(hash common.Hash, tx *types.Transaction, local
if pool.queue[from] == nil {
pool.queue[from] = newList(false)
}
inserted, old := pool.queue[from].Add(tx, pool.config.PriceBump)
inserted, old := pool.queue[from].Add(tx, pool.config.PriceBump, pool.l1CostFn)
if !inserted {
// An older transaction was better, discard this
queuedDiscardMeter.Mark(1)
@ -875,7 +938,7 @@ func (pool *LegacyPool) promoteTx(addr common.Address, hash common.Hash, tx *typ
}
list := pool.pending[addr]
inserted, old := list.Add(tx, pool.config.PriceBump)
inserted, old := list.Add(tx, pool.config.PriceBump, pool.l1CostFn)
if !inserted {
// An older transaction was better, discard this
pool.all.Remove(hash)
@ -1406,6 +1469,23 @@ func (pool *LegacyPool) reset(oldHead, newHead *types.Header) {
pool.addTxsLocked(reinject, false)
}
// <specular modification>
// getBalanceWithL1Fee returns the balance of the addr minus the L1 fee of the first tx in the list
func (pool *LegacyPool) getBalanceWithL1Fee(addr common.Address, txList *list) *big.Int {
balance := pool.currentState.GetBalance(addr)
if !txList.Empty() && pool.chain.GetVMConfig().SpecularL1FeeReader != nil {
// Reduce the cost-cap by L1 rollup cost of the first tx if necessary. Other txs will get filtered out afterwards.
first := txList.txs.Get((*txList.txs.index)[0])
l1Fee, _ := pool.chain.GetVMConfig().SpecularL1FeeReader(first, pool.currentState)
balance = new(big.Int).Sub(balance, l1Fee) // negative big int is fine
}
return balance
}
// <specular modification />
// promoteExecutables moves transactions that have become processable from the
// future queue to the set of pending transactions. During this process, all
// invalidated transactions (low nonce, low balance) are deleted.
@ -1428,7 +1508,10 @@ func (pool *LegacyPool) promoteExecutables(accounts []common.Address) []*types.T
}
log.Trace("Removed old queued transactions", "count", len(forwards))
// Drop all transactions that are too costly (low balance or out of gas)
drops, _ := list.Filter(pool.currentState.GetBalance(addr), gasLimit)
// <specular modification>
balance := pool.getBalanceWithL1Fee(addr, list)
drops, _ := list.Filter(balance, gasLimit)
// <specular modification />
for _, tx := range drops {
hash := tx.Hash()
pool.all.Remove(hash)
@ -1629,7 +1712,10 @@ func (pool *LegacyPool) demoteUnexecutables() {
log.Trace("Removed old pending transaction", "hash", hash)
}
// Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later
drops, invalids := list.Filter(pool.currentState.GetBalance(addr), gasLimit)
// <specular modification>
balance := pool.getBalanceWithL1Fee(addr, list)
drops, invalids := list.Filter(balance, gasLimit)
// <specular modification />
for _, tx := range drops {
hash := tx.Hash()
log.Trace("Removed unpayable pending transaction", "hash", hash)

View file

@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
@ -65,14 +66,19 @@ type testBlockChain struct {
gasLimit atomic.Uint64
statedb *state.StateDB
chainHeadFeed *event.Feed
vmConfig vm.Config
}
func newTestBlockChain(config *params.ChainConfig, gasLimit uint64, statedb *state.StateDB, chainHeadFeed *event.Feed) *testBlockChain {
bc := testBlockChain{config: config, statedb: statedb, chainHeadFeed: new(event.Feed)}
bc := testBlockChain{config: config, statedb: statedb, chainHeadFeed: new(event.Feed), vmConfig: vm.Config{}}
bc.gasLimit.Store(gasLimit)
return &bc
}
func (bc *testBlockChain) GetVMConfig() *vm.Config {
return &bc.vmConfig
}
func (bc *testBlockChain) Config() *params.ChainConfig {
return bc.config
}
@ -171,6 +177,27 @@ func setupPoolWithConfig(config *params.ChainConfig) (*LegacyPool, *ecdsa.Privat
return pool, key
}
// returns a tx pool with an injected L1 Fee function
// L1 fee is hardcoded to 100 wei
func setupTxPoolWithL1Fee() (*LegacyPool, *ecdsa.PrivateKey) {
config := params.TestChainConfig
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
blockchain := newTestBlockChain(config, 10000000, statedb, new(event.Feed))
blockchain.vmConfig.SpecularL1FeeReader =
func(tx *types.Transaction, db vm.StateDB) (*big.Int, error) {
return big.NewInt(100), nil
}
key, _ := crypto.GenerateKey()
pool := New(testTxPoolConfig, blockchain)
if err := pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()); err != nil {
panic(err)
}
// wait for the pool to initialize
<-pool.initDoneCh
return pool, key
}
// validatePoolInternals checks various consistency invariants within the pool.
func validatePoolInternals(pool *LegacyPool) error {
pool.mu.RLock()

View file

@ -298,7 +298,7 @@ func (l *list) Contains(nonce uint64) bool {
//
// If the new transaction is accepted into the list, the lists' cost and gas
// thresholds are also potentially updated.
func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transaction) {
func (l *list) Add(tx *types.Transaction, priceBump uint64, l1CostFn L1CostFn) (bool, *types.Transaction) {
// If there's an older better transaction, abort
old := l.txs.Get(tx.Nonce())
if old != nil {
@ -326,6 +326,13 @@ func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transa
}
// Add new tx cost to totalcost
l.totalcost.Add(l.totalcost, tx.Cost())
// <specular modification />
if l1CostFn != nil {
if l1Cost := l1CostFn(tx); l1Cost != nil {
l.totalcost.Add(l.totalcost, l1Cost)
}
}
// <specular modification>
// Otherwise overwrite the old transaction with the current one
l.txs.Put(tx)
if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 {

View file

@ -38,7 +38,7 @@ func TestStrictListAdd(t *testing.T) {
// Insert the transactions in a random order
list := newList(true)
for _, v := range rand.Perm(len(txs)) {
list.Add(txs[v], DefaultConfig.PriceBump)
list.Add(txs[v], DefaultConfig.PriceBump, nil)
}
// Verify internal state
if len(list.txs.items) != len(txs) {
@ -65,7 +65,7 @@ func BenchmarkListAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
list := newList(true)
for _, v := range rand.Perm(len(txs)) {
list.Add(txs[v], DefaultConfig.PriceBump)
list.Add(txs[v], DefaultConfig.PriceBump, nil)
list.Filter(priceLimit, DefaultConfig.PriceBump)
}
}

View file

@ -30,6 +30,22 @@ import (
"github.com/ethereum/go-ethereum/params"
)
// <specular modification>
// L1Oracle Update Overhead is the amount of gas consumed by updating the L1Oracle every epoch
const l1OracleUpdateOverhead = uint64(70_000)
func EffectiveGasLimit(gasLimit uint64, config *params.ChainConfig) uint64 {
if (config.L1FeeRecipient != common.Address{}) {
if l1OracleUpdateOverhead < gasLimit {
gasLimit -= l1OracleUpdateOverhead
} else {
gasLimit = 0
}
}
return gasLimit
}
// <specular modification />
// ValidationOptions define certain differences between transaction validation
// across the different pools without having to duplicate those checks.
type ValidationOptions struct {
@ -76,7 +92,7 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
return ErrNegativeValue
}
// Ensure the transaction doesn't exceed the current block limit gas
if head.GasLimit < tx.Gas() {
if EffectiveGasLimit(head.GasLimit, opts.Config) < tx.Gas() {
return ErrGasLimit
}
// Sanity check for extremely large numbers (supported by RLP or RPC)

View file

@ -43,8 +43,8 @@ type MessageInterface interface {
GetSkipAccountChecks() bool
}
type EVMHook func(msg MessageInterface, evm *EVM) error
type EVMHook func(msg MessageInterface, db StateDB) error
type EVMReader func(tx *types.Transaction, db StateDB) (*big.Int, error) //
// <specular modification/>
// Config are the configuration options for the Interpreter
@ -56,6 +56,7 @@ type Config struct {
// <specular modification>
SpecularEVMPreTransferHook EVMHook
SpecularL1FeeReader EVMReader
// <specular modification/>
}

6
go.mod
View file

@ -2,6 +2,8 @@ module github.com/ethereum/go-ethereum
go 1.20
replace github.com/specularL2/specular/lib/el_golang_lib => ../../../lib/el_golang_lib
require (
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0
github.com/Microsoft/go-winio v0.6.1
@ -24,7 +26,7 @@ require (
github.com/fatih/color v1.7.0
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5
github.com/fsnotify/fsnotify v1.6.0
github.com/fsnotify/fsnotify v1.7.0
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff
github.com/gballet/go-verkle v0.0.0-20230607174250-df487255f46b
github.com/go-stack/stack v1.8.1
@ -56,6 +58,7 @@ require (
github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7
github.com/rs/cors v1.7.0
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
github.com/specularL2/specular/lib/el_golang_lib v0.0.0-00010101000000-000000000000
github.com/status-im/keycard-go v0.2.0
github.com/stretchr/testify v1.8.1
github.com/supranational/blst v0.3.11
@ -123,6 +126,7 @@ require (
github.com/prometheus/procfs v0.7.3 // indirect
github.com/rogpeppe/go-internal v1.6.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/specularL2/specular/ops v0.0.0-20231129092153-13f66846bd07 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect

7
go.sum
View file

@ -186,8 +186,8 @@ github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 h1:IZqZOB2fydHte3kUgxrzK5E1fW7RQGeDwE8F/ZZnUYc=
github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8=
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
@ -517,6 +517,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/specularL2/specular/ops v0.0.0-20231129092153-13f66846bd07 h1:1GATCkcQ+bFcTq+JBr18jOrS0WKZ5B62gob7zFm0Rac=
github.com/specularL2/specular/ops v0.0.0-20231129092153-13f66846bd07/go.mod h1:hxwB50nU3AN6FEWsb+RQ4zSrfTIIO6JGlKXPbsa5C2c=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
@ -754,7 +756,6 @@ golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View file

@ -335,8 +335,10 @@ type ChainConfig struct {
IsDevMode bool `json:"isDev,omitempty"`
// <specular modification>
EnableL2EngineApi bool `json:"enableL2EngineApi,omitempty"`
L2BaseFeeRecipient common.Address `json:"l2BaseFeeRecipient,omitempty"`
EnableL2EngineApi bool `json:"enableL2EngineApi,omitempty"`
EnableL2GasLimitApi bool `json:"enableL2GasLimitApi,omitempty"`
L2BaseFeeRecipient common.Address `json:"l2BaseFeeRecipient,omitempty"`
L1FeeRecipient common.Address `json:"l1FeeRecipient,omitempty"`
// <specular modification/>
}
@ -374,6 +376,9 @@ func (c *ChainConfig) Description() string {
case c.EnableL2EngineApi:
banner += "Consensus: L2 gas limit API enabled\n"
banner += fmt.Sprintf(" - L2 Base fee recipient: %s\n", c.L2BaseFeeRecipient)
case c.L1FeeRecipient != common.Address{}:
banner += "Consensus: L1 Fee is enabled\n"
banner += fmt.Sprintf("Consensus: L1 Fee Recipient: %s\n", c.L1FeeRecipient)
// <specular modification/>
case c.Ethash != nil:
if c.TerminalTotalDifficulty == nil {
@ -396,6 +401,14 @@ func (c *ChainConfig) Description() string {
}
banner += "\n"
// <specular modification>
if (c.L1FeeRecipient != common.Address{}) {
banner += "Rollup: L1 Fee is enabled\n"
banner += fmt.Sprintf("Rollup: L1 Fee Recipient: %s\n", c.L1FeeRecipient)
banner += "\n"
}
// <specular modification />
// Create a list of forks with a short description of them. Forks that only
// makes sense for mainnet should be optional at printing to avoid bloating
// the output for testnets and private networks.