forked from TrueCloudLab/neoneo-go
Merge pull request #650 from nspcc-dev/handle-bad-notifications
Handle bad notifications
This commit is contained in:
commit
55ef14f920
4 changed files with 20 additions and 8 deletions
|
@ -343,7 +343,17 @@ func (ic *interopContext) runtimeCheckWitness(v *vm.VM) error {
|
||||||
func (ic *interopContext) runtimeNotify(v *vm.VM) error {
|
func (ic *interopContext) runtimeNotify(v *vm.VM) error {
|
||||||
// It can be just about anything.
|
// It can be just about anything.
|
||||||
e := v.Estack().Pop()
|
e := v.Estack().Pop()
|
||||||
ne := state.NotificationEvent{ScriptHash: getContextScriptHash(v, 0), Item: e.Item()}
|
item := e.Item()
|
||||||
|
// But it has to be serializable, otherwise we either have some broken
|
||||||
|
// (recursive) structure inside or an interop item that can't be used
|
||||||
|
// outside of the interop subsystem anyway. I'd probably fail transactions
|
||||||
|
// that emit such broken notifications, but that might break compatibility
|
||||||
|
// with testnet/mainnet, so we're replacing these with error messages.
|
||||||
|
_, err := vm.SerializeItem(item)
|
||||||
|
if err != nil {
|
||||||
|
item = vm.NewByteArrayItem([]byte(fmt.Sprintf("bad notification: %v", err)))
|
||||||
|
}
|
||||||
|
ne := state.NotificationEvent{ScriptHash: getContextScriptHash(v, 0), Item: item}
|
||||||
ic.notifications = append(ic.notifications, ne)
|
ic.notifications = append(ic.notifications, ne)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ func runtimeNotify(vm *VM) error {
|
||||||
// RuntimeSerialize handles syscalls System.Runtime.Serialize and Neo.Runtime.Serialize.
|
// RuntimeSerialize handles syscalls System.Runtime.Serialize and Neo.Runtime.Serialize.
|
||||||
func RuntimeSerialize(vm *VM) error {
|
func RuntimeSerialize(vm *VM) error {
|
||||||
item := vm.Estack().Pop()
|
item := vm.Estack().Pop()
|
||||||
data, err := serializeItem(item.value)
|
data, err := SerializeItem(item.value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else if len(data) > MaxItemSize {
|
} else if len(data) > MaxItemSize {
|
||||||
|
@ -109,7 +109,7 @@ func RuntimeSerialize(vm *VM) error {
|
||||||
func RuntimeDeserialize(vm *VM) error {
|
func RuntimeDeserialize(vm *VM) error {
|
||||||
data := vm.Estack().Pop().Bytes()
|
data := vm.Estack().Pop().Bytes()
|
||||||
|
|
||||||
item, err := deserializeItem(data)
|
item, err := DeserializeItem(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,8 @@ const (
|
||||||
mapT stackItemType = 0x82
|
mapT stackItemType = 0x82
|
||||||
)
|
)
|
||||||
|
|
||||||
func serializeItem(item StackItem) ([]byte, error) {
|
// SerializeItem encodes given StackItem into the byte slice.
|
||||||
|
func SerializeItem(item StackItem) ([]byte, error) {
|
||||||
w := io.NewBufBinWriter()
|
w := io.NewBufBinWriter()
|
||||||
EncodeBinaryStackItem(item, w.BinWriter)
|
EncodeBinaryStackItem(item, w.BinWriter)
|
||||||
if w.Err != nil {
|
if w.Err != nil {
|
||||||
|
@ -35,7 +36,7 @@ func EncodeBinaryStackItem(item StackItem, w *io.BinWriter) {
|
||||||
|
|
||||||
func serializeItemTo(item StackItem, w *io.BinWriter, seen map[StackItem]bool) {
|
func serializeItemTo(item StackItem, w *io.BinWriter, seen map[StackItem]bool) {
|
||||||
if seen[item] {
|
if seen[item] {
|
||||||
w.Err = errors.New("recursive structures are not supported")
|
w.Err = errors.New("recursive structures can't be serialized")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +51,7 @@ func serializeItemTo(item StackItem, w *io.BinWriter, seen map[StackItem]bool) {
|
||||||
w.WriteBytes([]byte{byte(integerT)})
|
w.WriteBytes([]byte{byte(integerT)})
|
||||||
w.WriteVarBytes(IntToBytes(t.value))
|
w.WriteVarBytes(IntToBytes(t.value))
|
||||||
case *InteropItem:
|
case *InteropItem:
|
||||||
w.Err = errors.New("not supported")
|
w.Err = errors.New("interop item can't be serialized")
|
||||||
case *ArrayItem, *StructItem:
|
case *ArrayItem, *StructItem:
|
||||||
seen[item] = true
|
seen[item] = true
|
||||||
|
|
||||||
|
@ -78,7 +79,8 @@ func serializeItemTo(item StackItem, w *io.BinWriter, seen map[StackItem]bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func deserializeItem(data []byte) (StackItem, error) {
|
// DeserializeItem decodes StackItem from the given byte slice.
|
||||||
|
func DeserializeItem(data []byte) (StackItem, error) {
|
||||||
r := io.NewBinReaderFromBuf(data)
|
r := io.NewBinReaderFromBuf(data)
|
||||||
item := DecodeBinaryStackItem(r)
|
item := DecodeBinaryStackItem(r)
|
||||||
if r.Err != nil {
|
if r.Err != nil {
|
||||||
|
|
|
@ -653,7 +653,7 @@ func TestDeserializeUnknown(t *testing.T) {
|
||||||
prog := append(getSyscallProg("Neo.Runtime.Deserialize"), byte(opcode.RET))
|
prog := append(getSyscallProg("Neo.Runtime.Deserialize"), byte(opcode.RET))
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
|
||||||
data, err := serializeItem(NewBigIntegerItem(123))
|
data, err := SerializeItem(NewBigIntegerItem(123))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
data[0] = 0xFF
|
data[0] = 0xFF
|
||||||
|
|
Loading…
Reference in a new issue