diff --git a/miner/builder.go b/miner/builder.go new file mode 100644 index 0000000000..3aea42a42f --- /dev/null +++ b/miner/builder.go @@ -0,0 +1,221 @@ +package miner + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" +) + +type BuilderConfig struct { + ChainConfig *params.ChainConfig + Engine consensus.Engine + EthBackend Backend + Chain *core.BlockChain + GasCeil uint64 +} + +type BuilderArgs struct { + ParentHash common.Hash + FeeRecipient common.Address + Extra []byte +} + +type Builder struct { + env *environment + wrk *worker + args *BuilderArgs + + profitPre *big.Int +} + +func NewBuilder(config *BuilderConfig, args *BuilderArgs) (*Builder, error) { + b := &Builder{ + args: args, + } + + b.wrk = &worker{ + config: &Config{ + GasCeil: config.GasCeil, + }, + eth: config.EthBackend, + chainConfig: config.ChainConfig, + engine: config.Engine, + chain: config.Chain, + } + + workerParams := &generateParams{ + parentHash: args.ParentHash, + forceTime: false, + coinbase: args.FeeRecipient, + extra: args.Extra, + } + env, err := b.wrk.prepareWork(workerParams) + if err != nil { + return nil, err + } + + env.gasPool = new(core.GasPool).AddGas(env.header.GasLimit) + b.env = env + b.profitPre = env.state.GetBalance(env.coinbase) + + return b, nil +} + +type SBundle struct { + BlockNumber *big.Int `json:"blockNumber,omitempty"` // if BlockNumber is set it must match DecryptionCondition! + MaxBlock *big.Int `json:"maxBlock,omitempty"` + Txs types.Transactions `json:"txs"` + RevertingHashes []common.Hash `json:"revertingHashes,omitempty"` + RefundPercent *int `json:"percent,omitempty"` +} + +func (b *Builder) AddTransaction(txn *types.Transaction) (*types.SimulateTransactionResult, error) { + logs, err := b.wrk.commitTransaction(b.env, txn) + if err != nil { + return &types.SimulateTransactionResult{ + Success: false, + }, nil + } + return receiptToSimResult(&types.Receipt{Logs: logs}), nil +} + +func (b *Builder) AddBundles(bundles []*SBundle) error { + for _, bundle := range bundles { + if err := b.AddBundle(bundle); err != nil { + return err + } + } + return nil +} + +func (b *Builder) AddBundle(bundle *SBundle) error { + work := b.env + + // Assume static 28000 gas transfers for both mev-share and proposer payments + refundTransferCost := new(big.Int).Mul(big.NewInt(28000), work.header.BaseFee) + + // create ephemeral addr and private key for payment txn + ephemeralPrivKey, err := crypto.GenerateKey() + if err != nil { + return err + } + ephemeralAddr := crypto.PubkeyToAddress(ephemeralPrivKey.PublicKey) + + // apply bundle + profitPreBundle := work.state.GetBalance(b.env.coinbase) + if err := b.wrk.rawCommitTransactions(work, bundle.Txs); err != nil { + return err + } + profitPostBundle := work.state.GetBalance(b.env.coinbase) + + // calc & refund user if bundle has multiple txns and wants refund + if len(bundle.Txs) > 1 && bundle.RefundPercent != nil { + // Note: PoC logic, this could be gamed by not sending any eth to coinbase + refundPrct := *bundle.RefundPercent + if refundPrct == 0 { + // default refund + refundPrct = 10 + } + bundleProfit := new(big.Int).Sub(profitPostBundle, profitPreBundle) + refundAmt := new(big.Int).Div(bundleProfit, big.NewInt(int64(refundPrct))) + // subtract payment txn transfer costs + refundAmt = new(big.Int).Sub(refundAmt, refundTransferCost) + + currNonce := work.state.GetNonce(ephemeralAddr) + // HACK to include payment txn + // multi refund block untested + userTx := bundle.Txs[0] // NOTE : assumes first txn is refund recipient + refundAddr, err := types.Sender(types.LatestSignerForChainID(userTx.ChainId()), userTx) + if err != nil { + return err + } + paymentTx, err := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: currNonce, + To: &refundAddr, + Value: refundAmt, + Gas: 28000, + GasPrice: work.header.BaseFee, + }), work.signer, ephemeralPrivKey) + + if err != nil { + return err + } + + // commit payment txn + if err := b.wrk.rawCommitTransactions(work, types.Transactions{paymentTx}); err != nil { + return err + } + } + + return nil +} + +func (b *Builder) FillPending() error { + if err := b.wrk.commitPendingTxs(b.env); err != nil { + return err + } + return nil +} + +func (b *Builder) BuildBlock() (*types.Block, error) { + work := b.env + + // Assume static 28000 gas transfers for both mev-share and proposer payments + refundTransferCost := new(big.Int).Mul(big.NewInt(28000), work.header.BaseFee) + + // create ephemeral addr and private key for payment txn + ephemeralPrivKey, err := crypto.GenerateKey() + if err != nil { + return nil, err + } + ephemeralAddr := crypto.PubkeyToAddress(ephemeralPrivKey.PublicKey) + + profitPost := work.state.GetBalance(b.env.coinbase) + proposerProfit := new(big.Int).Set(profitPost) // = post-pre-transfer_cost + proposerProfit = proposerProfit.Sub(profitPost, b.profitPre) + proposerProfit = proposerProfit.Sub(proposerProfit, refundTransferCost) + + currNonce := work.state.GetNonce(ephemeralAddr) + paymentTx, err := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: currNonce, + To: &b.args.FeeRecipient, + Value: proposerProfit, + Gas: 28000, + GasPrice: work.header.BaseFee, + }), work.signer, ephemeralPrivKey) + if err != nil { + return nil, fmt.Errorf("could not sign proposer payment: %w", err) + } + + // commit payment txn + if err := b.wrk.rawCommitTransactions(work, types.Transactions{paymentTx}); err != nil { + return nil, fmt.Errorf("could not sign proposer payment: %w", err) + } + + block, err := b.wrk.engine.FinalizeAndAssemble(b.wrk.chain, work.header, work.state, work.txs, nil, work.receipts, nil) + if err != nil { + return nil, err + } + return block, nil +} + +func receiptToSimResult(receipt *types.Receipt) *types.SimulateTransactionResult { + result := &types.SimulateTransactionResult{ + Success: true, + Logs: []*types.SimulatedLog{}, + } + for _, log := range receipt.Logs { + result.Logs = append(result.Logs, &types.SimulatedLog{ + Addr: log.Address, + Topics: log.Topics, + Data: log.Data, + }) + } + return result +} diff --git a/miner/builder_test.go b/miner/builder_test.go new file mode 100644 index 0000000000..0077f95656 --- /dev/null +++ b/miner/builder_test.go @@ -0,0 +1,97 @@ +package miner + +import ( + "fmt" + "testing" + + "github.com/ethereum/go-ethereum/consensus/clique" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" + "github.com/stretchr/testify/require" +) + +func TestBuilder_AddTxn_Simple(t *testing.T) { + config, backend := newMockBuilderConfig(t) + + builder, err := NewBuilder(config, &BuilderArgs{}) + require.NoError(t, err) + + tx1 := backend.newRandomTx(true) + + res, err := builder.AddTransaction(tx1) + require.NoError(t, err) + require.True(t, res.Success) + require.Len(t, builder.env.receipts, 1) + + // we cannot add the same transaction again. Note that by design the + // function does not error but returns the SimulateTransactionResult.success = false + res, err = builder.AddTransaction(tx1) + require.NoError(t, err) + require.False(t, res.Success) + require.Len(t, builder.env.receipts, 1) +} + +func TestBuilder_FillTransactions(t *testing.T) { + config, backend := newMockBuilderConfig(t) + + builder, err := NewBuilder(config, &BuilderArgs{}) + require.NoError(t, err) + + tx1 := backend.newRandomTx(true) + errArr := backend.TxPool().Add(types.Transactions{tx1}, false, true) + require.NoError(t, errArr[0]) + + tx2 := backend.newRandomTx(true) + errArr = backend.TxPool().Add(types.Transactions{tx2}, false, true) + require.NoError(t, errArr[0]) + + require.NoError(t, builder.FillPending()) + require.Len(t, builder.env.receipts, 2) + + require.Equal(t, tx1.Hash(), builder.env.receipts[0].TxHash) + require.Equal(t, tx2.Hash(), builder.env.receipts[1].TxHash) +} + +func TestBuilder_Bundle(t *testing.T) { + t.Skip("TODO") +} + +func TestBuilder_BuildBlock(t *testing.T) { + t.Skip("TODO") + + config, backend := newMockBuilderConfig(t) + + builder, err := NewBuilder(config, &BuilderArgs{}) + require.NoError(t, err) + + tx1 := backend.newRandomTx(true) + + _, err = builder.AddTransaction(tx1) + require.NoError(t, err) + + block, err := builder.BuildBlock() + require.NoError(t, err) + fmt.Println(block) +} + +func newMockBuilderConfig(t *testing.T) (*BuilderConfig, *testWorkerBackend) { + var ( + db = rawdb.NewMemoryDatabase() + config = *params.AllCliqueProtocolChanges + ) + config.Clique = ¶ms.CliqueConfig{Period: 1, Epoch: 30000} + engine := clique.New(config.Clique, db) + + w, backend := newTestWorker(t, &config, engine, db, 0) + w.close() + + bConfig := &BuilderConfig{ + ChainConfig: w.chainConfig, + Engine: w.engine, + EthBackend: w.eth, + Chain: w.chain, + GasCeil: 10000000, + } + return bConfig, backend +} diff --git a/suave/builder/builder.go b/suave/builder/builder.go deleted file mode 100644 index 83c695f87a..0000000000 --- a/suave/builder/builder.go +++ /dev/null @@ -1,275 +0,0 @@ -package builder - -import ( - "fmt" - "math/big" - "sync/atomic" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/state" - "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/params" - "github.com/ethereum/go-ethereum/suave/builder/api" -) - -type builder struct { - config *builderConfig - txns []*types.Transaction - receipts []*types.Receipt - state *state.StateDB - gasPool *core.GasPool - gasUsed *uint64 - signer types.Signer - args api.BuildBlockArgs - coinbasePreBalance *big.Int - engine consensus.Engine -} - -type builderConfig struct { - preState *state.StateDB - header *types.Header - config *params.ChainConfig - context core.ChainContext - chainReader consensus.ChainHeaderReader - - // newpayloadTimeout is the maximum timeout allowance for creating payload. - // The default value is 2 seconds but node operator can set it to arbitrary - // large value. A large timeout allowance may cause Geth to fail creating - // a non-empty payload within the specified time and eventually miss the slot - // in case there are some computation expensive transactions in txpool. - newpayloadTimeout time.Duration -} - -func newBuilder(config *builderConfig) *builder { - gp := core.GasPool(config.header.GasLimit) - var gasUsed uint64 - - return &builder{ - config: config, - state: config.preState.Copy(), - gasPool: &gp, - gasUsed: &gasUsed, - signer: types.MakeSigner(config.config, config.header.Number, config.header.Time), - coinbasePreBalance: config.preState.GetBalance(config.header.Coinbase), - } -} - -func (b *builder) takeSnapshot() func() { - indx := len(b.txns) - snap := b.state.Snapshot() - - return func() { - b.txns = b.txns[:indx] - b.receipts = b.receipts[:indx] - b.state.RevertToSnapshot(snap) - } -} - -func (b *builder) AddBundle(bundle api.Bundle) error { - revertFn := b.takeSnapshot() - - // create ephemeral addr and private key for payment txn - ephemeralPrivKey, err := crypto.GenerateKey() - if err != nil { - return err - } - ephemeralAddr := crypto.PubkeyToAddress(ephemeralPrivKey.PublicKey) - - // Assume static 28000 gas transfers for both mev-share and proposer payments - refundTransferCost := new(big.Int).Mul(big.NewInt(28000), b.config.header.BaseFee) - - // apply bundle - profitPreBundle := b.state.GetBalance(b.config.header.Coinbase) - if err := b.AddTransactions(bundle.Txs); err != nil { - revertFn() - return err - } - - profitPostBundle := b.state.GetBalance(b.config.header.Coinbase) - - // calc & refund user if bundle has multiple txns and wants refund - if len(bundle.Txs) > 1 && bundle.RefundPercent != nil { - // Note: PoC logic, this could be gamed by not sending any eth to coinbase - refundPrct := *bundle.RefundPercent - if refundPrct == 0 { - // default refund - refundPrct = 10 - } - bundleProfit := new(big.Int).Sub(profitPostBundle, profitPreBundle) - refundAmt := new(big.Int).Div(bundleProfit, big.NewInt(int64(refundPrct))) - // subtract payment txn transfer costs - refundAmt = new(big.Int).Sub(refundAmt, refundTransferCost) - - currNonce := b.state.GetNonce(ephemeralAddr) - - // HACK to include payment txn - // multi refund block untested - userTx := bundle.Txs[0] // NOTE : assumes first txn is refund recipient - refundAddr, err := types.Sender(types.LatestSignerForChainID(userTx.ChainId()), userTx) - if err != nil { - return err - } - paymentTx, err := types.SignTx(types.NewTx(&types.LegacyTx{ - Nonce: currNonce, - To: &refundAddr, - Value: refundAmt, - Gas: 28000, - GasPrice: b.config.header.BaseFee, - }), b.signer, ephemeralPrivKey) - - if err != nil { - return err - } - - // commit payment txn - if _, err := b.AddTransaction(paymentTx); err != nil { - revertFn() - return err - } - } - - return nil -} - -func (b *builder) AddTransactions(txns types.Transactions) error { - revertFn := b.takeSnapshot() - - for _, txn := range txns { - if _, err := b.AddTransaction(txn); err != nil { - revertFn() - return err - } - } - - return nil -} - -func (b *builder) AddTransaction(txn *types.Transaction) (*types.SimulateTransactionResult, error) { - dummyAuthor := common.Address{} - - vmConfig := vm.Config{ - NoBaseFee: true, - } - - snap := b.state.Snapshot() - - b.state.SetTxContext(txn.Hash(), len(b.txns)) - receipt, err := core.ApplyTransaction(b.config.config, b.config.context, &dummyAuthor, b.gasPool, b.state, b.config.header, txn, b.gasUsed, vmConfig) - if err != nil { - b.state.RevertToSnapshot(snap) - - result := &types.SimulateTransactionResult{ - Success: false, - Error: err.Error(), - } - return result, nil - } - - b.txns = append(b.txns, txn) - b.receipts = append(b.receipts, receipt) - - result := &types.SimulateTransactionResult{ - Success: true, - Logs: []*types.SimulatedLog{}, - } - for _, log := range receipt.Logs { - result.Logs = append(result.Logs, &types.SimulatedLog{ - Addr: log.Address, - Topics: log.Topics, - Data: log.Data, - }) - } - - return result, nil -} - -func (b *builder) commitPendingTxs() error { - interrupt := new(atomic.Int32) - timer := time.AfterFunc(b.config.newpayloadTimeout, func() { - interrupt.Store(commitInterruptTimeout) - }) - defer timer.Stop() - if err := b.fillTransactions(); err != nil { - return err - } - return nil -} - -func (b *builder) fillTransactions() error { - // Split the pending transactions into locals and remotes - // Fill the block with all available pending transactions. - pending := w.eth.TxPool().Pending(true) - localTxs, remoteTxs := make(map[common.Address]types.Transactions), pending - for _, account := range w.eth.TxPool().Locals() { - if txs := remoteTxs[account]; len(txs) > 0 { - delete(remoteTxs, account) - localTxs[account] = txs - } - } - if len(localTxs) > 0 { - txs := types.NewTransactionsByPriceAndNonce(env.signer, localTxs, env.header.BaseFee) - if err := b.commitTransactions(env, txs, interrupt); err != nil { - return err - } - } - if len(remoteTxs) > 0 { - txs := types.NewTransactionsByPriceAndNonce(env.signer, remoteTxs, env.header.BaseFee) - if err := w.commitTransactions(env, txs, interrupt); err != nil { - return err - } - } - return nil -} - -func (b *builder) BuildBlock() error { - if b.args.FillPending { - if err := b.commitPendingTxs(); err != nil { - return err - } - } - - // create ephemeral addr and private key for payment txn - ephemeralPrivKey, err := crypto.GenerateKey() - if err != nil { - return err - } - ephemeralAddr := crypto.PubkeyToAddress(ephemeralPrivKey.PublicKey) - - // Assume static 28000 gas transfers for both mev-share and proposer payments - refundTransferCost := new(big.Int).Mul(big.NewInt(28000), b.config.header.BaseFee) - - profitPost := b.state.GetBalance(b.config.header.Coinbase) - proposerProfit := new(big.Int).Set(profitPost) // = post-pre-transfer_cost - proposerProfit = proposerProfit.Sub(profitPost, b.coinbasePreBalance) - proposerProfit = proposerProfit.Sub(proposerProfit, refundTransferCost) - - currNonce := b.state.GetNonce(ephemeralAddr) - paymentTx, err := types.SignTx(types.NewTx(&types.LegacyTx{ - Nonce: currNonce, - To: &b.args.FeeRecipient, - Value: proposerProfit, - Gas: 28000, - GasPrice: b.config.header.BaseFee, - }), b.signer, ephemeralPrivKey) - if err != nil { - return fmt.Errorf("could not sign proposer payment: %w", err) - } - - // commit payment txn - if _, err := b.AddTransaction(paymentTx); err != nil { - return err - } - - block, err := b.engine.FinalizeAndAssemble(b.config.chainReader, b.config.header, b.state, b.txns, []*types.Header{}, b.receipts, b.args.Withdrawals) - if err != nil { - return err - } - - fmt.Println("-- block --", block) - return nil -} diff --git a/suave/builder/builder_test.go b/suave/builder/builder_test.go deleted file mode 100644 index 0ceae209ae..0000000000 --- a/suave/builder/builder_test.go +++ /dev/null @@ -1,122 +0,0 @@ -package builder - -import ( - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/core/types" - "github.com/stretchr/testify/require" -) - -func TestBuilder_AddTxn_Simple(t *testing.T) { - to := common.Address{0x01, 0x10, 0xab} - - mock := newMockBuilder(t) - txn := mock.state.newTransfer(t, to, big.NewInt(1)) - - _, err := mock.builder.AddTransaction(txn) - require.NoError(t, err) - - mock.expect(t, expectedResult{ - txns: []*types.Transaction{ - txn, - }, - balances: map[common.Address]*big.Int{ - to: big.NewInt(1), - }, - }) -} - -func newMockBuilder(t *testing.T) *mockBuilder { - // create a dummy header at 0 - header := &types.Header{ - Number: big.NewInt(0), - GasLimit: 1000000000000, - Time: 1000, - Difficulty: big.NewInt(1), - } - - mState := newMockState(t) - - m := &mockBuilder{ - state: mState, - } - - stateRef, err := mState.stateAt(mState.stateRoot) - require.NoError(t, err) - - config := &builderConfig{ - header: header, - preState: stateRef, - config: mState.chainConfig, - context: m, // m implements ChainContext with panics - } - m.builder = newBuilder(config) - - return m -} - -type mockBuilder struct { - builder *builder - state *mockState -} - -func (m *mockBuilder) Engine() consensus.Engine { - panic("TODO") -} - -func (m *mockBuilder) GetHeader(common.Hash, uint64) *types.Header { - panic("TODO") -} - -type expectedResult struct { - txns []*types.Transaction - balances map[common.Address]*big.Int -} - -func (m *mockBuilder) expect(t *testing.T, res expectedResult) { - // validate txns - if len(res.txns) != len(m.builder.txns) { - t.Fatalf("expected %d txns, got %d", len(res.txns), len(m.builder.txns)) - } - for indx, txn := range res.txns { - if txn.Hash() != m.builder.txns[indx].Hash() { - t.Fatalf("expected txn %d to be %s, got %s", indx, txn.Hash(), m.builder.txns[indx].Hash()) - } - } - - // The receipts must be the same as the txns - if len(res.txns) != len(m.builder.receipts) { - t.Fatalf("expected %d receipts, got %d", len(res.txns), len(m.builder.receipts)) - } - for indx, txn := range res.txns { - if txn.Hash() != m.builder.receipts[indx].TxHash { - t.Fatalf("expected receipt %d to be %s, got %s", indx, txn.Hash(), m.builder.receipts[indx].TxHash) - } - } - - // The gas left in the pool must be the header gas limit minus - // the total gas consumed by all the transactions in the block. - totalGasConsumed := uint64(0) - for _, receipt := range m.builder.receipts { - totalGasConsumed += receipt.GasUsed - } - if m.builder.gasPool.Gas() != m.builder.config.header.GasLimit-totalGasConsumed { - t.Fatalf("expected gas pool to be %d, got %d", m.builder.config.header.GasLimit-totalGasConsumed, m.builder.gasPool.Gas()) - } - - // The 'gasUsed' must match the total gas consumed by all the transactions - if *m.builder.gasUsed != totalGasConsumed { - t.Fatalf("expected gas used to be %d, got %d", totalGasConsumed, m.builder.gasUsed) - } - - // The state must match the expected balances - for addr, expectedBalance := range res.balances { - balance := m.builder.state.GetBalance(addr) - if balance.Cmp(expectedBalance) != 0 { - t.Fatalf("expected balance of %s to be %d, got %d", addr, expectedBalance, balance) - } - } -} diff --git a/suave/builder/session_manager.go b/suave/builder/session_manager.go index 6ed89f288e..012f628514 100644 --- a/suave/builder/session_manager.go +++ b/suave/builder/session_manager.go @@ -12,6 +12,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/suave/builder/api" "github.com/google/uuid" @@ -40,7 +41,7 @@ type Config struct { type SessionManager struct { sem chan struct{} - sessions map[string]*builder + sessions map[string]*miner.Builder sessionTimers map[string]*time.Timer sessionsLock sync.RWMutex blockchain blockchain @@ -65,7 +66,7 @@ func NewSessionManager(blockchain blockchain, config *Config) *SessionManager { s := &SessionManager{ sem: sem, - sessions: make(map[string]*builder), + sessions: make(map[string]*miner.Builder), sessionTimers: make(map[string]*time.Timer), blockchain: blockchain, config: config, @@ -84,41 +85,22 @@ func (s *SessionManager) NewSession(ctx context.Context, args *api.BuildBlockArg return "", ctx.Err() } - parent := s.blockchain.CurrentHeader() - chainConfig := s.blockchain.Config() - - header := &types.Header{ - ParentHash: parent.Hash(), - Number: new(big.Int).Add(parent.Number, common.Big1), - GasLimit: core.CalcGasLimit(parent.GasLimit, s.config.GasCeil), - Time: 1000, // TODO: fix this - Coinbase: common.Address{}, // TODO: fix this - Difficulty: big.NewInt(1), + builderCfg := &miner.BuilderConfig{ + ChainConfig: s.blockchain.Config(), + Engine: s.blockchain.Engine(), + // TODO } - // Set baseFee and GasLimit if we are on an EIP-1559 chain - if chainConfig.IsLondon(header.Number) { - header.BaseFee = CalcBaseFee(chainConfig, parent) - if !chainConfig.IsLondon(parent.Number) { - parentGasLimit := parent.GasLimit * chainConfig.ElasticityMultiplier() - header.GasLimit = core.CalcGasLimit(parentGasLimit, s.config.GasCeil) - } - } - - stateRef, err := s.blockchain.StateAt(parent.Root) - if err != nil { - return "", err - } - - cfg := &builderConfig{ - preState: stateRef, - header: header, - config: s.blockchain.Config(), - context: s.blockchain, + builderArgs := &miner.BuilderArgs{ + ParentHash: args.Parent, } id := uuid.New().String()[:7] - s.sessions[id] = newBuilder(cfg) + session, err := miner.NewBuilder(builderCfg, builderArgs) + if err != nil { + return "", err + } + s.sessions[id] = session // start session timer s.sessionTimers[id] = time.AfterFunc(s.config.SessionIdleTimeout, func() { @@ -140,7 +122,7 @@ func (s *SessionManager) NewSession(ctx context.Context, args *api.BuildBlockArg return id, nil } -func (s *SessionManager) getSession(sessionId string) (*builder, error) { +func (s *SessionManager) getSession(sessionId string) (*miner.Builder, error) { s.sessionsLock.RLock() defer s.sessionsLock.RUnlock() @@ -168,7 +150,7 @@ func (s *SessionManager) AddBundle(sessionId string, bundle api.Bundle) error { if err != nil { return err } - return builder.AddBundle(bundle) + return builder.AddBundle(nil) // TODO: Use api.Bundle type } func (s *SessionManager) BuildBlock(sessionId string) error { @@ -176,7 +158,8 @@ func (s *SessionManager) BuildBlock(sessionId string) error { if err != nil { return err } - return builder.BuildBlock() + _, err = builder.BuildBlock() // TODO: Return more info + return err } // CalcBaseFee calculates the basefee of the header.