Skip to content

Commit

Permalink
fix(miner): payload building writing to closed channel (ethereum#91)
Browse files Browse the repository at this point in the history
  • Loading branch information
cyberhorsey authored and davidtaikocha committed Jun 8, 2023
1 parent 9da8845 commit d706c13
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 0 deletions.
3 changes: 3 additions & 0 deletions miner/payload_building.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ type Payload struct {
stop chan struct{}
lock sync.Mutex
cond *sync.Cond
done chan struct{} // CHANGE(taiko): done channel to communicate we shouldnt write to stop chan
}

// newPayload initializes the payload object.
Expand All @@ -77,6 +78,7 @@ func newPayload(empty *types.Block, id engine.PayloadID) *Payload {
id: id,
empty: empty,
stop: make(chan struct{}),
done: make(chan struct{}, 1), // CHANGE(taiko): buffered channel to communicate done to taiko payload builder
}
log.Info("Starting work on payload", "id", payload.id)
payload.cond = sync.NewCond(&payload.lock)
Expand Down Expand Up @@ -117,6 +119,7 @@ func (payload *Payload) Resolve() *engine.ExecutionPayloadEnvelope {
select {
case <-payload.stop:
default:
payload.done <- struct{}{} // CHANGE(taiko): signal to taiko payload builder to not write to payload.stop channel
close(payload.stop)
}
if payload.full != nil {
Expand Down
2 changes: 2 additions & 0 deletions miner/taiko_payload_building.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ func (payload *Payload) SetFullBlock(block *types.Block, fees *big.Int) {
defer payload.lock.Unlock()

select {
case <-payload.done:
log.Info("SetFullBlock payload done received", "id", payload.id)
case payload.stop <- struct{}{}:
default:
}
Expand Down
83 changes: 83 additions & 0 deletions miner/taiko_payload_building_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package miner

import (
"math/big"
"testing"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
"github.com/stretchr/testify/assert"
)

func newTestBlock() *types.Block {
tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11})
txs := []*types.Transaction{tx1}

block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txs, nil, nil, trie.NewStackTrie(nil))
return block
}

func Test_SetFullBlock_AvoidPanic(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
recipient = common.HexToAddress("0xdeadbeef")
)
w, b := newTestWorker(t, params.TestChainConfig, ethash.NewFaker(), db, 0)
defer w.close()

timestamp := uint64(time.Now().Unix())
args := &BuildPayloadArgs{
Parent: b.chain.CurrentBlock().Hash(),
Timestamp: timestamp,
Random: common.Hash{},
FeeRecipient: recipient,
}
payload, err := w.buildPayload(args)
if err != nil {
t.Fatalf("Failed to build payload %v", err)
}

fees := big.NewInt(1)

payload.done <- struct{}{}
close(payload.stop)

block := newTestBlock()
// expect not to panic sending to payload.stop
// now that done is closed
payload.SetFullBlock(block, fees)
}

func Test_SetFullBlock(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
recipient = common.HexToAddress("0xdeadbeef")
)
w, b := newTestWorker(t, params.TestChainConfig, ethash.NewFaker(), db, 0)
defer w.close()

timestamp := uint64(time.Now().Unix())
args := &BuildPayloadArgs{
Parent: b.chain.CurrentBlock().Hash(),
Timestamp: timestamp,
Random: common.Hash{},
FeeRecipient: recipient,
}
payload, err := w.buildPayload(args)
if err != nil {
t.Fatalf("Failed to build payload %v", err)
}

fees := big.NewInt(1)

block := newTestBlock()
payload.SetFullBlock(block, fees)

assert.Equal(t, block, payload.full)
assert.Equal(t, fees, payload.fullFees)
}

0 comments on commit d706c13

Please sign in to comment.