Merge pull request #650 from nspcc-dev/handle-bad-notifications

Handle bad notifications
This commit is contained in:
Roman Khimov 2020-02-07 16:15:44 +03:00 committed by GitHub
commit 55ef14f920
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 20 additions and 8 deletions

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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 {

View file

@ -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