diff --git a/pkg/consensus/payload.go b/pkg/consensus/payload.go index a8bca0391..f202e4065 100644 --- a/pkg/consensus/payload.go +++ b/pkg/consensus/payload.go @@ -222,9 +222,7 @@ func (p *Payload) Verify(scriptHash util.Uint160) bool { return false } - res, err := v.Estack().Pop().TryBool() - - return err == nil && res + return v.Estack().Pop().Bool() } // DecodeBinaryUnsigned reads payload from w excluding signature. diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index aab57ddd6..c6321b365 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1978,11 +1978,7 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa } resEl := vm.Estack().Pop() if resEl != nil { - res, err := resEl.TryBool() - if err != nil { - return err - } - if !res { + if !resEl.Bool() { return errors.Errorf("signature check failed") } if useKeys { diff --git a/pkg/vm/context.go b/pkg/vm/context.go index 8296f2a8c..131c2e06c 100644 --- a/pkg/vm/context.go +++ b/pkg/vm/context.go @@ -176,6 +176,9 @@ func (c *Context) Dup() StackItem { return c } +// Bool implements StackItem interface. +func (c *Context) Bool() bool { panic("can't convert Context to Bool") } + // TryBytes implements StackItem interface. func (c *Context) TryBytes() ([]byte, error) { return nil, errors.New("can't convert Context to ByteArray") diff --git a/pkg/vm/stack.go b/pkg/vm/stack.go index 6730c4456..d24993057 100644 --- a/pkg/vm/stack.go +++ b/pkg/vm/stack.go @@ -80,38 +80,10 @@ func (e *Element) BigInt() *big.Int { return val } -// TryBool attempts to get the underlying value of the element as 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 { - val, err := e.TryBool() - if err != nil { - panic(err) - } - return val + return e.value.Bool() } // Bytes attempts to get the underlying value of the element as a byte array. diff --git a/pkg/vm/stack_item.go b/pkg/vm/stack_item.go index fbe80346f..bff691ab9 100644 --- a/pkg/vm/stack_item.go +++ b/pkg/vm/stack_item.go @@ -20,6 +20,8 @@ type StackItem interface { Value() interface{} // Dup duplicates current StackItem. Dup() StackItem + // Bool converts StackItem to a boolean value. + Bool() bool // TryBytes converts StackItem to a byte slice. TryBytes() ([]byte, error) // TryInteger converts StackItem to an integer. @@ -133,6 +135,9 @@ func (i *StructItem) Dup() StackItem { return i } +// Bool implements StackItem interface. +func (i *StructItem) Bool() bool { return true } + // TryBytes implements StackItem interface. func (i *StructItem) TryBytes() ([]byte, error) { return nil, errors.New("can't convert Struct to ByteArray") @@ -217,6 +222,9 @@ func (i NullItem) Dup() StackItem { return i } +// Bool implements StackItem interface. +func (i NullItem) Bool() bool { return false } + // TryBytes implements StackItem interface. func (i NullItem) TryBytes() ([]byte, error) { return nil, errors.New("can't convert Null to ByteArray") @@ -260,6 +268,11 @@ func (i *BigIntegerItem) Bytes() []byte { return emit.IntToBytes(i.value) } +// Bool implements StackItem interface. +func (i *BigIntegerItem) Bool() bool { + return i.value.Sign() != 0 +} + // TryBytes implements StackItem interface. func (i *BigIntegerItem) TryBytes() ([]byte, error) { return i.Bytes(), nil @@ -347,6 +360,9 @@ func (i *BoolItem) Dup() StackItem { return &BoolItem{i.value} } +// Bool implements StackItem interface. +func (i *BoolItem) Bool() bool { return i.value } + // Bytes converts BoolItem to bytes. func (i *BoolItem) Bytes() []byte { if i.value { @@ -420,6 +436,19 @@ func (i *ByteArrayItem) String() string { 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. func (i *ByteArrayItem) TryBytes() ([]byte, error) { return i.value, nil @@ -485,6 +514,9 @@ func (i *ArrayItem) String() string { return "Array" } +// Bool implements StackItem interface. +func (i *ArrayItem) Bool() bool { return true } + // TryBytes implements StackItem interface. func (i *ArrayItem) TryBytes() ([]byte, error) { return nil, errors.New("can't convert Array to ByteArray") @@ -553,6 +585,9 @@ func (i *MapItem) Value() interface{} { return i.value } +// Bool implements StackItem interface. +func (i *MapItem) Bool() bool { return true } + // TryBytes implements StackItem interface. func (i *MapItem) TryBytes() ([]byte, error) { return nil, errors.New("can't convert Map to ByteArray") @@ -672,6 +707,9 @@ func (i *InteropItem) Dup() StackItem { return i } +// Bool implements StackItem interface. +func (i *InteropItem) Bool() bool { return true } + // TryBytes implements StackItem interface. func (i *InteropItem) TryBytes() ([]byte, error) { return nil, errors.New("can't convert Interop to ByteArray")