forked from TrueCloudLab/neoneo-go
interop: add System.Runtime.BurnGas
This commit is contained in:
parent
5924123927
commit
0114f9a912
6 changed files with 74 additions and 0 deletions
|
@ -68,6 +68,7 @@ func TestSyscallExecution(t *testing.T) {
|
|||
"iterator.Create": {interopnames.SystemIteratorCreate, []string{pubs}, false},
|
||||
"iterator.Next": {interopnames.SystemIteratorNext, []string{"iterator.Iterator{}"}, false},
|
||||
"iterator.Value": {interopnames.SystemIteratorValue, []string{"iterator.Iterator{}"}, false},
|
||||
"runtime.BurnGas": {interopnames.SystemRuntimeBurnGas, []string{"1"}, true},
|
||||
"runtime.CheckWitness": {interopnames.SystemRuntimeCheckWitness, []string{b}, false},
|
||||
"runtime.GasLeft": {interopnames.SystemRuntimeGasLeft, nil, false},
|
||||
"runtime.GetCallingScriptHash": {interopnames.SystemRuntimeGetCallingScriptHash, nil, false},
|
||||
|
|
|
@ -16,6 +16,7 @@ const (
|
|||
SystemIteratorCreate = "System.Iterator.Create"
|
||||
SystemIteratorNext = "System.Iterator.Next"
|
||||
SystemIteratorValue = "System.Iterator.Value"
|
||||
SystemRuntimeBurnGas = "System.Runtime.BurnGas"
|
||||
SystemRuntimeCheckWitness = "System.Runtime.CheckWitness"
|
||||
SystemRuntimeGasLeft = "System.Runtime.GasLeft"
|
||||
SystemRuntimeGetCallingScriptHash = "System.Runtime.GetCallingScriptHash"
|
||||
|
@ -55,6 +56,7 @@ var names = []string{
|
|||
SystemIteratorCreate,
|
||||
SystemIteratorNext,
|
||||
SystemIteratorValue,
|
||||
SystemRuntimeBurnGas,
|
||||
SystemRuntimeCheckWitness,
|
||||
SystemRuntimeGasLeft,
|
||||
SystemRuntimeGetCallingScriptHash,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package runtime
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
|
@ -99,3 +100,21 @@ func GetTime(ic *interop.Context) error {
|
|||
ic.VM.Estack().PushVal(ic.Block.Timestamp)
|
||||
return nil
|
||||
}
|
||||
|
||||
// BurnGas burns GAS to benefit NEO ecosystem.
|
||||
func BurnGas(ic *interop.Context) error {
|
||||
gas := ic.VM.Estack().Pop().BigInt()
|
||||
if !gas.IsInt64() {
|
||||
return errors.New("invalid GAS value")
|
||||
}
|
||||
|
||||
g := gas.Int64()
|
||||
if g <= 0 {
|
||||
return errors.New("GAS must be positive")
|
||||
}
|
||||
|
||||
if !ic.VM.AddGas(g) {
|
||||
return errors.New("GAS limit exceeded")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
|
@ -346,6 +347,9 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
|
|||
emit.Opcodes(w.BinWriter, opcode.CALLT, 1, 0, opcode.RET)
|
||||
callT2Off := w.Len()
|
||||
emit.Opcodes(w.BinWriter, opcode.CALLT, 0, 0, opcode.RET)
|
||||
burnGasOff := w.Len()
|
||||
emit.Syscall(w.BinWriter, interopnames.SystemRuntimeBurnGas)
|
||||
emit.Opcodes(w.BinWriter, opcode.RET)
|
||||
|
||||
script := w.Bytes()
|
||||
h := hash.Hash160(script)
|
||||
|
@ -506,6 +510,14 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
|
|||
Offset: callT2Off,
|
||||
ReturnType: smartcontract.IntegerType,
|
||||
},
|
||||
{
|
||||
Name: "burnGas",
|
||||
Offset: burnGasOff,
|
||||
Parameters: []manifest.Parameter{
|
||||
manifest.NewParameter("amount", smartcontract.IntegerType),
|
||||
},
|
||||
ReturnType: smartcontract.VoidType,
|
||||
},
|
||||
}
|
||||
m.Permissions = make([]manifest.Permission, 2)
|
||||
m.Permissions[0].Contract.Type = manifest.PermissionHash
|
||||
|
@ -941,3 +953,37 @@ func TestLoadToken(t *testing.T) {
|
|||
checkFAULTState(t, aer)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRuntimeBurnGas(t *testing.T) {
|
||||
bc := newTestChain(t)
|
||||
|
||||
cs, _ := getTestContractState(bc)
|
||||
require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs))
|
||||
|
||||
const sysFee = 2_000000
|
||||
|
||||
t.Run("good", func(t *testing.T) {
|
||||
aer, err := invokeContractMethod(bc, sysFee, cs.Hash, "burnGas", int64(1))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, vm.HaltState, aer.VMState)
|
||||
|
||||
t.Run("gas limit exceeded", func(t *testing.T) {
|
||||
aer, err = invokeContractMethod(bc, aer.GasConsumed, cs.Hash, "burnGas", int64(2))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, vm.FaultState, aer.VMState)
|
||||
})
|
||||
})
|
||||
t.Run("too big integer", func(t *testing.T) {
|
||||
gas := big.NewInt(math.MaxInt64)
|
||||
gas.Add(gas, big.NewInt(1))
|
||||
|
||||
aer, err := invokeContractMethod(bc, sysFee, cs.Hash, "burnGas", gas)
|
||||
require.NoError(t, err)
|
||||
checkFAULTState(t, aer)
|
||||
})
|
||||
t.Run("zero GAS", func(t *testing.T) {
|
||||
aer, err := invokeContractMethod(bc, sysFee, cs.Hash, "burnGas", int64(0))
|
||||
require.NoError(t, err)
|
||||
checkFAULTState(t, aer)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ var systemInterops = []interop.Function{
|
|||
{Name: interopnames.SystemIteratorCreate, Func: iterator.Create, Price: 1 << 4, ParamCount: 1},
|
||||
{Name: interopnames.SystemIteratorNext, Func: iterator.Next, Price: 1 << 15, ParamCount: 1},
|
||||
{Name: interopnames.SystemIteratorValue, Func: iterator.Value, Price: 1 << 4, ParamCount: 1},
|
||||
{Name: interopnames.SystemRuntimeBurnGas, Func: runtime.BurnGas, Price: 1 << 4, ParamCount: 1},
|
||||
{Name: interopnames.SystemRuntimeCheckWitness, Func: runtime.CheckWitness, Price: 1 << 10,
|
||||
RequiredFlags: callflag.NoneFlag, ParamCount: 1},
|
||||
{Name: interopnames.SystemRuntimeGasLeft, Func: runtime.GasLeft, Price: 1 << 4},
|
||||
|
|
|
@ -17,6 +17,11 @@ const (
|
|||
Verification byte = 0x20
|
||||
)
|
||||
|
||||
// BurnGas burns provided amount of GAS. It uses `System.Runtime.BurnGas` syscall.
|
||||
func BurnGas(gas int) {
|
||||
neogointernal.Syscall1NoReturn("System.Runtime.BurnGas", gas)
|
||||
}
|
||||
|
||||
// CheckWitness verifies if the given script hash (160-bit BE value in a 20 byte
|
||||
// slice) or key (compressed serialized 33-byte form) is one of the signers of
|
||||
// this invocation. It uses `System.Runtime.CheckWitness` syscall.
|
||||
|
|
Loading…
Reference in a new issue