Skip to content

Commit

Permalink
go/worker/client: Better handle latest round queries with verification
Browse files Browse the repository at this point in the history
When a query is requesting to be executed against the latest round and
the runtime reports a consensus verifier error, use an earlier round
instead as the latest round may not yet be verifiable by the light
client as it needs to wait for the validator signatures.
  • Loading branch information
kostko committed Jan 10, 2023
1 parent c58646e commit 8120981
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 13 deletions.
6 changes: 6 additions & 0 deletions .changelog/5123.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
go/worker/client: Better handle latest round queries with verification

When a query is requesting to be executed against the latest round and
the runtime reports a consensus verifier error, use an earlier round
instead as the latest round may not yet be verifiable by the light
client as it needs to wait for the validator signatures.
12 changes: 12 additions & 0 deletions go/runtime/host/protocol/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package protocol

import (
"github.com/oasisprotocol/oasis-core/go/common/errors"
)

// ModuleVerifierName is the name of the consensus verifier module inside the runtime.
const ModuleVerifierName = "verifier"

// ErrVerifierVerificationFailed is the error returned when consensus verifier fails to verify the
// passed consensus light block.
var ErrVerifierVerificationFailed = errors.New(ModuleVerifierName, 2, "verifier: light block verification failed")
57 changes: 44 additions & 13 deletions go/worker/client/committee/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

cmnBackoff "github.com/oasisprotocol/oasis-core/go/common/backoff"
"github.com/oasisprotocol/oasis-core/go/common/crypto/hash"
"github.com/oasisprotocol/oasis-core/go/common/errors"
"github.com/oasisprotocol/oasis-core/go/common/logging"
roothash "github.com/oasisprotocol/oasis-core/go/roothash/api"
"github.com/oasisprotocol/oasis-core/go/roothash/api/block"
Expand Down Expand Up @@ -149,22 +150,52 @@ func (n *Node) Query(ctx context.Context, round uint64, method string, args []by
}
maxMessages := dsc.Executor.MaxMessages

annBlk, err := n.commonNode.Runtime.History().GetAnnotatedBlock(ctx, round)
if err != nil {
return nil, fmt.Errorf("client: failed to fetch annotated block from history: %w", err)
}
var resolvedRound uint64
queryFn := func(round uint64) ([]byte, error) {
annBlk, err := n.commonNode.Runtime.History().GetAnnotatedBlock(ctx, round)
if err != nil {
return nil, fmt.Errorf("client: failed to fetch annotated block from history: %w", err)
}
resolvedRound = annBlk.Block.Header.Round

// Get consensus light block for state after executing block at given height.
lb, err := n.commonNode.Consensus.GetLightBlockForState(ctx, annBlk.Height)
if err != nil {
return nil, fmt.Errorf("client: failed to get light block at height %d: %w", annBlk.Height, err)
}
epoch, err := n.commonNode.Consensus.Beacon().GetEpoch(ctx, annBlk.Height)
if err != nil {
return nil, fmt.Errorf("client: failed to get epoch at height %d: %w", annBlk.Height, err)
// Get consensus light block for state after executing block at given height.
lb, err := n.commonNode.Consensus.GetLightBlockForState(ctx, annBlk.Height)
if err != nil {
return nil, fmt.Errorf("client: failed to get light block at height %d: %w", annBlk.Height, err)
}
epoch, err := n.commonNode.Consensus.Beacon().GetEpoch(ctx, annBlk.Height)
if err != nil {
return nil, fmt.Errorf("client: failed to get epoch at height %d: %w", annBlk.Height, err)
}

return hrt.Query(ctx, annBlk.Block, lb, epoch, maxMessages, method, args)
}

return hrt.Query(ctx, annBlk.Block, lb, epoch, maxMessages, method, args)
data, err := queryFn(round)
if errors.Is(err, protocol.ErrVerifierVerificationFailed) {
// The query failed due to the runtime's consensus verifier failing to verify the given
// header. We assume that this is because a finalized header is not yet available for the
// given round.
switch round {
case api.RoundLatest:
// Since we are allowed to decide what we see as the latest round, use an earlier one.
n.logger.Debug("runtime's consensus verifier reports failure, retrying",
"method", method,
"target_round", resolvedRound,
)

data, err = queryFn(resolvedRound - 1)
default:
// A specific round was given so this query is not yet possible.
n.logger.Debug("runtime's consensus verifier reports failure",
"method", method,
"target_round", round,
)

return nil, roothash.ErrNotFound
}
}
return data, err
}

func (n *Node) checkBlock(ctx context.Context, blk *block.Block, pending map[hash.Hash]*pendingTx) error {
Expand Down

0 comments on commit 8120981

Please sign in to comment.