Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Defer consensus verification #2350

Draft
wants to merge 52 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
ce4b15d
Add verification to consensus
StephenButtolph Nov 20, 2023
6ba4e25
Improve height monitoring
StephenButtolph Nov 20, 2023
4c6433c
nit
StephenButtolph Nov 20, 2023
548c178
merged
StephenButtolph Nov 20, 2023
464dd31
Finish moving verification into consensus
StephenButtolph Nov 20, 2023
a1d0653
wip add VerifyProposer
StephenButtolph Nov 20, 2023
ae3f144
Cleanup snowman consensus
StephenButtolph Nov 21, 2023
f090502
nit
StephenButtolph Nov 21, 2023
43c2a43
reduce diff
StephenButtolph Nov 21, 2023
8be33ac
merged
StephenButtolph Nov 21, 2023
23834c5
fix
StephenButtolph Nov 21, 2023
320484d
wip
StephenButtolph Nov 21, 2023
222f2a6
nit
StephenButtolph Nov 21, 2023
0b06e44
wip
StephenButtolph Nov 21, 2023
92fd787
reduce diff
StephenButtolph Nov 21, 2023
bd5be37
minimal maps + sets
StephenButtolph Nov 21, 2023
dfa3889
wip
StephenButtolph Nov 21, 2023
6250a87
compiling
StephenButtolph Nov 21, 2023
4d99680
Add metric
StephenButtolph Nov 21, 2023
aad5d8a
merged
StephenButtolph Nov 21, 2023
d25d5a0
rate limit reverification
StephenButtolph Nov 21, 2023
fa8b0e2
nit
StephenButtolph Nov 21, 2023
0f18b3d
ok
StephenButtolph Nov 21, 2023
0cf9cc0
Add last accepted info to consensus health check
StephenButtolph Nov 21, 2023
bc07b9f
nit
StephenButtolph Nov 21, 2023
29f67c0
nit
StephenButtolph Nov 21, 2023
eb6700a
Merge branch 'expand-consensus-health-check' into deferred-verification
StephenButtolph Nov 21, 2023
37b8dca
nit
StephenButtolph Nov 21, 2023
ae55ed5
fix metric
StephenButtolph Nov 21, 2023
11f5e37
Add ideal accepted block verification count metric
StephenButtolph Nov 21, 2023
456c49b
Merge branch 'dev' into deferred-verification
StephenButtolph Nov 21, 2023
f81f9eb
nit
StephenButtolph Nov 21, 2023
ffbc96d
wip
StephenButtolph Nov 22, 2023
f6c0949
wip
StephenButtolph Nov 23, 2023
3b817f2
wip
StephenButtolph Nov 23, 2023
743e176
fix unit tests
StephenButtolph Nov 23, 2023
6a35a2c
Merge branch 'dev' into options-before-verify
StephenButtolph Nov 23, 2023
527c22c
fix typo
StephenButtolph Nov 23, 2023
5edf87a
nit
StephenButtolph Nov 23, 2023
7d49953
nit
StephenButtolph Nov 23, 2023
decdd10
merged
StephenButtolph Nov 23, 2023
6655c06
fix tests
StephenButtolph Nov 23, 2023
8d266a8
Merge branch 'dev' into options-before-verify
StephenButtolph Nov 25, 2023
73c06c0
merged
StephenButtolph Nov 25, 2023
f0cfa6d
Merge branch 'dev' into options-before-verify
StephenButtolph Nov 29, 2023
82b4338
Merge branch 'dev' into options-before-verify
StephenButtolph Dec 4, 2023
0e37af9
Merge branch 'dev' into options-before-verify
StephenButtolph Dec 5, 2023
f1ff7c0
merged
StephenButtolph Dec 5, 2023
2e863f4
Merge branch 'dev' into options-before-verify
StephenButtolph Dec 5, 2023
92363ec
Allow errors from Options() calls
StephenButtolph Dec 5, 2023
dc6e557
add test
StephenButtolph Dec 5, 2023
d565479
Merge branch 'options-before-verify' into deferred-verification
StephenButtolph Dec 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,221 changes: 646 additions & 575 deletions proto/pb/vm/vm.pb.go

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions proto/pb/vm/vm_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions proto/vm/vm.proto
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ service VM {
rpc GetStateSummary(GetStateSummaryRequest) returns (GetStateSummaryResponse);

// Block
rpc BlockVerifyProposer(BlockVerifyProposerRequest) returns (google.protobuf.Empty);
rpc BlockVerify(BlockVerifyRequest) returns (BlockVerifyResponse);
rpc BlockAccept(BlockAcceptRequest) returns (google.protobuf.Empty);
rpc BlockReject(BlockRejectRequest) returns (google.protobuf.Empty);
Expand Down Expand Up @@ -215,6 +216,10 @@ message SetPreferenceRequest {
bytes id = 1;
}

message BlockVerifyProposerRequest {
bytes bytes = 1;
}

message BlockVerifyRequest {
bytes bytes = 1;

Expand Down
2 changes: 2 additions & 0 deletions snow/consensus/snowman/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ type Block interface {
// Parent returns the ID of this block's parent.
Parent() ids.ID

VerifyProposer(context.Context) error

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment pls


// Verify that the state transition this block would make if accepted is
// valid. If the state transition is invalid, a non-nil error should be
// returned.
Expand Down
62 changes: 54 additions & 8 deletions snow/consensus/snowman/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ type metrics struct {
// numProcessing keeps track of the number of processing blocks
numProcessing prometheus.Gauge

blockSizeAcceptedSum prometheus.Gauge
blockSizeAcceptedSum prometheus.Gauge
timesVerifiedAcceptedSum prometheus.Gauge
verifiedOnceBlocksAccepted prometheus.Counter
// pollsAccepted tracks the number of polls that a block was in processing
// for before being accepted
pollsAccepted metric.Averager
Expand All @@ -50,7 +52,9 @@ type metrics struct {
latAccepted metric.Averager
buildLatencyAccepted prometheus.Gauge

blockSizeRejectedSum prometheus.Gauge
blockSizeRejectedSum prometheus.Gauge
timesVerifiedRejectedSum prometheus.Gauge
unverifiedBlocksRejected prometheus.Counter
// pollsRejected tracks the number of polls that a block was in processing
// for before being rejected
pollsRejected metric.Averager
Expand Down Expand Up @@ -107,6 +111,21 @@ func newMetrics(
Name: "blks_accepted_container_size_sum",
Help: "cumulative size of all accepted blocks",
}),
buildLatencyAccepted: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: namespace,
Name: "blks_build_accept_latency",
Help: "time (in ns) from the timestamp of a block to the time it was accepted",
}),
timesVerifiedAcceptedSum: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: namespace,
Name: "blks_times_verified_accepted_sum",
Help: "cumulative number of times all accepted blocks were verified",
}),
verifiedOnceBlocksAccepted: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: namespace,
Name: "verified_once_blks_rejected",
Help: "number of blocks accepted that were only verified once",
}),
pollsAccepted: metric.NewAveragerWithErrs(
namespace,
"blks_polls_accepted",
Expand All @@ -127,17 +146,22 @@ func newMetrics(
reg,
&errs,
),
buildLatencyAccepted: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: namespace,
Name: "blks_build_accept_latency",
Help: "time (in ns) from the timestamp of a block to the time it was accepted",
}),

blockSizeRejectedSum: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: namespace,
Name: "blks_rejected_container_size_sum",
Help: "cumulative size of all rejected blocks",
}),
timesVerifiedRejectedSum: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: namespace,
Name: "blks_times_verified_rejected_sum",
Help: "cumulative number of times all rejected blocks were verified",
}),
unverifiedBlocksRejected: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: namespace,
Name: "unverified_blks_rejected",
Help: "number of blocks rejected that were never verified",
}),
pollsRejected: metric.NewAveragerWithErrs(
namespace,
"blks_polls_rejected",
Expand Down Expand Up @@ -183,7 +207,11 @@ func newMetrics(
reg.Register(m.numProcessing),
reg.Register(m.blockSizeAcceptedSum),
reg.Register(m.buildLatencyAccepted),
reg.Register(m.timesVerifiedAcceptedSum),
reg.Register(m.verifiedOnceBlocksAccepted),
reg.Register(m.blockSizeRejectedSum),
reg.Register(m.timesVerifiedRejectedSum),
reg.Register(m.unverifiedBlocksRejected),
reg.Register(m.numSuccessfulPolls),
reg.Register(m.numFailedPolls),
)
Expand All @@ -207,6 +235,7 @@ func (m *metrics) Accepted(
blkID ids.ID,
height uint64,
timestamp time.Time,
timesVerified int,
pollNumber uint64,
blockSize int,
) {
Expand All @@ -224,6 +253,11 @@ func (m *metrics) Accepted(
m.numProcessing.Dec()

m.blockSizeAcceptedSum.Add(float64(blockSize))
m.timesVerifiedAcceptedSum.Add(float64(timesVerified))

if timesVerified == 1 {
m.verifiedOnceBlocksAccepted.Inc()
}

m.pollsAccepted.Observe(float64(pollNumber - start.pollNumber))

Expand All @@ -235,7 +269,12 @@ func (m *metrics) Accepted(
m.buildLatencyAccepted.Add(float64(builtDuration))
}

func (m *metrics) Rejected(blkID ids.ID, pollNumber uint64, blockSize int) {
func (m *metrics) Rejected(
blkID ids.ID,
timesVerified int,
pollNumber uint64,
blockSize int,
) {
start, ok := m.processingBlocks.Get(blkID)
if !ok {
m.log.Error("unable to measure latency",
Expand All @@ -249,6 +288,13 @@ func (m *metrics) Rejected(blkID ids.ID, pollNumber uint64, blockSize int) {

m.blockSizeRejectedSum.Add(float64(blockSize))

m.blockSizeRejectedSum.Add(float64(blockSize))
m.timesVerifiedRejectedSum.Add(float64(timesVerified))

if timesVerified == 0 {
m.unverifiedBlocksRejected.Inc()
}

m.pollsRejected.Observe(float64(pollNumber - start.pollNumber))

duration := time.Since(start.time)
Expand Down
14 changes: 14 additions & 0 deletions snow/consensus/snowman/mock_block.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion snow/consensus/snowman/oracle_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,5 @@ var ErrNotOracle = errors.New("block isn't an oracle")
type OracleBlock interface {
// Options returns the possible children of this block in the order this
// validator prefers the blocks.
// Options is guaranteed to only be called on a verified block.
Options(context.Context) ([2]Block, error)
}
43 changes: 38 additions & 5 deletions snow/consensus/snowman/snowman_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,21 @@
package snowman

import (
"context"
"errors"
"fmt"
"time"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/snow/choices"
"github.com/ava-labs/avalanchego/snow/consensus/snowball"
"github.com/ava-labs/avalanchego/utils/set"
)

const minReverificationDelay = 250 * time.Millisecond

var errRecentlyFailedVerification = errors.New("recently failed verification")

// Tracks the state of a snowman block
type snowmanBlock struct {
// parameters to initialize the snowball instance with
Expand All @@ -17,6 +27,13 @@ type snowmanBlock struct {
// block that this node contains. For the genesis, this value will be nil
blk Block

// verified is set to true when it is safe to mark this block as preferred.
// If consensus implies that this block should be preferred and it hasn't
// been verified, the block should be verified.
verified bool
lastTimeVerified time.Time
numTimesVerified int

// shouldFalter is set to true if this node, and all its descendants received
// less than Alpha votes
shouldFalter bool
Expand All @@ -27,9 +44,8 @@ type snowmanBlock struct {
sb snowball.Consensus

// children is the set of blocks that have been issued that name this block
// as their parent. If this node has not had a child issued under it, this value
// will be nil
children map[ids.ID]Block
// as their parent.
children set.Set[ids.ID]
}

func (n *snowmanBlock) AddChild(child Block) {
Expand All @@ -39,12 +55,29 @@ func (n *snowmanBlock) AddChild(child Block) {
// should be initialized.
if n.sb == nil {
n.sb = snowball.NewTree(n.params, childID)
n.children = make(map[ids.ID]Block)
} else {
n.sb.Add(childID)
}

n.children[childID] = child
n.children.Add(childID)
}

func (n *snowmanBlock) Verify(ctx context.Context) error {
if n.verified {
return nil
}

now := time.Now()
if timeSinceLastVerification := now.Sub(n.lastTimeVerified); timeSinceLastVerification < minReverificationDelay {
return fmt.Errorf("%w: %s", errRecentlyFailedVerification, timeSinceLastVerification)
}

n.lastTimeVerified = now
n.numTimesVerified++

err := n.blk.Verify(ctx)
n.verified = err == nil
return err
}

func (n *snowmanBlock) Accepted() bool {
Expand Down
15 changes: 10 additions & 5 deletions snow/consensus/snowman/test_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ var (
type TestBlock struct {
choices.TestDecidable

ParentV ids.ID
HeightV uint64
TimestampV time.Time
VerifyV error
BytesV []byte
ParentV ids.ID
HeightV uint64
TimestampV time.Time
VerifyProposerV error
VerifyV error
BytesV []byte
}

func (b *TestBlock) Parent() ids.ID {
Expand All @@ -40,6 +41,10 @@ func (b *TestBlock) Timestamp() time.Time {
return b.TimestampV
}

func (b *TestBlock) VerifyProposer(context.Context) error {
return b.VerifyProposerV
}

func (b *TestBlock) Verify(context.Context) error {
return b.VerifyV
}
Expand Down
Loading
Loading