diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 3be0d70cac..9d92f6c633 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -170,6 +170,7 @@ var ( utils.RollupHaltOnIncompatibleProtocolVersionFlag, utils.RollupSuperchainUpgradesFlag, utils.ParallelTxDAGFlag, + utils.ParallelTxDAGSenderPrivFlag, configFileFlag, utils.LogDebugFlag, utils.LogBacktraceAtFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 92b6e9710a..1cd92cf89c 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -23,7 +23,6 @@ import ( "encoding/hex" "errors" "fmt" - "github.com/ethereum/go-ethereum/core/txpool/bundlepool" "math" "math/big" "net" @@ -35,6 +34,8 @@ import ( "strings" "time" + "github.com/ethereum/go-ethereum/core/txpool/bundlepool" + pcsclite "github.com/gballet/go-libpcsclite" gopsutil "github.com/shirou/gopsutil/mem" "github.com/urfave/cli/v2" @@ -1104,6 +1105,13 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server. Usage: "enable opcode optimization", Category: flags.VMCategory, } + + ParallelTxDAGSenderPrivFlag = &cli.StringFlag{ + Name: "parallel.txdagsenderpriv", + Usage: "private key of the sender who sends the TxDAG transactions", + Value: "", + Category: flags.VMCategory, + } ) var ( @@ -1993,6 +2001,13 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { cfg.EnableParallelTxDAG = ctx.Bool(ParallelTxDAGFlag.Name) } + if ctx.IsSet(ParallelTxDAGSenderPrivFlag.Name) { + priHex := ctx.String(ParallelTxDAGSenderPrivFlag.Name) + if cfg.Miner.ParallelTxDAGSenderPriv, err = crypto.HexToECDSA(priHex); err != nil { + Fatalf("Failed to parse txdag private key of %s, err: %v", ParallelTxDAGSenderPrivFlag.Name, err) + } + } + if ctx.IsSet(VMOpcodeOptimizeFlag.Name) { cfg.EnableOpcodeOptimizing = ctx.Bool(VMOpcodeOptimizeFlag.Name) if cfg.EnableOpcodeOptimizing { diff --git a/miner/miner.go b/miner/miner.go index 8dbe58c45e..08c60c186e 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -19,14 +19,16 @@ package miner import ( "context" + "crypto/ecdsa" "errors" "fmt" - "github.com/ethereum/go-ethereum/consensus/misc/eip1559" - "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "math/big" "sync" "time" + "github.com/ethereum/go-ethereum/consensus/misc/eip1559" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" @@ -108,6 +110,8 @@ type Config struct { EffectiveGasCeil uint64 // if non-zero, a gas ceiling to apply independent of the header's gaslimit value Mev MevConfig // Mev configuration + + ParallelTxDAGSenderPriv *ecdsa.PrivateKey // The private key for the parallel tx DAG sender } // DefaultConfig contains default settings for miner. diff --git a/miner/worker.go b/miner/worker.go index 453700f06e..7c40519cb0 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -18,14 +18,16 @@ package miner import ( "context" + "crypto/ecdsa" "errors" "fmt" - mapset "github.com/deckarep/golang-set/v2" "math/big" "sync" "sync/atomic" "time" + mapset "github.com/deckarep/golang-set/v2" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" @@ -36,6 +38,7 @@ import ( "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/eth/tracers" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" @@ -99,6 +102,10 @@ var ( txErrReplayMeter = metrics.NewRegisteredMeter("miner/tx/replay", nil) ) +var ( + DefaultTxDAGAddress = common.HexToAddress("0xda90000000000000000000000000000000000000") +) + // environment is the worker's current environment and holds all // information of the sealing block generation. type environment struct { @@ -905,10 +912,32 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac } var coalescedLogs []*types.Log + //append the tx DAG transaction to the block + appendTxDAG := func() { + // whether enable TxDAG + if !w.chain.TxDAGEnabledWhenMine() { + return + } + // TODO this is a placeholder for the tx DAG data that will be generated by the stateDB + txForDAG, err := w.generateDAGTx(env.state, env.signer, env.tcount, env.coinbase) + if err != nil { + log.Warn("failed to generate DAG tx", "err", err) + return + } + logs, err := w.commitTransaction(env, txForDAG) + if err != nil { + log.Warn("failed to commit DAG tx", "err", err) + return + } + coalescedLogs = append(coalescedLogs, logs...) + env.tcount++ + } + for { // Check interruption signal and abort building if it's fired. if interrupt != nil { if signal := interrupt.Load(); signal != commitInterruptNone { + appendTxDAG() return signalToErr(signal) } } @@ -1007,6 +1036,7 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac txErrUnknownMeter.Mark(1) } } + appendTxDAG() if !w.isRunning() && len(coalescedLogs) > 0 { // We don't push the pendingLogsEvent while we are sealing. The reason is that // when we are sealing, the worker will regenerate a sealing block every 3 seconds. @@ -1025,6 +1055,58 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac return nil } +// generateDAGTx generates a DAG transaction for the block +func (w *worker) generateDAGTx(statedb *state.StateDB, signer types.Signer, txIndex int, coinbase common.Address) (*types.Transaction, error) { + if statedb == nil { + return nil, fmt.Errorf("failed to get state db, env.state=nil") + } + + if signer == nil { + return nil, fmt.Errorf("current signer is nil") + } + + //privateKey, err := crypto.HexToECDSA(privateKeyHex) + sender := w.config.ParallelTxDAGSenderPriv + receiver := DefaultTxDAGAddress + if sender == nil { + return nil, fmt.Errorf("missing sender private key") + } + + // get txDAG data from the stateDB + txDAG, err := statedb.ResolveTxDAG(txIndex, []common.Address{coinbase, params.OptimismBaseFeeRecipient, params.OptimismL1FeeRecipient}) + if txDAG == nil { + return nil, err + } + // txIndex is the index of this txDAG transaction + txDAG.SetTxDep(txIndex, types.TxDep{Flags: &types.NonDependentRelFlag}) + + publicKey := sender.Public() + publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) + if !ok { + return nil, fmt.Errorf("error casting public key to ECDSA") + } + fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA) + + // get nonce from the + nonce := statedb.GetNonce(fromAddress) + + data, err := types.EncodeTxDAGCalldata(txDAG) + if err != nil { + return nil, fmt.Errorf("failed to encode txDAG, err: %v", err) + } + + // Create the transaction + tx := types.NewTransaction(nonce, receiver, big.NewInt(0), 21100, big.NewInt(0), data) + + // Sign the transaction with the private key + signedTx, err := types.SignTx(tx, signer, sender) + if err != nil { + return nil, fmt.Errorf("failed to sign transaction, err: %v", err) + } + + return signedTx, nil +} + // generateParams wraps various of settings for generating sealing task. type generateParams struct { timestamp uint64 // The timestamp for sealing task