Skip to content

Commit 32a101a

Browse files
committed
feat: before- and after-block hooks with additional arguments
1 parent 866bb86 commit 32a101a

File tree

2 files changed

+36
-10
lines changed

2 files changed

+36
-10
lines changed

libevm/precompiles/parallel/parallel.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/ava-labs/libevm/core/types"
3030
"github.com/ava-labs/libevm/core/vm"
3131
"github.com/ava-labs/libevm/libevm"
32+
"github.com/ava-labs/libevm/libevm/stateconf"
3233
"github.com/ava-labs/libevm/params"
3334
)
3435

@@ -43,10 +44,22 @@ import (
4344
//
4445
// Scenario (2) allows precompile access to be determined through inspection of
4546
// the [types.Transaction] alone, without the need for execution.
47+
//
48+
// All [libevm.StateReader] instances are opened to the state at the beginning
49+
// of the block. The [StateDB] is the same one used to execute the block,
50+
// before being committed, and MAY be written to.
4651
type Handler[Result any] interface {
47-
BeforeBlock(*types.Header)
52+
BeforeBlock(libevm.StateReader, *types.Block)
4853
Gas(*types.Transaction) (gas uint64, process bool)
4954
Process(sdb libevm.StateReader, index int, tx *types.Transaction) Result
55+
AfterBlock(StateDB, *types.Block, types.Receipts)
56+
}
57+
58+
// StateDB is the subset of [state.StateDB] methods that MAY be called by
59+
// [Handler.AfterBlock].
60+
type StateDB interface {
61+
libevm.StateReader
62+
SetState(_ common.Address, key, val common.Hash, _ ...stateconf.StateDBStateOption)
5063
}
5164

5265
// A Processor orchestrates dispatch and collection of results from a [Handler].
@@ -162,9 +175,19 @@ func (p *Processor[R]) Close() {
162175
// StartBlock dispatches transactions to the [Handler] and returns immediately.
163176
// It MUST be paired with a call to [Processor.FinishBlock], without overlap of
164177
// blocks.
165-
func (p *Processor[R]) StartBlock(b *types.Block, rules params.Rules, sdb *state.StateDB) error {
178+
func (p *Processor[R]) StartBlock(sdb *state.StateDB, rules params.Rules, b *types.Block) error {
179+
// The distribution mechanism copies the StateDB so we don't need to do it
180+
// here, but the [Handler] is called directly so we do copy.
166181
p.stateShare.distribute(sdb)
167-
p.handler.BeforeBlock(types.CopyHeader(b.Header()))
182+
p.handler.BeforeBlock(
183+
sdb.Copy(),
184+
types.NewBlockWithHeader(
185+
b.Header(),
186+
).WithBody(
187+
*b.Body(),
188+
),
189+
)
190+
168191
txs := b.Transactions()
169192
jobs := make([]*job, 0, len(txs))
170193

@@ -206,14 +229,15 @@ func (p *Processor[R]) StartBlock(b *types.Block, rules params.Rules, sdb *state
206229
// FinishBlock returns the [Processor] to a state ready for the next block. A
207230
// return from FinishBlock guarantees that all dispatched work from the
208231
// respective call to [Processor.StartBlock] has been completed.
209-
func (p *Processor[R]) FinishBlock(b *types.Block) {
232+
func (p *Processor[R]) FinishBlock(sdb vm.StateDB, b *types.Block, rs types.Receipts) {
210233
for i := range len(b.Transactions()) {
211234
// Every result channel is guaranteed to have some value in its buffer
212235
// because [Processor.BeforeBlock] either sends a nil *R or it
213236
// dispatches a job, which will send a non-nil *R.
214237
tx := (<-p.results[i]).tx
215238
delete(p.txGas, tx)
216239
}
240+
p.handler.AfterBlock(sdb, b, rs)
217241
}
218242

219243
// Result blocks until the i'th transaction passed to [Processor.StartBlock] has

libevm/precompiles/parallel/parallel_test.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ type concat struct {
5454
gas uint64
5555
}
5656

57-
func (c *concat) BeforeBlock(h *types.Header) {
58-
c.headerExtra = slices.Clone(h.Extra)
57+
func (c *concat) BeforeBlock(_ libevm.StateReader, b *types.Block) {
58+
c.headerExtra = slices.Clone(b.Header().Extra)
5959
}
6060

6161
func (c *concat) Gas(tx *types.Transaction) (uint64, bool) {
@@ -77,6 +77,8 @@ func (c *concat) Process(sdb libevm.StateReader, i int, tx *types.Transaction) [
7777
)
7878
}
7979

80+
func (*concat) AfterBlock(StateDB, *types.Block, types.Receipts) {}
81+
8082
func TestProcessor(t *testing.T) {
8183
handler := &concat{
8284
addr: common.Address{'c', 'o', 'n', 'c', 'a', 't'},
@@ -173,8 +175,8 @@ func TestProcessor(t *testing.T) {
173175

174176
extra := []byte("extra")
175177
block := types.NewBlock(&types.Header{Extra: extra}, txs, nil, nil, trie.NewStackTrie(nil))
176-
require.NoError(t, p.StartBlock(block, rules, sdb), "StartBlock()")
177-
defer p.FinishBlock(block)
178+
require.NoError(t, p.StartBlock(sdb, rules, block), "StartBlock()")
179+
defer p.FinishBlock(sdb, block, nil)
178180

179181
for i, tx := range txs {
180182
wantOK := wantProcessed[i]
@@ -305,8 +307,7 @@ func TestIntegration(t *testing.T) {
305307
}
306308

307309
block := types.NewBlock(header, txs, nil, nil, trie.NewStackTrie(nil))
308-
require.NoError(t, sut.StartBlock(block, rules, state), "StartBlock()")
309-
defer sut.FinishBlock(block)
310+
require.NoError(t, sut.StartBlock(state, rules, block), "StartBlock()")
310311

311312
pool := core.GasPool(math.MaxUint64)
312313
var got []*types.Receipt
@@ -332,4 +333,5 @@ func TestIntegration(t *testing.T) {
332333
if diff := cmp.Diff(want, got, ignore); diff != "" {
333334
t.Errorf("%T diff (-want +got):\n%s", got, diff)
334335
}
336+
sut.FinishBlock(state, block, got)
335337
}

0 commit comments

Comments
 (0)