Skip to content

Commit f5266fb

Browse files
vms/platformvm: Process atomicRequests and onAcceptFunc in option blocks (#2459)
Co-authored-by: Stephen Buttolph <stephen@avalabs.org>
1 parent 2fd8931 commit f5266fb

File tree

5 files changed

+98
-27
lines changed

5 files changed

+98
-27
lines changed

vms/platformvm/block/executor/acceptor.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,23 @@ func (a *acceptor) optionBlock(b, parent block.Block, blockType string) error {
180180
return err
181181
}
182182

183-
if err := a.state.Commit(); err != nil {
184-
return err
183+
defer a.state.Abort()
184+
batch, err := a.state.CommitBatch()
185+
if err != nil {
186+
return fmt.Errorf(
187+
"failed to commit VM's database for block %s: %w",
188+
blkID,
189+
err,
190+
)
191+
}
192+
193+
// Note that this method writes [batch] to the database.
194+
if err := a.ctx.SharedMemory.Apply(blkState.atomicRequests, batch); err != nil {
195+
return fmt.Errorf("failed to apply vm's state to shared memory: %w", err)
196+
}
197+
198+
if onAcceptFunc := blkState.onAcceptFunc; onAcceptFunc != nil {
199+
onAcceptFunc()
185200
}
186201

187202
a.ctx.Log.Trace(

vms/platformvm/block/executor/acceptor_test.go

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package executor
55

66
import (
77
"testing"
8+
"time"
89

910
"github.com/stretchr/testify/require"
1011

@@ -124,7 +125,7 @@ func TestAcceptorVisitAtomicBlock(t *testing.T) {
124125
// Set [blk]'s state in the map as though it had been verified.
125126
onAcceptState := state.NewMockDiff(ctrl)
126127
childID := ids.GenerateTestID()
127-
atomicRequests := map[ids.ID]*atomic.Requests{ids.GenerateTestID(): nil}
128+
atomicRequests := make(map[ids.ID]*atomic.Requests)
128129
acceptor.backend.blkIDToState[blk.ID()] = &blockState{
129130
onAcceptState: onAcceptState,
130131
atomicRequests: atomicRequests,
@@ -207,7 +208,7 @@ func TestAcceptorVisitStandardBlock(t *testing.T) {
207208
// Set [blk]'s state in the map as though it had been verified.
208209
onAcceptState := state.NewMockDiff(ctrl)
209210
childID := ids.GenerateTestID()
210-
atomicRequests := map[ids.ID]*atomic.Requests{ids.GenerateTestID(): nil}
211+
atomicRequests := make(map[ids.ID]*atomic.Requests)
211212
calledOnAcceptFunc := false
212213
acceptor.backend.blkIDToState[blk.ID()] = &blockState{
213214
onAcceptState: onAcceptState,
@@ -280,13 +281,21 @@ func TestAcceptorVisitCommitBlock(t *testing.T) {
280281
parentOnAbortState := state.NewMockDiff(ctrl)
281282
parentOnCommitState := state.NewMockDiff(ctrl)
282283
parentStatelessBlk := block.NewMockBlock(ctrl)
284+
calledOnAcceptFunc := false
285+
atomicRequests := make(map[ids.ID]*atomic.Requests)
283286
parentState := &blockState{
284-
statelessBlock: parentStatelessBlk,
285-
onAcceptState: parentOnAcceptState,
286287
proposalBlockState: proposalBlockState{
287288
onAbortState: parentOnAbortState,
288289
onCommitState: parentOnCommitState,
289290
},
291+
statelessBlock: parentStatelessBlk,
292+
293+
onAcceptState: parentOnAcceptState,
294+
onAcceptFunc: func() {
295+
calledOnAcceptFunc = true
296+
},
297+
298+
atomicRequests: atomicRequests,
290299
}
291300
acceptor.backend.blkIDToState[parentID] = parentState
292301

@@ -308,13 +317,21 @@ func TestAcceptorVisitCommitBlock(t *testing.T) {
308317
err = acceptor.ApricotCommitBlock(blk)
309318
require.ErrorIs(err, errMissingBlockState)
310319

320+
parentOnCommitState.EXPECT().GetTimestamp().Return(time.Unix(0, 0))
321+
311322
// Set [blk]'s state in the map as though it had been verified.
312323
acceptor.backend.blkIDToState[parentID] = parentState
313-
onAcceptState := state.NewMockDiff(ctrl)
314324
acceptor.backend.blkIDToState[blkID] = &blockState{
315-
onAcceptState: onAcceptState,
325+
onAcceptState: parentState.onCommitState,
326+
onAcceptFunc: parentState.onAcceptFunc,
327+
328+
inputs: parentState.inputs,
329+
timestamp: parentOnCommitState.GetTimestamp(),
330+
atomicRequests: parentState.atomicRequests,
316331
}
317332

333+
batch := database.NewMockBatch(ctrl)
334+
318335
// Set expected calls on dependencies.
319336
// Make sure the parent is accepted first.
320337
gomock.InOrder(
@@ -328,12 +345,15 @@ func TestAcceptorVisitCommitBlock(t *testing.T) {
328345
s.EXPECT().SetHeight(blk.Height()).Times(1),
329346
s.EXPECT().AddStatelessBlock(blk).Times(1),
330347

331-
onAcceptState.EXPECT().Apply(s).Times(1),
332-
s.EXPECT().Commit().Return(nil).Times(1),
348+
parentOnCommitState.EXPECT().Apply(s).Times(1),
349+
s.EXPECT().CommitBatch().Return(batch, nil).Times(1),
350+
sharedMemory.EXPECT().Apply(atomicRequests, batch).Return(nil).Times(1),
333351
s.EXPECT().Checksum().Return(ids.Empty).Times(1),
352+
s.EXPECT().Abort().Times(1),
334353
)
335354

336355
require.NoError(acceptor.ApricotCommitBlock(blk))
356+
require.True(calledOnAcceptFunc)
337357
require.Equal(blk.ID(), acceptor.backend.lastAccepted)
338358
}
339359

@@ -371,13 +391,21 @@ func TestAcceptorVisitAbortBlock(t *testing.T) {
371391
parentOnAbortState := state.NewMockDiff(ctrl)
372392
parentOnCommitState := state.NewMockDiff(ctrl)
373393
parentStatelessBlk := block.NewMockBlock(ctrl)
394+
calledOnAcceptFunc := false
395+
atomicRequests := make(map[ids.ID]*atomic.Requests)
374396
parentState := &blockState{
375-
statelessBlock: parentStatelessBlk,
376-
onAcceptState: parentOnAcceptState,
377397
proposalBlockState: proposalBlockState{
378398
onAbortState: parentOnAbortState,
379399
onCommitState: parentOnCommitState,
380400
},
401+
statelessBlock: parentStatelessBlk,
402+
403+
onAcceptState: parentOnAcceptState,
404+
onAcceptFunc: func() {
405+
calledOnAcceptFunc = true
406+
},
407+
408+
atomicRequests: atomicRequests,
381409
}
382410
acceptor.backend.blkIDToState[parentID] = parentState
383411

@@ -399,14 +427,21 @@ func TestAcceptorVisitAbortBlock(t *testing.T) {
399427
err = acceptor.ApricotAbortBlock(blk)
400428
require.ErrorIs(err, errMissingBlockState)
401429

430+
parentOnAbortState.EXPECT().GetTimestamp().Return(time.Unix(0, 0))
431+
402432
// Set [blk]'s state in the map as though it had been verified.
403433
acceptor.backend.blkIDToState[parentID] = parentState
404-
405-
onAcceptState := state.NewMockDiff(ctrl)
406434
acceptor.backend.blkIDToState[blkID] = &blockState{
407-
onAcceptState: onAcceptState,
435+
onAcceptState: parentState.onAbortState,
436+
onAcceptFunc: parentState.onAcceptFunc,
437+
438+
inputs: parentState.inputs,
439+
timestamp: parentOnAbortState.GetTimestamp(),
440+
atomicRequests: parentState.atomicRequests,
408441
}
409442

443+
batch := database.NewMockBatch(ctrl)
444+
410445
// Set expected calls on dependencies.
411446
// Make sure the parent is accepted first.
412447
gomock.InOrder(
@@ -420,11 +455,14 @@ func TestAcceptorVisitAbortBlock(t *testing.T) {
420455
s.EXPECT().SetHeight(blk.Height()).Times(1),
421456
s.EXPECT().AddStatelessBlock(blk).Times(1),
422457

423-
onAcceptState.EXPECT().Apply(s).Times(1),
424-
s.EXPECT().Commit().Return(nil).Times(1),
458+
parentOnAbortState.EXPECT().Apply(s).Times(1),
459+
s.EXPECT().CommitBatch().Return(batch, nil).Times(1),
460+
sharedMemory.EXPECT().Apply(atomicRequests, batch).Return(nil).Times(1),
425461
s.EXPECT().Checksum().Return(ids.Empty).Times(1),
462+
s.EXPECT().Abort().Times(1),
426463
)
427464

428465
require.NoError(acceptor.ApricotAbortBlock(blk))
466+
require.True(calledOnAcceptFunc)
429467
require.Equal(blk.ID(), acceptor.backend.lastAccepted)
430468
}

vms/platformvm/block/executor/backend.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,20 @@ func (b *backend) GetState(blkID ids.ID) (state.Chain, bool) {
5151
return b.state, blkID == b.state.GetLastAccepted()
5252
}
5353

54-
func (b *backend) getOnAbortState(blkID ids.ID) (state.Diff, bool) {
54+
func (b *backend) getBlkWithOnAbortState(blkID ids.ID) (*blockState, bool) {
5555
state, ok := b.blkIDToState[blkID]
5656
if !ok || state.onAbortState == nil {
5757
return nil, false
5858
}
59-
return state.onAbortState, true
59+
return state, true
6060
}
6161

62-
func (b *backend) getOnCommitState(blkID ids.ID) (state.Diff, bool) {
62+
func (b *backend) getBlkWithOnCommitState(blkID ids.ID) (*blockState, bool) {
6363
state, ok := b.blkIDToState[blkID]
6464
if !ok || state.onCommitState == nil {
6565
return nil, false
6666
}
67-
return state.onCommitState, true
67+
return state, true
6868
}
6969

7070
func (b *backend) GetBlock(blkID ids.ID) (block.Block, error) {

vms/platformvm/block/executor/verifier.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -319,33 +319,43 @@ func (v *verifier) commonBlock(b block.Block) error {
319319
// abortBlock populates the state of this block if [nil] is returned
320320
func (v *verifier) abortBlock(b block.Block) error {
321321
parentID := b.Parent()
322-
onAcceptState, ok := v.getOnAbortState(parentID)
322+
parentState, ok := v.getBlkWithOnAbortState(parentID)
323323
if !ok {
324324
return fmt.Errorf("%w: %s", state.ErrMissingParentState, parentID)
325325
}
326326

327327
blkID := b.ID()
328328
v.blkIDToState[blkID] = &blockState{
329329
statelessBlock: b,
330-
onAcceptState: onAcceptState,
331-
timestamp: onAcceptState.GetTimestamp(),
330+
331+
onAcceptState: parentState.onAbortState,
332+
onAcceptFunc: parentState.onAcceptFunc,
333+
334+
inputs: parentState.inputs,
335+
timestamp: parentState.onAbortState.GetTimestamp(),
336+
atomicRequests: parentState.atomicRequests,
332337
}
333338
return nil
334339
}
335340

336341
// commitBlock populates the state of this block if [nil] is returned
337342
func (v *verifier) commitBlock(b block.Block) error {
338343
parentID := b.Parent()
339-
onAcceptState, ok := v.getOnCommitState(parentID)
344+
parentState, ok := v.getBlkWithOnCommitState(parentID)
340345
if !ok {
341346
return fmt.Errorf("%w: %s", state.ErrMissingParentState, parentID)
342347
}
343348

344349
blkID := b.ID()
345350
v.blkIDToState[blkID] = &blockState{
346351
statelessBlock: b,
347-
onAcceptState: onAcceptState,
348-
timestamp: onAcceptState.GetTimestamp(),
352+
353+
onAcceptState: parentState.onCommitState,
354+
onAcceptFunc: parentState.onAcceptFunc,
355+
356+
inputs: parentState.inputs,
357+
timestamp: parentState.onCommitState.GetTimestamp(),
358+
atomicRequests: parentState.atomicRequests,
349359
}
350360
return nil
351361
}

vms/platformvm/vm_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1873,6 +1873,10 @@ func TestUptimeDisallowedWithRestart(t *testing.T) {
18731873
secondCtx.Lock.Unlock()
18741874
}()
18751875

1876+
atomicDB := prefixdb.New([]byte{1}, db)
1877+
m := atomic.NewMemory(atomicDB)
1878+
secondCtx.SharedMemory = m.NewSharedMemory(secondCtx.ChainID)
1879+
18761880
secondMsgChan := make(chan common.Message, 1)
18771881
require.NoError(secondVM.Initialize(
18781882
context.Background(),
@@ -1962,6 +1966,10 @@ func TestUptimeDisallowedAfterNeverConnecting(t *testing.T) {
19621966
ctx := defaultContext(t)
19631967
ctx.Lock.Lock()
19641968

1969+
atomicDB := prefixdb.New([]byte{1}, db)
1970+
m := atomic.NewMemory(atomicDB)
1971+
ctx.SharedMemory = m.NewSharedMemory(ctx.ChainID)
1972+
19651973
msgChan := make(chan common.Message, 1)
19661974
appSender := &common.SenderTest{T: t}
19671975
require.NoError(vm.Initialize(

0 commit comments

Comments
 (0)