emit: optimize Bool GAS cost

NOT is 1 byte shorter and 2048 times cheaper than CONVERT. Inspired by
neo-project/neo-vm#493.
This commit is contained in:
Roman Khimov 2022-10-25 13:08:33 +03:00
parent 4313b7f0c7
commit 5d43367082
7 changed files with 42 additions and 47 deletions

View file

@ -99,7 +99,7 @@ func TestNEP17Balance(t *testing.T) {
} }
e.CheckNextLine(t, "^\\s*$") e.CheckNextLine(t, "^\\s*$")
addr4, err := address.StringToUint160("NQ3nAdFQXzemHC9uvr4af2Ysap6aZJpqgN") // deployed verify.go contract addr4, err := address.StringToUint160("NfWu6j9KPLQMsWLfHz9iZRy5sNw2bUZWQL") // deployed verify.go contract
require.NoError(t, err) require.NoError(t, err)
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr4)) e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr4))
e.CheckEOF(t) e.CheckEOF(t)

View file

@ -61,11 +61,10 @@
"isDefault": false "isDefault": false
}, },
{ {
"address": "NQ3nAdFQXzemHC9uvr4af2Ysap6aZJpqgN", "address": "NfWu6j9KPLQMsWLfHz9iZRy5sNw2bUZWQL",
"key": "6PYSATFztBa3CHjSR6sLAKungUEAbQUCVE16KzmaQQ38gLeYGZ9Knd5mGv", "key": "6PYSATFztBa3CHjSR6sLAKungUEAbQUCVE16KzmaQQ38gLeYGZ9Knd5mGv",
"label": "verify", "label": "verify",
"contract": { "contract": {
"script": "EdsgQFcAA0BXAQR4eXp7VBTAcAwOT25ORVAxMVBheW1lbnRoUEGVAW9hIUA=",
"parameters": [], "parameters": [],
"deployed": true "deployed": true
}, },

View file

@ -914,7 +914,7 @@ func TestRunWithHistoricState(t *testing.T) {
e.checkNextLine(t, "READY: loaded 36 instructions") e.checkNextLine(t, "READY: loaded 36 instructions")
e.checkStack(t, []byte{1}) e.checkStack(t, []byte{1})
e.checkNextLine(t, "READY: loaded 36 instructions") e.checkNextLine(t, "READY: loaded 36 instructions")
e.checkNextLineExact(t, "Error: at instruction 31 (SYSCALL): failed to invoke syscall 1381727586: called contract a00e3c2643a08a452d8b0bdd31849ae11a17c445 not found: key not found\n") e.checkNextLineExact(t, "Error: at instruction 31 (SYSCALL): failed to invoke syscall 1381727586: called contract cd583ac7a1a4faef70d6e9f513bc988dde22f672 not found: key not found\n")
} }
func TestEvents(t *testing.T) { func TestEvents(t *testing.T) {
@ -939,7 +939,7 @@ func TestEvents(t *testing.T) {
}), }),
}), }),
} }
e.checkNextLine(t, "READY: loaded 44 instructions") e.checkNextLine(t, "READY: loaded 43 instructions")
e.checkStack(t, stackitem.Null{}) e.checkStack(t, stackitem.Null{})
e.checkEvents(t, true, expectedEvent) // automatically printed after `run` command e.checkEvents(t, true, expectedEvent) // automatically printed after `run` command
e.checkEvents(t, false, expectedEvent) // printed after `events` command e.checkEvents(t, false, expectedEvent) // printed after `events` command

View file

@ -2557,7 +2557,7 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
t.Run("contract-based verification with parameters", func(t *testing.T) { t.Run("contract-based verification with parameters", func(t *testing.T) {
verAcc, err := util.Uint160DecodeStringLE(verifyWithArgsContractHash) verAcc, err := util.Uint160DecodeStringLE(verifyWithArgsContractHash)
require.NoError(t, err) require.NoError(t, err)
checkContract(t, verAcc, []byte{}, 737530) // No C# match, but we believe it's OK and it differs from the one above. checkContract(t, verAcc, []byte{}, 490890) // No C# match, but we believe it's OK and it differs from the one above.
}) })
t.Run("contract-based verification with invocation script", func(t *testing.T) { t.Run("contract-based verification with invocation script", func(t *testing.T) {
verAcc, err := util.Uint160DecodeStringLE(verifyWithArgsContractHash) verAcc, err := util.Uint160DecodeStringLE(verifyWithArgsContractHash)
@ -2567,7 +2567,7 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
emit.Int(invocWriter.BinWriter, 5) emit.Int(invocWriter.BinWriter, 5)
emit.String(invocWriter.BinWriter, "") emit.String(invocWriter.BinWriter, "")
invocScript := invocWriter.Bytes() invocScript := invocWriter.Bytes()
checkContract(t, verAcc, invocScript, 640360) // No C# match, but we believe it's OK and it has a specific invocation script overriding anything server-side. checkContract(t, verAcc, invocScript, 393720) // No C# match, but we believe it's OK and it has a specific invocation script overriding anything server-side.
}) })
}) })
} }

View file

@ -347,7 +347,7 @@ func TestEncodeDefaultValue(t *testing.T) {
for p, l := range map[ParamType]int{ for p, l := range map[ParamType]int{
UnknownType: 0, UnknownType: 0,
AnyType: 66, AnyType: 66,
BoolType: 3, BoolType: 2,
IntegerType: 33, IntegerType: 33,
ByteArrayType: 66, ByteArrayType: 66,
StringType: 66, StringType: 66,

View file

@ -31,12 +31,11 @@ func Opcodes(w *io.BinWriter, ops ...opcode.Opcode) {
// Bool emits a bool type to the given buffer. // Bool emits a bool type to the given buffer.
func Bool(w *io.BinWriter, ok bool) { func Bool(w *io.BinWriter, ok bool) {
if ok { var opVal = opcode.PUSHF
Opcodes(w, opcode.PUSHT) if !ok {
} else { opVal = opcode.PUSHT
Opcodes(w, opcode.PUSHF)
} }
Instruction(w, opcode.CONVERT, []byte{byte(stackitem.BooleanT)}) Opcodes(w, opVal, opcode.NOT)
} }
func padRight(s int, buf []byte) []byte { func padRight(s int, buf []byte) []byte {

View file

@ -231,35 +231,34 @@ func TestEmitArray(t *testing.T) {
assert.EqualValues(t, opcode.PUSHDATA1, res[0]) assert.EqualValues(t, opcode.PUSHDATA1, res[0])
assert.EqualValues(t, 2, res[1]) assert.EqualValues(t, 2, res[1])
assert.EqualValues(t, []byte{0xCA, 0xFE}, res[2:4]) assert.EqualValues(t, []byte{0xCA, 0xFE}, res[2:4])
assert.EqualValues(t, opcode.PUSHT, res[4]) assert.EqualValues(t, opcode.PUSHF, res[4])
assert.EqualValues(t, opcode.CONVERT, res[5]) assert.EqualValues(t, opcode.NOT, res[5])
assert.EqualValues(t, stackitem.BooleanT, res[6]) assert.EqualValues(t, opcode.PUSHDATA1, res[6])
assert.EqualValues(t, opcode.PUSHDATA1, res[7]) assert.EqualValues(t, 3, res[7])
assert.EqualValues(t, 3, res[8]) assert.EqualValues(t, []byte("str"), res[8:11])
assert.EqualValues(t, []byte("str"), res[9:12]) assert.EqualValues(t, opcode.PUSH1, res[11])
assert.EqualValues(t, opcode.PUSH1, res[12]) assert.EqualValues(t, opcode.PUSHNULL, res[12])
assert.EqualValues(t, opcode.PUSHNULL, res[13]) assert.EqualValues(t, opcode.PUSH2, res[13])
assert.EqualValues(t, opcode.PUSH2, res[14]) assert.EqualValues(t, opcode.PUSH1, res[14])
assert.EqualValues(t, opcode.PUSH1, res[15]) assert.EqualValues(t, opcode.PUSH2, res[15])
assert.EqualValues(t, opcode.PUSH2, res[16]) assert.EqualValues(t, opcode.PACK, res[16])
assert.EqualValues(t, opcode.PACK, res[17]) assert.EqualValues(t, opcode.PUSHINT128, res[17])
assert.EqualValues(t, opcode.PUSHINT128, res[18]) assert.EqualValues(t, veryBig, bigint.FromBytes(res[18:34]))
assert.EqualValues(t, veryBig, bigint.FromBytes(res[19:35])) assert.EqualValues(t, opcode.PUSH0, res[34])
assert.EqualValues(t, opcode.PUSH0, res[35]) assert.EqualValues(t, opcode.PUSHDATA1, res[35])
assert.EqualValues(t, opcode.PUSHDATA1, res[36]) assert.EqualValues(t, 32, res[36])
assert.EqualValues(t, 32, res[37]) assert.EqualValues(t, u256.BytesBE(), res[37:69])
assert.EqualValues(t, u256.BytesBE(), res[38:70]) assert.EqualValues(t, opcode.PUSHDATA1, res[69])
assert.EqualValues(t, opcode.PUSHDATA1, res[70]) assert.EqualValues(t, 20, res[70])
assert.EqualValues(t, 20, res[71]) assert.EqualValues(t, u160.BytesBE(), res[71:91])
assert.EqualValues(t, u160.BytesBE(), res[72:92]) assert.EqualValues(t, opcode.PUSHDATA1, res[91])
assert.EqualValues(t, opcode.PUSHDATA1, res[92]) assert.EqualValues(t, 32, res[92])
assert.EqualValues(t, 32, res[93]) assert.EqualValues(t, u256.BytesBE(), res[93:125])
assert.EqualValues(t, u256.BytesBE(), res[94:126]) assert.EqualValues(t, opcode.PUSHDATA1, res[125])
assert.EqualValues(t, opcode.PUSHDATA1, res[126]) assert.EqualValues(t, 20, res[126])
assert.EqualValues(t, 20, res[127]) assert.EqualValues(t, u160.BytesBE(), res[127:147])
assert.EqualValues(t, u160.BytesBE(), res[128:148]) assert.EqualValues(t, opcode.PUSHNULL, res[147])
assert.EqualValues(t, opcode.PUSHNULL, res[148]) assert.EqualValues(t, opcode.PUSHNULL, res[148])
assert.EqualValues(t, opcode.PUSHNULL, res[149])
}) })
t.Run("empty", func(t *testing.T) { t.Run("empty", func(t *testing.T) {
@ -281,12 +280,10 @@ func TestEmitBool(t *testing.T) {
Bool(buf.BinWriter, true) Bool(buf.BinWriter, true)
Bool(buf.BinWriter, false) Bool(buf.BinWriter, false)
result := buf.Bytes() result := buf.Bytes()
assert.EqualValues(t, opcode.PUSH1, result[0]) assert.EqualValues(t, opcode.PUSH0, result[0])
assert.EqualValues(t, opcode.CONVERT, result[1]) assert.EqualValues(t, opcode.NOT, result[1])
assert.EqualValues(t, stackitem.BooleanT, result[2]) assert.EqualValues(t, opcode.PUSH1, result[2])
assert.EqualValues(t, opcode.PUSH0, result[3]) assert.EqualValues(t, opcode.NOT, result[3])
assert.EqualValues(t, opcode.CONVERT, result[4])
assert.EqualValues(t, stackitem.BooleanT, result[5])
} }
func TestEmitOpcode(t *testing.T) { func TestEmitOpcode(t *testing.T) {