vm: introduce TryBool() for Element and use it in VerifyWitnesses
Script can return non-bool results that can still be converted to bool according to the usual VM rules. Unfortunately Bool() panics if this conversion fails which is OK for things done in vm.execute(), but certainly not for VerifyWitnesses(), thus there is a need for TryBool() that will just return an error in this case.
This commit is contained in:
parent
8441b31b4b
commit
1bf232ad50
2 changed files with 29 additions and 16 deletions
|
@ -1045,14 +1045,17 @@ func (bc *Blockchain) VerifyWitnesses(t *transaction.Transaction) error {
|
|||
if vm.HasFailed() {
|
||||
return errors.Errorf("vm failed to execute the script")
|
||||
}
|
||||
res := vm.PopResult()
|
||||
switch res.(type) {
|
||||
case bool:
|
||||
if !(res.(bool)) {
|
||||
resEl := vm.Estack().Pop()
|
||||
if resEl != nil {
|
||||
res, err := resEl.TryBool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !res {
|
||||
return errors.Errorf("signature check failed")
|
||||
}
|
||||
default:
|
||||
return errors.Errorf("vm returned non-boolean result")
|
||||
} else {
|
||||
return errors.Errorf("no result returned from the script")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,30 +80,40 @@ func (e *Element) BigInt() *big.Int {
|
|||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// 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
|
||||
return t.value.Int64() != 0, nil
|
||||
case *BoolItem:
|
||||
return t.value
|
||||
return t.value, nil
|
||||
case *ArrayItem, *StructItem:
|
||||
return true
|
||||
return true, nil
|
||||
case *ByteArrayItem:
|
||||
for _, b := range t.value {
|
||||
if b != 0 {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false
|
||||
return false, nil
|
||||
case *InteropItem:
|
||||
return t.value != nil
|
||||
return t.value != nil, nil
|
||||
default:
|
||||
panic("can't convert to bool: " + t.String())
|
||||
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
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (e *Element) Bytes() []byte {
|
||||
|
|
Loading…
Reference in a new issue