Skip to content

Commit

Permalink
Merge branch 'dev' into sorting-remove-IsSortedAndUnique
Browse files Browse the repository at this point in the history
  • Loading branch information
StephenButtolph authored Jul 13, 2023
2 parents 979b92c + e604fb2 commit b3fd8e4
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 5 deletions.
17 changes: 17 additions & 0 deletions vms/proposervm/tree/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,23 @@ import (
"github.com/ava-labs/avalanchego/snow/consensus/snowman"
)

// Tree handles the propagation of block acceptance and rejection to inner
// blocks.
//
// The Tree is needed because:
// 1. The consensus engine guarantees that for each verified block, either
// Accept() or Reject() are eventually called, and they are called only once.
// The proposervm must maintain these invariants for the wrapped VM.
// 2. A given inner block may be wrapped into multiple different proposervm
// blocks (e.g. same inner block generated by two validators).
//
// The Tree prevents Accept() and Reject() from being called multiple times on
// the same inner block by:
// 1. tracking inner blocks in a tree-like structure, to be able to easily spot
// siblings
// 2. rejecting an inner block only when one of the siblings is accepted.
// Rejection of a proposervm block does not imply its inner block rejection
// (it may be held by a different proposervm block).
type Tree interface {
// Add places the block in the tree
Add(snowman.Block)
Expand Down
32 changes: 27 additions & 5 deletions vms/proposervm/tree/tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ func TestAcceptSingleBlock(t *testing.T) {

require.NoError(tr.Accept(context.Background(), block))
require.Equal(choices.Accepted, block.Status())

_, contains = tr.Get(block)
require.False(contains)
}

func TestAcceptBlockConflict(t *testing.T) {
Expand All @@ -68,18 +71,26 @@ func TestAcceptBlockConflict(t *testing.T) {

tr := New()

// add conflicting blocks
tr.Add(blockToAccept)
tr.Add(blockToReject)

_, contains := tr.Get(blockToAccept)
require.True(contains)

tr.Add(blockToReject)
_, contains = tr.Get(blockToReject)
require.True(contains)

// accept one of them
require.NoError(tr.Accept(context.Background(), blockToAccept))

// check their statuses and that they are removed from the tree
require.Equal(choices.Accepted, blockToAccept.Status())
_, contains = tr.Get(blockToAccept)
require.False(contains)

require.Equal(choices.Rejected, blockToReject.Status())
_, contains = tr.Get(blockToReject)
require.False(contains)
}

func TestAcceptChainConflict(t *testing.T) {
Expand Down Expand Up @@ -111,21 +122,32 @@ func TestAcceptChainConflict(t *testing.T) {

tr := New()

// add conflicting blocks.
tr.Add(blockToAccept)
tr.Add(blockToReject)
tr.Add(blockToRejectChild)

_, contains := tr.Get(blockToAccept)
require.True(contains)

tr.Add(blockToReject)
_, contains = tr.Get(blockToReject)
require.True(contains)

tr.Add(blockToRejectChild)
_, contains = tr.Get(blockToRejectChild)
require.True(contains)

// accept one of them
require.NoError(tr.Accept(context.Background(), blockToAccept))

// check their statuses and whether they are removed from tree
require.Equal(choices.Accepted, blockToAccept.Status())
_, contains = tr.Get(blockToAccept)
require.False(contains)

require.Equal(choices.Rejected, blockToReject.Status())
_, contains = tr.Get(blockToReject)
require.False(contains)

require.Equal(choices.Rejected, blockToRejectChild.Status())
_, contains = tr.Get(blockToRejectChild)
require.False(contains)
}

0 comments on commit b3fd8e4

Please sign in to comment.