Skip to content

Commit 0edb14c

Browse files
beck-8rjan90tediou5
authored
feat(spcli): correctly handle the batch logic of lotus-miner actor settle-deal (#13189)
* feat(spcli): correctly handle the batch logic of `lotus-miner actor settle-deal` * retain StateWaitMsg logic * use v0api.WrapperV1Full * opt(spcli): push settle-deals Chucks with MpoolBatchPushMessage * chore(spcli): combine logs to prevent interleaving caused by concurrency * fix typo * chore: remove unnecessary var --------- Co-authored-by: Phi-rjan <[email protected]> Co-authored-by: qians <[email protected]>
1 parent 60a3695 commit 0edb14c

File tree

5 files changed

+122
-51
lines changed

5 files changed

+122
-51
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
- fix(cli): use F3GetPowerTableByInstance to resolve F3 power tables by default, `--by-tipset` flag can be used to restore old behavior ([filecoin-project/lotus#13201](https://github.com/filecoin-project/lotus/pull/13201))
4040
- fix(cli): correctly construct the TerminateSectors params ([filecoin-project/lotus#13207](https://github.com/filecoin-project/lotus/pull/13207))
4141
- feat(net): add LOTUS_ENABLE_MESSAGE_FETCH_INSTRUMENTATION=1 to turn on metrics and debugging for local vs bitswap message fetching during block validation ([filecoin-project/lotus#13221](https://github.com/filecoin-project/lotus/pull/13221))
42+
- feat(spcli): correctly handle the batch logic of `lotus-miner actor settle-deal`; replace the dealid data source ([filecoin-project/lotus#13189](https://github.com/filecoin-project/lotus/pull/13189))
4243

4344
# Node v1.33.0 / 2025-05-08
4445
The Lotus v1.33.0 release introduces experimental v2 APIs with F3 awareness, featuring a new TipSet selection mechanism that significantly enhances how applications interact with the Filecoin blockchain. This release candidate also adds F3-aware Ethereum APIs via the /v2 endpoint. All of the /v2 APIs implement intelligent fallback mechanisms between F3 and Expected Consensus and are exposed through the Lotus Gateway.
@@ -660,4 +661,4 @@ For the set of changes since the last stable release:
660661
| DemoYeti | 1 | +2/-1 | 1 |
661662
| qwdsds | 1 | +1/-1 | 1 |
662663
| Samuel Arogbonlo | 1 | +2/-0 | 2 |
663-
| Elias Rad | 1 | +1/-1 | 1 |
664+
| Elias Rad | 1 | +1/-1 | 1 |

cli/miner/actor.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ var actorCmd = &cli.Command{
2323
Usage: "manipulate the miner actor",
2424
Subcommands: []*cli.Command{
2525
spcli.ActorSetAddrsCmd(LMActorGetter),
26-
spcli.ActorDealSettlementCmd(LMActorGetter),
26+
spcli.ActorDealSettlementCmd(LMActorOrEnvGetter),
2727
spcli.ActorWithdrawCmd(LMActorGetter),
2828
spcli.ActorRepayDebtCmd(LMActorGetter),
2929
spcli.ActorSetPeeridCmd(LMActorGetter),

cli/spcli/actor.go

Lines changed: 112 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@ package spcli
33
import (
44
"bytes"
55
"fmt"
6+
"sort"
67
"strconv"
78
"strings"
89

910
"github.com/docker/go-units"
1011
cbor "github.com/ipfs/go-ipld-cbor"
1112
"github.com/libp2p/go-libp2p/core/peer"
1213
ma "github.com/multiformats/go-multiaddr"
14+
"github.com/samber/lo"
1315
"github.com/urfave/cli/v2"
16+
"golang.org/x/sync/errgroup"
1417
"golang.org/x/xerrors"
1518

1619
"github.com/filecoin-project/go-address"
@@ -24,6 +27,7 @@ import (
2427
"github.com/filecoin-project/go-state-types/network"
2528

2629
lapi "github.com/filecoin-project/lotus/api"
30+
"github.com/filecoin-project/lotus/api/v0api"
2731
"github.com/filecoin-project/lotus/blockstore"
2832
"github.com/filecoin-project/lotus/build/buildconstants"
2933
"github.com/filecoin-project/lotus/chain/actors"
@@ -48,6 +52,23 @@ func ActorDealSettlementCmd(getActor ActorAddressGetter) *cli.Command {
4852
Usage: "number of block confirmations to wait for",
4953
Value: int(buildconstants.MessageConfidence),
5054
},
55+
&cli.StringFlag{
56+
Name: "from",
57+
Usage: "specify where to send the message from (any address)",
58+
},
59+
&cli.IntFlag{
60+
Name: "max-deals",
61+
Usage: "the maximum number of deals contained in each message",
62+
Value: 50,
63+
},
64+
&cli.BoolFlag{
65+
Name: "skip-wait-msg",
66+
Usage: "skip to check the message status",
67+
},
68+
&cli.BoolFlag{
69+
Name: "really-do-it",
70+
Usage: "Actually send transaction performing the action",
71+
},
5172
},
5273

5374
Action: func(cctx *cli.Context) error {
@@ -63,6 +84,19 @@ func ActorDealSettlementCmd(getActor ActorAddressGetter) *cli.Command {
6384
return err
6485
}
6586

87+
mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
88+
if err != nil {
89+
return xerrors.Errorf("Error getting miner info: %w", err)
90+
}
91+
92+
fromAddr := mi.Worker
93+
if addr := cctx.String("from"); addr != "" {
94+
fromAddr, err = address.NewFromString(addr)
95+
if err != nil {
96+
return err
97+
}
98+
}
99+
66100
var (
67101
dealIDs []uint64
68102
dealId uint64
@@ -107,69 +141,101 @@ func ActorDealSettlementCmd(getActor ActorAddressGetter) *cli.Command {
107141
}
108142
}
109143
} else {
110-
if dealIDs, err = GetMinerAllDeals(ctx, api, maddr, types.EmptyTSK); err != nil {
111-
return xerrors.Errorf("Error getting all deals for miner: %w", err)
144+
sectors, err := api.StateMinerSectors(ctx, maddr, nil, types.EmptyTSK)
145+
if err != nil {
146+
return xerrors.Errorf("Error getting StateMinerSectors for miner: %w", err)
147+
}
148+
wapi := &v0api.WrapperV1Full{FullNode: api}
149+
for _, sector := range sectors {
150+
data, err := lcli.GetMarketDealIDs(ctx, wapi, maddr, sector.SectorNumber, types.EmptyTSK)
151+
if err != nil {
152+
return xerrors.Errorf("Error getting all deals for miner: %w", err)
153+
}
154+
for _, deal := range data {
155+
dealIDs = append(dealIDs, uint64(deal))
156+
}
112157
}
113158
}
114159

115-
mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
116-
if err != nil {
117-
return xerrors.Errorf("Error getting miner info: %w", err)
160+
fmt.Printf("There are a total of %v deals, and about %v messages will be sent out.\n", len(dealIDs), len(dealIDs)/cctx.Int("max-deals"))
161+
162+
if !cctx.Bool("really-do-it") {
163+
return fmt.Errorf("pass --really-do-it to confirm this action")
118164
}
119165

120-
dealParams := bitfield.NewFromSet(dealIDs)
121-
params, err := actors.SerializeParams(&dealParams)
122-
if err != nil {
123-
return err
166+
sort.Slice(dealIDs, func(i, j int) bool {
167+
return dealIDs[i] < dealIDs[j]
168+
})
169+
dealChucks := lo.Chunk(dealIDs, cctx.Int("max-deals"))
170+
171+
var msgs []*types.Message
172+
for _, deals := range dealChucks {
173+
dealParams := bitfield.NewFromSet(deals)
174+
params, err := actors.SerializeParams(&dealParams)
175+
if err != nil {
176+
return err
177+
}
178+
msg := &types.Message{
179+
To: marketactor.Address,
180+
From: fromAddr,
181+
Value: types.NewInt(0),
182+
Method: marketactor.Methods.SettleDealPaymentsExported,
183+
Params: params,
184+
}
185+
msgs = append(msgs, msg)
124186
}
125187

126-
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
127-
To: marketactor.Address,
128-
From: mi.Owner,
129-
Value: types.NewInt(0),
130-
Method: marketactor.Methods.SettleDealPaymentsExported,
131-
Params: params,
132-
}, nil)
133-
if err != nil {
188+
// MpoolBatchPushMessage method will take care of gas estimation and funds check
189+
smsgs, err := api.MpoolBatchPushMessage(ctx, msgs, nil)
190+
if smsgs == nil && err != nil {
134191
return err
135192
}
136193

137-
res := smsg.Cid()
138-
139-
fmt.Printf("Requested deal settlement in message %s\nwaiting for it to be included in a block..\n", res)
140-
141-
// wait for it to get mined into a block
142-
wait, err := api.StateWaitMsg(ctx, res, uint64(cctx.Int("confidence")), lapi.LookbackNoLimit, true)
143-
if err != nil {
144-
return xerrors.Errorf("Timeout waiting for deal settlement message %s", res)
194+
if cctx.Bool("skip-wait-msg") {
195+
fmt.Printf("skip the check status, please pay attention to the message status on the chain by yourself.\n")
196+
return nil
145197
}
146198

147-
if wait.Receipt.ExitCode.IsError() {
148-
return xerrors.Errorf("Failed to execute withdrawal message %s: %w", wait.Message, wait.Receipt.ExitCode.Error())
149-
}
199+
// wait for msgs to get mined into a block
200+
eg := errgroup.Group{}
201+
eg.SetLimit(10)
202+
for _, smsg := range smsgs {
203+
res := smsg.Cid()
204+
fmt.Printf("Requested deal settlement in message: %s\nwaiting for it to be included in a block..\n", res)
205+
eg.Go(func() error {
206+
// wait for it to get mined into a block
207+
wait, err := api.StateWaitMsg(ctx, res, uint64(cctx.Int("confidence")), lapi.LookbackNoLimit, true)
208+
if err != nil {
209+
return xerrors.Errorf("Timeout waiting for deal settlement message %s", res)
210+
}
150211

151-
var settlementReturn markettypes14.SettleDealPaymentsReturn
152-
if err = settlementReturn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
153-
return err
154-
}
212+
if wait.Receipt.ExitCode.IsError() {
213+
return xerrors.Errorf("Failed to execute withdrawal message %s: %w", wait.Message, wait.Receipt.ExitCode.Error())
214+
}
155215

156-
fmt.Printf("Settled %d out of %d deals\n", settlementReturn.Results.SuccessCount, len(dealIDs))
216+
var settlementReturn markettypes14.SettleDealPaymentsReturn
217+
if err = settlementReturn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
218+
return err
219+
}
157220

158-
var (
159-
totalPayment = big.Zero()
160-
totalCompletedDeals = 0
161-
)
221+
var (
222+
totalPayment = big.Zero()
223+
totalCompletedDeals = 0
224+
)
162225

163-
for _, s := range settlementReturn.Settlements {
164-
totalPayment = big.Add(totalPayment, s.Payment)
165-
if s.Completed {
166-
totalCompletedDeals++
167-
}
168-
}
226+
for _, s := range settlementReturn.Settlements {
227+
totalPayment = big.Add(totalPayment, s.Payment)
228+
if s.Completed {
229+
totalCompletedDeals++
230+
}
231+
}
169232

170-
fmt.Printf("Total payment: %s\n", types.FIL(totalPayment))
171-
fmt.Printf("Total number of deals finished their lifetime: %d\n", totalCompletedDeals)
172-
return nil
233+
fmt.Printf("Message CID: %s\nSettled %d out of %d deals\nTotal payment: %s\nTotal number of deals finished their lifetime: %d\n",
234+
res, settlementReturn.Results.SuccessCount, len(dealIDs), types.FIL(totalPayment), totalCompletedDeals)
235+
return nil
236+
})
237+
}
238+
return eg.Wait()
173239
},
174240
}
175241
}

cli/state.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,7 +1556,7 @@ var StateSectorCmd = &cli.Command{
15561556

15571557
// Deals were moved into market actor's ProviderSectors in NV22 / Actors v13
15581558
if nv >= network.Version22 {
1559-
marketDealIDs, err := getMarketDealIDs(ctx, api, maddr, abi.SectorNumber(sid), ts.Key())
1559+
marketDealIDs, err := GetMarketDealIDs(ctx, api, maddr, abi.SectorNumber(sid), ts.Key())
15601560
if err != nil {
15611561
fmt.Printf("DealIDs (market): error retrieving from market actor: %v\n", err)
15621562
} else if len(marketDealIDs) > 0 {
@@ -1769,8 +1769,8 @@ var StateSysActorCIDsCmd = &cli.Command{
17691769
},
17701770
}
17711771

1772-
// getMarketDealIDs retrieves deal IDs for a sector from the market actor's ProviderSectors HAMT
1773-
func getMarketDealIDs(ctx context.Context, api v0api.FullNode, maddr address.Address, sid abi.SectorNumber, tsKey types.TipSetKey) ([]abi.DealID, error) {
1772+
// GetMarketDealIDs retrieves deal IDs for a sector from the market actor's ProviderSectors HAMT
1773+
func GetMarketDealIDs(ctx context.Context, api v0api.FullNode, maddr address.Address, sid abi.SectorNumber, tsKey types.TipSetKey) ([]abi.DealID, error) {
17741774
// Convert miner address to actor ID
17751775
actorID, err := getMinerActorID(ctx, api, maddr, tsKey)
17761776
if err != nil {

documentation/en/cli-lotus-miner.md

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)