Proof submission calls callback even if submission fails
Description
The function SubmitProof
, implemented in sdk/app.go, can be used by the client to submit a proof.
After starting the submission, if an error occurs, the function returns immediately with the error:
res, err := q.gc.SubmitProof(&gwproto.SubmitAppCircuitProofRequest{
QueryKey: &gwproto.QueryKey{
QueryHash: hexutil.Encode(q.queryId),
Nonce: q.nonce,
},
TargetChainId: q.dstChainId,
Proof: hexutil.Encode(buf.Bytes()),
})
if err != nil {
return fmt.Errorf("error calling brevis gateway SubmitProof: %s", err.Error())
}
if !res.GetSuccess() {
return fmt.Errorf("error calling brevis gateway SubmitProof: cdoe %s, msg %s",
res.GetErr().GetCode(), res.GetErr().GetMsg())
}
The caller of SubmitProof
can pass a callback function that is to be called once the submission has been completed. Should such a callback function be set, SubmitProof
thus waits using waitFinalProofSubmitted
until the submission has been completed. Should waitFinalProofSubmitted
not return any error, opts.onSubmitted
is called. Should waitFinalProofSubmitted
return an error, that error is printed, and a callback for that occasion, opts.onError
, is called.
if opts.onSubmitted != nil {
var cancel <-chan struct{}
if opts.ctx != nil {
cancel = opts.ctx.Done()
}
go func() {
tx, err := q.waitFinalProofSubmitted(cancel)
if err != nil {
fmt.Println(err.Error())
opts.onError(err)
}
opts.onSubmitted(tx)
}()
}
However, note that in the error case, the function does not return early. Thus, opts.onSubmitted
will still be called, even though tx
likely does not contain useful data.
Impact
The callback opts.onSubmitted
will be called even if waiting for the final submission failure. This callback may then carry out further actions that should only be done after successful submissions.
Recommendations
If it is intended that opts.onSubmitted
is only called after a successfully completed submission, we recommend to return after the call to opts.onError
in the error case:
if opts.onSubmitted != nil {
var cancel <-chan struct{}
if opts.ctx != nil {
cancel = opts.ctx.Done()
}
go func() {
tx, err := q.waitFinalProofSubmitted(cancel)
if err != nil {
fmt.Println(err.Error())
opts.onError(err)
+ return err
}
opts.onSubmitted(tx)
}()
}
Remediation
This issue has been acknowledged by Brevis, and fixes were implemented in the following commits: