diff --git a/cli/wallet/multisig.go b/cli/wallet/multisig.go index 974c3adae..c1c4b0104 100644 --- a/cli/wallet/multisig.go +++ b/cli/wallet/multisig.go @@ -58,14 +58,14 @@ func signStoredTransaction(ctx *cli.Context) error { } if out := ctx.String("out"); out != "" { if err := paramcontext.Save(c, out); err != nil { - return cli.NewExitError(err, 1) + return cli.NewExitError(fmt.Errorf("failed to dump resulting transaction: %w", err), 1) } } if len(ctx.String(options.RPCEndpointFlag)) != 0 { for i := range tx.Signers { w, err := c.GetWitness(tx.Signers[i].Account) if err != nil { - return cli.NewExitError(err, 1) + return cli.NewExitError(fmt.Errorf("failed to construct witness for signer #%d: %w", i, err), 1) } tx.Scripts = append(tx.Scripts, *w) } @@ -76,11 +76,11 @@ func signStoredTransaction(ctx *cli.Context) error { var err error // `GetRPCClient` returns specialized type. c, err := options.GetRPCClient(gctx, ctx) if err != nil { - return cli.NewExitError(err, 1) + return cli.NewExitError(fmt.Errorf("failed to create RPC client: %w", err), 1) } res, err := c.SendRawTransaction(tx) if err != nil { - return cli.NewExitError(err, 1) + return cli.NewExitError(fmt.Errorf("failed to submit transaction to RPC node: %w", err), 1) } fmt.Fprintln(ctx.App.Writer, res.StringLE()) return nil diff --git a/pkg/core/oracle_test.go b/pkg/core/oracle_test.go index 7657446aa..6461d08bf 100644 --- a/pkg/core/oracle_test.go +++ b/pkg/core/oracle_test.go @@ -168,6 +168,25 @@ func TestOracle(t *testing.T) { checkEmitTx := func(t *testing.T, ch chan *transaction.Transaction) { require.Len(t, ch, 1) tx := <-ch + + // Response transaction has its hash being precalculated. Check that this hash + // matches the actual one. + cachedHash := tx.Hash() + cp := transaction.Transaction{ + Version: tx.Version, + Nonce: tx.Nonce, + SystemFee: tx.SystemFee, + NetworkFee: tx.NetworkFee, + ValidUntilBlock: tx.ValidUntilBlock, + Script: tx.Script, + Attributes: tx.Attributes, + Signers: tx.Signers, + Scripts: tx.Scripts, + Trimmed: tx.Trimmed, + } + actualHash := cp.Hash() + require.Equal(t, actualHash, cachedHash, "transaction hash was changed during ") + require.NoError(t, bc.verifyAndPoolTx(tx, bc.GetMemPool(), bc)) } diff --git a/pkg/services/oracle/response.go b/pkg/services/oracle/response.go index 38a69550e..f188778d5 100644 --- a/pkg/services/oracle/response.go +++ b/pkg/services/oracle/response.go @@ -134,7 +134,11 @@ func (o *Oracle) CreateResponseTx(gasForResponse int64, vub uint32, resp *transa } func (o *Oracle) testVerify(tx *transaction.Transaction) (int64, bool) { - v, finalize := o.Chain.GetTestVM(trigger.Verification, tx, nil) + // (*Blockchain).GetTestVM calls Hash() method of provided transaction; once being called, this + // method caches transaction hash, but tx building is not yet completed and hash will be changed. + // So make a copy of tx to avoid wrong hash caching. + cp := *tx + v, finalize := o.Chain.GetTestVM(trigger.Verification, &cp, nil) v.GasLimit = o.Chain.GetPolicer().GetMaxVerificationGAS() v.LoadScriptWithHash(o.oracleScript, o.oracleHash, callflag.ReadOnly) v.Jump(v.Context(), o.verifyOffset)