mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2025-01-25 15:14:48 +00:00
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
|
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.
|
easy way to make RPC interface accessible from the browser.
|
||||||
- `MaxGasInvoke` is the maximum GAS allowed to spend during `invokefunction` and
|
- `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
|
- `MaxIteratorResultItems` - maximum number of elements extracted from iterator
|
||||||
returned by `invoke*` call. When the `MaxIteratorResultItems` value is set to
|
returned by `invoke*` call. When the `MaxIteratorResultItems` value is set to
|
||||||
`n`, only `n` iterations are returned and truncated is true, indicating that
|
`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))
|
return 0, neorpc.WrapErrorWithData(neorpc.ErrInvalidParams, fmt.Sprintf("failed to compute tx size: %s", err))
|
||||||
}
|
}
|
||||||
size := len(hashablePart) + io.GetVarSize(len(tx.Signers))
|
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 {
|
for i, signer := range tx.Signers {
|
||||||
w := tx.Scripts[i]
|
w := tx.Scripts[i]
|
||||||
if len(w.InvocationScript) == 0 { // No invocation provided, try to infer one.
|
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()
|
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
|
netFee += gasConsumed
|
||||||
size += io.GetVarSize(w.VerificationScript) + io.GetVarSize(w.InvocationScript)
|
size += io.GetVarSize(w.VerificationScript) + io.GetVarSize(w.InvocationScript)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package rpcsrv
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
gio "io"
|
gio "io"
|
||||||
|
@ -26,6 +27,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core"
|
"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/block"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
"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/native/nativenames"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/storage/dboper"
|
"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)
|
body := calcReq(t, tx)
|
||||||
_ = checkErrGetResult(t, body, true, neorpc.ErrInvalidVerificationFunctionCode, "signer 0 has no verify method in deployed contract")
|
_ = 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) {
|
checkCalc := func(t *testing.T, tx *transaction.Transaction, fee int64) {
|
||||||
resp := checkErrGetResult(t, calcReq(t, tx), false, 0)
|
resp := checkErrGetResult(t, calcReq(t, tx), false, 0)
|
||||||
res := new(result.NetworkFee)
|
res := new(result.NetworkFee)
|
||||||
|
@ -3258,6 +3275,20 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
|
||||||
invocScript := invocWriter.Bytes()
|
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.
|
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) {
|
t.Run("sendrawtransaction", func(t *testing.T) {
|
||||||
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "sendrawtransaction", "params": ["%s"]}`
|
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "sendrawtransaction", "params": ["%s"]}`
|
||||||
|
|
Loading…
Reference in a new issue