Skip to content

Commit 8120981

Browse files
committed
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.
1 parent c58646e commit 8120981

File tree

3 files changed

+62
-13
lines changed

3 files changed

+62
-13
lines changed

.changelog/5123.bugfix.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
go/worker/client: Better handle latest round queries with verification
2+
3+
When a query is requesting to be executed against the latest round and
4+
the runtime reports a consensus verifier error, use an earlier round
5+
instead as the latest round may not yet be verifiable by the light
6+
client as it needs to wait for the validator signatures.

go/runtime/host/protocol/errors.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package protocol
2+
3+
import (
4+
"github.com/oasisprotocol/oasis-core/go/common/errors"
5+
)
6+
7+
// ModuleVerifierName is the name of the consensus verifier module inside the runtime.
8+
const ModuleVerifierName = "verifier"
9+
10+
// ErrVerifierVerificationFailed is the error returned when consensus verifier fails to verify the
11+
// passed consensus light block.
12+
var ErrVerifierVerificationFailed = errors.New(ModuleVerifierName, 2, "verifier: light block verification failed")

go/worker/client/committee/node.go

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

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

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

157-
// Get consensus light block for state after executing block at given height.
158-
lb, err := n.commonNode.Consensus.GetLightBlockForState(ctx, annBlk.Height)
159-
if err != nil {
160-
return nil, fmt.Errorf("client: failed to get light block at height %d: %w", annBlk.Height, err)
161-
}
162-
epoch, err := n.commonNode.Consensus.Beacon().GetEpoch(ctx, annBlk.Height)
163-
if err != nil {
164-
return nil, fmt.Errorf("client: failed to get epoch at height %d: %w", annBlk.Height, err)
161+
// Get consensus light block for state after executing block at given height.
162+
lb, err := n.commonNode.Consensus.GetLightBlockForState(ctx, annBlk.Height)
163+
if err != nil {
164+
return nil, fmt.Errorf("client: failed to get light block at height %d: %w", annBlk.Height, err)
165+
}
166+
epoch, err := n.commonNode.Consensus.Beacon().GetEpoch(ctx, annBlk.Height)
167+
if err != nil {
168+
return nil, fmt.Errorf("client: failed to get epoch at height %d: %w", annBlk.Height, err)
169+
}
170+
171+
return hrt.Query(ctx, annBlk.Block, lb, epoch, maxMessages, method, args)
165172
}
166173

167-
return hrt.Query(ctx, annBlk.Block, lb, epoch, maxMessages, method, args)
174+
data, err := queryFn(round)
175+
if errors.Is(err, protocol.ErrVerifierVerificationFailed) {
176+
// The query failed due to the runtime's consensus verifier failing to verify the given
177+
// header. We assume that this is because a finalized header is not yet available for the
178+
// given round.
179+
switch round {
180+
case api.RoundLatest:
181+
// Since we are allowed to decide what we see as the latest round, use an earlier one.
182+
n.logger.Debug("runtime's consensus verifier reports failure, retrying",
183+
"method", method,
184+
"target_round", resolvedRound,
185+
)
186+
187+
data, err = queryFn(resolvedRound - 1)
188+
default:
189+
// A specific round was given so this query is not yet possible.
190+
n.logger.Debug("runtime's consensus verifier reports failure",
191+
"method", method,
192+
"target_round", round,
193+
)
194+
195+
return nil, roothash.ErrNotFound
196+
}
197+
}
198+
return data, err
168199
}
169200

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

0 commit comments

Comments
 (0)