Skip to content

Commit

Permalink
vms/platformvm: Move VerifyUniqueInputs from verifier to `backe…
Browse files Browse the repository at this point in the history
…nd` (#2410)
  • Loading branch information
dhrubabasu authored Dec 4, 2023
1 parent 6aa20fc commit b741c19
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 31 deletions.
4 changes: 2 additions & 2 deletions vms/avm/block/executor/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ type Manager interface {
// preferred state. This should *not* be used to verify transactions in a block.
VerifyTx(tx *txs.Tx) error

// VerifyUniqueInputs verifies that the inputs are not duplicated in the
// provided blk or any of its ancestors pinned in memory.
// VerifyUniqueInputs returns nil iff no blocks in the inclusive
// ancestry of [blkID] consume an input in [inputs].
VerifyUniqueInputs(blkID ids.ID, inputs set.Set[ids.ID]) error
}

Expand Down
29 changes: 29 additions & 0 deletions vms/platformvm/block/executor/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@
package executor

import (
"errors"
"time"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/snow"
"github.com/ava-labs/avalanchego/utils/set"
"github.com/ava-labs/avalanchego/vms/platformvm/block"
"github.com/ava-labs/avalanchego/vms/platformvm/state"
"github.com/ava-labs/avalanchego/vms/platformvm/txs/mempool"
)

var errConflictingParentTxs = errors.New("block contains a transaction that conflicts with a transaction in a parent block")

// Shared fields used by visitors.
type backend struct {
mempool.Mempool
Expand Down Expand Up @@ -95,3 +99,28 @@ func (b *backend) getTimestamp(blkID ids.ID) time.Time {
// so we just return the chain time.
return b.state.GetTimestamp()
}

// verifyUniqueInputs returns nil iff no blocks in the inclusive
// ancestry of [blkID] consume an input in [inputs].
func (b *backend) verifyUniqueInputs(blkID ids.ID, inputs set.Set[ids.ID]) error {
if inputs.Len() == 0 {
return nil
}

// Check for conflicts in ancestors.
for {
state, ok := b.blkIDToState[blkID]
if !ok {
// The parent state isn't pinned in memory.
// This means the parent must be accepted already.
return nil
}

if state.inputs.Overlaps(inputs) {
return errConflictingParentTxs
}

blk := state.statelessBlock
blkID = blk.Parent()
}
}
31 changes: 2 additions & 29 deletions vms/platformvm/block/executor/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

"github.com/ava-labs/avalanchego/chains/atomic"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/set"
"github.com/ava-labs/avalanchego/vms/platformvm/block"
"github.com/ava-labs/avalanchego/vms/platformvm/state"
"github.com/ava-labs/avalanchego/vms/platformvm/status"
Expand All @@ -26,7 +25,6 @@ var (
errIncorrectBlockHeight = errors.New("incorrect block height")
errChildBlockEarlierThanParent = errors.New("proposed timestamp before current chain time")
errConflictingBatchTxs = errors.New("block contains conflicting transactions")
errConflictingParentTxs = errors.New("block contains a transaction that conflicts with a transaction in a parent block")
errOptionBlockTimestampNotMatchingParent = errors.New("option block proposed timestamp not matching parent block one")
)

Expand Down Expand Up @@ -203,7 +201,7 @@ func (v *verifier) ApricotAtomicBlock(b *block.ApricotAtomicBlock) error {

atomicExecutor.OnAccept.AddTx(b.Tx, status.Committed)

if err := v.verifyUniqueInputs(b, atomicExecutor.Inputs); err != nil {
if err := v.verifyUniqueInputs(b.Parent(), atomicExecutor.Inputs); err != nil {
return err
}

Expand Down Expand Up @@ -441,7 +439,7 @@ func (v *verifier) standardBlock(
}
}

if err := v.verifyUniqueInputs(b, blkState.inputs); err != nil {
if err := v.verifyUniqueInputs(b.Parent(), blkState.inputs); err != nil {
return err
}

Expand All @@ -461,28 +459,3 @@ func (v *verifier) standardBlock(
v.Mempool.Remove(b.Transactions)
return nil
}

// verifyUniqueInputs verifies that the inputs of the given block are not
// duplicated in any of the parent blocks pinned in memory.
func (v *verifier) verifyUniqueInputs(block block.Block, inputs set.Set[ids.ID]) error {
if inputs.Len() == 0 {
return nil
}

// Check for conflicts in ancestors.
for {
parentID := block.Parent()
parentState, ok := v.blkIDToState[parentID]
if !ok {
// The parent state isn't pinned in memory.
// This means the parent must be accepted already.
return nil
}

if parentState.inputs.Overlaps(inputs) {
return errConflictingParentTxs
}

block = parentState.statelessBlock
}
}

0 comments on commit b741c19

Please sign in to comment.