Merge pull request #911 from nspcc-dev/feature/convert
vm: implement CONVERT opcode
This commit is contained in:
commit
c1aa96d614
16 changed files with 472 additions and 121 deletions
|
@ -17,6 +17,7 @@ var (
|
||||||
"AppCall",
|
"AppCall",
|
||||||
"FromAddress", "Equals",
|
"FromAddress", "Equals",
|
||||||
"panic",
|
"panic",
|
||||||
|
"ToBool", "ToByteArray", "ToInteger",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,9 @@ func (c *codegen) emitLoadConst(t types.TypeAndValue) {
|
||||||
|
|
||||||
func (c *codegen) convertBasicType(t types.TypeAndValue, typ *types.Basic) {
|
func (c *codegen) convertBasicType(t types.TypeAndValue, typ *types.Basic) {
|
||||||
switch typ.Kind() {
|
switch typ.Kind() {
|
||||||
case types.Int, types.UntypedInt, types.Uint:
|
case types.Int, types.UntypedInt, types.Uint,
|
||||||
|
types.Int16, types.Uint16,
|
||||||
|
types.Int32, types.Uint32, types.Int64, types.Uint64:
|
||||||
val, _ := constant.Int64Val(t.Value)
|
val, _ := constant.Int64Val(t.Value)
|
||||||
emit.Int(c.prog.BinWriter, val)
|
emit.Int(c.prog.BinWriter, val)
|
||||||
case types.String, types.UntypedString:
|
case types.String, types.UntypedString:
|
||||||
|
@ -1053,6 +1055,15 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
|
||||||
} else {
|
} else {
|
||||||
c.prog.Err = errors.New("panic should have string or nil argument")
|
c.prog.Err = errors.New("panic should have string or nil argument")
|
||||||
}
|
}
|
||||||
|
case "ToInteger", "ToByteArray", "ToBool":
|
||||||
|
typ := vm.IntegerT
|
||||||
|
switch name {
|
||||||
|
case "ToByteArray":
|
||||||
|
typ = vm.ByteArrayT
|
||||||
|
case "ToBool":
|
||||||
|
typ = vm.BooleanT
|
||||||
|
}
|
||||||
|
emit.Instruction(c.prog.BinWriter, opcode.CONVERT, []byte{byte(typ)})
|
||||||
case "SHA256":
|
case "SHA256":
|
||||||
emit.Opcode(c.prog.BinWriter, opcode.SHA256)
|
emit.Opcode(c.prog.BinWriter, opcode.SHA256)
|
||||||
case "SHA1":
|
case "SHA1":
|
||||||
|
|
62
pkg/compiler/convert_test.go
Normal file
62
pkg/compiler/convert_test.go
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
package compiler_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type convertTestCase struct {
|
||||||
|
returnType string
|
||||||
|
argValue string
|
||||||
|
result interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFunctionName(typ string) string {
|
||||||
|
switch typ {
|
||||||
|
case "bool":
|
||||||
|
return "Bool"
|
||||||
|
case "[]byte":
|
||||||
|
return "ByteArray"
|
||||||
|
case "int64":
|
||||||
|
return "Integer"
|
||||||
|
}
|
||||||
|
panic("invalid type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvert(t *testing.T) {
|
||||||
|
srcTmpl := `package foo
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop/convert"
|
||||||
|
func Main() %s {
|
||||||
|
arg := %s
|
||||||
|
return convert.To%s(arg)
|
||||||
|
}`
|
||||||
|
|
||||||
|
convertTestCases := []convertTestCase{
|
||||||
|
{"bool", "true", true},
|
||||||
|
{"bool", "false", false},
|
||||||
|
{"bool", "12", true},
|
||||||
|
{"bool", "0", false},
|
||||||
|
{"bool", "[]byte{0, 1, 0}", true},
|
||||||
|
{"bool", "[]byte{0}", false},
|
||||||
|
{"int64", "true", big.NewInt(1)},
|
||||||
|
{"int64", "false", big.NewInt(0)},
|
||||||
|
{"int64", "12", big.NewInt(12)},
|
||||||
|
{"int64", "0", big.NewInt(0)},
|
||||||
|
{"int64", "[]byte{0, 1, 0}", big.NewInt(256)},
|
||||||
|
{"int64", "[]byte{0}", big.NewInt(0)},
|
||||||
|
{"[]byte", "true", []byte{1}},
|
||||||
|
{"[]byte", "false", []byte{0}},
|
||||||
|
{"[]byte", "12", []byte{0x0C}},
|
||||||
|
{"[]byte", "0", []byte{}},
|
||||||
|
{"[]byte", "[]byte{0, 1, 0}", []byte{0, 1, 0}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range convertTestCases {
|
||||||
|
name := getFunctionName(tc.returnType)
|
||||||
|
t.Run(tc.argValue+"->"+name, func(t *testing.T) {
|
||||||
|
src := fmt.Sprintf(srcTmpl, tc.returnType, tc.argValue, name)
|
||||||
|
eval(t, src, tc.result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,14 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestReturnInt64(t *testing.T) {
|
||||||
|
src := `package foo
|
||||||
|
func Main() int64 {
|
||||||
|
return 1
|
||||||
|
}`
|
||||||
|
eval(t, src, big.NewInt(1))
|
||||||
|
}
|
||||||
|
|
||||||
func TestMultipleReturn1(t *testing.T) {
|
func TestMultipleReturn1(t *testing.T) {
|
||||||
src := `
|
src := `
|
||||||
package hello
|
package hello
|
||||||
|
|
|
@ -274,7 +274,7 @@ var structTestCases = []testCase{
|
||||||
vm.NewBigIntegerItem(big.NewInt(1)),
|
vm.NewBigIntegerItem(big.NewInt(1)),
|
||||||
vm.NewBigIntegerItem(big.NewInt(2)),
|
vm.NewBigIntegerItem(big.NewInt(2)),
|
||||||
vm.NewByteArrayItem([]byte("hello")),
|
vm.NewByteArrayItem([]byte("hello")),
|
||||||
vm.NewByteArrayItem([]byte{}),
|
vm.NewBoolItem(false),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -222,9 +222,7 @@ func (p *Payload) Verify(scriptHash util.Uint160) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := v.Estack().Pop().TryBool()
|
return v.Estack().Pop().Bool()
|
||||||
|
|
||||||
return err == nil && res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeBinaryUnsigned reads payload from w excluding signature.
|
// DecodeBinaryUnsigned reads payload from w excluding signature.
|
||||||
|
|
|
@ -1656,11 +1656,7 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa
|
||||||
}
|
}
|
||||||
resEl := vm.Estack().Pop()
|
resEl := vm.Estack().Pop()
|
||||||
if resEl != nil {
|
if resEl != nil {
|
||||||
res, err := resEl.TryBool()
|
if !resEl.Bool() {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !res {
|
|
||||||
return errors.Errorf("signature check failed")
|
return errors.Errorf("signature check failed")
|
||||||
}
|
}
|
||||||
if useKeys {
|
if useKeys {
|
||||||
|
|
17
pkg/interop/convert/convert.go
Normal file
17
pkg/interop/convert/convert.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Package convert provides functions for type conversion.
|
||||||
|
package convert
|
||||||
|
|
||||||
|
// ToInteger converts it's argument to an Integer.
|
||||||
|
func ToInteger(v interface{}) int64 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToByteArray converts it's argument to a ByteArray.
|
||||||
|
func ToByteArray(v interface{}) []byte {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToBool converts it's argument to a Boolean.
|
||||||
|
func ToBool(v interface{}) bool {
|
||||||
|
return false
|
||||||
|
}
|
|
@ -101,7 +101,7 @@ func (c *Context) Next() (opcode.Opcode, []byte, error) {
|
||||||
}
|
}
|
||||||
case opcode.JMP, opcode.JMPIF, opcode.JMPIFNOT, opcode.JMPEQ, opcode.JMPNE,
|
case opcode.JMP, opcode.JMPIF, opcode.JMPIFNOT, opcode.JMPEQ, opcode.JMPNE,
|
||||||
opcode.JMPGT, opcode.JMPGE, opcode.JMPLT, opcode.JMPLE,
|
opcode.JMPGT, opcode.JMPGE, opcode.JMPLT, opcode.JMPLE,
|
||||||
opcode.CALL, opcode.ISTYPE, opcode.NEWARRAYT:
|
opcode.CALL, opcode.ISTYPE, opcode.CONVERT, opcode.NEWARRAYT:
|
||||||
numtoread = 1
|
numtoread = 1
|
||||||
case opcode.JMPL, opcode.JMPIFL, opcode.JMPIFNOTL, opcode.JMPEQL, opcode.JMPNEL,
|
case opcode.JMPL, opcode.JMPIFL, opcode.JMPIFNOTL, opcode.JMPEQL, opcode.JMPNEL,
|
||||||
opcode.JMPGTL, opcode.JMPGEL, opcode.JMPLTL, opcode.JMPLEL,
|
opcode.JMPGTL, opcode.JMPGEL, opcode.JMPLTL, opcode.JMPLEL,
|
||||||
|
@ -176,6 +176,9 @@ func (c *Context) Dup() StackItem {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bool implements StackItem interface.
|
||||||
|
func (c *Context) Bool() bool { panic("can't convert Context to Bool") }
|
||||||
|
|
||||||
// TryBytes implements StackItem interface.
|
// TryBytes implements StackItem interface.
|
||||||
func (c *Context) TryBytes() ([]byte, error) {
|
func (c *Context) TryBytes() ([]byte, error) {
|
||||||
return nil, errors.New("can't convert Context to ByteArray")
|
return nil, errors.New("can't convert Context to ByteArray")
|
||||||
|
@ -189,6 +192,11 @@ func (c *Context) TryInteger() (*big.Int, error) {
|
||||||
// Type implements StackItem interface.
|
// Type implements StackItem interface.
|
||||||
func (c *Context) Type() StackItemType { panic("Context cannot appear on evaluation stack") }
|
func (c *Context) Type() StackItemType { panic("Context cannot appear on evaluation stack") }
|
||||||
|
|
||||||
|
// Convert implements StackItem interface.
|
||||||
|
func (c *Context) Convert(_ StackItemType) (StackItem, error) {
|
||||||
|
panic("Context cannot be converted to anything")
|
||||||
|
}
|
||||||
|
|
||||||
// Equals implements StackItem interface.
|
// Equals implements StackItem interface.
|
||||||
func (c *Context) Equals(s StackItem) bool {
|
func (c *Context) Equals(s StackItem) bool {
|
||||||
return c == s
|
return c == s
|
||||||
|
|
|
@ -31,6 +31,7 @@ func Bool(w *io.BinWriter, ok bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Opcode(w, opcode.PUSHF)
|
Opcode(w, opcode.PUSHF)
|
||||||
|
Instruction(w, opcode.CONVERT, []byte{0x20}) // 0x20 for Boolean type
|
||||||
}
|
}
|
||||||
|
|
||||||
func padRight(s int, buf []byte) []byte {
|
func padRight(s int, buf []byte) []byte {
|
||||||
|
|
|
@ -73,8 +73,6 @@ const (
|
||||||
SYSCALL Opcode = 0x68
|
SYSCALL Opcode = 0x68
|
||||||
TAILCALL Opcode = 0x69
|
TAILCALL Opcode = 0x69
|
||||||
|
|
||||||
ISNULL Opcode = 0x70
|
|
||||||
|
|
||||||
// Stack
|
// Stack
|
||||||
DUPFROMALTSTACK Opcode = 0x6A
|
DUPFROMALTSTACK Opcode = 0x6A
|
||||||
TOALTSTACK Opcode = 0x6B
|
TOALTSTACK Opcode = 0x6B
|
||||||
|
@ -163,7 +161,9 @@ const (
|
||||||
CLEARITEMS Opcode = 0xD3
|
CLEARITEMS Opcode = 0xD3
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
|
ISNULL Opcode = 0xD8
|
||||||
ISTYPE Opcode = 0xD9
|
ISTYPE Opcode = 0xD9
|
||||||
|
CONVERT Opcode = 0xDB
|
||||||
|
|
||||||
// Exceptions
|
// Exceptions
|
||||||
THROW Opcode = 0xF0
|
THROW Opcode = 0xF0
|
||||||
|
|
|
@ -64,7 +64,6 @@ func _() {
|
||||||
_ = x[APPCALL-103]
|
_ = x[APPCALL-103]
|
||||||
_ = x[SYSCALL-104]
|
_ = x[SYSCALL-104]
|
||||||
_ = x[TAILCALL-105]
|
_ = x[TAILCALL-105]
|
||||||
_ = x[ISNULL-112]
|
|
||||||
_ = x[DUPFROMALTSTACK-106]
|
_ = x[DUPFROMALTSTACK-106]
|
||||||
_ = x[TOALTSTACK-107]
|
_ = x[TOALTSTACK-107]
|
||||||
_ = x[FROMALTSTACK-108]
|
_ = x[FROMALTSTACK-108]
|
||||||
|
@ -140,12 +139,14 @@ func _() {
|
||||||
_ = x[REVERSEITEMS-209]
|
_ = x[REVERSEITEMS-209]
|
||||||
_ = x[REMOVE-210]
|
_ = x[REMOVE-210]
|
||||||
_ = x[CLEARITEMS-211]
|
_ = x[CLEARITEMS-211]
|
||||||
|
_ = x[ISNULL-216]
|
||||||
_ = x[ISTYPE-217]
|
_ = x[ISTYPE-217]
|
||||||
|
_ = x[CONVERT-219]
|
||||||
_ = x[THROW-240]
|
_ = x[THROW-240]
|
||||||
_ = x[THROWIFNOT-241]
|
_ = x[THROWIFNOT-241]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLOLDPUSH1RETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXDROPISNULLXSWAPXTUCKDEPTHDROPDUPNIPOVERPICKROLLROTSWAPTUCKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALINCDECSIGNNEGATEABSNOTNZADDSUBMULDIVMODSHLSHRBOOLANDBOOLORNUMEQUALNUMNOTEQUALLTGTLTEGTEMINMAXWITHINSHA1SHA256HASH160HASH256CHECKSIGVERIFYCHECKMULTISIGPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISTYPETHROWTHROWIFNOT"
|
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLOLDPUSH1RETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXDROPXSWAPXTUCKDEPTHDROPDUPNIPOVERPICKROLLROTSWAPTUCKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALINCDECSIGNNEGATEABSNOTNZADDSUBMULDIVMODSHLSHRBOOLANDBOOLORNUMEQUALNUMNOTEQUALLTGTLTEGTEMINMAXWITHINSHA1SHA256HASH160HASH256CHECKSIGVERIFYCHECKMULTISIGPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERTTHROWTHROWIFNOT"
|
||||||
|
|
||||||
var _Opcode_map = map[Opcode]string{
|
var _Opcode_map = map[Opcode]string{
|
||||||
0: _Opcode_name[0:8],
|
0: _Opcode_name[0:8],
|
||||||
|
@ -206,81 +207,82 @@ var _Opcode_map = map[Opcode]string{
|
||||||
107: _Opcode_name[349:359],
|
107: _Opcode_name[349:359],
|
||||||
108: _Opcode_name[359:371],
|
108: _Opcode_name[359:371],
|
||||||
109: _Opcode_name[371:376],
|
109: _Opcode_name[371:376],
|
||||||
112: _Opcode_name[376:382],
|
114: _Opcode_name[376:381],
|
||||||
114: _Opcode_name[382:387],
|
115: _Opcode_name[381:386],
|
||||||
115: _Opcode_name[387:392],
|
116: _Opcode_name[386:391],
|
||||||
116: _Opcode_name[392:397],
|
117: _Opcode_name[391:395],
|
||||||
117: _Opcode_name[397:401],
|
118: _Opcode_name[395:398],
|
||||||
118: _Opcode_name[401:404],
|
119: _Opcode_name[398:401],
|
||||||
119: _Opcode_name[404:407],
|
120: _Opcode_name[401:405],
|
||||||
120: _Opcode_name[407:411],
|
121: _Opcode_name[405:409],
|
||||||
121: _Opcode_name[411:415],
|
122: _Opcode_name[409:413],
|
||||||
122: _Opcode_name[415:419],
|
123: _Opcode_name[413:416],
|
||||||
123: _Opcode_name[419:422],
|
124: _Opcode_name[416:420],
|
||||||
124: _Opcode_name[422:426],
|
125: _Opcode_name[420:424],
|
||||||
125: _Opcode_name[426:430],
|
126: _Opcode_name[424:427],
|
||||||
126: _Opcode_name[430:433],
|
127: _Opcode_name[427:433],
|
||||||
127: _Opcode_name[433:439],
|
128: _Opcode_name[433:437],
|
||||||
128: _Opcode_name[439:443],
|
129: _Opcode_name[437:442],
|
||||||
129: _Opcode_name[443:448],
|
131: _Opcode_name[442:448],
|
||||||
131: _Opcode_name[448:454],
|
132: _Opcode_name[448:451],
|
||||||
132: _Opcode_name[454:457],
|
133: _Opcode_name[451:453],
|
||||||
133: _Opcode_name[457:459],
|
134: _Opcode_name[453:456],
|
||||||
134: _Opcode_name[459:462],
|
135: _Opcode_name[456:461],
|
||||||
135: _Opcode_name[462:467],
|
139: _Opcode_name[461:464],
|
||||||
139: _Opcode_name[467:470],
|
140: _Opcode_name[464:467],
|
||||||
140: _Opcode_name[470:473],
|
141: _Opcode_name[467:471],
|
||||||
141: _Opcode_name[473:477],
|
143: _Opcode_name[471:477],
|
||||||
143: _Opcode_name[477:483],
|
144: _Opcode_name[477:480],
|
||||||
144: _Opcode_name[483:486],
|
145: _Opcode_name[480:483],
|
||||||
145: _Opcode_name[486:489],
|
146: _Opcode_name[483:485],
|
||||||
146: _Opcode_name[489:491],
|
147: _Opcode_name[485:488],
|
||||||
147: _Opcode_name[491:494],
|
148: _Opcode_name[488:491],
|
||||||
148: _Opcode_name[494:497],
|
149: _Opcode_name[491:494],
|
||||||
149: _Opcode_name[497:500],
|
150: _Opcode_name[494:497],
|
||||||
150: _Opcode_name[500:503],
|
151: _Opcode_name[497:500],
|
||||||
151: _Opcode_name[503:506],
|
152: _Opcode_name[500:503],
|
||||||
152: _Opcode_name[506:509],
|
153: _Opcode_name[503:506],
|
||||||
153: _Opcode_name[509:512],
|
154: _Opcode_name[506:513],
|
||||||
154: _Opcode_name[512:519],
|
155: _Opcode_name[513:519],
|
||||||
155: _Opcode_name[519:525],
|
156: _Opcode_name[519:527],
|
||||||
156: _Opcode_name[525:533],
|
158: _Opcode_name[527:538],
|
||||||
158: _Opcode_name[533:544],
|
159: _Opcode_name[538:540],
|
||||||
159: _Opcode_name[544:546],
|
160: _Opcode_name[540:542],
|
||||||
160: _Opcode_name[546:548],
|
161: _Opcode_name[542:545],
|
||||||
161: _Opcode_name[548:551],
|
162: _Opcode_name[545:548],
|
||||||
162: _Opcode_name[551:554],
|
163: _Opcode_name[548:551],
|
||||||
163: _Opcode_name[554:557],
|
164: _Opcode_name[551:554],
|
||||||
164: _Opcode_name[557:560],
|
165: _Opcode_name[554:560],
|
||||||
165: _Opcode_name[560:566],
|
167: _Opcode_name[560:564],
|
||||||
167: _Opcode_name[566:570],
|
168: _Opcode_name[564:570],
|
||||||
168: _Opcode_name[570:576],
|
169: _Opcode_name[570:577],
|
||||||
169: _Opcode_name[576:583],
|
170: _Opcode_name[577:584],
|
||||||
170: _Opcode_name[583:590],
|
172: _Opcode_name[584:592],
|
||||||
172: _Opcode_name[590:598],
|
173: _Opcode_name[592:598],
|
||||||
173: _Opcode_name[598:604],
|
174: _Opcode_name[598:611],
|
||||||
174: _Opcode_name[604:617],
|
192: _Opcode_name[611:615],
|
||||||
192: _Opcode_name[617:621],
|
193: _Opcode_name[615:621],
|
||||||
193: _Opcode_name[621:627],
|
194: _Opcode_name[621:630],
|
||||||
194: _Opcode_name[627:636],
|
195: _Opcode_name[630:638],
|
||||||
195: _Opcode_name[636:644],
|
196: _Opcode_name[638:647],
|
||||||
196: _Opcode_name[644:653],
|
197: _Opcode_name[647:657],
|
||||||
197: _Opcode_name[653:663],
|
198: _Opcode_name[657:666],
|
||||||
198: _Opcode_name[663:672],
|
200: _Opcode_name[666:672],
|
||||||
200: _Opcode_name[672:678],
|
202: _Opcode_name[672:676],
|
||||||
202: _Opcode_name[678:682],
|
203: _Opcode_name[676:682],
|
||||||
203: _Opcode_name[682:688],
|
204: _Opcode_name[682:686],
|
||||||
204: _Opcode_name[688:692],
|
205: _Opcode_name[686:692],
|
||||||
205: _Opcode_name[692:698],
|
206: _Opcode_name[692:700],
|
||||||
206: _Opcode_name[698:706],
|
207: _Opcode_name[700:706],
|
||||||
207: _Opcode_name[706:712],
|
208: _Opcode_name[706:713],
|
||||||
208: _Opcode_name[712:719],
|
209: _Opcode_name[713:725],
|
||||||
209: _Opcode_name[719:731],
|
210: _Opcode_name[725:731],
|
||||||
210: _Opcode_name[731:737],
|
211: _Opcode_name[731:741],
|
||||||
211: _Opcode_name[737:747],
|
216: _Opcode_name[741:747],
|
||||||
217: _Opcode_name[747:753],
|
217: _Opcode_name[747:753],
|
||||||
240: _Opcode_name[753:758],
|
219: _Opcode_name[753:760],
|
||||||
241: _Opcode_name[758:768],
|
240: _Opcode_name[760:765],
|
||||||
|
241: _Opcode_name[765:775],
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i Opcode) String() string {
|
func (i Opcode) String() string {
|
||||||
|
|
|
@ -80,38 +80,9 @@ func (e *Element) BigInt() *big.Int {
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryBool attempts to get the underlying value of the element as a boolean.
|
// Bool converts an underlying value of the element to a boolean.
|
||||||
// Returns error if can't convert value to boolean type.
|
|
||||||
func (e *Element) TryBool() (bool, error) {
|
|
||||||
switch t := e.value.(type) {
|
|
||||||
case *BigIntegerItem:
|
|
||||||
return t.value.Int64() != 0, nil
|
|
||||||
case *BoolItem:
|
|
||||||
return t.value, nil
|
|
||||||
case *ArrayItem, *StructItem:
|
|
||||||
return true, nil
|
|
||||||
case *ByteArrayItem:
|
|
||||||
for _, b := range t.value {
|
|
||||||
if b != 0 {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
case *InteropItem:
|
|
||||||
return t.value != nil, nil
|
|
||||||
default:
|
|
||||||
return false, fmt.Errorf("can't convert to bool: " + t.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bool attempts to get the underlying value of the element as a boolean.
|
|
||||||
// Will panic if the assertion failed which will be caught by the VM.
|
|
||||||
func (e *Element) Bool() bool {
|
func (e *Element) Bool() bool {
|
||||||
val, err := e.TryBool()
|
return e.value.Bool()
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bytes attempts to get the underlying value of the element as a byte array.
|
// Bytes attempts to get the underlying value of the element as a byte array.
|
||||||
|
|
|
@ -20,6 +20,8 @@ type StackItem interface {
|
||||||
Value() interface{}
|
Value() interface{}
|
||||||
// Dup duplicates current StackItem.
|
// Dup duplicates current StackItem.
|
||||||
Dup() StackItem
|
Dup() StackItem
|
||||||
|
// Bool converts StackItem to a boolean value.
|
||||||
|
Bool() bool
|
||||||
// TryBytes converts StackItem to a byte slice.
|
// TryBytes converts StackItem to a byte slice.
|
||||||
TryBytes() ([]byte, error)
|
TryBytes() ([]byte, error)
|
||||||
// TryInteger converts StackItem to an integer.
|
// TryInteger converts StackItem to an integer.
|
||||||
|
@ -30,8 +32,12 @@ type StackItem interface {
|
||||||
ToContractParameter(map[StackItem]bool) smartcontract.Parameter
|
ToContractParameter(map[StackItem]bool) smartcontract.Parameter
|
||||||
// Type returns stack item type.
|
// Type returns stack item type.
|
||||||
Type() StackItemType
|
Type() StackItemType
|
||||||
|
// Convert converts StackItem to another type.
|
||||||
|
Convert(StackItemType) (StackItem, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errInvalidConversion = errors.New("invalid conversion type")
|
||||||
|
|
||||||
func makeStackItem(v interface{}) StackItem {
|
func makeStackItem(v interface{}) StackItem {
|
||||||
switch val := v.(type) {
|
switch val := v.(type) {
|
||||||
case int:
|
case int:
|
||||||
|
@ -106,6 +112,33 @@ func makeStackItem(v interface{}) StackItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convertPrimitive converts primitive item to a specified type.
|
||||||
|
func convertPrimitive(item StackItem, typ StackItemType) (StackItem, error) {
|
||||||
|
if item.Type() == typ {
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
switch typ {
|
||||||
|
case IntegerT:
|
||||||
|
bi, err := item.TryInteger()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewBigIntegerItem(bi), nil
|
||||||
|
case ByteArrayT:
|
||||||
|
b, err := item.TryBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewByteArrayItem(b), nil
|
||||||
|
case BufferT:
|
||||||
|
panic("TODO") // #877
|
||||||
|
case BooleanT:
|
||||||
|
return NewBoolItem(item.Bool()), nil
|
||||||
|
default:
|
||||||
|
return nil, errInvalidConversion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// StructItem represents a struct on the stack.
|
// StructItem represents a struct on the stack.
|
||||||
type StructItem struct {
|
type StructItem struct {
|
||||||
value []StackItem
|
value []StackItem
|
||||||
|
@ -133,6 +166,9 @@ func (i *StructItem) Dup() StackItem {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bool implements StackItem interface.
|
||||||
|
func (i *StructItem) Bool() bool { return true }
|
||||||
|
|
||||||
// TryBytes implements StackItem interface.
|
// TryBytes implements StackItem interface.
|
||||||
func (i *StructItem) TryBytes() ([]byte, error) {
|
func (i *StructItem) TryBytes() ([]byte, error) {
|
||||||
return nil, errors.New("can't convert Struct to ByteArray")
|
return nil, errors.New("can't convert Struct to ByteArray")
|
||||||
|
@ -182,6 +218,20 @@ func (i *StructItem) ToContractParameter(seen map[StackItem]bool) smartcontract.
|
||||||
// Type implements StackItem interface.
|
// Type implements StackItem interface.
|
||||||
func (i *StructItem) Type() StackItemType { return StructT }
|
func (i *StructItem) Type() StackItemType { return StructT }
|
||||||
|
|
||||||
|
// Convert implements StackItem interface.
|
||||||
|
func (i *StructItem) Convert(typ StackItemType) (StackItem, error) {
|
||||||
|
switch typ {
|
||||||
|
case StructT:
|
||||||
|
return i, nil
|
||||||
|
case ArrayT:
|
||||||
|
return NewArrayItem(i.value), nil
|
||||||
|
case BooleanT:
|
||||||
|
return NewBoolItem(i.Bool()), nil
|
||||||
|
default:
|
||||||
|
return nil, errInvalidConversion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clone returns a Struct with all Struct fields copied by value.
|
// Clone returns a Struct with all Struct fields copied by value.
|
||||||
// Array fields are still copied by reference.
|
// Array fields are still copied by reference.
|
||||||
func (i *StructItem) Clone() *StructItem {
|
func (i *StructItem) Clone() *StructItem {
|
||||||
|
@ -217,6 +267,9 @@ func (i NullItem) Dup() StackItem {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bool implements StackItem interface.
|
||||||
|
func (i NullItem) Bool() bool { return false }
|
||||||
|
|
||||||
// TryBytes implements StackItem interface.
|
// TryBytes implements StackItem interface.
|
||||||
func (i NullItem) TryBytes() ([]byte, error) {
|
func (i NullItem) TryBytes() ([]byte, error) {
|
||||||
return nil, errors.New("can't convert Null to ByteArray")
|
return nil, errors.New("can't convert Null to ByteArray")
|
||||||
|
@ -243,6 +296,14 @@ func (i NullItem) ToContractParameter(map[StackItem]bool) smartcontract.Paramete
|
||||||
// Type implements StackItem interface.
|
// Type implements StackItem interface.
|
||||||
func (i NullItem) Type() StackItemType { return AnyT }
|
func (i NullItem) Type() StackItemType { return AnyT }
|
||||||
|
|
||||||
|
// Convert implements StackItem interface.
|
||||||
|
func (i NullItem) Convert(typ StackItemType) (StackItem, error) {
|
||||||
|
if typ == AnyT || !typ.IsValid() {
|
||||||
|
return nil, errInvalidConversion
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
|
||||||
// BigIntegerItem represents a big integer on the stack.
|
// BigIntegerItem represents a big integer on the stack.
|
||||||
type BigIntegerItem struct {
|
type BigIntegerItem struct {
|
||||||
value *big.Int
|
value *big.Int
|
||||||
|
@ -260,6 +321,11 @@ func (i *BigIntegerItem) Bytes() []byte {
|
||||||
return emit.IntToBytes(i.value)
|
return emit.IntToBytes(i.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bool implements StackItem interface.
|
||||||
|
func (i *BigIntegerItem) Bool() bool {
|
||||||
|
return i.value.Sign() != 0
|
||||||
|
}
|
||||||
|
|
||||||
// TryBytes implements StackItem interface.
|
// TryBytes implements StackItem interface.
|
||||||
func (i *BigIntegerItem) TryBytes() ([]byte, error) {
|
func (i *BigIntegerItem) TryBytes() ([]byte, error) {
|
||||||
return i.Bytes(), nil
|
return i.Bytes(), nil
|
||||||
|
@ -311,6 +377,11 @@ func (i *BigIntegerItem) ToContractParameter(map[StackItem]bool) smartcontract.P
|
||||||
// Type implements StackItem interface.
|
// Type implements StackItem interface.
|
||||||
func (i *BigIntegerItem) Type() StackItemType { return IntegerT }
|
func (i *BigIntegerItem) Type() StackItemType { return IntegerT }
|
||||||
|
|
||||||
|
// Convert implements StackItem interface.
|
||||||
|
func (i *BigIntegerItem) Convert(typ StackItemType) (StackItem, error) {
|
||||||
|
return convertPrimitive(i, typ)
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface.
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
func (i *BigIntegerItem) MarshalJSON() ([]byte, error) {
|
func (i *BigIntegerItem) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(i.value)
|
return json.Marshal(i.value)
|
||||||
|
@ -347,6 +418,9 @@ func (i *BoolItem) Dup() StackItem {
|
||||||
return &BoolItem{i.value}
|
return &BoolItem{i.value}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bool implements StackItem interface.
|
||||||
|
func (i *BoolItem) Bool() bool { return i.value }
|
||||||
|
|
||||||
// Bytes converts BoolItem to bytes.
|
// Bytes converts BoolItem to bytes.
|
||||||
func (i *BoolItem) Bytes() []byte {
|
func (i *BoolItem) Bytes() []byte {
|
||||||
if i.value {
|
if i.value {
|
||||||
|
@ -394,6 +468,11 @@ func (i *BoolItem) ToContractParameter(map[StackItem]bool) smartcontract.Paramet
|
||||||
// Type implements StackItem interface.
|
// Type implements StackItem interface.
|
||||||
func (i *BoolItem) Type() StackItemType { return BooleanT }
|
func (i *BoolItem) Type() StackItemType { return BooleanT }
|
||||||
|
|
||||||
|
// Convert implements StackItem interface.
|
||||||
|
func (i *BoolItem) Convert(typ StackItemType) (StackItem, error) {
|
||||||
|
return convertPrimitive(i, typ)
|
||||||
|
}
|
||||||
|
|
||||||
// ByteArrayItem represents a byte array on the stack.
|
// ByteArrayItem represents a byte array on the stack.
|
||||||
type ByteArrayItem struct {
|
type ByteArrayItem struct {
|
||||||
value []byte
|
value []byte
|
||||||
|
@ -420,6 +499,19 @@ func (i *ByteArrayItem) String() string {
|
||||||
return "ByteArray"
|
return "ByteArray"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bool implements StackItem interface.
|
||||||
|
func (i *ByteArrayItem) Bool() bool {
|
||||||
|
if len(i.value) > MaxBigIntegerSizeBits/8 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for _, b := range i.value {
|
||||||
|
if b != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// TryBytes implements StackItem interface.
|
// TryBytes implements StackItem interface.
|
||||||
func (i *ByteArrayItem) TryBytes() ([]byte, error) {
|
func (i *ByteArrayItem) TryBytes() ([]byte, error) {
|
||||||
return i.value, nil
|
return i.value, nil
|
||||||
|
@ -459,6 +551,11 @@ func (i *ByteArrayItem) ToContractParameter(map[StackItem]bool) smartcontract.Pa
|
||||||
// Type implements StackItem interface.
|
// Type implements StackItem interface.
|
||||||
func (i *ByteArrayItem) Type() StackItemType { return ByteArrayT }
|
func (i *ByteArrayItem) Type() StackItemType { return ByteArrayT }
|
||||||
|
|
||||||
|
// Convert implements StackItem interface.
|
||||||
|
func (i *ByteArrayItem) Convert(typ StackItemType) (StackItem, error) {
|
||||||
|
return convertPrimitive(i, typ)
|
||||||
|
}
|
||||||
|
|
||||||
// ArrayItem represents a new ArrayItem object.
|
// ArrayItem represents a new ArrayItem object.
|
||||||
type ArrayItem struct {
|
type ArrayItem struct {
|
||||||
value []StackItem
|
value []StackItem
|
||||||
|
@ -485,6 +582,9 @@ func (i *ArrayItem) String() string {
|
||||||
return "Array"
|
return "Array"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bool implements StackItem interface.
|
||||||
|
func (i *ArrayItem) Bool() bool { return true }
|
||||||
|
|
||||||
// TryBytes implements StackItem interface.
|
// TryBytes implements StackItem interface.
|
||||||
func (i *ArrayItem) TryBytes() ([]byte, error) {
|
func (i *ArrayItem) TryBytes() ([]byte, error) {
|
||||||
return nil, errors.New("can't convert Array to ByteArray")
|
return nil, errors.New("can't convert Array to ByteArray")
|
||||||
|
@ -526,6 +626,20 @@ func (i *ArrayItem) ToContractParameter(seen map[StackItem]bool) smartcontract.P
|
||||||
// Type implements StackItem interface.
|
// Type implements StackItem interface.
|
||||||
func (i *ArrayItem) Type() StackItemType { return ArrayT }
|
func (i *ArrayItem) Type() StackItemType { return ArrayT }
|
||||||
|
|
||||||
|
// Convert implements StackItem interface.
|
||||||
|
func (i *ArrayItem) Convert(typ StackItemType) (StackItem, error) {
|
||||||
|
switch typ {
|
||||||
|
case ArrayT:
|
||||||
|
return i, nil
|
||||||
|
case StructT:
|
||||||
|
return NewStructItem(i.value), nil
|
||||||
|
case BooleanT:
|
||||||
|
return NewBoolItem(i.Bool()), nil
|
||||||
|
default:
|
||||||
|
return nil, errInvalidConversion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MapElement is a key-value pair of StackItems.
|
// MapElement is a key-value pair of StackItems.
|
||||||
type MapElement struct {
|
type MapElement struct {
|
||||||
Key StackItem
|
Key StackItem
|
||||||
|
@ -553,6 +667,9 @@ func (i *MapItem) Value() interface{} {
|
||||||
return i.value
|
return i.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bool implements StackItem interface.
|
||||||
|
func (i *MapItem) Bool() bool { return true }
|
||||||
|
|
||||||
// TryBytes implements StackItem interface.
|
// TryBytes implements StackItem interface.
|
||||||
func (i *MapItem) TryBytes() ([]byte, error) {
|
func (i *MapItem) TryBytes() ([]byte, error) {
|
||||||
return nil, errors.New("can't convert Map to ByteArray")
|
return nil, errors.New("can't convert Map to ByteArray")
|
||||||
|
@ -614,6 +731,18 @@ func (i *MapItem) ToContractParameter(seen map[StackItem]bool) smartcontract.Par
|
||||||
// Type implements StackItem interface.
|
// Type implements StackItem interface.
|
||||||
func (i *MapItem) Type() StackItemType { return MapT }
|
func (i *MapItem) Type() StackItemType { return MapT }
|
||||||
|
|
||||||
|
// Convert implements StackItem interface.
|
||||||
|
func (i *MapItem) Convert(typ StackItemType) (StackItem, error) {
|
||||||
|
switch typ {
|
||||||
|
case MapT:
|
||||||
|
return i, nil
|
||||||
|
case BooleanT:
|
||||||
|
return NewBoolItem(i.Bool()), nil
|
||||||
|
default:
|
||||||
|
return nil, errInvalidConversion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add adds key-value pair to the map.
|
// Add adds key-value pair to the map.
|
||||||
func (i *MapItem) Add(key, value StackItem) {
|
func (i *MapItem) Add(key, value StackItem) {
|
||||||
if !isValidMapKey(key) {
|
if !isValidMapKey(key) {
|
||||||
|
@ -672,6 +801,9 @@ func (i *InteropItem) Dup() StackItem {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bool implements StackItem interface.
|
||||||
|
func (i *InteropItem) Bool() bool { return true }
|
||||||
|
|
||||||
// TryBytes implements StackItem interface.
|
// TryBytes implements StackItem interface.
|
||||||
func (i *InteropItem) TryBytes() ([]byte, error) {
|
func (i *InteropItem) TryBytes() ([]byte, error) {
|
||||||
return nil, errors.New("can't convert Interop to ByteArray")
|
return nil, errors.New("can't convert Interop to ByteArray")
|
||||||
|
@ -704,6 +836,18 @@ func (i *InteropItem) ToContractParameter(map[StackItem]bool) smartcontract.Para
|
||||||
// Type implements StackItem interface.
|
// Type implements StackItem interface.
|
||||||
func (i *InteropItem) Type() StackItemType { return InteropT }
|
func (i *InteropItem) Type() StackItemType { return InteropT }
|
||||||
|
|
||||||
|
// Convert implements StackItem interface.
|
||||||
|
func (i *InteropItem) Convert(typ StackItemType) (StackItem, error) {
|
||||||
|
switch typ {
|
||||||
|
case InteropT:
|
||||||
|
return i, nil
|
||||||
|
case BooleanT:
|
||||||
|
return NewBoolItem(i.Bool()), nil
|
||||||
|
default:
|
||||||
|
return nil, errInvalidConversion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface.
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
func (i *InteropItem) MarshalJSON() ([]byte, error) {
|
func (i *InteropItem) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(i.value)
|
return json.Marshal(i.value)
|
||||||
|
|
|
@ -569,6 +569,15 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
res := v.estack.Pop().Item()
|
res := v.estack.Pop().Item()
|
||||||
v.estack.PushVal(res.Type() == StackItemType(parameter[0]))
|
v.estack.PushVal(res.Type() == StackItemType(parameter[0]))
|
||||||
|
|
||||||
|
case opcode.CONVERT:
|
||||||
|
typ := StackItemType(parameter[0])
|
||||||
|
item := v.estack.Pop().Item()
|
||||||
|
result, err := item.Convert(typ)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
v.estack.PushVal(result)
|
||||||
|
|
||||||
// Stack operations.
|
// Stack operations.
|
||||||
case opcode.TOALTSTACK:
|
case opcode.TOALTSTACK:
|
||||||
v.astack.Push(v.estack.Pop())
|
v.astack.Push(v.estack.Pop())
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -256,6 +257,128 @@ func TestISTYPE(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testCONVERT(isErr bool, to StackItemType, item, res StackItem) func(t *testing.T) {
|
||||||
|
return func(t *testing.T) {
|
||||||
|
prog := []byte{byte(opcode.CONVERT), byte(to)}
|
||||||
|
v := load(prog)
|
||||||
|
v.estack.PushVal(item)
|
||||||
|
if isErr {
|
||||||
|
checkVMFailed(t, v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
runVM(t, v)
|
||||||
|
require.Equal(t, 1, v.estack.Len())
|
||||||
|
require.Equal(t, res, v.estack.Pop().value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCONVERT(t *testing.T) {
|
||||||
|
type convertTC struct {
|
||||||
|
item, res StackItem
|
||||||
|
}
|
||||||
|
arr := []StackItem{
|
||||||
|
NewBigIntegerItem(big.NewInt(7)),
|
||||||
|
NewByteArrayItem([]byte{4, 8, 15}),
|
||||||
|
}
|
||||||
|
m := NewMapItem()
|
||||||
|
m.Add(NewByteArrayItem([]byte{1}), NewByteArrayItem([]byte{2}))
|
||||||
|
|
||||||
|
getName := func(item StackItem, typ StackItemType) string { return fmt.Sprintf("%s->%s", item, typ) }
|
||||||
|
|
||||||
|
t.Run("->Bool", func(t *testing.T) {
|
||||||
|
testBool := func(a, b StackItem) func(t *testing.T) {
|
||||||
|
return testCONVERT(false, BooleanT, a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
trueCases := []StackItem{
|
||||||
|
NewBoolItem(true), NewBigIntegerItem(big.NewInt(11)), NewByteArrayItem([]byte{1, 2, 3}),
|
||||||
|
NewArrayItem(arr), NewArrayItem(nil),
|
||||||
|
NewStructItem(arr), NewStructItem(nil),
|
||||||
|
NewMapItem(), m, NewInteropItem(struct{}{}),
|
||||||
|
}
|
||||||
|
for i := range trueCases {
|
||||||
|
t.Run(getName(trueCases[i], BooleanT), testBool(trueCases[i], NewBoolItem(true)))
|
||||||
|
}
|
||||||
|
|
||||||
|
falseCases := []StackItem{
|
||||||
|
NewBigIntegerItem(big.NewInt(0)), NewByteArrayItem([]byte{0, 0}), NewBoolItem(false),
|
||||||
|
}
|
||||||
|
for i := range falseCases {
|
||||||
|
testBool(falseCases[i], NewBoolItem(false))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("compound/interop -> basic", func(t *testing.T) {
|
||||||
|
types := []StackItemType{IntegerT, ByteArrayT}
|
||||||
|
items := []StackItem{NewArrayItem(nil), NewStructItem(nil), NewMapItem(), NewInteropItem(struct{}{})}
|
||||||
|
for _, typ := range types {
|
||||||
|
for j := range items {
|
||||||
|
t.Run(getName(items[j], typ), testCONVERT(true, typ, items[j], nil))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("primitive -> Integer/ByteArray", func(t *testing.T) {
|
||||||
|
n := big.NewInt(42)
|
||||||
|
b := emit.IntToBytes(n)
|
||||||
|
|
||||||
|
itemInt := NewBigIntegerItem(n)
|
||||||
|
itemBytes := NewByteArrayItem(b)
|
||||||
|
|
||||||
|
trueCases := map[StackItemType][]convertTC{
|
||||||
|
IntegerT: {
|
||||||
|
{itemInt, itemInt},
|
||||||
|
{itemBytes, itemInt},
|
||||||
|
{NewBoolItem(true), NewBigIntegerItem(big.NewInt(1))},
|
||||||
|
{NewBoolItem(false), NewBigIntegerItem(big.NewInt(0))},
|
||||||
|
},
|
||||||
|
ByteArrayT: {
|
||||||
|
{itemInt, itemBytes},
|
||||||
|
{itemBytes, itemBytes},
|
||||||
|
{NewBoolItem(true), NewByteArrayItem([]byte{1})},
|
||||||
|
{NewBoolItem(false), NewByteArrayItem([]byte{0})},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for typ := range trueCases {
|
||||||
|
for _, tc := range trueCases[typ] {
|
||||||
|
t.Run(getName(tc.item, typ), testCONVERT(false, typ, tc.item, tc.res))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Struct<->Array", func(t *testing.T) {
|
||||||
|
arrayItem := NewArrayItem(arr)
|
||||||
|
structItem := NewStructItem(arr)
|
||||||
|
t.Run("Array->Array", testCONVERT(false, ArrayT, arrayItem, arrayItem))
|
||||||
|
t.Run("Array->Struct", testCONVERT(false, StructT, arrayItem, structItem))
|
||||||
|
t.Run("Struct->Array", testCONVERT(false, ArrayT, structItem, arrayItem))
|
||||||
|
t.Run("Struct->Struct", testCONVERT(false, StructT, structItem, structItem))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Map->Map", testCONVERT(false, MapT, m, m))
|
||||||
|
|
||||||
|
t.Run("Null->", func(t *testing.T) {
|
||||||
|
types := []StackItemType{
|
||||||
|
BooleanT, ByteArrayT, IntegerT, ArrayT, StructT, MapT, InteropT,
|
||||||
|
}
|
||||||
|
for i := range types {
|
||||||
|
t.Run(types[i].String(), testCONVERT(false, types[i], NullItem{}, NullItem{}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("->Any", func(t *testing.T) {
|
||||||
|
items := []StackItem{
|
||||||
|
NewBigIntegerItem(big.NewInt(1)), NewByteArrayItem([]byte{1}), NewBoolItem(true),
|
||||||
|
NewArrayItem(arr), NewStructItem(arr), m, NewInteropItem(struct{}{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range items {
|
||||||
|
t.Run(items[i].String(), testCONVERT(true, AnyT, items[i], nil))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// appendBigStruct returns a program which:
|
// appendBigStruct returns a program which:
|
||||||
// 1. pushes size Structs on stack
|
// 1. pushes size Structs on stack
|
||||||
// 2. packs them into a new struct
|
// 2. packs them into a new struct
|
||||||
|
|
Loading…
Reference in a new issue