From 1449744c487727093f021d73130007dbc8e002e9 Mon Sep 17 00:00:00 2001 From: zenground0 Date: Sun, 14 Sep 2025 23:40:22 -0600 Subject: [PATCH 1/2] Rough draft DDO notifications --- cmd/boostd/import_direct_data.go | 33 +++++++++ db/directdeals.go | 1 + db/fielddef/fielddef.go | 33 +++++++++ .../20230816133342_direct_deals_db.sql | 1 + storagemarket/direct_deals_provider.go | 3 +- storagemarket/types/direct_deal.go | 4 ++ storagemarket/types/types.go | 2 + storagemarket/types/types_cbor_gen.go | 68 ++++++++++++++++++- 8 files changed, 143 insertions(+), 2 deletions(-) diff --git a/cmd/boostd/import_direct_data.go b/cmd/boostd/import_direct_data.go index 05b33f1f9..77215af13 100644 --- a/cmd/boostd/import_direct_data.go +++ b/cmd/boostd/import_direct_data.go @@ -1,15 +1,18 @@ package main import ( + "encoding/hex" "fmt" "os" "path/filepath" + "strings" bcli "github.com/filecoin-project/boost/cli" "github.com/filecoin-project/boost/storagemarket/types" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/builtin/v13/miner" "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" lcli "github.com/filecoin-project/lotus/cli" "github.com/google/uuid" @@ -52,6 +55,10 @@ var importDirectDataCmd = &cli.Command{ Name: "start-epoch", Usage: "start epoch by when the deal should be proved by provider on-chain (default: 2 days from now)", }, + &cli.StringSliceFlag{ + Name: "notify", + Usage: "DDO notifications in format 'address:payload", + }, }, Action: func(cctx *cli.Context) error { if cctx.Args().Len() < 2 { @@ -127,6 +134,31 @@ var importDirectDataCmd = &cli.Command{ // Since StartEpoch is more than Head+StartEpochSealingBuffer, we can set end epoch as start+TermMin endEpoch := startEpoch + alloc.TermMin + var notifications []miner.DataActivationNotification + for _, notifyStr := range cctx.StringSlice("notify") { + parts := strings.SplitN(notifyStr, ":", 2) + if len(parts) != 2 { + return fmt.Errorf("invalid notify format '%s': expected 'address:payload'", notifyStr) + } + + // Parse address + addr, err := address.NewFromString(parts[0]) + if err != nil { + return fmt.Errorf("invalid address in notify '%s': %w", parts[0], err) + } + + // Parse payload (hex string) + payload, err := hex.DecodeString(strings.TrimPrefix(parts[1], "0x")) + if err != nil { + return fmt.Errorf("invalid hex payload in notify '%s': %w", parts[1], err) + } + + notifications = append(notifications, miner.DataActivationNotification{ + Address: addr, + Payload: payload, + }) + } + ddParams := types.DirectDealParams{ DealUUID: uuid.New(), AllocationID: verifreg.AllocationId(allocationId), @@ -138,6 +170,7 @@ var importDirectDataCmd = &cli.Command{ DeleteAfterImport: cctx.Bool("delete-after-import"), RemoveUnsealedCopy: cctx.Bool("remove-unsealed-copy"), SkipIPNIAnnounce: cctx.Bool("skip-ipni-announce"), + Notifications: notifications, } rej, err := napi.BoostDirectDeal(cctx.Context, ddParams) if err != nil { diff --git a/db/directdeals.go b/db/directdeals.go index 9e1ef0653..2d9ac87a7 100644 --- a/db/directdeals.go +++ b/db/directdeals.go @@ -66,6 +66,7 @@ func newDirectDealsAccessor(db *sql.DB, deal *types.DirectDeal) *directDealsAcce "Retry": &fielddef.FieldDef{F: &deal.Retry}, "KeepUnsealedCopy": &fielddef.FieldDef{F: &deal.KeepUnsealedCopy}, "AnnounceToIPNI": &fielddef.FieldDef{F: &deal.AnnounceToIPNI}, + "Notifications": &fielddef.DDONotificationsFieldDef{F: deal.Notifications}, }, } } diff --git a/db/fielddef/fielddef.go b/db/fielddef/fielddef.go index 39e2d34cd..341d9b545 100644 --- a/db/fielddef/fielddef.go +++ b/db/fielddef/fielddef.go @@ -1,6 +1,7 @@ package fielddef import ( + "bytes" "database/sql" "encoding/hex" "fmt" @@ -9,6 +10,7 @@ import ( "github.com/filecoin-project/go-address" cborutil "github.com/filecoin-project/go-cbor-util" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/builtin/v14/miner" "github.com/filecoin-project/go-state-types/builtin/v9/market" "github.com/filecoin-project/go-state-types/crypto" "github.com/ipfs/go-cid" @@ -356,3 +358,34 @@ func (fd *SignedPropFieldDef) Unmarshall() error { *fd.F = c return nil } + +type DDONotificationsFieldDef struct { + Marshalled string + F []miner.DataActivationNotification +} + +func (fd *DDONotificationsFieldDef) FieldPtr() interface{} { + return &fd.Marshalled +} + +func (fd *DDONotificationsFieldDef) Marshall() (interface{}, error) { + b, err := cborutil.Dump(fd.F) + if err != nil { + return nil, fmt.Errorf("failed to cbor dump DataActivationNotification: %w", err) + } + hexStr := fmt.Sprintf("%x", b) + return hexStr, nil +} + +func (fd *DDONotificationsFieldDef) Unmarshall() error { + b, err := hex.DecodeString(fd.Marshalled) + if err != nil { + return fmt.Errorf("failed to decode hex string for DataActivationNotification: %w", err) + } + var out []miner.DataActivationNotification + if err := cborutil.ReadCborRPC(bytes.NewReader(b), &out); err != nil { + return fmt.Errorf("failed to cbor unmarshal DataActivationNotification: %w", err) + } + fd.F = out + return nil +} diff --git a/db/migrations/20230816133342_direct_deals_db.sql b/db/migrations/20230816133342_direct_deals_db.sql index ef405385e..ff1e85d9a 100644 --- a/db/migrations/20230816133342_direct_deals_db.sql +++ b/db/migrations/20230816133342_direct_deals_db.sql @@ -22,6 +22,7 @@ CREATE TABLE IF NOT EXISTS DirectDeals ( Retry TEXT, AnnounceToIPNI BOOL, KeepUnsealedCopy BOOL, + Notifications TEXT, PRIMARY KEY(ID) ); -- +goose StatementEnd diff --git a/storagemarket/direct_deals_provider.go b/storagemarket/direct_deals_provider.go index a7334b132..f58af4daf 100644 --- a/storagemarket/direct_deals_provider.go +++ b/storagemarket/direct_deals_provider.go @@ -216,6 +216,7 @@ func (ddp *DirectDealsProvider) Import(ctx context.Context, params types.DirectD AllocationID: params.AllocationID, KeepUnsealedCopy: !params.RemoveUnsealedCopy, AnnounceToIPNI: !params.SkipIPNIAnnounce, + Notifications: params.Notifications, Retry: types.DealRetryAuto, } @@ -424,7 +425,7 @@ func (ddp *DirectDealsProvider) execDeal(ctx context.Context, entry *types.Direc Client: abi.ActorID(clientId), ID: verifreg13types.AllocationId(entry.AllocationID), }, - Notify: nil, + Notify: entry.Notifications, }, // Best-effort deal asks diff --git a/storagemarket/types/direct_deal.go b/storagemarket/types/direct_deal.go index c8ec869e0..4dbd66e44 100644 --- a/storagemarket/types/direct_deal.go +++ b/storagemarket/types/direct_deal.go @@ -7,6 +7,7 @@ import ( "github.com/filecoin-project/boost/storagemarket/types/dealcheckpoints" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/builtin/v13/miner" verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" "github.com/google/uuid" "github.com/ipfs/go-cid" @@ -57,6 +58,9 @@ type DirectDeal struct { //Announce deal to the IPNI(Index Provider) AnnounceToIPNI bool + + // Notify actors with payload info upon prove commit + Notifications []miner.DataActivationNotification } func (d *DirectDeal) String() string { diff --git a/storagemarket/types/types.go b/storagemarket/types/types.go index 6ecf85aa0..da86730ed 100644 --- a/storagemarket/types/types.go +++ b/storagemarket/types/types.go @@ -12,6 +12,7 @@ import ( "github.com/filecoin-project/boost/transport/types" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/builtin/v13/miner" "github.com/filecoin-project/go-state-types/builtin/v9/market" "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" "github.com/filecoin-project/go-state-types/crypto" @@ -98,6 +99,7 @@ type DirectDealParams struct { DeleteAfterImport bool RemoveUnsealedCopy bool SkipIPNIAnnounce bool + Notifications []miner.DataActivationNotification } // Transfer has the parameters for a data transfer diff --git a/storagemarket/types/types_cbor_gen.go b/storagemarket/types/types_cbor_gen.go index 79072d685..415e3abb1 100644 --- a/storagemarket/types/types_cbor_gen.go +++ b/storagemarket/types/types_cbor_gen.go @@ -9,6 +9,7 @@ import ( "sort" abi "github.com/filecoin-project/go-state-types/abi" + miner "github.com/filecoin-project/go-state-types/builtin/v13/miner" verifreg "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" cid "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -756,7 +757,7 @@ func (t *DirectDealParams) MarshalCBOR(w io.Writer) error { cw := cbg.NewCborWriter(w) - if _, err := cw.Write([]byte{170}); err != nil { + if _, err := cw.Write([]byte{171}); err != nil { return err } @@ -899,6 +900,32 @@ func (t *DirectDealParams) MarshalCBOR(w io.Writer) error { return err } + // t.Notifications ([]miner.DataActivationNotification) (slice) + if len("Notifications") > 8192 { + return xerrors.Errorf("Value in field \"Notifications\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("Notifications"))); err != nil { + return err + } + if _, err := cw.WriteString(string("Notifications")); err != nil { + return err + } + + if len(t.Notifications) > 8192 { + return xerrors.Errorf("Slice value in field t.Notifications was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Notifications))); err != nil { + return err + } + for _, v := range t.Notifications { + if err := v.MarshalCBOR(cw); err != nil { + return err + } + + } + // t.SkipIPNIAnnounce (bool) (bool) if len("SkipIPNIAnnounce") > 8192 { return xerrors.Errorf("Value in field \"SkipIPNIAnnounce\" was too long") @@ -1113,6 +1140,45 @@ func (t *DirectDealParams) UnmarshalCBOR(r io.Reader) (err error) { t.AllocationID = verifreg.AllocationId(extra) } + // t.Notifications ([]miner.DataActivationNotification) (slice) + case "Notifications": + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + + if extra > 8192 { + return fmt.Errorf("t.Notifications: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Notifications = make([]miner.DataActivationNotification, extra) + } + + for i := 0; i < int(extra); i++ { + { + var maj byte + var extra uint64 + var err error + _ = maj + _ = extra + _ = err + + { + + if err := t.Notifications[i].UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Notifications[i]: %w", err) + } + + } + + } + } // t.SkipIPNIAnnounce (bool) (bool) case "SkipIPNIAnnounce": From 131e5072974ff2148037a92592b4abb3abbfc8f6 Mon Sep 17 00:00:00 2001 From: zenground0 Date: Mon, 15 Sep 2025 00:01:16 -0600 Subject: [PATCH 2/2] Fix types --- db/fielddef/fielddef.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/fielddef/fielddef.go b/db/fielddef/fielddef.go index 341d9b545..c8fb1d719 100644 --- a/db/fielddef/fielddef.go +++ b/db/fielddef/fielddef.go @@ -10,7 +10,7 @@ import ( "github.com/filecoin-project/go-address" cborutil "github.com/filecoin-project/go-cbor-util" "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/go-state-types/builtin/v14/miner" + "github.com/filecoin-project/go-state-types/builtin/v13/miner" "github.com/filecoin-project/go-state-types/builtin/v9/market" "github.com/filecoin-project/go-state-types/crypto" "github.com/ipfs/go-cid"