Merge pull request #3141 from nspcc-dev/limit-calculatenetworkfee-gas
Limit calculatenetworkfee GAS
This commit is contained in:
commit
4598f3d3c2
3 changed files with 48 additions and 3 deletions
|
@ -233,7 +233,9 @@ where:
|
|||
proxy can be used to have proper app-specific CORS settings), but it's an
|
||||
easy way to make RPC interface accessible from the browser.
|
||||
- `MaxGasInvoke` is the maximum GAS allowed to spend during `invokefunction` and
|
||||
`invokescript` RPC-calls.
|
||||
`invokescript` RPC-calls. `calculatenetworkfee` also can't exceed this GAS amount
|
||||
(normally the limit for it is MaxVerificationGAS from Policy, but if MaxGasInvoke
|
||||
is lower than that then this limit is respected).
|
||||
- `MaxIteratorResultItems` - maximum number of elements extracted from iterator
|
||||
returned by `invoke*` call. When the `MaxIteratorResultItems` value is set to
|
||||
`n`, only `n` iterations are returned and truncated is true, indicating that
|
||||
|
|
|
@ -917,7 +917,15 @@ func (s *Server) calculateNetworkFee(reqParams params.Params) (any, *neorpc.Erro
|
|||
return 0, neorpc.WrapErrorWithData(neorpc.ErrInvalidParams, fmt.Sprintf("failed to compute tx size: %s", err))
|
||||
}
|
||||
size := len(hashablePart) + io.GetVarSize(len(tx.Signers))
|
||||
var netFee int64
|
||||
var (
|
||||
netFee int64
|
||||
// Verification GAS cost can't exceed this policy.
|
||||
gasLimit = s.chain.GetMaxVerificationGAS()
|
||||
)
|
||||
if gasLimit > int64(s.config.MaxGasInvoke) {
|
||||
// But we honor instance configuration as well.
|
||||
gasLimit = int64(s.config.MaxGasInvoke)
|
||||
}
|
||||
for i, signer := range tx.Signers {
|
||||
w := tx.Scripts[i]
|
||||
if len(w.InvocationScript) == 0 { // No invocation provided, try to infer one.
|
||||
|
@ -951,7 +959,11 @@ func (s *Server) calculateNetworkFee(reqParams params.Params) (any, *neorpc.Erro
|
|||
}
|
||||
w.InvocationScript = inv.Bytes()
|
||||
}
|
||||
gasConsumed, _ := s.chain.VerifyWitness(signer.Account, tx, &w, int64(s.config.MaxGasInvoke))
|
||||
gasConsumed, err := s.chain.VerifyWitness(signer.Account, tx, &w, gasLimit)
|
||||
if err != nil && !errors.Is(err, core.ErrInvalidSignature) {
|
||||
return nil, neorpc.WrapErrorWithData(neorpc.ErrInvalidSignature, err.Error())
|
||||
}
|
||||
gasLimit -= gasConsumed
|
||||
netFee += gasConsumed
|
||||
size += io.GetVarSize(w.VerificationScript) + io.GetVarSize(w.InvocationScript)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package rpcsrv
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
gio "io"
|
||||
|
@ -26,6 +27,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/storage/dboper"
|
||||
|
@ -3184,6 +3186,21 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
|
|||
body := calcReq(t, tx)
|
||||
_ = checkErrGetResult(t, body, true, neorpc.ErrInvalidVerificationFunctionCode, "signer 0 has no verify method in deployed contract")
|
||||
})
|
||||
t.Run("execution limit, fail", func(t *testing.T) {
|
||||
// 1_6000_0000 GAS with the default 1.5 allowed by Policy
|
||||
verifScript := []byte{byte(opcode.PUSHINT32), 0x00, 0x58, 0x89, 0x09, byte(opcode.SYSCALL), 0, 0, 0, 0, byte(opcode.PUSHT)}
|
||||
binary.LittleEndian.PutUint32(verifScript[6:], interopnames.ToID([]byte(interopnames.SystemRuntimeBurnGas)))
|
||||
tx := &transaction.Transaction{
|
||||
Script: []byte{byte(opcode.RET)},
|
||||
Signers: []transaction.Signer{{Account: hash.Hash160(verifScript)}},
|
||||
Scripts: []transaction.Witness{{
|
||||
InvocationScript: []byte{byte(opcode.NOP)},
|
||||
VerificationScript: verifScript,
|
||||
}},
|
||||
}
|
||||
body := calcReq(t, tx)
|
||||
_ = checkErrGetResult(t, body, true, neorpc.ErrInvalidSignatureCode, "GAS limit exceeded")
|
||||
})
|
||||
checkCalc := func(t *testing.T, tx *transaction.Transaction, fee int64) {
|
||||
resp := checkErrGetResult(t, calcReq(t, tx), false, 0)
|
||||
res := new(result.NetworkFee)
|
||||
|
@ -3258,6 +3275,20 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
|
|||
invocScript := invocWriter.Bytes()
|
||||
checkContract(t, verAcc, invocScript, 146960) // No C# match, but we believe it's OK and it has a specific invocation script overriding anything server-side.
|
||||
})
|
||||
t.Run("execution limit, ok", func(t *testing.T) {
|
||||
// 1_4000_0000 GAS with the default 1.5 allowed by Policy
|
||||
verifScript := []byte{byte(opcode.PUSHINT32), 0x00, 0x3b, 0x58, 0x08, byte(opcode.SYSCALL), 0, 0, 0, 0, byte(opcode.PUSHT)}
|
||||
binary.LittleEndian.PutUint32(verifScript[6:], interopnames.ToID([]byte(interopnames.SystemRuntimeBurnGas)))
|
||||
tx := &transaction.Transaction{
|
||||
Script: []byte{byte(opcode.RET)},
|
||||
Signers: []transaction.Signer{{Account: hash.Hash160(verifScript)}},
|
||||
Scripts: []transaction.Witness{{
|
||||
InvocationScript: []byte{byte(opcode.NOP)},
|
||||
VerificationScript: verifScript,
|
||||
}},
|
||||
}
|
||||
checkCalc(t, tx, 140065570)
|
||||
})
|
||||
})
|
||||
t.Run("sendrawtransaction", func(t *testing.T) {
|
||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "sendrawtransaction", "params": ["%s"]}`
|
||||
|
|
Loading…
Reference in a new issue