forked from TrueCloudLab/neoneo-go
Merge pull request #382 from nspcc-dev/feature/implicit-stackitem-conversion
VM: implement stack item conversion Fixes #372. Also added tests for NOT and SIGN to check new behavior. Also fixed a bug with Bool casting: it should be != 0 instead of == 1.
This commit is contained in:
commit
c6d3313f82
2 changed files with 182 additions and 4 deletions
|
@ -63,6 +63,11 @@ func (e *Element) BigInt() *big.Int {
|
||||||
switch t := e.value.(type) {
|
switch t := e.value.(type) {
|
||||||
case *BigIntegerItem:
|
case *BigIntegerItem:
|
||||||
return t.value
|
return t.value
|
||||||
|
case *BoolItem:
|
||||||
|
if t.value {
|
||||||
|
return big.NewInt(1)
|
||||||
|
}
|
||||||
|
return big.NewInt(0)
|
||||||
default:
|
default:
|
||||||
b := t.Value().([]uint8)
|
b := t.Value().([]uint8)
|
||||||
return new(big.Int).SetBytes(util.ArrayReverse(b))
|
return new(big.Int).SetBytes(util.ArrayReverse(b))
|
||||||
|
@ -72,16 +77,41 @@ func (e *Element) BigInt() *big.Int {
|
||||||
// Bool attempts to get the underlying value of the element as a boolean.
|
// 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.
|
// Will panic if the assertion failed which will be caught by the VM.
|
||||||
func (e *Element) Bool() bool {
|
func (e *Element) Bool() bool {
|
||||||
if v, ok := e.value.Value().(*big.Int); ok {
|
switch t := e.value.(type) {
|
||||||
return v.Int64() == 1
|
case *BigIntegerItem:
|
||||||
|
return t.value.Int64() != 0
|
||||||
|
case *BoolItem:
|
||||||
|
return t.value
|
||||||
|
case *ArrayItem, *StructItem:
|
||||||
|
return true
|
||||||
|
case *ByteArrayItem:
|
||||||
|
for _, b := range t.value {
|
||||||
|
if b != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
panic("can't convert to bool: " + t.String())
|
||||||
}
|
}
|
||||||
return e.value.Value().(bool)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
// Will panic if the assertion failed which will be caught by the VM.
|
// Will panic if the assertion failed which will be caught by the VM.
|
||||||
func (e *Element) Bytes() []byte {
|
func (e *Element) Bytes() []byte {
|
||||||
return e.value.Value().([]byte)
|
switch t := e.value.(type) {
|
||||||
|
case *ByteArrayItem:
|
||||||
|
return t.value
|
||||||
|
case *BigIntegerItem:
|
||||||
|
return util.ArrayReverse(t.value.Bytes()) // neoVM returns in LE
|
||||||
|
case *BoolItem:
|
||||||
|
if t.value {
|
||||||
|
return []byte{1}
|
||||||
|
}
|
||||||
|
return []byte{0}
|
||||||
|
default:
|
||||||
|
panic("can't convert to []byte: " + t.String())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Array attempts to get the underlying value of the element as an array of
|
// Array attempts to get the underlying value of the element as an array of
|
||||||
|
|
|
@ -111,6 +111,67 @@ func TestPushData4(t *testing.T) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNOTNoArgument(t *testing.T) {
|
||||||
|
prog := makeProgram(NOT)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNOTBool(t *testing.T) {
|
||||||
|
prog := makeProgram(NOT)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(false)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, &BoolItem{true}, vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNOTNonZeroInt(t *testing.T) {
|
||||||
|
prog := makeProgram(NOT)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(3)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, &BoolItem{false}, vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNOTArray(t *testing.T) {
|
||||||
|
prog := makeProgram(NOT)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]StackItem{})
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, &BoolItem{false}, vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNOTStruct(t *testing.T) {
|
||||||
|
prog := makeProgram(NOT)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.Push(NewElement(&StructItem{[]StackItem{}}))
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, &BoolItem{false}, vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNOTByteArray0(t *testing.T) {
|
||||||
|
prog := makeProgram(NOT)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]byte{0, 0})
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, &BoolItem{true}, vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNOTByteArray1(t *testing.T) {
|
||||||
|
prog := makeProgram(NOT)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]byte{0, 1})
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, &BoolItem{false}, vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
func TestAdd(t *testing.T) {
|
func TestAdd(t *testing.T) {
|
||||||
prog := makeProgram(ADD)
|
prog := makeProgram(ADD)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
@ -312,6 +373,71 @@ func TestNEWSTRUCTWrongType(t *testing.T) {
|
||||||
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSIGNNoArgument(t *testing.T) {
|
||||||
|
prog := makeProgram(SIGN)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSIGNWrongType(t *testing.T) {
|
||||||
|
prog := makeProgram(SIGN)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]StackItem{})
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSIGNBool(t *testing.T) {
|
||||||
|
prog := makeProgram(SIGN)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(false)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, &BigIntegerItem{big.NewInt(0)}, vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSIGNPositiveInt(t *testing.T) {
|
||||||
|
prog := makeProgram(SIGN)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(1)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, &BigIntegerItem{big.NewInt(1)}, vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSIGNNegativeInt(t *testing.T) {
|
||||||
|
prog := makeProgram(SIGN)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(-1)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, &BigIntegerItem{big.NewInt(-1)}, vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSIGNZero(t *testing.T) {
|
||||||
|
prog := makeProgram(SIGN)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(0)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, &BigIntegerItem{big.NewInt(0)}, vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSIGNByteArray(t *testing.T) {
|
||||||
|
prog := makeProgram(SIGN)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]byte{0, 1})
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, &BigIntegerItem{big.NewInt(1)}, vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
func TestAppCall(t *testing.T) {
|
func TestAppCall(t *testing.T) {
|
||||||
prog := []byte{byte(APPCALL)}
|
prog := []byte{byte(APPCALL)}
|
||||||
hash := util.Uint160{}
|
hash := util.Uint160{}
|
||||||
|
@ -603,6 +729,28 @@ func TestCATGood(t *testing.T) {
|
||||||
assert.Equal(t, []byte("abcdef"), vm.estack.Peek(0).Bytes())
|
assert.Equal(t, []byte("abcdef"), vm.estack.Peek(0).Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCATInt0ByteArray(t *testing.T) {
|
||||||
|
prog := makeProgram(CAT)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(0)
|
||||||
|
vm.estack.PushVal([]byte{})
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, &ByteArrayItem{[]byte{}}, vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCATByteArrayInt1(t *testing.T) {
|
||||||
|
prog := makeProgram(CAT)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]byte{})
|
||||||
|
vm.estack.PushVal(1)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, &ByteArrayItem{[]byte{1}}, vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSUBSTRBadNoArgs(t *testing.T) {
|
func TestSUBSTRBadNoArgs(t *testing.T) {
|
||||||
prog := makeProgram(SUBSTR)
|
prog := makeProgram(SUBSTR)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
|
Loading…
Reference in a new issue