Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions chain/actors/builtin/cbor_marshal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package builtin_test

import (
"fmt"
"reflect"
"testing"

"github.com/stretchr/testify/require"
cbg "github.com/whyrusleeping/cbor-gen"

actorstypes "github.com/filecoin-project/go-state-types/actors"

"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/vm"
)

// TestAllActorTypesCBORMarshaling checks that all types in the actor registry
// implement the CBORMarshaler and CBORUnmarshaler interfaces
func TestAllActorTypesCBORMarshaling(t *testing.T) {
allTypesMissingCBOR := []string{}

for _, v := range actors.Versions {
if v < 8 { // Skip versions before 8, as they's not referenced in the registry
continue
}
av := actorstypes.Version(v)

t.Logf("\n=== Checking Actor Version %d ===", av)

// Create an ActorRegistry like the VM does
ar := vm.NewActorRegistry()

// Register actors
vmActors := builtin.MakeRegistry(av)
ar.Register(av, nil, vmActors)

// Get actor code IDs for naming
codeIDs, err := actors.GetActorCodeIDs(av)
require.NoError(t, err, "Failed to get code IDs for version %d", av)

// Create reverse mapping from code ID to actor name
codeToName := make(map[string]string)
for name, codeID := range codeIDs {
codeToName[codeID.String()] = name
}

// Track statistics for this version
totalChecked := 0
typesMissingCBOR := []string{}

// Check each actor's methods
for codeID, methods := range ar.Methods {
actorName := codeToName[codeID.String()]
if actorName == "" {
actorName = fmt.Sprintf("Unknown(%s)", codeID)
}

for methodNum, methodMeta := range methods {
// Check params type
if methodMeta.Params != nil && methodMeta.Params.Kind() != reflect.Invalid {
totalChecked++
if !implementsCBORInterfaces(methodMeta.Params) {
msg := fmt.Sprintf("v%d %s Method %d (%s) - Params type %s",
av, actorName, methodNum, methodMeta.Name, methodMeta.Params)
typesMissingCBOR = append(typesMissingCBOR, msg)
allTypesMissingCBOR = append(allTypesMissingCBOR, msg)
}
}

// Check return type
if methodMeta.Ret != nil && methodMeta.Ret.Kind() != reflect.Invalid {
totalChecked++
if !implementsCBORInterfaces(methodMeta.Ret) {
msg := fmt.Sprintf("v%d %s Method %d (%s) - Return type %s",
av, actorName, methodNum, methodMeta.Name, methodMeta.Ret)
typesMissingCBOR = append(typesMissingCBOR, msg)
allTypesMissingCBOR = append(allTypesMissingCBOR, msg)
}
}
}
}

// Also check state types from the registry
for _, entry := range vmActors {
codeStr := entry.Code().String()
actorName := codeToName[codeStr]
if actorName == "" {
actorName = fmt.Sprintf("Unknown(%s)", entry.Code())
}

if entry.State() != nil {
totalChecked++
stateType := reflect.TypeOf(entry.State())
if !implementsCBORInterfaces(stateType) {
msg := fmt.Sprintf("v%d %s - State type %s",
av, actorName, stateType)
typesMissingCBOR = append(typesMissingCBOR, msg)
allTypesMissingCBOR = append(allTypesMissingCBOR, msg)
}
}
}

t.Logf("Version %d: Checked %d types, %d missing CBOR marshaling",
av, totalChecked, len(typesMissingCBOR))

if len(typesMissingCBOR) > 0 {
t.Logf("Types missing CBOR in v%d:", av)
for _, typeInfo := range typesMissingCBOR {
t.Logf(" ❌ %s", typeInfo)
}
}
}

t.Logf("\n=== FINAL SUMMARY ===")
t.Logf("Total types missing CBOR marshaling across all versions: %d", len(allTypesMissingCBOR))

if len(allTypesMissingCBOR) > 0 {
// Print unique types for easier analysis
uniqueTypes := make(map[string]bool)
for _, msg := range allTypesMissingCBOR {
uniqueTypes[msg] = true
}

t.Logf("\nUnique types missing CBOR marshaling:")
for typeInfo := range uniqueTypes {
t.Logf(" - %s", typeInfo)
}

// This test is expected to fail currently
require.Failf(t, "CBOR marshaling missing", "Found %d types that do not implement CBORMarshaler/CBORUnmarshaler interfaces", len(uniqueTypes))
}
}

// implementsCBORInterfaces checks if a reflect.Type implements both CBORMarshaler and CBORUnmarshaler
func implementsCBORInterfaces(t reflect.Type) bool {
if t == nil || t.Kind() == reflect.Invalid {
return true // nil/invalid is considered "implementing" for our purposes
}

// Get interface types
marshalerType := reflect.TypeOf((*cbg.CBORMarshaler)(nil)).Elem()
unmarshalerType := reflect.TypeOf((*cbg.CBORUnmarshaler)(nil)).Elem()

// For interface types, we can't check implementation
if t.Kind() == reflect.Interface {
return true // assume interfaces are OK
}

// Check if either the type or pointer to type implements both interfaces
implementsAsValue := t.Implements(marshalerType) && t.Implements(unmarshalerType)

// For non-pointer types, also check if pointer to type implements
if t.Kind() != reflect.Ptr && t.Kind() != reflect.Interface {
ptrType := reflect.PointerTo(t)
implementsAsPointer := ptrType.Implements(marshalerType) && ptrType.Implements(unmarshalerType)
return implementsAsValue || implementsAsPointer
}

return implementsAsValue
}
39 changes: 20 additions & 19 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ require (
github.com/filecoin-project/go-jsonrpc v0.7.0
github.com/filecoin-project/go-padreader v0.0.1
github.com/filecoin-project/go-paramfetch v0.0.4
github.com/filecoin-project/go-state-types v0.17.0-dev2 // dependency-check-ignore: unknown
github.com/filecoin-project/go-state-types v0.17.0-dev2.0.20250704112250-b7cbcb227e0b // dependency-check-ignore: unknown
github.com/filecoin-project/go-statemachine v1.0.3
github.com/filecoin-project/go-statestore v0.2.0
github.com/filecoin-project/go-storedcounter v0.1.0
Expand Down Expand Up @@ -85,21 +85,21 @@ require (
github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab
github.com/invopop/jsonschema v0.12.0
github.com/ipfs/bbloom v0.0.4
github.com/ipfs/boxo v0.20.0
github.com/ipfs/go-block-format v0.2.0
github.com/ipfs/boxo v0.32.0
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ugh!

github.com/ipfs/go-block-format v0.2.2
github.com/ipfs/go-cid v0.5.0
github.com/ipfs/go-datastore v0.8.2
github.com/ipfs/go-ds-badger2 v0.1.5
github.com/ipfs/go-ds-leveldb v0.5.0
github.com/ipfs/go-ds-measure v0.2.0
github.com/ipfs/go-fs-lock v0.0.7
github.com/ipfs/go-ipld-cbor v0.2.0
github.com/ipfs/go-ipld-format v0.6.0
github.com/ipfs/go-ipld-cbor v0.2.1
github.com/ipfs/go-ipld-format v0.6.2
github.com/ipfs/go-log/v2 v2.6.0
github.com/ipfs/go-metrics-interface v0.0.1
github.com/ipfs/go-metrics-interface v0.3.0
github.com/ipfs/go-metrics-prometheus v0.0.2
github.com/ipld/go-car v0.6.2
github.com/ipld/go-car/v2 v2.13.1
github.com/ipld/go-car/v2 v2.14.3
github.com/ipld/go-ipld-prime v0.21.0
github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438
github.com/jpillora/backoff v1.0.0
Expand All @@ -108,10 +108,10 @@ require (
github.com/koalacxr/quantile v0.0.1
github.com/libp2p/go-buffer-pool v0.1.0
github.com/libp2p/go-libp2p v0.42.0
github.com/libp2p/go-libp2p-kad-dht v0.25.2
github.com/libp2p/go-libp2p-kad-dht v0.33.1
github.com/libp2p/go-libp2p-pubsub v0.13.0
github.com/libp2p/go-libp2p-record v0.2.0
github.com/libp2p/go-libp2p-routing-helpers v0.7.3
github.com/libp2p/go-libp2p-record v0.3.1
github.com/libp2p/go-libp2p-routing-helpers v0.7.5
github.com/libp2p/go-maddr-filter v0.1.0
github.com/libp2p/go-msgio v0.3.0
github.com/manifoldco/promptui v0.9.0
Expand All @@ -130,7 +130,7 @@ require (
github.com/puzpuzpuz/xsync/v2 v2.4.0
github.com/raulk/clock v1.1.0
github.com/raulk/go-watchdog v1.3.0
github.com/samber/lo v1.39.0
github.com/samber/lo v1.47.0
github.com/sirupsen/logrus v1.9.2
github.com/stretchr/testify v1.10.0
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // dependency-check-ignore: unknown
Expand All @@ -145,11 +145,11 @@ require (
github.com/zondax/ledger-filecoin-go v1.0.1
github.com/zyedidia/generic v1.2.1
go.opencensus.io v0.24.0
go.opentelemetry.io/otel v1.34.0
go.opentelemetry.io/otel v1.35.0
go.opentelemetry.io/otel/bridge/opencensus v1.28.0
go.opentelemetry.io/otel/exporters/jaeger v1.14.0
go.opentelemetry.io/otel/exporters/prometheus v0.50.0
go.opentelemetry.io/otel/metric v1.34.0
go.opentelemetry.io/otel/metric v1.35.0
go.opentelemetry.io/otel/sdk v1.34.0
go.opentelemetry.io/otel/sdk/metric v1.32.0
go.uber.org/fx v1.24.0
Expand Down Expand Up @@ -240,16 +240,15 @@ require (
github.com/ipfs/go-ipld-legacy v0.2.1 // indirect
github.com/ipfs/go-log v1.0.5 // indirect
github.com/ipfs/go-merkledag v0.11.0 // indirect
github.com/ipfs/go-peertaskqueue v0.8.1 // indirect
github.com/ipfs/go-peertaskqueue v0.8.2 // indirect
github.com/ipfs/go-verifcid v0.0.3 // indirect
github.com/ipld/go-codec-dagpb v1.6.0 // indirect
github.com/ipld/go-codec-dagpb v1.7.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
github.com/jackc/pgx/v5 v5.6.0 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/jbenet/goprocess v0.1.4 // indirect
github.com/jessevdk/go-flags v1.4.0 // indirect
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect
github.com/josharian/intern v1.0.0 // indirect
Expand All @@ -259,7 +258,7 @@ require (
github.com/libp2p/go-cidranger v1.1.0 // indirect
github.com/libp2p/go-flow-metrics v0.2.0 // indirect
github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect
github.com/libp2p/go-libp2p-kbucket v0.6.3 // indirect
github.com/libp2p/go-libp2p-kbucket v0.7.0 // indirect
github.com/libp2p/go-netroute v0.2.2 // indirect
github.com/libp2p/go-reuseport v0.4.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
Expand Down Expand Up @@ -332,14 +331,14 @@ require (
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect
go.dedis.ch/fixbuf v1.0.3 // indirect
go.dedis.ch/kyber/v4 v4.0.0-pre2.0.20240924132404-4de33740016e // indirect; dependency-check-ignore: unknown
go.opentelemetry.io/otel/trace v1.34.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/dig v1.19.0 // indirect
go.uber.org/mock v0.5.2 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 // indirect
golang.org/x/text v0.26.0 // indirect
gonum.org/v1/gonum v0.15.0 // indirect
gonum.org/v1/gonum v0.16.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b // indirect
google.golang.org/grpc v1.70.0 // indirect
Expand All @@ -353,6 +352,8 @@ require (
)

require (
github.com/gammazero/chanqueue v1.1.0 // indirect
github.com/gammazero/deque v1.0.0 // indirect
github.com/libp2p/go-yamux/v5 v5.0.1 // indirect
github.com/pion/dtls/v3 v3.0.6 // indirect
github.com/pion/ice/v4 v4.0.10 // indirect
Expand Down
Loading
Loading