Merge pull request #2762 from nspcc-dev/optimize-emit-bool
emit: optimize Bool GAS cost
This commit is contained in:
commit
6af71755c1
8 changed files with 52 additions and 51 deletions
|
@ -99,7 +99,7 @@ func TestNEP17Balance(t *testing.T) {
|
|||
}
|
||||
|
||||
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)
|
||||
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr4))
|
||||
e.CheckEOF(t)
|
||||
|
|
3
cli/testdata/wallet1_solo.json
vendored
3
cli/testdata/wallet1_solo.json
vendored
|
@ -61,11 +61,10 @@
|
|||
"isDefault": false
|
||||
},
|
||||
{
|
||||
"address": "NQ3nAdFQXzemHC9uvr4af2Ysap6aZJpqgN",
|
||||
"address": "NfWu6j9KPLQMsWLfHz9iZRy5sNw2bUZWQL",
|
||||
"key": "6PYSATFztBa3CHjSR6sLAKungUEAbQUCVE16KzmaQQ38gLeYGZ9Knd5mGv",
|
||||
"label": "verify",
|
||||
"contract": {
|
||||
"script": "EdsgQFcAA0BXAQR4eXp7VBTAcAwOT25ORVAxMVBheW1lbnRoUEGVAW9hIUA=",
|
||||
"parameters": [],
|
||||
"deployed": true
|
||||
},
|
||||
|
|
|
@ -914,7 +914,7 @@ func TestRunWithHistoricState(t *testing.T) {
|
|||
e.checkNextLine(t, "READY: loaded 36 instructions")
|
||||
e.checkStack(t, []byte{1})
|
||||
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) {
|
||||
|
@ -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.checkEvents(t, true, expectedEvent) // automatically printed after `run` command
|
||||
e.checkEvents(t, false, expectedEvent) // printed after `events` command
|
||||
|
|
|
@ -1945,10 +1945,16 @@ func transformArgs(fs *funcScope, fun ast.Expr, isBuiltin bool, args []ast.Expr)
|
|||
|
||||
// emitConvert converts the top stack item to the specified type.
|
||||
func (c *codegen) emitConvert(typ stackitem.Type) {
|
||||
emit.Opcodes(c.prog.BinWriter, opcode.DUP)
|
||||
emit.Instruction(c.prog.BinWriter, opcode.ISTYPE, []byte{byte(typ)})
|
||||
emit.Instruction(c.prog.BinWriter, opcode.JMPIF, []byte{2 + 2}) // After CONVERT.
|
||||
emit.Instruction(c.prog.BinWriter, opcode.CONVERT, []byte{byte(typ)})
|
||||
if typ == stackitem.BooleanT {
|
||||
// DUP + ISTYPE + JMPIF costs 3 already with CONVERT of a cost 8192.
|
||||
// NOT+NOT at the same time costs 4 and always works (and is shorter).
|
||||
emit.Opcodes(c.prog.BinWriter, opcode.NOT, opcode.NOT)
|
||||
} else {
|
||||
emit.Opcodes(c.prog.BinWriter, opcode.DUP)
|
||||
emit.Instruction(c.prog.BinWriter, opcode.ISTYPE, []byte{byte(typ)})
|
||||
emit.Instruction(c.prog.BinWriter, opcode.JMPIF, []byte{2 + 2}) // After CONVERT.
|
||||
emit.Instruction(c.prog.BinWriter, opcode.CONVERT, []byte{byte(typ)})
|
||||
}
|
||||
}
|
||||
|
||||
func (c *codegen) convertByteArray(elems []ast.Expr) {
|
||||
|
|
|
@ -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) {
|
||||
verAcc, err := util.Uint160DecodeStringLE(verifyWithArgsContractHash)
|
||||
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) {
|
||||
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.String(invocWriter.BinWriter, "")
|
||||
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.
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -347,7 +347,7 @@ func TestEncodeDefaultValue(t *testing.T) {
|
|||
for p, l := range map[ParamType]int{
|
||||
UnknownType: 0,
|
||||
AnyType: 66,
|
||||
BoolType: 3,
|
||||
BoolType: 2,
|
||||
IntegerType: 33,
|
||||
ByteArrayType: 66,
|
||||
StringType: 66,
|
||||
|
|
|
@ -31,12 +31,11 @@ func Opcodes(w *io.BinWriter, ops ...opcode.Opcode) {
|
|||
|
||||
// Bool emits a bool type to the given buffer.
|
||||
func Bool(w *io.BinWriter, ok bool) {
|
||||
if ok {
|
||||
Opcodes(w, opcode.PUSHT)
|
||||
} else {
|
||||
Opcodes(w, opcode.PUSHF)
|
||||
var opVal = opcode.PUSHF
|
||||
if !ok {
|
||||
opVal = opcode.PUSHT
|
||||
}
|
||||
Instruction(w, opcode.CONVERT, []byte{byte(stackitem.BooleanT)})
|
||||
Opcodes(w, opVal, opcode.NOT)
|
||||
}
|
||||
|
||||
func padRight(s int, buf []byte) []byte {
|
||||
|
|
|
@ -231,35 +231,34 @@ func TestEmitArray(t *testing.T) {
|
|||
assert.EqualValues(t, opcode.PUSHDATA1, res[0])
|
||||
assert.EqualValues(t, 2, res[1])
|
||||
assert.EqualValues(t, []byte{0xCA, 0xFE}, res[2:4])
|
||||
assert.EqualValues(t, opcode.PUSHT, res[4])
|
||||
assert.EqualValues(t, opcode.CONVERT, res[5])
|
||||
assert.EqualValues(t, stackitem.BooleanT, res[6])
|
||||
assert.EqualValues(t, opcode.PUSHDATA1, res[7])
|
||||
assert.EqualValues(t, 3, res[8])
|
||||
assert.EqualValues(t, []byte("str"), res[9:12])
|
||||
assert.EqualValues(t, opcode.PUSH1, res[12])
|
||||
assert.EqualValues(t, opcode.PUSHNULL, res[13])
|
||||
assert.EqualValues(t, opcode.PUSH2, res[14])
|
||||
assert.EqualValues(t, opcode.PUSH1, res[15])
|
||||
assert.EqualValues(t, opcode.PUSH2, res[16])
|
||||
assert.EqualValues(t, opcode.PACK, res[17])
|
||||
assert.EqualValues(t, opcode.PUSHINT128, res[18])
|
||||
assert.EqualValues(t, veryBig, bigint.FromBytes(res[19:35]))
|
||||
assert.EqualValues(t, opcode.PUSH0, res[35])
|
||||
assert.EqualValues(t, opcode.PUSHDATA1, res[36])
|
||||
assert.EqualValues(t, 32, res[37])
|
||||
assert.EqualValues(t, u256.BytesBE(), res[38:70])
|
||||
assert.EqualValues(t, opcode.PUSHDATA1, res[70])
|
||||
assert.EqualValues(t, 20, res[71])
|
||||
assert.EqualValues(t, u160.BytesBE(), res[72:92])
|
||||
assert.EqualValues(t, opcode.PUSHDATA1, res[92])
|
||||
assert.EqualValues(t, 32, res[93])
|
||||
assert.EqualValues(t, u256.BytesBE(), res[94:126])
|
||||
assert.EqualValues(t, opcode.PUSHDATA1, res[126])
|
||||
assert.EqualValues(t, 20, res[127])
|
||||
assert.EqualValues(t, u160.BytesBE(), res[128:148])
|
||||
assert.EqualValues(t, opcode.PUSHF, res[4])
|
||||
assert.EqualValues(t, opcode.NOT, res[5])
|
||||
assert.EqualValues(t, opcode.PUSHDATA1, res[6])
|
||||
assert.EqualValues(t, 3, res[7])
|
||||
assert.EqualValues(t, []byte("str"), res[8:11])
|
||||
assert.EqualValues(t, opcode.PUSH1, res[11])
|
||||
assert.EqualValues(t, opcode.PUSHNULL, res[12])
|
||||
assert.EqualValues(t, opcode.PUSH2, res[13])
|
||||
assert.EqualValues(t, opcode.PUSH1, res[14])
|
||||
assert.EqualValues(t, opcode.PUSH2, res[15])
|
||||
assert.EqualValues(t, opcode.PACK, res[16])
|
||||
assert.EqualValues(t, opcode.PUSHINT128, res[17])
|
||||
assert.EqualValues(t, veryBig, bigint.FromBytes(res[18:34]))
|
||||
assert.EqualValues(t, opcode.PUSH0, res[34])
|
||||
assert.EqualValues(t, opcode.PUSHDATA1, res[35])
|
||||
assert.EqualValues(t, 32, res[36])
|
||||
assert.EqualValues(t, u256.BytesBE(), res[37:69])
|
||||
assert.EqualValues(t, opcode.PUSHDATA1, res[69])
|
||||
assert.EqualValues(t, 20, res[70])
|
||||
assert.EqualValues(t, u160.BytesBE(), res[71:91])
|
||||
assert.EqualValues(t, opcode.PUSHDATA1, res[91])
|
||||
assert.EqualValues(t, 32, res[92])
|
||||
assert.EqualValues(t, u256.BytesBE(), res[93:125])
|
||||
assert.EqualValues(t, opcode.PUSHDATA1, res[125])
|
||||
assert.EqualValues(t, 20, res[126])
|
||||
assert.EqualValues(t, u160.BytesBE(), res[127:147])
|
||||
assert.EqualValues(t, opcode.PUSHNULL, res[147])
|
||||
assert.EqualValues(t, opcode.PUSHNULL, res[148])
|
||||
assert.EqualValues(t, opcode.PUSHNULL, res[149])
|
||||
})
|
||||
|
||||
t.Run("empty", func(t *testing.T) {
|
||||
|
@ -281,12 +280,10 @@ func TestEmitBool(t *testing.T) {
|
|||
Bool(buf.BinWriter, true)
|
||||
Bool(buf.BinWriter, false)
|
||||
result := buf.Bytes()
|
||||
assert.EqualValues(t, opcode.PUSH1, result[0])
|
||||
assert.EqualValues(t, opcode.CONVERT, result[1])
|
||||
assert.EqualValues(t, stackitem.BooleanT, result[2])
|
||||
assert.EqualValues(t, opcode.PUSH0, result[3])
|
||||
assert.EqualValues(t, opcode.CONVERT, result[4])
|
||||
assert.EqualValues(t, stackitem.BooleanT, result[5])
|
||||
assert.EqualValues(t, opcode.PUSH0, result[0])
|
||||
assert.EqualValues(t, opcode.NOT, result[1])
|
||||
assert.EqualValues(t, opcode.PUSH1, result[2])
|
||||
assert.EqualValues(t, opcode.NOT, result[3])
|
||||
}
|
||||
|
||||
func TestEmitOpcode(t *testing.T) {
|
||||
|
|
Loading…
Reference in a new issue