@@ -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
170201func (n * Node ) checkBlock (ctx context.Context , blk * block.Block , pending map [hash.Hash ]* pendingTx ) error {
0 commit comments