neo-go/pkg/core/gas_price.go
Roman Khimov bbd802681e cli: make gas parameter to deployment add gas to the base price
That's how it was intended to behave originally. One thing questionable here
is contract price (policy thing, basically) being moved to smartcontract
package, but it's probably fine for NEO 2.0 (as it won't change) and we'll
make something better for NEO 3.0.
2020-03-11 20:34:36 +03:00

105 lines
3.3 KiB
Go

package core
import (
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
)
// interopGasRatio is a multiplier by which a number returned from price getter
// and Fixed8 amount of GAS differ. Numbers defined in syscall tables are a multiple
// of 0.001 GAS = Fixed8(10^5).
const interopGasRatio = 100000
// getPrice returns a price for executing op with the provided parameter.
// Some SYSCALLs have variable price depending on their arguments.
func getPrice(v *vm.VM, op opcode.Opcode, parameter []byte) util.Fixed8 {
if op <= opcode.NOP {
return 0
}
switch op {
case opcode.APPCALL, opcode.TAILCALL:
return toFixed8(10)
case opcode.SYSCALL:
interopID := vm.GetInteropID(parameter)
return getSyscallPrice(v, interopID)
case opcode.SHA1, opcode.SHA256:
return toFixed8(10)
case opcode.HASH160, opcode.HASH256:
return toFixed8(20)
case opcode.CHECKSIG, opcode.VERIFY:
return toFixed8(100)
case opcode.CHECKMULTISIG:
estack := v.Estack()
if estack.Len() == 0 {
return toFixed8(1)
}
var cost int
item := estack.Peek(0)
switch item.Item().(type) {
case *vm.ArrayItem, *vm.StructItem:
cost = len(item.Array())
default:
cost = int(item.BigInt().Int64())
}
if cost < 1 {
return toFixed8(1)
}
return toFixed8(int64(100 * cost))
default:
return toFixed8(1)
}
}
func toFixed8(n int64) util.Fixed8 {
return util.Fixed8(n * interopGasRatio)
}
// getSyscallPrice returns cost of executing syscall with provided id.
// Is SYSCALL is not found, cost is 1.
func getSyscallPrice(v *vm.VM, id uint32) util.Fixed8 {
ifunc := v.GetInteropByID(id)
if ifunc != nil && ifunc.Price > 0 {
return toFixed8(int64(ifunc.Price))
}
const (
neoAssetCreate = 0x1fc6c583 // Neo.Asset.Create
antSharesAssetCreate = 0x99025068 // AntShares.Asset.Create
neoAssetRenew = 0x71908478 // Neo.Asset.Renew
antSharesAssetRenew = 0xaf22447b // AntShares.Asset.Renew
neoContractCreate = 0x6ea56cf6 // Neo.Contract.Create
neoContractMigrate = 0x90621b47 // Neo.Contract.Migrate
antSharesContractCreate = 0x2a28d29b // AntShares.Contract.Create
antSharesContractMigrate = 0xa934c8bb // AntShares.Contract.Migrate
systemStoragePut = 0x84183fe6 // System.Storage.Put
systemStoragePutEx = 0x3a9be173 // System.Storage.PutEx
neoStoragePut = 0xf541a152 // Neo.Storage.Put
antSharesStoragePut = 0x5f300a9e // AntShares.Storage.Put
)
estack := v.Estack()
switch id {
case neoAssetCreate, antSharesAssetCreate:
return util.Fixed8FromInt64(5000)
case neoAssetRenew, antSharesAssetRenew:
arg := estack.Peek(1).BigInt().Int64()
return util.Fixed8FromInt64(arg * 5000)
case neoContractCreate, neoContractMigrate, antSharesContractCreate, antSharesContractMigrate:
return smartcontract.GetDeploymentPrice(smartcontract.PropertyState(estack.Peek(3).BigInt().Int64()))
case systemStoragePut, systemStoragePutEx, neoStoragePut, antSharesStoragePut:
// price for storage PUT is 1 GAS per 1 KiB
keySize := len(estack.Peek(1).Bytes())
valSize := len(estack.Peek(2).Bytes())
return util.Fixed8FromInt64(int64((keySize+valSize-1)/1024 + 1))
default:
return util.Fixed8FromInt64(1)
}
}