diff --git a/chain/types/cbor_gen.go b/chain/types/cbor_gen.go index 314b2be6c..fd2462756 100644 --- a/chain/types/cbor_gen.go +++ b/chain/types/cbor_gen.go @@ -2078,3 +2078,224 @@ func (t *EventEntry) UnmarshalCBOR(r io.Reader) (err error) { } return nil } + +var lengthBufLegacyEvent = []byte{130} + +func (t *LegacyEvent) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write(lengthBufLegacyEvent); err != nil { + return err + } + + // t.Emitter (abi.ActorID) (uint64) + + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Emitter)); err != nil { + return err + } + + // t.Entries ([]types.LegacyEventEntry) (slice) + if len(t.Entries) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Entries was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Entries))); err != nil { + return err + } + for _, v := range t.Entries { + if err := v.MarshalCBOR(cw); err != nil { + return err + } + } + return nil +} + +func (t *LegacyEvent) UnmarshalCBOR(r io.Reader) (err error) { + *t = LegacyEvent{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Emitter (abi.ActorID) (uint64) + + { + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.Emitter = abi.ActorID(extra) + + } + // t.Entries ([]types.LegacyEventEntry) (slice) + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Entries: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Entries = make([]LegacyEventEntry, extra) + } + + for i := 0; i < int(extra); i++ { + + var v LegacyEventEntry + if err := v.UnmarshalCBOR(cr); err != nil { + return err + } + + t.Entries[i] = v + } + + return nil +} + +var lengthBufLegacyEventEntry = []byte{131} + +func (t *LegacyEventEntry) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write(lengthBufLegacyEventEntry); err != nil { + return err + } + + // t.Flags (uint8) (uint8) + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Flags)); err != nil { + return err + } + + // t.Key (string) (string) + if len(t.Key) > cbg.MaxLength { + return xerrors.Errorf("Value in field t.Key was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Key))); err != nil { + return err + } + if _, err := io.WriteString(w, string(t.Key)); err != nil { + return err + } + + // t.Value ([]uint8) (slice) + if len(t.Value) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Value was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(t.Value))); err != nil { + return err + } + + if _, err := cw.Write(t.Value[:]); err != nil { + return err + } + return nil +} + +func (t *LegacyEventEntry) UnmarshalCBOR(r io.Reader) (err error) { + *t = LegacyEventEntry{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Flags (uint8) (uint8) + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint8 field") + } + if extra > math.MaxUint8 { + return fmt.Errorf("integer in input was too large for uint8 field") + } + t.Flags = uint8(extra) + // t.Key (string) (string) + + { + sval, err := cbg.ReadString(cr) + if err != nil { + return err + } + + t.Key = string(sval) + } + // t.Value ([]uint8) (slice) + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Value: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + if extra > 0 { + t.Value = make([]uint8, extra) + } + + if _, err := io.ReadFull(cr, t.Value[:]); err != nil { + return err + } + return nil +} diff --git a/chain/types/event.go b/chain/types/event.go index f87385160..106a120e2 100644 --- a/chain/types/event.go +++ b/chain/types/event.go @@ -1,11 +1,6 @@ package types import ( - "bytes" - "fmt" - - cbg "github.com/whyrusleeping/cbor-gen" - "github.com/filecoin-project/go-state-types/abi" ) @@ -38,25 +33,3 @@ type EventEntry struct { } type FilterID [32]byte // compatible with EthHash - -// DecodeEvents decodes a CBOR list of CBOR-encoded events. -func DecodeEvents(input []byte) ([]Event, error) { - r := bytes.NewReader(input) - typ, len, err := cbg.NewCborReader(r).ReadHeader() - if err != nil { - return nil, fmt.Errorf("failed to read events: %w", err) - } - if typ != cbg.MajArray { - return nil, fmt.Errorf("expected a CBOR list, was major type %d", typ) - } - - events := make([]Event, 0, len) - for i := 0; i < int(len); i++ { - var evt Event - if err := evt.UnmarshalCBOR(r); err != nil { - return nil, fmt.Errorf("failed to parse event: %w", err) - } - events = append(events, evt) - } - return events, nil -} diff --git a/chain/types/legacy/cbor_gen.go b/chain/types/legacy/cbor_gen.go deleted file mode 100644 index 7fedfe5b6..000000000 --- a/chain/types/legacy/cbor_gen.go +++ /dev/null @@ -1,242 +0,0 @@ -// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. - -package legacy - -import ( - "fmt" - "io" - "math" - "sort" - - cid "github.com/ipfs/go-cid" - cbg "github.com/whyrusleeping/cbor-gen" - xerrors "golang.org/x/xerrors" - - abi "github.com/filecoin-project/go-state-types/abi" -) - -var _ = xerrors.Errorf -var _ = cid.Undef -var _ = math.E -var _ = sort.Sort - -var lengthBufEvent = []byte{130} - -func (t *Event) MarshalCBOR(w io.Writer) error { - if t == nil { - _, err := w.Write(cbg.CborNull) - return err - } - - cw := cbg.NewCborWriter(w) - - if _, err := cw.Write(lengthBufEvent); err != nil { - return err - } - - // t.Emitter (abi.ActorID) (uint64) - - if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Emitter)); err != nil { - return err - } - - // t.Entries ([]legacy.EventEntry) (slice) - if len(t.Entries) > cbg.MaxLength { - return xerrors.Errorf("Slice value in field t.Entries was too long") - } - - if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Entries))); err != nil { - return err - } - for _, v := range t.Entries { - if err := v.MarshalCBOR(cw); err != nil { - return err - } - } - return nil -} - -func (t *Event) UnmarshalCBOR(r io.Reader) (err error) { - *t = Event{} - - cr := cbg.NewCborReader(r) - - maj, extra, err := cr.ReadHeader() - if err != nil { - return err - } - defer func() { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - }() - - if maj != cbg.MajArray { - return fmt.Errorf("cbor input should be of type array") - } - - if extra != 2 { - return fmt.Errorf("cbor input had wrong number of fields") - } - - // t.Emitter (abi.ActorID) (uint64) - - { - - maj, extra, err = cr.ReadHeader() - if err != nil { - return err - } - if maj != cbg.MajUnsignedInt { - return fmt.Errorf("wrong type for uint64 field") - } - t.Emitter = abi.ActorID(extra) - - } - // t.Entries ([]legacy.EventEntry) (slice) - - maj, extra, err = cr.ReadHeader() - if err != nil { - return err - } - - if extra > cbg.MaxLength { - return fmt.Errorf("t.Entries: array too large (%d)", extra) - } - - if maj != cbg.MajArray { - return fmt.Errorf("expected cbor array") - } - - if extra > 0 { - t.Entries = make([]EventEntry, extra) - } - - for i := 0; i < int(extra); i++ { - - var v EventEntry - if err := v.UnmarshalCBOR(cr); err != nil { - return err - } - - t.Entries[i] = v - } - - return nil -} - -var lengthBufEventEntry = []byte{131} - -func (t *EventEntry) MarshalCBOR(w io.Writer) error { - if t == nil { - _, err := w.Write(cbg.CborNull) - return err - } - - cw := cbg.NewCborWriter(w) - - if _, err := cw.Write(lengthBufEventEntry); err != nil { - return err - } - - // t.Flags (uint8) (uint8) - if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Flags)); err != nil { - return err - } - - // t.Key (string) (string) - if len(t.Key) > cbg.MaxLength { - return xerrors.Errorf("Value in field t.Key was too long") - } - - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Key))); err != nil { - return err - } - if _, err := io.WriteString(w, string(t.Key)); err != nil { - return err - } - - // t.Value ([]uint8) (slice) - if len(t.Value) > cbg.ByteArrayMaxLen { - return xerrors.Errorf("Byte array in field t.Value was too long") - } - - if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(t.Value))); err != nil { - return err - } - - if _, err := cw.Write(t.Value[:]); err != nil { - return err - } - return nil -} - -func (t *EventEntry) UnmarshalCBOR(r io.Reader) (err error) { - *t = EventEntry{} - - cr := cbg.NewCborReader(r) - - maj, extra, err := cr.ReadHeader() - if err != nil { - return err - } - defer func() { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - }() - - if maj != cbg.MajArray { - return fmt.Errorf("cbor input should be of type array") - } - - if extra != 3 { - return fmt.Errorf("cbor input had wrong number of fields") - } - - // t.Flags (uint8) (uint8) - - maj, extra, err = cr.ReadHeader() - if err != nil { - return err - } - if maj != cbg.MajUnsignedInt { - return fmt.Errorf("wrong type for uint8 field") - } - if extra > math.MaxUint8 { - return fmt.Errorf("integer in input was too large for uint8 field") - } - t.Flags = uint8(extra) - // t.Key (string) (string) - - { - sval, err := cbg.ReadString(cr) - if err != nil { - return err - } - - t.Key = string(sval) - } - // t.Value ([]uint8) (slice) - - maj, extra, err = cr.ReadHeader() - if err != nil { - return err - } - - if extra > cbg.ByteArrayMaxLen { - return fmt.Errorf("t.Value: byte array too large (%d)", extra) - } - if maj != cbg.MajByteString { - return fmt.Errorf("expected byte array") - } - - if extra > 0 { - t.Value = make([]uint8, extra) - } - - if _, err := io.ReadFull(cr, t.Value[:]); err != nil { - return err - } - return nil -} diff --git a/chain/types/legacy/event.go b/chain/types/legacy_event.go similarity index 55% rename from chain/types/legacy/event.go rename to chain/types/legacy_event.go index a06910f9a..de2dba4c9 100644 --- a/chain/types/legacy/event.go +++ b/chain/types/legacy_event.go @@ -1,4 +1,4 @@ -package legacy +package types import ( "bytes" @@ -8,19 +8,17 @@ import ( cbg "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-state-types/abi" - - "github.com/filecoin-project/lotus/chain/types" ) -type Event struct { +type LegacyEvent struct { // The ID of the actor that emitted this event. Emitter abi.ActorID // Key values making up this event. - Entries []EventEntry + Entries []LegacyEventEntry } -type EventEntry struct { +type LegacyEventEntry struct { // A bitmap conveying metadata or hints about this entry. Flags uint8 @@ -31,16 +29,24 @@ type EventEntry struct { Value []byte } +var keyRewrites = map[string]string{ + "topic1": "t1", + "topic2": "t2", + "topic3": "t3", + "topic4": "t4", + "data": "d", +} + // Adapt method assumes that all events are EVM events (which is the case for // nv<20, the network versions for which this code is active), and performs the // following adaptations: // - Upgrades the schema to new Events, setting codec = Raw. // - Removes the CBOR framing from values. // - Left pads EVM log topic entry values to 32 bytes. -func (e *Event) Adapt() (types.Event, error) { - entries := make([]types.EventEntry, 0, len(e.Entries)) +func (e *LegacyEvent) Adapt() (Event, error) { + entries := make([]EventEntry, 0, len(e.Entries)) for _, ee := range e.Entries { - entry := types.EventEntry{ + entry := EventEntry{ Flags: ee.Flags, Key: ee.Key, Codec: uint64(multicodec.Raw), @@ -48,17 +54,37 @@ func (e *Event) Adapt() (types.Event, error) { } value, err := cbg.ReadByteArray(bytes.NewReader(ee.Value), 64) if err != nil { - return types.Event{}, fmt.Errorf("failed to decode event value while adapting: %w", err) + return Event{}, fmt.Errorf("failed to decode event value while adapting: %w", err) } if l := len(value); l < 32 { pvalue := make([]byte, 32) copy(pvalue[32-len(value):], value) - value = pvalue + entry.Value = pvalue + } + if r, ok := keyRewrites[entry.Key]; ok { + entry.Key = r } entries = append(entries, entry) } - return types.Event{ + return Event{ Emitter: e.Emitter, Entries: entries, }, nil } + +// AsLegacy strips the codec off an Event object and returns a LegacyEvent. +func (e *Event) AsLegacy() *LegacyEvent { + entries := make([]LegacyEventEntry, 0, len(e.Entries)) + for _, ee := range e.Entries { + entry := LegacyEventEntry{ + Flags: ee.Flags, + Key: ee.Key, + Value: ee.Value, + } + entries = append(entries, entry) + } + return &LegacyEvent{ + Emitter: e.Emitter, + Entries: entries, + } +} diff --git a/chain/vm/fvm.go b/chain/vm/fvm.go index 60e0a545b..266ede393 100644 --- a/chain/vm/fvm.go +++ b/chain/vm/fvm.go @@ -35,7 +35,6 @@ import ( "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/chain/types/legacy" "github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/lotus/node/bundle" ) @@ -521,9 +520,9 @@ func (vm *FVM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet if vm.returnEvents && len(ret.EventsBytes) > 0 { if vm.nv < network.Version20 { - applyRet.Events, err = DecodeList[*legacy.Event](ret.EventsBytes) + applyRet.Events, err = DecodeEvents(ret.EventsBytes, true) } else { - applyRet.Events, err = DecodeList[*types.Event](ret.EventsBytes) + applyRet.Events, err = DecodeEvents(ret.EventsBytes, false) } if err != nil { return nil, fmt.Errorf("failed to decode events returned by the FVM: %w", err) @@ -590,9 +589,9 @@ func (vm *FVM) ApplyImplicitMessage(ctx context.Context, cmsg *types.Message) (* if vm.returnEvents && len(ret.EventsBytes) > 0 { if vm.nv < network.Version20 { - applyRet.Events, err = DecodeList[*legacy.Event](ret.EventsBytes) + applyRet.Events, err = DecodeEvents(ret.EventsBytes, true) } else { - applyRet.Events, err = DecodeList[*types.Event](ret.EventsBytes) + applyRet.Events, err = DecodeEvents(ret.EventsBytes, false) } if err != nil { return nil, fmt.Errorf("failed to decode events returned by the FVM: %w", err) @@ -717,16 +716,11 @@ func (r *xRedirect) MarshalCBOR(w io.Writer) error { return nil } -type CBOR interface { - cbg.CBORMarshaler - cbg.CBORUnmarshaler -} - -func DecodeList[T CBOR](input []byte) ([]cbg.CBORMarshaler, error) { +func DecodeEvents(input []byte, legacy bool) ([]cbg.CBORMarshaler, error) { r := bytes.NewReader(input) typ, len, err := cbg.NewCborReader(r).ReadHeader() if err != nil { - return nil, fmt.Errorf("failed to read list: %w", err) + return nil, fmt.Errorf("failed to read events: %w", err) } if typ != cbg.MajArray { return nil, fmt.Errorf("expected a CBOR list, was major type %d", typ) @@ -734,11 +728,15 @@ func DecodeList[T CBOR](input []byte) ([]cbg.CBORMarshaler, error) { events := make([]cbg.CBORMarshaler, 0, len) for i := 0; i < int(len); i++ { - var evt T + var evt types.Event if err := evt.UnmarshalCBOR(r); err != nil { - return nil, fmt.Errorf("failed to parse list element: %w", err) + return nil, fmt.Errorf("failed to parse event: %w", err) + } + if legacy { + events = append(events, evt.AsLegacy()) + } else { + events = append(events, &evt) } - events = append(events, evt) } return events, nil } diff --git a/gen/main.go b/gen/main.go index 52c88eb22..d4c603ee1 100644 --- a/gen/main.go +++ b/gen/main.go @@ -11,7 +11,6 @@ import ( "github.com/filecoin-project/lotus/chain/exchange" "github.com/filecoin-project/lotus/chain/market" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/chain/types/legacy" "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/cmd/lotus-shed/shedgen" "github.com/filecoin-project/lotus/node/hello" @@ -38,15 +37,8 @@ func main() { types.StateInfo0{}, types.Event{}, types.EventEntry{}, - ) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - err = gen.WriteTupleEncodersToFile("./chain/types/legacy/cbor_gen.go", "legacy", - legacy.Event{}, - legacy.EventEntry{}, + types.LegacyEvent{}, + types.LegacyEventEntry{}, ) if err != nil { fmt.Println(err) diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 17eee1cfc..0b23477f8 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -34,7 +34,6 @@ import ( "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/chain/types/legacy" "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/lib/oldpath" "github.com/filecoin-project/lotus/lib/oldpath/oldresolver" @@ -685,7 +684,7 @@ func (a *ChainAPI) ChainGetEvents(ctx context.Context, root cid.Cid) ([]types.Ev r := bytes.NewReader(deferred.Raw) if isLegacy { - var evt legacy.Event + var evt types.LegacyEvent if err := evt.UnmarshalCBOR(r); err != nil { return err } @@ -724,7 +723,25 @@ func isLegacyEvents(ctx context.Context, root *amt4.Root) (bool, error) { return false, xerrors.Errorf("failed to peek into events AMT: %w", err) } - switch h, len, err := cbg.CborReadHeader(bytes.NewReader(obj.Raw)); { + r := cbg.NewCborReader(bytes.NewReader(obj.Raw)) + + // StampedEvent. + if typ, len, err := r.ReadHeader(); err != nil || typ != cbg.MajArray || len != 2 { + return false, xerrors.Errorf("expected cbor list with length 2 (stamped event); type: %d, size: %d, err: %w", typ, len, err) + } + + // ActorID + if typ, _, err := r.ReadHeader(); err != nil || typ != cbg.MajUnsignedInt { + return false, xerrors.Errorf("expected cbor unsigned int (actor id); err: %w", err) + } + + // Entries + if typ, len, err := r.ReadHeader(); err != nil || typ != cbg.MajArray || len == 0 { + return false, xerrors.Errorf("expected non-empty cbor list (entries); type: %d, size: %d, err: %w", typ, len, err) + } + + // First entry, finally + switch h, len, err := r.ReadHeader(); { case err != nil: return false, err case h != cbg.MajArray: @@ -734,6 +751,6 @@ func isLegacyEvents(ctx context.Context, root *amt4.Root) (bool, error) { case len == 4: return false, nil default: - return false, xerrors.Errorf("unexpected event tuple length: %d", h) + return false, xerrors.Errorf("unexpected event tuple length: %d", len) } }