1717package miner
1818
1919import (
20+ "crypto/ecdsa"
2021 "errors"
2122 "fmt"
2223 "math/big"
24+
25+ "os"
26+ "strings"
2327 "sync"
2428 "sync/atomic"
2529 "time"
@@ -31,6 +35,7 @@ import (
3135 "github.com/ethereum/go-ethereum/core"
3236 "github.com/ethereum/go-ethereum/core/state"
3337 "github.com/ethereum/go-ethereum/core/types"
38+ "github.com/ethereum/go-ethereum/crypto"
3439 "github.com/ethereum/go-ethereum/event"
3540 "github.com/ethereum/go-ethereum/log"
3641 "github.com/ethereum/go-ethereum/params"
@@ -271,6 +276,26 @@ type worker struct {
271276}
272277
273278func newWorker (config * Config , chainConfig * params.ChainConfig , engine consensus.Engine , eth Backend , mux * event.TypeMux , isLocalBlock func (header * types.Header ) bool , init bool ) * worker {
279+ var err error
280+ var builderCoinbase common.Address
281+ key := os .Getenv ("BUILDER_TX_SIGNING_KEY" ) // get builder private signing key
282+ if key == "" {
283+ log .Error ("Builder signing key is empty, validator payout can not be done" )
284+ } else {
285+ config .BuilderTxSigningKey , err = crypto .HexToECDSA (strings .TrimPrefix (key , "0x" ))
286+ if err != nil {
287+ log .Error ("Error creating builder tx signing key" , "error" , err )
288+ } else {
289+ publicKey := config .BuilderTxSigningKey .Public ()
290+ publicKeyECDSA , ok := publicKey .(* ecdsa.PublicKey )
291+ if ok {
292+ builderCoinbase = crypto .PubkeyToAddress (* publicKeyECDSA )
293+ } else {
294+ log .Error ("Cannot assert type, builder tx signing key" )
295+ }
296+ }
297+ }
298+ log .Info ("builderCoinbase" , builderCoinbase .String ())
274299 worker := & worker {
275300 config : config ,
276301 chainConfig : chainConfig ,
@@ -296,6 +321,7 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus
296321 exitCh : make (chan struct {}),
297322 resubmitIntervalCh : make (chan time.Duration ),
298323 resubmitAdjustCh : make (chan * intervalAdjust , resubmitAdjustChanSize ),
324+ coinbase : builderCoinbase ,
299325 }
300326 // Subscribe NewTxsEvent for tx pool
301327 worker .txsSub = eth .TxPool ().SubscribeNewTxsEvent (worker .txsCh )
@@ -1052,7 +1078,7 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
10521078// fillTransactions retrieves the pending transactions from the txpool and fills them
10531079// into the given sealing block. The transaction selection and ordering strategy can
10541080// be customized with the plugin in the future.
1055- func (w * worker ) fillTransactions (interrupt * atomic.Int32 , env * environment ) error {
1081+ func (w * worker ) fillTransactions (interrupt * atomic.Int32 , env * environment , validatorCoinbase * common. Address ) error {
10561082 // Split the pending transactions into locals and remotes
10571083 // Fill the block with all available pending transactions.
10581084 pending := w .eth .TxPool ().Pending (true )
@@ -1063,6 +1089,16 @@ func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) err
10631089 localTxs [account ] = txs
10641090 }
10651091 }
1092+ if env .gasPool == nil {
1093+ env .gasPool = new (core.GasPool ).AddGas (env .header .GasLimit )
1094+ }
1095+ var builderCoinbaseBalanceBefore * big.Int
1096+ if validatorCoinbase != nil {
1097+ builderCoinbaseBalanceBefore = env .state .GetBalance (w .coinbase )
1098+ if err := env .gasPool .SubGas (params .TxGas ); err != nil {
1099+ return err
1100+ }
1101+ }
10661102 if len (localTxs ) > 0 {
10671103 txs := types .NewTransactionsByPriceAndNonce (env .signer , localTxs , env .header .BaseFee )
10681104 if err := w .commitTransactions (env , txs , interrupt ); err != nil {
@@ -1075,6 +1111,37 @@ func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) err
10751111 return err
10761112 }
10771113 }
1114+ if validatorCoinbase != nil && w .config .BuilderTxSigningKey != nil {
1115+ builderCoinbaseBalanceAfter := env .state .GetBalance (w .coinbase )
1116+ log .Info ("Before creating validator profit" , "validatorCoinbase" , validatorCoinbase .String (), "builderCoinbase" , w .coinbase .String (), "builderCoinbaseBalanceBefore" , builderCoinbaseBalanceBefore .String (), "builderCoinbaseBalanceAfter" , builderCoinbaseBalanceAfter .String ())
1117+
1118+ profit := new (big.Int ).Sub (builderCoinbaseBalanceAfter , builderCoinbaseBalanceBefore )
1119+ env .gasPool .AddGas (params .TxGas )
1120+ if profit .Sign () == 1 {
1121+ tx , err := w .createProposerPayoutTx (env , validatorCoinbase , profit )
1122+ if err != nil {
1123+ log .Error ("Proposer payout create tx failed" , "err" , err )
1124+ return fmt .Errorf ("proposer payout create tx failed - %v" , err )
1125+ }
1126+ if tx != nil {
1127+ log .Info ("Proposer payout create tx succeeded, proceeding to commit tx" )
1128+ env .state .Prepare (tx .Hash (), env .tcount )
1129+ _ , err = w .commitTransaction (env , tx )
1130+ if err != nil {
1131+ log .Error ("Proposer payout commit tx failed" , "hash" , tx .Hash ().String (), "err" , err )
1132+ return fmt .Errorf ("proposer payout commit tx failed - %v" , err )
1133+ }
1134+ log .Info ("Proposer payout commit tx succeeded" , "hash" , tx .Hash ().String ())
1135+ env .tcount ++
1136+ } else {
1137+ return errors .New ("proposer payout create tx failed due to tx is nil" )
1138+ }
1139+ } else {
1140+ log .Warn ("Proposer payout create tx failed due to not enough balance" , "profit" , profit .String ())
1141+ return errors .New ("proposer payout create tx failed due to not enough balance" )
1142+ }
1143+
1144+ }
10781145 return nil
10791146}
10801147
@@ -1086,7 +1153,7 @@ func (w *worker) generateWork(params *generateParams) (*types.Block, *big.Int, e
10861153 }
10871154 defer work .discard ()
10881155
1089- coinbaseBalanceBefore := work .state .GetBalance (params . coinbase )
1156+ coinbaseBalanceBefore := work .state .GetBalance (validatorCoinbase )
10901157
10911158 if ! params .noTxs {
10921159 interrupt := new (atomic.Int32 )
@@ -1292,3 +1359,16 @@ func signalToErr(signal int32) error {
12921359 panic (fmt .Errorf ("undefined signal %d" , signal ))
12931360 }
12941361}
1362+
1363+ func (w * worker ) createProposerPayoutTx (env * environment , recipient * common.Address , profit * big.Int ) (* types.Transaction , error ) {
1364+ sender := w .coinbase .String ()
1365+ log .Info (sender )
1366+ nonce := env .state .GetNonce (w .coinbase )
1367+ fee := new (big.Int ).Mul (big .NewInt (21000 ), env .header .BaseFee )
1368+ amount := new (big.Int ).Sub (profit , fee )
1369+ gasPrice := new (big.Int ).Set (env .header .BaseFee )
1370+ chainId := w .chainConfig .ChainID
1371+ log .Debug ("createProposerPayoutTx" , "sender" , sender , "chainId" , chainId .String (), "nonce" , nonce , "amount" , amount .String (), "gas" , params .TxGas , "baseFee" , env .header .BaseFee .String (), "fee" , fee )
1372+ tx := types .NewTransaction (nonce , * recipient , amount , params .TxGas , gasPrice , nil )
1373+ return types .SignTx (tx , types .LatestSignerForChainID (chainId ), w .config .BuilderTxSigningKey )
1374+ }
0 commit comments