Skip to content

Commit 0114f9a

Browse files
committed
interop: add System.Runtime.BurnGas
1 parent 5924123 commit 0114f9a

File tree

6 files changed

+74
-0
lines changed

6 files changed

+74
-0
lines changed

pkg/compiler/syscall_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ func TestSyscallExecution(t *testing.T) {
6868
"iterator.Create": {interopnames.SystemIteratorCreate, []string{pubs}, false},
6969
"iterator.Next": {interopnames.SystemIteratorNext, []string{"iterator.Iterator{}"}, false},
7070
"iterator.Value": {interopnames.SystemIteratorValue, []string{"iterator.Iterator{}"}, false},
71+
"runtime.BurnGas": {interopnames.SystemRuntimeBurnGas, []string{"1"}, true},
7172
"runtime.CheckWitness": {interopnames.SystemRuntimeCheckWitness, []string{b}, false},
7273
"runtime.GasLeft": {interopnames.SystemRuntimeGasLeft, nil, false},
7374
"runtime.GetCallingScriptHash": {interopnames.SystemRuntimeGetCallingScriptHash, nil, false},

pkg/core/interop/interopnames/names.go

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const (
1616
SystemIteratorCreate = "System.Iterator.Create"
1717
SystemIteratorNext = "System.Iterator.Next"
1818
SystemIteratorValue = "System.Iterator.Value"
19+
SystemRuntimeBurnGas = "System.Runtime.BurnGas"
1920
SystemRuntimeCheckWitness = "System.Runtime.CheckWitness"
2021
SystemRuntimeGasLeft = "System.Runtime.GasLeft"
2122
SystemRuntimeGetCallingScriptHash = "System.Runtime.GetCallingScriptHash"
@@ -55,6 +56,7 @@ var names = []string{
5556
SystemIteratorCreate,
5657
SystemIteratorNext,
5758
SystemIteratorValue,
59+
SystemRuntimeBurnGas,
5860
SystemRuntimeCheckWitness,
5961
SystemRuntimeGasLeft,
6062
SystemRuntimeGetCallingScriptHash,

pkg/core/interop/runtime/engine.go

+19
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package runtime
22

33
import (
4+
"errors"
45
"fmt"
56

67
"github.com/nspcc-dev/neo-go/pkg/core/interop"
@@ -99,3 +100,21 @@ func GetTime(ic *interop.Context) error {
99100
ic.VM.Estack().PushVal(ic.Block.Timestamp)
100101
return nil
101102
}
103+
104+
// BurnGas burns GAS to benefit NEO ecosystem.
105+
func BurnGas(ic *interop.Context) error {
106+
gas := ic.VM.Estack().Pop().BigInt()
107+
if !gas.IsInt64() {
108+
return errors.New("invalid GAS value")
109+
}
110+
111+
g := gas.Int64()
112+
if g <= 0 {
113+
return errors.New("GAS must be positive")
114+
}
115+
116+
if !ic.VM.AddGas(g) {
117+
return errors.New("GAS limit exceeded")
118+
}
119+
return nil
120+
}

pkg/core/interop_system_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
2424
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
2525
"github.com/nspcc-dev/neo-go/pkg/util"
26+
"github.com/nspcc-dev/neo-go/pkg/vm"
2627
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
2728
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
2829
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
@@ -346,6 +347,9 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
346347
emit.Opcodes(w.BinWriter, opcode.CALLT, 1, 0, opcode.RET)
347348
callT2Off := w.Len()
348349
emit.Opcodes(w.BinWriter, opcode.CALLT, 0, 0, opcode.RET)
350+
burnGasOff := w.Len()
351+
emit.Syscall(w.BinWriter, interopnames.SystemRuntimeBurnGas)
352+
emit.Opcodes(w.BinWriter, opcode.RET)
349353

350354
script := w.Bytes()
351355
h := hash.Hash160(script)
@@ -506,6 +510,14 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
506510
Offset: callT2Off,
507511
ReturnType: smartcontract.IntegerType,
508512
},
513+
{
514+
Name: "burnGas",
515+
Offset: burnGasOff,
516+
Parameters: []manifest.Parameter{
517+
manifest.NewParameter("amount", smartcontract.IntegerType),
518+
},
519+
ReturnType: smartcontract.VoidType,
520+
},
509521
}
510522
m.Permissions = make([]manifest.Permission, 2)
511523
m.Permissions[0].Contract.Type = manifest.PermissionHash
@@ -941,3 +953,37 @@ func TestLoadToken(t *testing.T) {
941953
checkFAULTState(t, aer)
942954
})
943955
}
956+
957+
func TestRuntimeBurnGas(t *testing.T) {
958+
bc := newTestChain(t)
959+
960+
cs, _ := getTestContractState(bc)
961+
require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs))
962+
963+
const sysFee = 2_000000
964+
965+
t.Run("good", func(t *testing.T) {
966+
aer, err := invokeContractMethod(bc, sysFee, cs.Hash, "burnGas", int64(1))
967+
require.NoError(t, err)
968+
require.Equal(t, vm.HaltState, aer.VMState)
969+
970+
t.Run("gas limit exceeded", func(t *testing.T) {
971+
aer, err = invokeContractMethod(bc, aer.GasConsumed, cs.Hash, "burnGas", int64(2))
972+
require.NoError(t, err)
973+
require.Equal(t, vm.FaultState, aer.VMState)
974+
})
975+
})
976+
t.Run("too big integer", func(t *testing.T) {
977+
gas := big.NewInt(math.MaxInt64)
978+
gas.Add(gas, big.NewInt(1))
979+
980+
aer, err := invokeContractMethod(bc, sysFee, cs.Hash, "burnGas", gas)
981+
require.NoError(t, err)
982+
checkFAULTState(t, aer)
983+
})
984+
t.Run("zero GAS", func(t *testing.T) {
985+
aer, err := invokeContractMethod(bc, sysFee, cs.Hash, "burnGas", int64(0))
986+
require.NoError(t, err)
987+
checkFAULTState(t, aer)
988+
})
989+
}

pkg/core/interops.go

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ var systemInterops = []interop.Function{
4141
{Name: interopnames.SystemIteratorCreate, Func: iterator.Create, Price: 1 << 4, ParamCount: 1},
4242
{Name: interopnames.SystemIteratorNext, Func: iterator.Next, Price: 1 << 15, ParamCount: 1},
4343
{Name: interopnames.SystemIteratorValue, Func: iterator.Value, Price: 1 << 4, ParamCount: 1},
44+
{Name: interopnames.SystemRuntimeBurnGas, Func: runtime.BurnGas, Price: 1 << 4, ParamCount: 1},
4445
{Name: interopnames.SystemRuntimeCheckWitness, Func: runtime.CheckWitness, Price: 1 << 10,
4546
RequiredFlags: callflag.NoneFlag, ParamCount: 1},
4647
{Name: interopnames.SystemRuntimeGasLeft, Func: runtime.GasLeft, Price: 1 << 4},

pkg/interop/runtime/runtime.go

+5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ const (
1717
Verification byte = 0x20
1818
)
1919

20+
// BurnGas burns provided amount of GAS. It uses `System.Runtime.BurnGas` syscall.
21+
func BurnGas(gas int) {
22+
neogointernal.Syscall1NoReturn("System.Runtime.BurnGas", gas)
23+
}
24+
2025
// CheckWitness verifies if the given script hash (160-bit BE value in a 20 byte
2126
// slice) or key (compressed serialized 33-byte form) is one of the signers of
2227
// this invocation. It uses `System.Runtime.CheckWitness` syscall.

0 commit comments

Comments
 (0)