Merge pull request #1177 from nspcc-dev/no-free-vm-runs

No free VM runs
This commit is contained in:
Roman Khimov 2020-07-14 08:42:13 +03:00 committed by GitHub
commit dafb9eea4d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 52 additions and 31 deletions

View file

@ -460,7 +460,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
if err != nil {
return cli.NewExitError(fmt.Errorf("bad script returned from the RPC node: %v", err), 1)
}
txHash, err := c.SignAndPushInvocationTx(script, acc, 0, gas, cosigners)
txHash, err := c.SignAndPushInvocationTx(script, acc, resp.GasConsumed, gas, cosigners)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to push invocation tx: %v", err), 1)
}

View file

@ -48,6 +48,7 @@ ApplicationConfiguration:
MinPeers: 5
RPC:
Enabled: true
MaxGasInvoke: 10
EnableCORSWorkaround: false
Port: 10332
TLSConfig:

View file

@ -44,6 +44,7 @@ ApplicationConfiguration:
MinPeers: 3
RPC:
Enabled: true
MaxGasInvoke: 10
EnableCORSWorkaround: false
Port: 30336
Prometheus:

View file

@ -44,6 +44,7 @@ ApplicationConfiguration:
MinPeers: 3
RPC:
Enabled: true
MaxGasInvoke: 10
EnableCORSWorkaround: false
Port: 30333
Prometheus:

View file

@ -44,6 +44,7 @@ ApplicationConfiguration:
MinPeers: 3
RPC:
Enabled: true
MaxGasInvoke: 10
EnableCORSWorkaround: false
Port: 30335
Prometheus:

View file

@ -44,6 +44,7 @@ ApplicationConfiguration:
MinPeers: 3
RPC:
Enabled: true
MaxGasInvoke: 10
EnableCORSWorkaround: false
Port: 30334
Prometheus:

View file

@ -44,6 +44,7 @@ ApplicationConfiguration:
MinPeers: 3
RPC:
Enabled: true
MaxGasInvoke: 10
EnableCORSWorkaround: false
Port: 20331
TLSConfig:

View file

@ -48,6 +48,7 @@ ApplicationConfiguration:
MinPeers: 5
RPC:
Enabled: true
MaxGasInvoke: 10
EnableCORSWorkaround: false
Port: 20332
TLSConfig:

View file

@ -43,6 +43,7 @@ ApplicationConfiguration:
MinPeers: 1
RPC:
Address: 127.0.0.1
MaxGasInvoke: 10
Enabled: true
EnableCORSWorkaround: false
Port: 0 # let the system choose port dynamically

View file

@ -24,7 +24,7 @@ import (
func TestNewService(t *testing.T) {
srv := newTestService(t)
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 100000)
tx.ValidUntilBlock = 1
addSender(t, tx)
signTx(t, srv.Chain.FeePerByte(), tx)
@ -42,7 +42,7 @@ func TestService_GetVerified(t *testing.T) {
srv.dbft.Start()
var txs []*transaction.Transaction
for i := 0; i < 4; i++ {
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 100000)
tx.Nonce = 123 + uint32(i)
tx.ValidUntilBlock = 1
txs = append(txs, tx)
@ -257,6 +257,7 @@ func signTx(t *testing.T, feePerByte int64, txs ...*transaction.Transaction) {
privNetKeys[i] = testchain.PrivateKey(i)
validators[i] = privNetKeys[i].PublicKey()
}
privNetKeys = privNetKeys[:3]
rawScript, err := smartcontract.CreateMultiSigRedeemScript(3, validators)
require.NoError(t, err)
for _, tx := range txs {

View file

@ -49,6 +49,8 @@ const (
commitType messageType = 0x30
recoveryRequestType messageType = 0x40
recoveryMessageType messageType = 0x41
payloadGasLimit = 2000000 // 0.02 GAS
)
// ViewNumber implements payload.ConsensusPayload interface.
@ -221,6 +223,7 @@ func (p *Payload) Verify(scriptHash util.Uint160) bool {
}
v := vm.New()
v.GasLimit = payloadGasLimit
v.RegisterInteropGetter(crypto.GetInterop(&interop.Context{Container: p}))
v.LoadScript(verification)
v.LoadScript(p.Witness.InvocationScript)

View file

@ -35,7 +35,8 @@ const (
headerBatchCount = 2000
version = "0.1.0"
defaultMemPoolSize = 50000
defaultMemPoolSize = 50000
verificationGasLimit = 100000000 // 1 GAS
)
var (
@ -567,6 +568,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
if block.Index > 0 {
systemInterop := bc.newInteropContext(trigger.System, cache, block, nil)
v := SpawnVM(systemInterop)
v.GasLimit = -1
v.LoadScriptWithFlags(bc.contracts.GetPersistScript(), smartcontract.AllowModifyStates|smartcontract.AllowCall)
v.SetPriceGetter(getPrice)
if err := v.Run(); err != nil {
@ -1299,13 +1301,15 @@ func ScriptFromWitness(hash util.Uint160, witness *transaction.Witness) ([]byte,
}
// verifyHashAgainstScript verifies given hash against the given witness.
func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transaction.Witness, interopCtx *interop.Context, useKeys bool) error {
func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transaction.Witness, interopCtx *interop.Context, useKeys bool, gas int64) error {
verification, err := ScriptFromWitness(hash, witness)
if err != nil {
return err
}
vm := SpawnVM(interopCtx)
vm.SetPriceGetter(getPrice)
vm.GasLimit = gas
vm.LoadScriptWithFlags(verification, smartcontract.ReadOnly)
vm.LoadScript(witness.InvocationScript)
if useKeys {
@ -1360,7 +1364,7 @@ func (bc *Blockchain) verifyTxWitnesses(t *transaction.Transaction, block *block
sort.Slice(witnesses, func(i, j int) bool { return witnesses[i].ScriptHash().Less(witnesses[j].ScriptHash()) })
interopCtx := bc.newInteropContext(trigger.Verification, bc.dao, block, t)
for i := 0; i < len(hashes); i++ {
err := bc.verifyHashAgainstScript(hashes[i], &witnesses[i], interopCtx, false)
err := bc.verifyHashAgainstScript(hashes[i], &witnesses[i], interopCtx, false, t.NetworkFee)
if err != nil {
numStr := fmt.Sprintf("witness #%d", i)
return errors.Wrap(err, numStr)
@ -1380,7 +1384,7 @@ func (bc *Blockchain) verifyHeaderWitnesses(currHeader, prevHeader *block.Header
}
interopCtx := bc.newInteropContext(trigger.Verification, bc.dao, nil, nil)
interopCtx.Container = currHeader
return bc.verifyHashAgainstScript(hash, &currHeader.Script, interopCtx, true)
return bc.verifyHashAgainstScript(hash, &currHeader.Script, interopCtx, true, verificationGasLimit)
}
// GoverningTokenHash returns the governing token (NEO) native contract hash.

View file

@ -257,7 +257,7 @@ func TestCreateBasicChain(t *testing.T) {
script = io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(script.BinWriter, hash.Hash160(avm), "Put", "testkey", "testvalue")
txInv := transaction.New(testchain.Network(), script.Bytes(), 0)
txInv := transaction.New(testchain.Network(), script.Bytes(), 1*native.GASFactor)
txInv.Nonce = getNextNonce()
txInv.ValidUntilBlock = validUntilBlock
txInv.Sender = priv0ScriptHash
@ -288,7 +288,7 @@ func TestCreateBasicChain(t *testing.T) {
sh := hash.Hash160(avm)
w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, sh, "init")
initTx := transaction.New(testchain.Network(), w.Bytes(), 0)
initTx := transaction.New(testchain.Network(), w.Bytes(), 1*native.GASFactor)
initTx.Nonce = getNextNonce()
initTx.ValidUntilBlock = validUntilBlock
initTx.Sender = priv0ScriptHash
@ -378,7 +378,7 @@ func newNEP5Transfer(sc, from, to util.Uint160, amount int64) *transaction.Trans
emit.Opcode(w.BinWriter, opcode.ASSERT)
script := w.Bytes()
return transaction.New(testchain.Network(), script, 0)
return transaction.New(testchain.Network(), script, 10000000)
}
func addSender(txs ...*transaction.Transaction) error {

View file

@ -60,6 +60,7 @@ func initCHECKMULTISIGVM(t *testing.T, n int, ik, is []int) *vm.VM {
binary.LittleEndian.PutUint32(buf[1:], ecdsaCheckMultisigID)
v := vm.New()
v.GasLimit = -1
ic := &interop.Context{Trigger: trigger.Verification}
v.RegisterInteropGetter(GetInterop(ic))
v.LoadScript(buf)

View file

@ -227,7 +227,7 @@ func invokeNativePolicyMethod(chain *Blockchain, method string, args ...interfac
return nil, w.Err
}
script := w.Bytes()
tx := transaction.New(chain.GetConfig().Magic, script, 0)
tx := transaction.New(chain.GetConfig().Magic, script, 10000000)
validUntil := chain.blockHeight + 1
tx.ValidUntilBlock = validUntil
err := addSender(tx)

View file

@ -6,6 +6,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/interop/crypto"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
@ -17,10 +18,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
)
// ecdsaVerifyInteropPrice returns the price of Neo.Crypto.ECDsaVerify
// syscall to calculate NetworkFee for transaction
const ecdsaVerifyInteropPrice = 100000
var (
// governingTokenTX represents transaction that is used to create
// governing (NEO) token. It's a part of the genesis block.
@ -138,13 +135,13 @@ func CalculateNetworkFee(script []byte) (int64, int) {
)
if vm.IsSignatureContract(script) {
size += 67 + io.GetVarSize(script)
netFee += opcodePrice(opcode.PUSHDATA1, opcode.PUSHNULL) + ecdsaVerifyInteropPrice
} else if n, pubs, ok := vm.ParseMultiSigContract(script); ok {
m := len(pubs)
netFee += opcodePrice(opcode.PUSHDATA1, opcode.PUSHNULL) + crypto.ECDSAVerifyPrice
} else if m, pubs, ok := vm.ParseMultiSigContract(script); ok {
n := len(pubs)
sizeInv := 66 * m
size += io.GetVarSize(sizeInv) + sizeInv + io.GetVarSize(script)
netFee += calculateMultisigFee(m) + calculateMultisigFee(n)
netFee += opcodePrice(opcode.PUSHNULL) + ecdsaVerifyInteropPrice*int64(n)
netFee += opcodePrice(opcode.PUSHNULL) + crypto.ECDSAVerifyPrice*int64(n)
} else {
// We can support more contract types in the future.
}

View file

@ -52,7 +52,7 @@ type rpcTestCase struct {
}
const testContractHash = "10e262ef80c76bdecca287a2c047841fc02c3129"
const deploymentTxHash = "ad8b149c799d4b2337162b0ad23e0ba8845cddb9cfca8a45587ee207015d2a7c"
const deploymentTxHash = "4843700d16be3e6507a25909d3b2aa1472dcd0526be2520f2bfdd53d768bfebf"
var rpcTestCases = map[string][]rpcTestCase{
"getapplicationlog": {
@ -148,7 +148,7 @@ var rpcTestCases = map[string][]rpcTestCase{
},
{
Asset: e.chain.UtilityTokenHash(),
Amount: "918.01738700",
Amount: "915.79002700",
LastUpdated: 6,
}},
Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(),
@ -720,7 +720,7 @@ var rpcTestCases = map[string][]rpcTestCase{
"sendrawtransaction": {
{
name: "positive",
params: `["000a000000316e851039019d39dfc2c37d6c3fee19fd5809870000000000000000f2ad050000000000b00400000001316e851039019d39dfc2c37d6c3fee19fd580987015d0300e87648170000000c1420728274afafc36f43a071d328cfa3e629d9cbb00c14316e851039019d39dfc2c37d6c3fee19fd58098713c00c087472616e736665720c14897720d8cd76f4f00abfa37c0edd889c208fde9b41627d5b523801420c409803db41e66a94e0bd6fdd3d7a7b1e106c1e2281c9782a231f32df036bb80c7f19155cdb9a52a45cf8d93ec9c1e8df69d6ee35625f352d1710c7cc6eee26003c290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b410a906ad4"]`,
params: `["000a000000316e851039019d39dfc2c37d6c3fee19fd58098780969800000000009269130000000000b00400000001316e851039019d39dfc2c37d6c3fee19fd580987015d0300e87648170000000c1420728274afafc36f43a071d328cfa3e629d9cbb00c14316e851039019d39dfc2c37d6c3fee19fd58098713c00c087472616e736665720c14897720d8cd76f4f00abfa37c0edd889c208fde9b41627d5b523801420c4037c8c002c3352329c5f2995567a355d57372447c156ea544844d5f8027babf4cd86142d986681992805e3f62f2625b551f18cf05897e6ea7c135f22537bb740e290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b410a906ad4"]`,
result: func(e *executor) interface{} {
v := true
return &v

Binary file not shown.

View file

@ -111,6 +111,7 @@ func TestParameterContext_AddSignatureMultisig(t *testing.T) {
func newTestVM(w *transaction.Witness, tx *transaction.Transaction) *vm.VM {
v := vm.New()
v.GasLimit = -1
v.RegisterInteropGetter(crypto.GetInterop(&interop.Context{Container: tx}))
v.LoadScript(w.VerificationScript)
v.LoadScript(w.InvocationScript)

View file

@ -133,7 +133,7 @@ func (v *VM) GasConsumed() int64 {
// AddGas consumes specified amount of gas. It returns true iff gas limit wasn't exceeded.
func (v *VM) AddGas(gas int64) bool {
v.gasConsumed += gas
return v.GasLimit == 0 || v.gasConsumed <= v.GasLimit
return v.GasLimit < 0 || v.gasConsumed <= v.GasLimit
}
// Estack returns the evaluation stack so interop hooks can utilize this.
@ -523,7 +523,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
if v.getPrice != nil && ctx.ip < len(ctx.prog) {
v.gasConsumed += v.getPrice(v, op, parameter)
if v.GasLimit > 0 && v.gasConsumed > v.GasLimit {
if v.GasLimit >= 0 && v.gasConsumed > v.GasLimit {
panic("gas limit is exceeded")
}
}

View file

@ -35,7 +35,7 @@ func fooInteropGetter(id uint32) *InteropFuncPrice {
}
func TestInteropHook(t *testing.T) {
v := New()
v := newTestVM()
v.RegisterInteropGetter(fooInteropGetter)
buf := io.NewBufBinWriter()
@ -48,14 +48,14 @@ func TestInteropHook(t *testing.T) {
}
func TestRegisterInteropGetter(t *testing.T) {
v := New()
v := newTestVM()
currRegistered := len(v.getInterop)
v.RegisterInteropGetter(fooInteropGetter)
assert.Equal(t, currRegistered+1, len(v.getInterop))
}
func TestVM_SetPriceGetter(t *testing.T) {
v := New()
v := newTestVM()
prog := []byte{
byte(opcode.PUSH4), byte(opcode.PUSH2),
byte(opcode.PUSHDATA1), 0x01, 0x01,
@ -103,7 +103,7 @@ func TestVM_SetPriceGetter(t *testing.T) {
}
func TestAddGas(t *testing.T) {
v := New()
v := newTestVM()
v.GasLimit = 10
require.True(t, v.AddGas(5))
require.True(t, v.AddGas(5))
@ -111,7 +111,7 @@ func TestAddGas(t *testing.T) {
}
func TestBytesToPublicKey(t *testing.T) {
v := New()
v := newTestVM()
cache := v.GetPublicKeys()
assert.Equal(t, 0, len(cache))
keyHex := "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"
@ -819,7 +819,7 @@ func TestSerializeInterop(t *testing.T) {
func getTestCallFlagsFunc(syscall []byte, flags smartcontract.CallFlag, result interface{}) func(t *testing.T) {
return func(t *testing.T) {
script := append([]byte{byte(opcode.SYSCALL)}, syscall...)
v := New()
v := newTestVM()
v.RegisterInteropGetter(getTestingInterop)
v.LoadScriptWithFlags(script, flags)
if result == nil {
@ -2518,7 +2518,7 @@ func makeProgram(opcodes ...opcode.Opcode) []byte {
}
func load(prog []byte) *VM {
vm := New()
vm := newTestVM()
if len(prog) != 0 {
vm.LoadScript(prog)
}
@ -2533,3 +2533,9 @@ func randomBytes(n int) []byte {
}
return b
}
func newTestVM() *VM {
v := New()
v.GasLimit = -1
return v
}