Assessment reports>Brevis>Low findings>Proof submission calls callback even if submission fails
Category: Coding Mistakes

Proof submission calls callback even if submission fails

Low Severity
Low Impact
Low Likelihood

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:

Zellic © 2025Back to top ↑