From 0784e5708246f6b25aaab4a3f0d1e0b8577c17ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sami=20M=C3=A4kel=C3=A4?= Date: Thu, 9 Jul 2020 13:36:22 +0300 Subject: [PATCH 001/353] handling verified price here --- api/api_storage.go | 2 +- api/apistruct/struct.go | 6 +++--- cli/client.go | 3 ++- cmd/lotus-storage-miner/market.go | 12 +++++++++--- go.mod | 2 ++ node/impl/storminer.go | 4 ++-- node/modules/storageminer.go | 2 +- 7 files changed, 20 insertions(+), 11 deletions(-) diff --git a/api/api_storage.go b/api/api_storage.go index 6402de2b6..a1558aea8 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -63,7 +63,7 @@ type StorageMiner interface { MarketImportDealData(ctx context.Context, propcid cid.Cid, path string) error MarketListDeals(ctx context.Context) ([]storagemarket.StorageDeal, error) MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, error) - MarketSetAsk(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error + MarketSetAsk(ctx context.Context, price types.BigInt, verifiedPrice types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error MarketGetAsk(ctx context.Context) (*storagemarket.SignedStorageAsk, error) DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index c23c7329a..b074c2f23 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -201,7 +201,7 @@ type StorageMinerStruct struct { MarketImportDealData func(context.Context, cid.Cid, string) error `perm:"write"` MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"` MarketListIncompleteDeals func(ctx context.Context) ([]storagemarket.MinerDeal, error) `perm:"read"` - MarketSetAsk func(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error `perm:"admin"` + MarketSetAsk func(ctx context.Context, price types.BigInt, verifiedPrice types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error `perm:"admin"` MarketGetAsk func(ctx context.Context) (*storagemarket.SignedStorageAsk, error) `perm:"read"` PledgeSector func(context.Context) error `perm:"write"` @@ -900,8 +900,8 @@ func (c *StorageMinerStruct) MarketListIncompleteDeals(ctx context.Context) ([]s return c.Internal.MarketListIncompleteDeals(ctx) } -func (c *StorageMinerStruct) MarketSetAsk(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error { - return c.Internal.MarketSetAsk(ctx, price, duration, minPieceSize, maxPieceSize) +func (c *StorageMinerStruct) MarketSetAsk(ctx context.Context, price types.BigInt, verifiedPrice types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error { + return c.Internal.MarketSetAsk(ctx, price, verifiedPrice, duration, minPieceSize, maxPieceSize) } func (c *StorageMinerStruct) MarketGetAsk(ctx context.Context) (*storagemarket.SignedStorageAsk, error) { diff --git a/cli/client.go b/cli/client.go index 4aaa789ba..a7ffaff69 100644 --- a/cli/client.go +++ b/cli/client.go @@ -631,7 +631,8 @@ var clientQueryAskCmd = &cli.Command{ } fmt.Printf("Ask: %s\n", maddr) - fmt.Printf("Price per GiB: %s\n", types.FIL(ask.Ask.Price)) + fmt.Printf("Price per GiB: %s\n", types.FIL(ask.Ask.VerifiedPrice)) + fmt.Printf("Verified Price per GiB: %s\n", types.FIL(ask.Ask.Price)) fmt.Printf("Max Piece size: %s\n", types.SizeStr(types.NewInt(uint64(ask.Ask.MaxPieceSize)))) size := cctx.Int64("size") diff --git a/cmd/lotus-storage-miner/market.go b/cmd/lotus-storage-miner/market.go index 4a82d5162..d4adc55f2 100644 --- a/cmd/lotus-storage-miner/market.go +++ b/cmd/lotus-storage-miner/market.go @@ -156,6 +156,11 @@ var setAskCmd = &cli.Command{ Usage: "Set the price of the ask (specified as FIL / GiB / Epoch) to `PRICE`", Required: true, }, + &cli.Uint64Flag{ + Name: "verified-price", + Usage: "Set the price of the ask (specified as FIL / GiB / Epoch) to `VERIFIED_PRICE`", + Required: true, + }, &cli.StringFlag{ Name: "duration", Usage: "Set duration of ask (a quantity of time after which the ask expires) `DURATION`", @@ -184,6 +189,7 @@ var setAskCmd = &cli.Command{ defer closer() pri := types.NewInt(cctx.Uint64("price")) + verifiedPri := types.NewInt(cctx.Uint64("verified-price")) dur, err := time.ParseDuration(cctx.String("duration")) if err != nil { @@ -226,7 +232,7 @@ var setAskCmd = &cli.Command{ return xerrors.Errorf("max piece size (w/bit-padding) %s cannot exceed miner sector size %s", types.SizeStr(types.NewInt(uint64(max))), types.SizeStr(types.NewInt(uint64(smax)))) } - return api.MarketSetAsk(ctx, pri, abi.ChainEpoch(qty), abi.PaddedPieceSize(min), abi.PaddedPieceSize(max)) + return api.MarketSetAsk(ctx, pri, verifiedPri, abi.ChainEpoch(qty), abi.PaddedPieceSize(min), abi.PaddedPieceSize(max)) }, } @@ -260,7 +266,7 @@ var getAskCmd = &cli.Command{ } w := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0) - fmt.Fprintf(w, "Price per GiB / Epoch\tMin. Piece Size (w/bit-padding)\tMax. Piece Size (w/bit-padding)\tExpiry (Epoch)\tExpiry (Appx. Rem. Time)\tSeq. No.\n") + fmt.Fprintf(w, "Price per GiB / Epoch\tVerified\tMin. Piece Size (w/bit-padding)\tMax. Piece Size (w/bit-padding)\tExpiry (Epoch)\tExpiry (Appx. Rem. Time)\tSeq. No.\n") if ask == nil { fmt.Fprintf(w, "\n") @@ -278,7 +284,7 @@ var getAskCmd = &cli.Command{ rem = (time.Second * time.Duration(int64(dlt)*int64(build.BlockDelaySecs))).String() } - fmt.Fprintf(w, "%s\t%s\t%s\t%d\t%s\t%d\n", ask.Price, types.SizeStr(types.NewInt(uint64(ask.MinPieceSize))), types.SizeStr(types.NewInt(uint64(ask.MaxPieceSize))), ask.Expiry, rem, ask.SeqNo) + fmt.Fprintf(w, "%s\t%s\t%s\t%d\t%s\t%d\n", ask.Price, ask.VerifiedPrice, types.SizeStr(types.NewInt(uint64(ask.MinPieceSize))), types.SizeStr(types.NewInt(uint64(ask.MaxPieceSize))), ask.Expiry, rem, ask.SeqNo) return w.Flush() }, diff --git a/go.mod b/go.mod index 015b99ce7..c6f557f79 100644 --- a/go.mod +++ b/go.mod @@ -128,3 +128,5 @@ require ( replace github.com/golangci/golangci-lint => github.com/golangci/golangci-lint v1.18.0 replace github.com/filecoin-project/filecoin-ffi => ./extern/filecoin-ffi + +replace github.com/filecoin-project/go-fil-markets => /home/sami/go-fil-markets diff --git a/node/impl/storminer.go b/node/impl/storminer.go index 8fcd2d2b0..3f20e6124 100644 --- a/node/impl/storminer.go +++ b/node/impl/storminer.go @@ -233,13 +233,13 @@ func (sm *StorageMinerAPI) MarketListIncompleteDeals(ctx context.Context) ([]sto return sm.StorageProvider.ListLocalDeals() } -func (sm *StorageMinerAPI) MarketSetAsk(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error { +func (sm *StorageMinerAPI) MarketSetAsk(ctx context.Context, price types.BigInt, verifiedPrice types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error { options := []storagemarket.StorageAskOption{ storagemarket.MinPieceSize(minPieceSize), storagemarket.MaxPieceSize(maxPieceSize), } - return sm.StorageProvider.SetAsk(price, duration, options...) + return sm.StorageProvider.SetAsk(price, verifiedPrice, duration, options...) } func (sm *StorageMinerAPI) MarketGetAsk(ctx context.Context) (*storagemarket.SignedStorageAsk, error) { diff --git a/node/modules/storageminer.go b/node/modules/storageminer.go index 4f1fe6e44..cecfbcd0e 100644 --- a/node/modules/storageminer.go +++ b/node/modules/storageminer.go @@ -328,7 +328,7 @@ func NewStorageAsk(ctx helpers.MetricsCtx, fapi lapi.FullNode, ds dtypes.Metadat } // Hacky way to set max piece size to the sector size a := storedAsk.GetAsk().Ask - err = storedAsk.SetAsk(a.Price, a.Expiry-a.Timestamp, storagemarket.MaxPieceSize(abi.PaddedPieceSize(mi.SectorSize))) + err = storedAsk.SetAsk(a.Price, a.VerifiedPrice, a.Expiry-a.Timestamp, storagemarket.MaxPieceSize(abi.PaddedPieceSize(mi.SectorSize))) if err != nil { return storedAsk, err } From bc381fc053527cfc0e005ddb8ccea4c4681bd13b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 10 Aug 2020 14:55:27 +0200 Subject: [PATCH 002/353] stmgr: Allow changing gas values in WaitMsg --- api/api_full.go | 1 + chain/stmgr/stmgr.go | 105 ++++++++++++++++++------------- chain/types/message.go | 11 ++++ chain/types/message_test.go | 72 +++++++++++++++++++++ markets/storageadapter/client.go | 2 +- node/impl/full/state.go | 6 +- 6 files changed, 149 insertions(+), 48 deletions(-) create mode 100644 chain/types/message_test.go diff --git a/api/api_full.go b/api/api_full.go index 1a3850cc6..1c01fee27 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -465,6 +465,7 @@ type DealInfo struct { } type MsgLookup struct { + Message cid.Cid // Can be different than requested, in case it was replaced, but only gas values changed Receipt types.MessageReceipt ReturnDec interface{} TipSet types.TipSetKey diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 566692b38..67ef58800 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -441,7 +441,7 @@ func (sm *StateManager) GetReceipt(ctx context.Context, msg cid.Cid, ts *types.T return nil, fmt.Errorf("failed to load message: %w", err) } - r, err := sm.tipsetExecutedMessage(ts, msg, m.VMMessage()) + r, _, err := sm.tipsetExecutedMessage(ts, msg, m.VMMessage()) if err != nil { return nil, err } @@ -450,7 +450,7 @@ func (sm *StateManager) GetReceipt(ctx context.Context, msg cid.Cid, ts *types.T return r, nil } - _, r, err = sm.searchBackForMsg(ctx, ts, m) + _, r, _, err = sm.searchBackForMsg(ctx, ts, m) if err != nil { return nil, fmt.Errorf("failed to look back through chain for message: %w", err) } @@ -461,44 +461,45 @@ func (sm *StateManager) GetReceipt(ctx context.Context, msg cid.Cid, ts *types.T // WaitForMessage blocks until a message appears on chain. It looks backwards in the chain to see if this has already // happened. It guarantees that the message has been on chain for at least confidence epochs without being reverted // before returning. -func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confidence uint64) (*types.TipSet, *types.MessageReceipt, error) { +func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confidence uint64) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) { ctx, cancel := context.WithCancel(ctx) defer cancel() msg, err := sm.cs.GetCMessage(mcid) if err != nil { - return nil, nil, fmt.Errorf("failed to load message: %w", err) + return nil, nil, cid.Undef, fmt.Errorf("failed to load message: %w", err) } tsub := sm.cs.SubHeadChanges(ctx) head, ok := <-tsub if !ok { - return nil, nil, fmt.Errorf("SubHeadChanges stream was invalid") + return nil, nil, cid.Undef, fmt.Errorf("SubHeadChanges stream was invalid") } if len(head) != 1 { - return nil, nil, fmt.Errorf("SubHeadChanges first entry should have been one item") + return nil, nil, cid.Undef, fmt.Errorf("SubHeadChanges first entry should have been one item") } if head[0].Type != store.HCCurrent { - return nil, nil, fmt.Errorf("expected current head on SHC stream (got %s)", head[0].Type) + return nil, nil, cid.Undef, fmt.Errorf("expected current head on SHC stream (got %s)", head[0].Type) } - r, err := sm.tipsetExecutedMessage(head[0].Val, mcid, msg.VMMessage()) + r, foundMsg, err := sm.tipsetExecutedMessage(head[0].Val, mcid, msg.VMMessage()) if err != nil { - return nil, nil, err + return nil, nil, cid.Undef, err } if r != nil { - return head[0].Val, r, nil + return head[0].Val, r, foundMsg, nil } var backTs *types.TipSet var backRcp *types.MessageReceipt + var backFm cid.Cid backSearchWait := make(chan struct{}) go func() { - fts, r, err := sm.searchBackForMsg(ctx, head[0].Val, msg) + fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head[0].Val, msg) if err != nil { log.Warnf("failed to look back through chain for message: %w", err) return @@ -506,11 +507,13 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confid backTs = fts backRcp = r + backFm = foundMsg close(backSearchWait) }() var candidateTs *types.TipSet var candidateRcp *types.MessageReceipt + var candidateFm cid.Cid heightOfHead := head[0].Val.Height() reverts := map[types.TipSetKey]bool{} @@ -518,7 +521,7 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confid select { case notif, ok := <-tsub: if !ok { - return nil, nil, ctx.Err() + return nil, nil, cid.Undef, ctx.Err() } for _, val := range notif { switch val.Type { @@ -526,24 +529,26 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confid if val.Val.Equals(candidateTs) { candidateTs = nil candidateRcp = nil + candidateFm = cid.Undef } if backSearchWait != nil { reverts[val.Val.Key()] = true } case store.HCApply: if candidateTs != nil && val.Val.Height() >= candidateTs.Height()+abi.ChainEpoch(confidence) { - return candidateTs, candidateRcp, nil + return candidateTs, candidateRcp, candidateFm, nil } - r, err := sm.tipsetExecutedMessage(val.Val, mcid, msg.VMMessage()) + r, foundMsg, err := sm.tipsetExecutedMessage(val.Val, mcid, msg.VMMessage()) if err != nil { - return nil, nil, err + return nil, nil, cid.Undef, err } if r != nil { if confidence == 0 { - return val.Val, r, err + return val.Val, r, foundMsg, err } candidateTs = val.Val candidateRcp = r + candidateFm = foundMsg } heightOfHead = val.Val.Height() } @@ -553,111 +558,112 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confid if backTs != nil && !reverts[backTs.Key()] { // if head is at or past confidence interval, return immediately if heightOfHead >= backTs.Height()+abi.ChainEpoch(confidence) { - return backTs, backRcp, nil + return backTs, backRcp, backFm, nil } // wait for confidence interval candidateTs = backTs candidateRcp = backRcp + candidateFm = backFm } reverts = nil backSearchWait = nil case <-ctx.Done(): - return nil, nil, ctx.Err() + return nil, nil, cid.Undef, ctx.Err() } } } -func (sm *StateManager) SearchForMessage(ctx context.Context, mcid cid.Cid) (*types.TipSet, *types.MessageReceipt, error) { +func (sm *StateManager) SearchForMessage(ctx context.Context, mcid cid.Cid) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) { msg, err := sm.cs.GetCMessage(mcid) if err != nil { - return nil, nil, fmt.Errorf("failed to load message: %w", err) + return nil, nil, cid.Undef, fmt.Errorf("failed to load message: %w", err) } head := sm.cs.GetHeaviestTipSet() - r, err := sm.tipsetExecutedMessage(head, mcid, msg.VMMessage()) + r, foundMsg, err := sm.tipsetExecutedMessage(head, mcid, msg.VMMessage()) if err != nil { - return nil, nil, err + return nil, nil, cid.Undef, err } if r != nil { - return head, r, nil + return head, r, foundMsg, nil } - fts, r, err := sm.searchBackForMsg(ctx, head, msg) + fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head, msg) if err != nil { log.Warnf("failed to look back through chain for message %s", mcid) - return nil, nil, err + return nil, nil, cid.Undef, err } if fts == nil { - return nil, nil, nil + return nil, nil, cid.Undef, nil } - return fts, r, nil + return fts, r, foundMsg, nil } -func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet, m types.ChainMsg) (*types.TipSet, *types.MessageReceipt, error) { +func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet, m types.ChainMsg) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) { cur := from for { if cur.Height() == 0 { // it ain't here! - return nil, nil, nil + return nil, nil, cid.Undef, nil } select { case <-ctx.Done(): - return nil, nil, nil + return nil, nil, cid.Undef, nil default: } var act types.Actor err := sm.WithParentState(cur, sm.WithActor(m.VMMessage().From, GetActor(&act))) if err != nil { - return nil, nil, err + return nil, nil, cid.Undef, err } // we either have no messages from the sender, or the latest message we found has a lower nonce than the one being searched for, // either way, no reason to lookback, it ain't there if act.Nonce == 0 || act.Nonce < m.VMMessage().Nonce { - return nil, nil, nil + return nil, nil, cid.Undef, nil } ts, err := sm.cs.LoadTipSet(cur.Parents()) if err != nil { - return nil, nil, fmt.Errorf("failed to load tipset during msg wait searchback: %w", err) + return nil, nil, cid.Undef, fmt.Errorf("failed to load tipset during msg wait searchback: %w", err) } - r, err := sm.tipsetExecutedMessage(ts, m.Cid(), m.VMMessage()) + r, foundMsg, err := sm.tipsetExecutedMessage(ts, m.Cid(), m.VMMessage()) if err != nil { - return nil, nil, fmt.Errorf("checking for message execution during lookback: %w", err) + return nil, nil, cid.Undef, fmt.Errorf("checking for message execution during lookback: %w", err) } if r != nil { - return ts, r, nil + return ts, r, foundMsg, nil } cur = ts } } -func (sm *StateManager) tipsetExecutedMessage(ts *types.TipSet, msg cid.Cid, vmm *types.Message) (*types.MessageReceipt, error) { +func (sm *StateManager) tipsetExecutedMessage(ts *types.TipSet, msg cid.Cid, vmm *types.Message) (*types.MessageReceipt, cid.Cid, error) { // The genesis block did not execute any messages if ts.Height() == 0 { - return nil, nil + return nil, cid.Undef, nil } pts, err := sm.cs.LoadTipSet(ts.Parents()) if err != nil { - return nil, err + return nil, cid.Undef, err } cm, err := sm.cs.MessagesForTipset(pts) if err != nil { - return nil, err + return nil, cid.Undef, err } for ii := range cm { @@ -667,21 +673,30 @@ func (sm *StateManager) tipsetExecutedMessage(ts *types.TipSet, msg cid.Cid, vmm if m.VMMessage().From == vmm.From { // cheaper to just check origin first if m.VMMessage().Nonce == vmm.Nonce { - if m.Cid() == msg { - return sm.cs.GetParentReceipt(ts.Blocks()[0], i) + if m.VMMessage().EqualCall(vmm) { + if m.Cid() != msg { + log.Warnw("found message with equal nonce and call params but different CID", + "wanted", msg, "found", m.Cid(), "nonce", vmm.Nonce, "from", vmm.From) + } + + pr, err := sm.cs.GetParentReceipt(ts.Blocks()[0], i) + if err != nil { + return nil, cid.Undef, err + } + return pr, m.Cid(), nil } // this should be that message - return nil, xerrors.Errorf("found message with equal nonce as the one we are looking for (F:%s n %d, TS: %s n%d)", + return nil, cid.Undef, xerrors.Errorf("found message with equal nonce as the one we are looking for (F:%s n %d, TS: %s n%d)", msg, vmm.Nonce, m.Cid(), m.VMMessage().Nonce) } if m.VMMessage().Nonce < vmm.Nonce { - return nil, nil // don't bother looking further + return nil, cid.Undef, nil // don't bother looking further } } } - return nil, nil + return nil, cid.Undef, nil } func (sm *StateManager) ListAllActors(ctx context.Context, ts *types.TipSet) ([]address.Address, error) { diff --git a/chain/types/message.go b/chain/types/message.go index eb03edd67..aab3020d5 100644 --- a/chain/types/message.go +++ b/chain/types/message.go @@ -118,6 +118,17 @@ func (m *Message) Equals(o *Message) bool { return m.Cid() == o.Cid() } +func (m *Message) EqualCall(o *Message) bool { + m1 := *m + m2 := *o + + m1.GasLimit, m2.GasLimit = 0, 0 + m1.GasFeeCap, m2.GasFeeCap = big.Zero(), big.Zero() + m1.GasPremium, m2.GasPremium = big.Zero(), big.Zero() + + return (&m1).Equals(&m2) +} + func (m *Message) ValidForBlockInclusion(minGas int64) error { if m.Version != 0 { return xerrors.New("'Version' unsupported") diff --git a/chain/types/message_test.go b/chain/types/message_test.go new file mode 100644 index 000000000..a7b4927e5 --- /dev/null +++ b/chain/types/message_test.go @@ -0,0 +1,72 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin" +) + +func TestEqualCall(t *testing.T) { + m1 := &Message{ + To: builtin.StoragePowerActorAddr, + From: builtin.SystemActorAddr, + Nonce: 34, + Value: big.Zero(), + + GasLimit: 123, + GasFeeCap: big.NewInt(234), + GasPremium: big.NewInt(234), + + Method: 6, + Params: []byte("hai"), + } + + m2 := &Message{ + To: builtin.StoragePowerActorAddr, + From: builtin.SystemActorAddr, + Nonce: 34, + Value: big.Zero(), + + GasLimit: 1236, // changed + GasFeeCap: big.NewInt(234), + GasPremium: big.NewInt(234), + + Method: 6, + Params: []byte("hai"), + } + + m3 := &Message{ + To: builtin.StoragePowerActorAddr, + From: builtin.SystemActorAddr, + Nonce: 34, + Value: big.Zero(), + + GasLimit: 123, + GasFeeCap: big.NewInt(4524), // changed + GasPremium: big.NewInt(234), + + Method: 6, + Params: []byte("hai"), + } + + m4 := &Message{ + To: builtin.StoragePowerActorAddr, + From: builtin.SystemActorAddr, + Nonce: 34, + Value: big.Zero(), + + GasLimit: 123, + GasFeeCap: big.NewInt(4524), + GasPremium: big.NewInt(234), + + Method: 5, // changed + Params: []byte("hai"), + } + + require.True(t, m1.EqualCall(m2)) + require.True(t, m1.EqualCall(m3)) + require.False(t, m1.EqualCall(m4)) +} diff --git a/markets/storageadapter/client.go b/markets/storageadapter/client.go index a97bcf758..74e3f8394 100644 --- a/markets/storageadapter/client.go +++ b/markets/storageadapter/client.go @@ -209,7 +209,7 @@ func (c *ClientNodeAdapter) ValidatePublishedDeal(ctx context.Context, deal stor } // TODO: timeout - _, ret, err := c.sm.WaitForMessage(ctx, *deal.PublishMessage, build.MessageConfidence) + _, ret, _, err := c.sm.WaitForMessage(ctx, *deal.PublishMessage, build.MessageConfidence) if err != nil { return 0, xerrors.Errorf("waiting for deal publish message: %w", err) } diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 5495581f1..73bd4a398 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -426,7 +426,7 @@ func (a *StateAPI) MinerCreateBlock(ctx context.Context, bt *api.BlockTemplate) } func (a *StateAPI) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) { - ts, recpt, err := a.StateManager.WaitForMessage(ctx, msg, confidence) + ts, recpt, found, err := a.StateManager.WaitForMessage(ctx, msg, confidence) if err != nil { return nil, err } @@ -453,6 +453,7 @@ func (a *StateAPI) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uin } return &api.MsgLookup{ + Message: found, Receipt: *recpt, ReturnDec: returndec, TipSet: ts.Key(), @@ -461,13 +462,14 @@ func (a *StateAPI) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uin } func (a *StateAPI) StateSearchMsg(ctx context.Context, msg cid.Cid) (*api.MsgLookup, error) { - ts, recpt, err := a.StateManager.SearchForMessage(ctx, msg) + ts, recpt, found, err := a.StateManager.SearchForMessage(ctx, msg) if err != nil { return nil, err } if ts != nil { return &api.MsgLookup{ + Message: found, Receipt: *recpt, TipSet: ts.Key(), Height: ts.Height(), From c72f853e093316d38e9dfc6e80551fa00afdbe80 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Sat, 8 Aug 2020 20:20:37 -0400 Subject: [PATCH 003/353] Add a test around duplicate nonces --- chain/gen/gen.go | 38 ++++++++---- chain/sync_test.go | 140 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 148 insertions(+), 30 deletions(-) diff --git a/chain/gen/gen.go b/chain/gen/gen.go index d4851a933..4d864c73e 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -272,6 +272,10 @@ func NewGenerator() (*ChainGen, error) { return NewGeneratorWithSectors(1) } +func (cg *ChainGen) StateManager() *stmgr.StateManager { + return cg.sm +} + func (cg *ChainGen) SetStateManager(sm *stmgr.StateManager) { cg.sm = sm } @@ -383,15 +387,32 @@ func (cg *ChainGen) SetWinningPoStProver(m address.Address, wpp WinningPoStProve } func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Address) (*MinedTipSet, error) { - var blks []*types.FullBlock - - msgs, err := cg.GetMessages(cg) + ms, err := cg.GetMessages(cg) if err != nil { return nil, xerrors.Errorf("get random messages: %w", err) } + msgs := make([][]*types.SignedMessage, len(miners)) + for i := range msgs { + msgs[i] = ms + } + + fts, err := cg.NextTipSetFromMinersWithMessages(base, miners, msgs) + if err != nil { + return nil, err + } + + return &MinedTipSet{ + TipSet: fts, + Messages: ms, + }, nil +} + +func (cg *ChainGen) NextTipSetFromMinersWithMessages(base *types.TipSet, miners []address.Address, msgs [][]*types.SignedMessage) (*store.FullTipSet, error) { + var blks []*types.FullBlock + for round := base.Height() + 1; len(blks) == 0; round++ { - for _, m := range miners { + for mi, m := range miners { bvals, et, ticket, err := cg.nextBlockProof(context.TODO(), base, m, round) if err != nil { return nil, xerrors.Errorf("next block proof: %w", err) @@ -404,7 +425,7 @@ func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Ad return nil, err } - fblk, err := cg.makeBlock(base, m, ticket, et, bvals, round, wpost, msgs) + fblk, err := cg.makeBlock(base, m, ticket, et, bvals, round, wpost, msgs[mi]) if err != nil { return nil, xerrors.Errorf("making a block for next tipset failed: %w", err) } @@ -418,12 +439,7 @@ func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Ad } } - fts := store.NewFullTipSet(blks) - - return &MinedTipSet{ - TipSet: fts, - Messages: msgs, - }, nil + return store.NewFullTipSet(blks), nil } func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticket *types.Ticket, diff --git a/chain/sync_test.go b/chain/sync_test.go index cf29023e6..d184442c7 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -3,6 +3,7 @@ package chain_test import ( "context" "fmt" + "github.com/ipfs/go-cid" "os" "testing" "time" @@ -172,7 +173,7 @@ func (tu *syncTestUtil) pushTsExpectErr(to int, fts *store.FullTipSet, experr bo } } -func (tu *syncTestUtil) mineOnBlock(blk *store.FullTipSet, to int, miners []int, wait, fail bool) *store.FullTipSet { +func (tu *syncTestUtil) mineOnBlock(blk *store.FullTipSet, to int, miners []int, wait, fail bool, msgs [][]*types.SignedMessage) *store.FullTipSet { if miners == nil { for i := range tu.g.Miners { miners = append(miners, i) @@ -186,20 +187,28 @@ func (tu *syncTestUtil) mineOnBlock(blk *store.FullTipSet, to int, miners []int, fmt.Println("Miner mining block: ", maddrs) - mts, err := tu.g.NextTipSetFromMiners(blk.TipSet(), maddrs) - require.NoError(tu.t, err) - - if fail { - tu.pushTsExpectErr(to, mts.TipSet, true) + var nts *store.FullTipSet + var err error + if msgs != nil { + nts, err = tu.g.NextTipSetFromMinersWithMessages(blk.TipSet(), maddrs, msgs) + require.NoError(tu.t, err) } else { - tu.pushFtsAndWait(to, mts.TipSet, wait) + mt, err := tu.g.NextTipSetFromMiners(blk.TipSet(), maddrs) + require.NoError(tu.t, err) + nts = mt.TipSet } - return mts.TipSet + if fail { + tu.pushTsExpectErr(to, nts, true) + } else { + tu.pushFtsAndWait(to, nts, wait) + } + + return nts } func (tu *syncTestUtil) mineNewBlock(src int, miners []int) { - mts := tu.mineOnBlock(tu.g.CurTipset, src, miners, true, false) + mts := tu.mineOnBlock(tu.g.CurTipset, src, miners, true, false, nil) tu.g.CurTipset = mts } @@ -416,7 +425,7 @@ func TestSyncBadTimestamp(t *testing.T) { fmt.Println("BASE: ", base.Cids()) tu.printHeads() - a1 := tu.mineOnBlock(base, 0, nil, false, true) + a1 := tu.mineOnBlock(base, 0, nil, false, true, nil) tu.g.Timestamper = nil require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet())) @@ -425,7 +434,7 @@ func TestSyncBadTimestamp(t *testing.T) { fmt.Println("After mine bad block!") tu.printHeads() - a2 := tu.mineOnBlock(base, 0, nil, true, false) + a2 := tu.mineOnBlock(base, 0, nil, true, false, nil) tu.waitUntilSync(0, client) @@ -469,7 +478,7 @@ func TestSyncBadWinningPoSt(t *testing.T) { tu.g.SetWinningPoStProver(tu.g.Miners[1], &badWpp{}) // now ensure that new blocks are not accepted - tu.mineOnBlock(base, client, nil, false, true) + tu.mineOnBlock(base, client, nil, false, true, nil) } func (tu *syncTestUtil) loadChainToNode(to int) { @@ -514,16 +523,16 @@ func TestSyncFork(t *testing.T) { fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height()) // The two nodes fork at this point into 'a' and 'b' - a1 := tu.mineOnBlock(base, p1, []int{0}, true, false) - a := tu.mineOnBlock(a1, p1, []int{0}, true, false) - a = tu.mineOnBlock(a, p1, []int{0}, true, false) + a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil) + a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil) + a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil) require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet())) // chain B will now be heaviest - b := tu.mineOnBlock(base, p2, []int{1}, true, false) - b = tu.mineOnBlock(b, p2, []int{1}, true, false) - b = tu.mineOnBlock(b, p2, []int{1}, true, false) - b = tu.mineOnBlock(b, p2, []int{1}, true, false) + b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil) + b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil) + b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil) + b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil) fmt.Println("A: ", a.Cids(), a.TipSet().Height()) fmt.Println("B: ", b.Cids(), b.TipSet().Height()) @@ -538,6 +547,99 @@ func TestSyncFork(t *testing.T) { phead() } +// This message crafts a tipset with 2 blocks, A and B. +// A and B both include _different_ messages from sender X with nonce N (where N is the correct nonce for X). +// We can confirm that the state can be correctly computed, and that `MessagesForTipset` behaves as expected. +func TestDuplicateNonce(t *testing.T) { + H := 10 + tu := prepSyncTest(t, H) + + base := tu.g.CurTipset + + // Produce a message from the banker to the rcvr + makeMsg := func(rcvr address.Address) *types.SignedMessage { + + ba, err := tu.nds[0].StateGetActor(context.TODO(), tu.g.Banker(), base.TipSet().Key()) + require.NoError(t, err) + msg := types.Message{ + To: rcvr, + From: tu.g.Banker(), + + Nonce: ba.Nonce, + + Value: types.NewInt(1), + + Method: 0, + + GasLimit: 100_000_000, + GasFeeCap: types.NewInt(0), + GasPremium: types.NewInt(0), + } + + sig, err := tu.g.Wallet().Sign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes()) + require.NoError(t, err) + + return &types.SignedMessage{ + Message: msg, + Signature: *sig, + } + } + + msgs := make([][]*types.SignedMessage, 2) + // Each miner includes a message from the banker with the same nonce, but to different addresses + for k, _ := range msgs { + msgs[k] = []*types.SignedMessage{makeMsg(tu.g.Miners[k])} + } + + ts1 := tu.mineOnBlock(base, 0, []int{0, 1}, true, false, msgs) + + tu.waitUntilSyncTarget(0, ts1.TipSet()) + + // mine another tipset + + ts2 := tu.mineOnBlock(ts1, 0, []int{0, 1}, true, false, make([][]*types.SignedMessage, 2)) + tu.waitUntilSyncTarget(0, ts2.TipSet()) + + var includedMsg cid.Cid + var skippedMsg cid.Cid + r0, err0 := tu.nds[0].StateGetReceipt(context.TODO(), msgs[0][0].Cid(), ts2.TipSet().Key()) + r1, err1 := tu.nds[0].StateGetReceipt(context.TODO(), msgs[1][0].Cid(), ts2.TipSet().Key()) + + if err0 == nil { + require.Error(t, err1, "at least one of the StateGetReceipt calls should fail") + require.True(t, r0.ExitCode.IsSuccess()) + includedMsg = msgs[0][0].Message.Cid() + skippedMsg = msgs[1][0].Message.Cid() + } else { + require.NoError(t, err1, "both the StateGetReceipt calls should not fail") + require.True(t, r1.ExitCode.IsSuccess()) + includedMsg = msgs[1][0].Message.Cid() + skippedMsg = msgs[0][0].Message.Cid() + } + + _, rslts, err := tu.g.StateManager().ExecutionTrace(context.TODO(), ts1.TipSet()) + require.NoError(t, err) + found := false + for _, v := range rslts { + if v.Msg.Cid() == skippedMsg { + t.Fatal("skipped message should not be in exec trace") + } + + if v.Msg.Cid() == includedMsg { + found = true + } + } + + if !found { + t.Fatal("included message should be in exec trace") + } + + mft, err := tu.g.ChainStore().MessagesForTipset(ts1.TipSet()) + require.NoError(t, err) + require.True(t, len(mft) == 1, "only expecting one message for this tipset") + require.Equal(t, includedMsg, mft[0].VMMessage().Cid(), "messages for tipset didn't contain expected message") +} + func BenchmarkSyncBasic(b *testing.B) { for i := 0; i < b.N; i++ { runSyncBenchLength(b, 100) From 532c32a741bf35b7087e121666c66f012f4b8fc1 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Sat, 8 Aug 2020 21:37:49 -0400 Subject: [PATCH 004/353] Add new BlockMsgsForTipset() --- chain/stmgr/call.go | 2 +- chain/stmgr/stmgr.go | 44 +++++-------------- chain/store/store.go | 85 ++++++++++++++++++++++++++++--------- chain/sync_test.go | 2 +- chain/validation/applier.go | 4 +- 5 files changed, 78 insertions(+), 59 deletions(-) diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index 19e241fce..2d448e490 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -196,7 +196,7 @@ func (sm *StateManager) Replay(ctx context.Context, ts *types.TipSet, mcid cid.C var outm *types.Message var outr *vm.ApplyRet - _, _, err := sm.computeTipSetState(ctx, ts.Blocks(), func(c cid.Cid, m *types.Message, ret *vm.ApplyRet) error { + _, _, err := sm.computeTipSetState(ctx, ts, func(c cid.Cid, m *types.Message, ret *vm.ApplyRet) error { if c == mcid { outm = m outr = ret diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 566692b38..8779912d1 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -111,7 +111,7 @@ func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st c return ts.Blocks()[0].ParentStateRoot, ts.Blocks()[0].ParentMessageReceipts, nil } - st, rec, err = sm.computeTipSetState(ctx, ts.Blocks(), nil) + st, rec, err = sm.computeTipSetState(ctx, ts, nil) if err != nil { return cid.Undef, cid.Undef, err } @@ -121,7 +121,7 @@ func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st c func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (cid.Cid, []*api.InvocResult, error) { var trace []*api.InvocResult - st, _, err := sm.computeTipSetState(ctx, ts.Blocks(), func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error { + st, _, err := sm.computeTipSetState(ctx, ts, func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error { ir := &api.InvocResult{ Msg: msg, MsgRct: &ret.MessageReceipt, @@ -141,16 +141,9 @@ func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (c return st, trace, nil } -type BlockMessages struct { - Miner address.Address - BlsMessages []types.ChainMsg - SecpkMessages []types.ChainMsg - WinCount int64 -} - type ExecCallback func(cid.Cid, *types.Message, *vm.ApplyRet) error -func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []BlockMessages, epoch abi.ChainEpoch, r vm.Rand, cb ExecCallback, baseFee abi.TokenAmount) (cid.Cid, cid.Cid, error) { +func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []store.BlockMessages, epoch abi.ChainEpoch, r vm.Rand, cb ExecCallback, baseFee abi.TokenAmount) (cid.Cid, cid.Cid, error) { vmopt := &vm.VMOpts{ StateBase: pstate, @@ -311,10 +304,12 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp return st, rectroot, nil } -func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.BlockHeader, cb ExecCallback) (cid.Cid, cid.Cid, error) { +func (sm *StateManager) computeTipSetState(ctx context.Context, ts *types.TipSet, cb ExecCallback) (cid.Cid, cid.Cid, error) { ctx, span := trace.StartSpan(ctx, "computeTipSetState") defer span.End() + blks := ts.Blocks() + for i := 0; i < len(blks); i++ { for j := i + 1; j < len(blks); j++ { if blks[i].Miner == blks[j].Miner { @@ -343,30 +338,11 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl r := store.NewChainRand(sm.cs, cids, blks[0].Height) - var blkmsgs []BlockMessages - for _, b := range blks { - bms, sms, err := sm.cs.MessagesForBlock(b) - if err != nil { - return cid.Undef, cid.Undef, xerrors.Errorf("failed to get messages for block: %w", err) - } - - bm := BlockMessages{ - Miner: b.Miner, - BlsMessages: make([]types.ChainMsg, 0, len(bms)), - SecpkMessages: make([]types.ChainMsg, 0, len(sms)), - WinCount: b.ElectionProof.WinCount, - } - - for _, m := range bms { - bm.BlsMessages = append(bm.BlsMessages, m) - } - - for _, m := range sms { - bm.SecpkMessages = append(bm.SecpkMessages, m) - } - - blkmsgs = append(blkmsgs, bm) + blkmsgs, err := sm.cs.BlockMsgsForTipset(ts) + if err != nil { + return cid.Undef, cid.Undef, xerrors.Errorf("getting block messages for tipset: %w", err) } + baseFee := blks[0].ParentBaseFee return sm.ApplyBlocks(ctx, parentEpoch, pstate, blkmsgs, blks[0].Height, r, cb, baseFee) diff --git a/chain/store/store.go b/chain/store/store.go index 50475e6c4..2665d0298 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -707,9 +707,15 @@ func (cs *ChainStore) readAMTCids(root cid.Cid) ([]cid.Cid, error) { return cids, nil } -func (cs *ChainStore) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) { +type BlockMessages struct { + Miner address.Address + BlsMessages []types.ChainMsg + SecpkMessages []types.ChainMsg + WinCount int64 +} + +func (cs *ChainStore) BlockMsgsForTipset(ts *types.TipSet) ([]BlockMessages, error) { applied := make(map[address.Address]uint64) - balances := make(map[address.Address]types.BigInt) cst := cbor.NewCborStore(cs.bs) st, err := state.LoadStateTree(cst, ts.Blocks()[0].ParentStateRoot) @@ -725,43 +731,80 @@ func (cs *ChainStore) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, err } applied[a] = act.Nonce - balances[a] = act.Balance } return nil } - var out []types.ChainMsg + selectMsg := func(m *types.Message) (bool, error) { + if err := preloadAddr(m.From); err != nil { + return false, err + } + + if applied[m.From] != m.Nonce { + return false, nil + } + applied[m.From]++ + + return true, nil + } + + var out []BlockMessages for _, b := range ts.Blocks() { + bms, sms, err := cs.MessagesForBlock(b) if err != nil { return nil, xerrors.Errorf("failed to get messages for block: %w", err) } - cmsgs := make([]types.ChainMsg, 0, len(bms)+len(sms)) - for _, m := range bms { - cmsgs = append(cmsgs, m) - } - for _, sm := range sms { - cmsgs = append(cmsgs, sm) + bm := BlockMessages{ + Miner: b.Miner, + BlsMessages: make([]types.ChainMsg, 0, len(bms)), + SecpkMessages: make([]types.ChainMsg, 0, len(sms)), + WinCount: b.ElectionProof.WinCount, } - for _, cm := range cmsgs { - m := cm.VMMessage() - if err := preloadAddr(m.From); err != nil { - return nil, err + for _, bmsg := range bms { + b, err := selectMsg(bmsg.VMMessage()) + if err != nil { + return nil, xerrors.Errorf("failed to decide whether to select message for block: %w", err) } - if applied[m.From] != m.Nonce { - continue + if b { + bm.BlsMessages = append(bm.BlsMessages, bmsg) } - applied[m.From]++ + } - if balances[m.From].LessThan(m.RequiredFunds()) { - continue + for _, smsg := range sms { + b, err := selectMsg(smsg.VMMessage()) + if err != nil { + return nil, xerrors.Errorf("failed to decide whether to select message for block: %w", err) } - balances[m.From] = types.BigSub(balances[m.From], m.RequiredFunds()) - out = append(out, cm) + if b { + bm.SecpkMessages = append(bm.SecpkMessages, smsg) + } + } + + out = append(out, bm) + } + + return out, nil +} + +func (cs *ChainStore) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) { + bmsgs, err := cs.BlockMsgsForTipset(ts) + if err != nil { + return nil, err + } + + var out []types.ChainMsg + for _, bm := range bmsgs { + for _, blsm := range bm.BlsMessages { + out = append(out, blsm) + } + + for _, secm := range bm.SecpkMessages { + out = append(out, secm) } } diff --git a/chain/sync_test.go b/chain/sync_test.go index d184442c7..2774571b2 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -547,7 +547,7 @@ func TestSyncFork(t *testing.T) { phead() } -// This message crafts a tipset with 2 blocks, A and B. +// This test crafts a tipset with 2 blocks, A and B. // A and B both include _different_ messages from sender X with nonce N (where N is the correct nonce for X). // We can confirm that the state can be correctly computed, and that `MessagesForTipset` behaves as expected. func TestDuplicateNonce(t *testing.T) { diff --git a/chain/validation/applier.go b/chain/validation/applier.go index 008b0a907..884561fa8 100644 --- a/chain/validation/applier.go +++ b/chain/validation/applier.go @@ -71,9 +71,9 @@ func (a *Applier) ApplyTipSetMessages(epoch abi.ChainEpoch, blocks []vtypes.Bloc cs := store.NewChainStore(a.stateWrapper.bs, a.stateWrapper.ds, a.syscalls) sm := stmgr.NewStateManager(cs) - var bms []stmgr.BlockMessages + var bms []store.BlockMessages for _, b := range blocks { - bm := stmgr.BlockMessages{ + bm := store.BlockMessages{ Miner: b.Miner, WinCount: 1, } From 51444c7f186d1335d41f5d259f37e0671706aa6f Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Mon, 10 Aug 2020 17:52:59 -0400 Subject: [PATCH 005/353] refactor: replace custom paych pubsub with existing impl --- go.mod | 1 + paychmgr/msglistener.go | 77 +++++++++++++++++------------------- paychmgr/msglistener_test.go | 24 +++++------ paychmgr/paych.go | 13 +++--- paychmgr/simple.go | 4 +- 5 files changed, 58 insertions(+), 61 deletions(-) diff --git a/go.mod b/go.mod index 51ca85830..89460674e 100644 --- a/go.mod +++ b/go.mod @@ -44,6 +44,7 @@ require ( github.com/google/uuid v1.1.1 github.com/gorilla/mux v1.7.4 github.com/gorilla/websocket v1.4.2 + github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e github.com/hashicorp/go-multierror v1.1.0 github.com/hashicorp/golang-lru v0.5.4 github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d diff --git a/paychmgr/msglistener.go b/paychmgr/msglistener.go index 0a38cc2da..d1204e486 100644 --- a/paychmgr/msglistener.go +++ b/paychmgr/msglistener.go @@ -1,61 +1,56 @@ package paychmgr import ( - "sync" + "golang.org/x/xerrors" + + "github.com/hannahhoward/go-pubsub" - "github.com/google/uuid" "github.com/ipfs/go-cid" ) -type msgListener struct { - id string - cb func(c cid.Cid, err error) -} - type msgListeners struct { - lk sync.Mutex - listeners []*msgListener + ps *pubsub.PubSub } -func (ml *msgListeners) onMsg(mcid cid.Cid, cb func(error)) string { - ml.lk.Lock() - defer ml.lk.Unlock() - - l := &msgListener{ - id: uuid.New().String(), - cb: func(c cid.Cid, err error) { - if mcid.Equals(c) { - cb(err) - } - }, - } - ml.listeners = append(ml.listeners, l) - return l.id +type msgCompleteEvt struct { + mcid cid.Cid + err error } -func (ml *msgListeners) fireMsgComplete(mcid cid.Cid, err error) { - ml.lk.Lock() - defer ml.lk.Unlock() +type subscriberFn func(msgCompleteEvt) - for _, l := range ml.listeners { - l.cb(mcid, err) - } +func newMsgListeners() msgListeners { + ps := pubsub.New(func(event pubsub.Event, subFn pubsub.SubscriberFn) error { + evt, ok := event.(msgCompleteEvt) + if !ok { + return xerrors.Errorf("wrong type of event") + } + sub, ok := subFn.(subscriberFn) + if !ok { + return xerrors.Errorf("wrong type of subscriber") + } + sub(evt) + return nil + }) + return msgListeners{ps: ps} } -func (ml *msgListeners) unsubscribe(sub string) { - ml.lk.Lock() - defer ml.lk.Unlock() - - for i, l := range ml.listeners { - if l.id == sub { - ml.removeListener(i) - return +// onMsgComplete registers a callback for when the message with the given cid +// completes +func (ml *msgListeners) onMsgComplete(mcid cid.Cid, cb func(error)) pubsub.Unsubscribe { + var fn subscriberFn = func(evt msgCompleteEvt) { + if mcid.Equals(evt.mcid) { + cb(evt.err) } } + return ml.ps.Subscribe(fn) } -func (ml *msgListeners) removeListener(i int) { - copy(ml.listeners[i:], ml.listeners[i+1:]) - ml.listeners[len(ml.listeners)-1] = nil - ml.listeners = ml.listeners[:len(ml.listeners)-1] +// fireMsgComplete is called when a message completes +func (ml *msgListeners) fireMsgComplete(mcid cid.Cid, err error) { + e := ml.ps.Publish(msgCompleteEvt{mcid: mcid, err: err}) + if e != nil { + // In theory we shouldn't ever get an error here + log.Errorf("unexpected error publishing message complete: %s", e) + } } diff --git a/paychmgr/msglistener_test.go b/paychmgr/msglistener_test.go index fd457a518..2c3ae16e4 100644 --- a/paychmgr/msglistener_test.go +++ b/paychmgr/msglistener_test.go @@ -17,12 +17,12 @@ func testCids() []cid.Cid { } func TestMsgListener(t *testing.T) { - var ml msgListeners + ml := newMsgListeners() done := false experr := xerrors.Errorf("some err") cids := testCids() - ml.onMsg(cids[0], func(err error) { + ml.onMsgComplete(cids[0], func(err error) { require.Equal(t, experr, err) done = true }) @@ -35,11 +35,11 @@ func TestMsgListener(t *testing.T) { } func TestMsgListenerNilErr(t *testing.T) { - var ml msgListeners + ml := newMsgListeners() done := false cids := testCids() - ml.onMsg(cids[0], func(err error) { + ml.onMsgComplete(cids[0], func(err error) { require.Nil(t, err) done = true }) @@ -52,20 +52,20 @@ func TestMsgListenerNilErr(t *testing.T) { } func TestMsgListenerUnsub(t *testing.T) { - var ml msgListeners + ml := newMsgListeners() done := false experr := xerrors.Errorf("some err") cids := testCids() - id1 := ml.onMsg(cids[0], func(err error) { + unsub := ml.onMsgComplete(cids[0], func(err error) { t.Fatal("should not call unsubscribed listener") }) - ml.onMsg(cids[0], func(err error) { + ml.onMsgComplete(cids[0], func(err error) { require.Equal(t, experr, err) done = true }) - ml.unsubscribe(id1) + unsub() ml.fireMsgComplete(cids[0], experr) if !done { @@ -74,17 +74,17 @@ func TestMsgListenerUnsub(t *testing.T) { } func TestMsgListenerMulti(t *testing.T) { - var ml msgListeners + ml := newMsgListeners() count := 0 cids := testCids() - ml.onMsg(cids[0], func(err error) { + ml.onMsgComplete(cids[0], func(err error) { count++ }) - ml.onMsg(cids[0], func(err error) { + ml.onMsgComplete(cids[0], func(err error) { count++ }) - ml.onMsg(cids[1], func(err error) { + ml.onMsgComplete(cids[1], func(err error) { count++ }) diff --git a/paychmgr/paych.go b/paychmgr/paych.go index f1d5199f6..37952379e 100644 --- a/paychmgr/paych.go +++ b/paychmgr/paych.go @@ -35,12 +35,13 @@ type channelAccessor struct { func newChannelAccessor(pm *Manager) *channelAccessor { return &channelAccessor{ - lk: &channelLock{globalLock: &pm.lk}, - sm: pm.sm, - sa: &stateAccessor{sm: pm.sm}, - api: pm.pchapi, - store: pm.store, - waitCtx: pm.ctx, + lk: &channelLock{globalLock: &pm.lk}, + sm: pm.sm, + sa: &stateAccessor{sm: pm.sm}, + api: pm.pchapi, + store: pm.store, + msgListeners: newMsgListeners(), + waitCtx: pm.ctx, } } diff --git a/paychmgr/simple.go b/paychmgr/simple.go index 12ff40d82..ea65b48b2 100644 --- a/paychmgr/simple.go +++ b/paychmgr/simple.go @@ -640,7 +640,7 @@ type onMsgRes struct { func (ca *channelAccessor) msgPromise(ctx context.Context, mcid cid.Cid) chan onMsgRes { promise := make(chan onMsgRes) triggerUnsub := make(chan struct{}) - sub := ca.msgListeners.onMsg(mcid, func(err error) { + unsub := ca.msgListeners.onMsgComplete(mcid, func(err error) { close(triggerUnsub) // Use a go-routine so as not to block the event handler loop @@ -671,7 +671,7 @@ func (ca *channelAccessor) msgPromise(ctx context.Context, mcid cid.Cid) chan on case <-triggerUnsub: } - ca.msgListeners.unsubscribe(sub) + unsub() }() return promise From 7a7cce2538085a2b2688c6148f1f6df996b19829 Mon Sep 17 00:00:00 2001 From: nikkolasg Date: Tue, 11 Aug 2020 12:58:27 +0100 Subject: [PATCH 006/353] use cache from drand --- chain/beacon/drand/drand.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/chain/beacon/drand/drand.go b/chain/beacon/drand/drand.go index 00ff05f81..c28c7d153 100644 --- a/chain/beacon/drand/drand.go +++ b/chain/beacon/drand/drand.go @@ -170,6 +170,9 @@ func (db *DrandBeacon) VerifyEntry(curr types.BeaconEntry, prev types.BeaconEntr // TODO handle genesis better return nil } + if be := db.getCachedValue(curr.Round); be != nil { + return be + } b := &dchain.Beacon{ PreviousSig: prev.Data, Round: curr.Round, From 37fe0dbed2055d7a6a8657ff1ab2adab9ae99098 Mon Sep 17 00:00:00 2001 From: nikkolasg Date: Tue, 11 Aug 2020 13:00:23 +0100 Subject: [PATCH 007/353] correct return argument --- chain/beacon/drand/drand.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chain/beacon/drand/drand.go b/chain/beacon/drand/drand.go index c28c7d153..768058e8d 100644 --- a/chain/beacon/drand/drand.go +++ b/chain/beacon/drand/drand.go @@ -171,7 +171,8 @@ func (db *DrandBeacon) VerifyEntry(curr types.BeaconEntry, prev types.BeaconEntr return nil } if be := db.getCachedValue(curr.Round); be != nil { - return be + // return no error if the value is in the cache already + return nil } b := &dchain.Beacon{ PreviousSig: prev.Data, From ca803d99fe0947df10b64aac23f7b06962743b4a Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 11 Aug 2020 12:33:17 +0300 Subject: [PATCH 008/353] nearly optimal message selection for a given ticket quality Signed-off-by: Jakub Sztandera --- chain/messagepool/selection.go | 319 ++++++++++++++++++++++++++-- chain/messagepool/selection_test.go | 8 +- 2 files changed, 300 insertions(+), 27 deletions(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 47923fd6f..2e44c896e 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -3,6 +3,7 @@ package messagepool import ( "context" "math/big" + "math/rand" "sort" "time" @@ -19,26 +20,283 @@ import ( var bigBlockGasLimit = big.NewInt(build.BlockGasLimit) +const MaxBlocks = 15 + type msgChain struct { msgs []*types.SignedMessage gasReward *big.Int gasLimit int64 gasPerf float64 + effPerf float64 valid bool + merged bool next *msgChain + prev *msgChain } -func (mp *MessagePool) SelectMessages(ts *types.TipSet) ([]*types.SignedMessage, error) { +func (mp *MessagePool) SelectMessages(ts *types.TipSet, tq float64) ([]*types.SignedMessage, error) { mp.curTsLk.Lock() defer mp.curTsLk.Unlock() mp.lk.Lock() defer mp.lk.Unlock() - return mp.selectMessages(mp.curTs, ts) + // if the ticket quality is high enough that the first block has higher probability + // than any other block, then we don't bother with optimal selection because the + // first block will always have higher effective performance + if tq > 0.84 { + return mp.selectMessagesGreedy(mp.curTs, ts) + } + + return mp.selectMessagesOptimal(mp.curTs, ts, tq) } -func (mp *MessagePool) selectMessages(curTs, ts *types.TipSet) ([]*types.SignedMessage, error) { +func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64) ([]*types.SignedMessage, error) { + start := time.Now() + + baseFee, err := mp.api.ChainComputeBaseFee(context.TODO(), ts) + if err != nil { + return nil, xerrors.Errorf("computing basefee: %w", err) + } + + // 0. Load messages from the targeti tipset; if it is the same as the current tipset in + // the mpoll, then this is just the pending messages + pending, err := mp.getPendingMessages(curTs, ts) + if err != nil { + return nil, err + } + + if len(pending) == 0 { + return nil, nil + } + + // defer only here so if we have no pending messages we don't spam + defer func() { + log.Infow("message selection done", "took", time.Since(start)) + }() + + // 0b. Select all priority messages that fit in the block + minGas := int64(gasguess.MinGas) + result, gasLimit := mp.selectPriorityMessages(pending, baseFee, ts) + + // have we filled the block? + if gasLimit < minGas { + return result, nil + } + + // 1. Create a list of dependent message chains with maximal gas reward per limit consumed + startChains := time.Now() + var chains []*msgChain + for actor, mset := range pending { + next := mp.createMessageChains(actor, mset, baseFee, ts) + chains = append(chains, next...) + } + log.Infow("create message chains done", "took", time.Since(startChains)) + + // 2. Sort the chains + sort.Slice(chains, func(i, j int) bool { + return chains[i].Before(chains[j]) + }) + + if len(chains) != 0 && chains[0].gasPerf < 0 { + log.Warnw("all messages in mpool have non-positive gas performance", "bestGasPerf", chains[0].gasPerf) + return nil, nil + } + + // 3. Parition chains into blocks (without trimming) + // we use the residual gas limit from the priority message selection as those message + // will be unconditionally included + residualGasLimit := gasLimit + nextChain := 0 + partitions := make([][]*msgChain, MaxBlocks) + for i := 0; i < MaxBlocks && nextChain < len(chains); i++ { + gasLimit := residualGasLimit + for nextChain < len(chains) { + chain := chains[nextChain] + partitions[i] = append(partitions[i], chain) + nextChain++ + gasLimit -= chain.gasLimit + if gasLimit < minGas { + break + } + } + } + + // 4. Compute effective performance for each chain, based on the partition they fall into + // The effective performance is the gasPerf of the chain * block probability + // Note that we don't have to do anything special about residues that didn't fit in any + // partition because these will already have an effective perf of 0 and will be pushed + // to the end by virtue of smaller gasPerf. + blockProb := mp.blockProbabilities(tq) + for i := 0; i < MaxBlocks; i++ { + for _, chain := range partitions[i] { + chain.SetEffectivePerf(blockProb[i]) + } + } + + // 5. Resort the chains based on effective performance + sort.Slice(chains, func(i, j int) bool { + return chains[i].BeforeEffective(chains[j]) + }) + + // 6. Merge the head chains to produce the list of messages selected for inclusion + // subject to the residual gas limit + // When a chain is merged in, all its previous dependent chains *must* also be + // merged in or we'll have a broken block + startMerge := time.Now() + last := len(chains) + for i, chain := range chains { + // did we run out of performing chains? + if chain.gasPerf < 0 { + break + } + + // has it already been merged? + if chain.merged { + continue + } + + // compute the dependencies that must be merged and the gas limit including deps + chainGasLimit := chain.gasLimit + var chainDeps []*msgChain + for curChain := chain.prev; curChain != nil && !curChain.merged; curChain = curChain.prev { + chainDeps = append(chainDeps, curChain) + chainGasLimit += curChain.gasLimit + } + + // does it all fit in the block? + if chainGasLimit <= gasLimit { + // include it together with all dependencies + for i := len(chainDeps) - 1; i >= 0; i-- { + curChain := chainDeps[i] + curChain.merged = true + result = append(result, curChain.msgs...) + } + + chain.merged = true + result = append(result, chain.msgs...) + gasLimit -= chainGasLimit + continue + } + + // we can't fit this chain and its dependencies because of block gasLimit -- we are + // at the edge + last = i + break + } + log.Infow("merge message chains done", "took", time.Since(startMerge)) + + // 7. We have reached the edge of what can fit wholesale; if we still hae available + // gasLimit to pack some more chains, then trim the last chain and push it down. + // Trimming invalidaates subsequent dependent chains so that they can't be selected + // as their dependency cannot be (fully) included. + // We do this in a loop because the blocker might have been inordinately large and + // we might have to do it multiple times to satisfy tail packing + startTail := time.Now() +tailLoop: + for gasLimit >= minGas && last < len(chains) { + // trim if necessary + if chains[last].gasLimit > gasLimit { + chains[last].Trim(gasLimit, mp, baseFee, ts, false) + } + + // push down if it hasn't been invalidated + if chains[last].valid { + for i := last; i < len(chains)-1; i++ { + if chains[i].BeforeEffective(chains[i+1]) { + break + } + chains[i], chains[i+1] = chains[i+1], chains[i] + } + } + + // select the next (valid and fitting) chain and its dependencies for inclusion + for i, chain := range chains[last:] { + // has the chain been invalidated? + if !chain.valid { + continue + } + + // has it already been merged? + if chain.merged { + continue + } + + // if gasPerf < 0 we have no more profitable chains + if chain.gasPerf < 0 { + break tailLoop + } + + // compute the dependencies that must be merged and the gas limit including deps + chainGasLimit := chain.gasLimit + depGasLimit := int64(0) + var chainDeps []*msgChain + for curChain := chain.prev; curChain != nil && !curChain.merged; curChain = curChain.prev { + chainDeps = append(chainDeps, curChain) + chainGasLimit += curChain.gasLimit + depGasLimit += curChain.gasLimit + } + + // does it all fit in the bock + if chainGasLimit <= gasLimit { + // include it together with all dependencies + for i := len(chainDeps) - 1; i >= 0; i-- { + curChain := chainDeps[i] + curChain.merged = true + result = append(result, curChain.msgs...) + } + + chain.merged = true + result = append(result, chain.msgs...) + gasLimit -= chainGasLimit + continue + } + + // it doesn't all fit; now we have to take into account the dependent chains before + // making a decision about trimming or invalidating. + // if the dependencies exceed the gas limit, then we must invalidate the chain + // as it can never be included. + // Otherwise we can just trim and continue + if depGasLimit > gasLimit { + chain.Invalidate() + last += i + 1 + continue tailLoop + } + + // dependencies fit, just trim it + chain.Trim(gasLimit-depGasLimit, mp, baseFee, ts, false) + last += i + continue tailLoop + } + + // the merge loop ended after processing all the chains and we we probably have still + // gas to spare; end the loop. + break + } + log.Infow("pack tail chains done", "took", time.Since(startTail)) + + return result, nil +} + +func (mp *MessagePool) blockProbabilities(tq float64) []float64 { + // TODO FIXME fit in the actual probability distribution + // this just makes a dummy random distribution for testing purposes + bps := make([]float64, MaxBlocks) + norm := 0.0 + for i := 0; i < MaxBlocks; i++ { + p := rand.Float64() + bps[i] = p + norm += p + } + // normalize to make it a distribution + for i := 0; i < MaxBlocks; i++ { + bps[i] /= norm + } + + return bps +} + +func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.SignedMessage, error) { start := time.Now() baseFee, err := mp.api.ChainComputeBaseFee(context.TODO(), ts) @@ -95,18 +353,18 @@ func (mp *MessagePool) selectMessages(curTs, ts *types.TipSet) ([]*types.SignedM startMerge := time.Now() last := len(chains) for i, chain := range chains { - // does it fit in the block? - if chain.gasLimit <= gasLimit && chain.gasPerf >= 0 { - gasLimit -= chain.gasLimit - result = append(result, chain.msgs...) - continue - } - // did we run out of performing chains? if chain.gasPerf < 0 { break } + // does it fit in the block? + if chain.gasLimit <= gasLimit { + gasLimit -= chain.gasLimit + result = append(result, chain.msgs...) + continue + } + // we can't fit this chain because of block gasLimit -- we are at the edge last = i break @@ -137,30 +395,31 @@ tailLoop: // select the next (valid and fitting) chain for inclusion for i, chain := range chains[last:] { - // has the chain been invalidated + // has the chain been invalidated? if !chain.valid { continue } - // does it fit in the bock? - if chain.gasLimit <= gasLimit && chain.gasPerf >= 0 { - gasLimit -= chain.gasLimit - result = append(result, chain.msgs...) - continue - } // if gasPerf < 0 we have no more profitable chains if chain.gasPerf < 0 { break tailLoop } + // does it fit in the bock? + if chain.gasLimit <= gasLimit { + gasLimit -= chain.gasLimit + result = append(result, chain.msgs...) + continue + } + // this chain needs to be trimmed last += i continue tailLoop } - // the merge loop ended after processing all the chains and we probably still have gas to spare - // -- mark the end. - last = len(chains) + // the merge loop ended after processing all the chains and we probably still have + // gas to spare; end the loop + break } log.Infow("pack tail chains done", "took", time.Since(startTail)) @@ -533,6 +792,10 @@ func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint6 chains[i].next = chains[i+1] } + for i := len(chains) - 1; i > 0; i-- { + chains[i].prev = chains[i-1] + } + return chains } @@ -563,16 +826,26 @@ func (mc *msgChain) Trim(gasLimit int64, mp *MessagePool, baseFee types.BigInt, } if mc.next != nil { - mc.next.invalidate() + mc.next.Invalidate() mc.next = nil } } -func (mc *msgChain) invalidate() { +func (mc *msgChain) Invalidate() { mc.valid = false mc.msgs = nil if mc.next != nil { - mc.next.invalidate() + mc.next.Invalidate() mc.next = nil } } + +func (mc *msgChain) SetEffectivePerf(bp float64) { + mc.effPerf = mc.gasPerf * bp +} + +func (mc *msgChain) BeforeEffective(other *msgChain) bool { + return mc.effPerf > other.effPerf || + (mc.effPerf == other.effPerf && mc.gasPerf > other.gasPerf) || + (mc.effPerf == other.effPerf && mc.gasPerf == other.gasPerf && mc.gasReward.Cmp(other.gasReward) > 0) +} diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 177c62dc2..02205d6e9 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -403,7 +403,7 @@ func TestBasicMessageSelection(t *testing.T) { mustAdd(t, mp, m) } - msgs, err := mp.SelectMessages(ts) + msgs, err := mp.SelectMessages(ts, 1.0) if err != nil { t.Fatal(err) } @@ -471,7 +471,7 @@ func TestBasicMessageSelection(t *testing.T) { tma.setStateNonce(a1, 10) tma.setStateNonce(a2, 10) - msgs, err = mp.SelectMessages(ts3) + msgs, err = mp.SelectMessages(ts3, 1.0) if err != nil { t.Fatal(err) } @@ -545,7 +545,7 @@ func TestMessageSelectionTrimming(t *testing.T) { mustAdd(t, mp, m) } - msgs, err := mp.SelectMessages(ts) + msgs, err := mp.SelectMessages(ts, 1.0) if err != nil { t.Fatal(err) } @@ -609,7 +609,7 @@ func TestPriorityMessageSelection(t *testing.T) { mustAdd(t, mp, m) } - msgs, err := mp.SelectMessages(ts) + msgs, err := mp.SelectMessages(ts, 1.0) if err != nil { t.Fatal(err) } From 28fe602a9b8e0abb9f8e071c871652a59861408f Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 11 Aug 2020 12:35:14 +0300 Subject: [PATCH 009/353] pass a ticket quality to mpool.SelectMessages -- temporary Signed-off-by: Jakub Sztandera --- node/impl/full/mpool.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/node/impl/full/mpool.go b/node/impl/full/mpool.go index caf4255f3..346f3e2c6 100644 --- a/node/impl/full/mpool.go +++ b/node/impl/full/mpool.go @@ -46,7 +46,8 @@ func (a *MpoolAPI) MpoolSelect(ctx context.Context, tsk types.TipSetKey) ([]*typ return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - return a.Mpool.SelectMessages(ts) + // TODO FIXME compute (or pass in) the actual ticket quality! + return a.Mpool.SelectMessages(ts, 1.0) } func (a *MpoolAPI) MpoolPending(ctx context.Context, tsk types.TipSetKey) ([]*types.SignedMessage, error) { From 8eff3a25f9f04a769e2fea2fa8d14b459b755d5e Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 11 Aug 2020 12:43:44 +0300 Subject: [PATCH 010/353] use BlockGasLimit instead of residual for partitioning Signed-off-by: Jakub Sztandera --- chain/messagepool/selection.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 2e44c896e..aba54cd96 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -104,13 +104,12 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64 } // 3. Parition chains into blocks (without trimming) - // we use the residual gas limit from the priority message selection as those message - // will be unconditionally included - residualGasLimit := gasLimit + // we use the full blockGasLimit (as opposed to the residual gas limit from the + // priority message selection) as we have to account for what other miners are doing nextChain := 0 partitions := make([][]*msgChain, MaxBlocks) for i := 0; i < MaxBlocks && nextChain < len(chains); i++ { - gasLimit := residualGasLimit + gasLimit := int64(build.BlockGasLimit) for nextChain < len(chains) { chain := chains[nextChain] partitions[i] = append(partitions[i], chain) From 080614098d0f4cde26684a07c53eba682253e6fd Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 11 Aug 2020 12:50:10 +0300 Subject: [PATCH 011/353] fix edge case of effective performance for chains that dont fit in any partition Signed-off-by: Jakub Sztandera --- chain/messagepool/selection.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index aba54cd96..6cc19b7f3 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -123,14 +123,18 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64 // 4. Compute effective performance for each chain, based on the partition they fall into // The effective performance is the gasPerf of the chain * block probability - // Note that we don't have to do anything special about residues that didn't fit in any - // partition because these will already have an effective perf of 0 and will be pushed - // to the end by virtue of smaller gasPerf. blockProb := mp.blockProbabilities(tq) + effChains := 0 for i := 0; i < MaxBlocks; i++ { for _, chain := range partitions[i] { chain.SetEffectivePerf(blockProb[i]) } + effChains += len(partitions[i]) + } + + // nullify the effective performance of chains that don't fit in any partition + for _, chain := range chains[effChains:] { + chain.SetNullEffectivePerf() } // 5. Resort the chains based on effective performance @@ -843,6 +847,14 @@ func (mc *msgChain) SetEffectivePerf(bp float64) { mc.effPerf = mc.gasPerf * bp } +func (mc *msgChain) SetNullEffectivePerf() { + if mc.gasPerf < 0 { + mc.effPerf = mc.gasPerf + } else { + mc.effPerf = 0 + } +} + func (mc *msgChain) BeforeEffective(other *msgChain) bool { return mc.effPerf > other.effPerf || (mc.effPerf == other.effPerf && mc.gasPerf > other.gasPerf) || From d3c8f295c2b4ecae300c5bcf236652ebea471933 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 11 Aug 2020 12:24:00 +0200 Subject: [PATCH 012/353] Use real blockProbabilities function Signed-off-by: Jakub Sztandera --- chain/messagepool/selection.go | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 6cc19b7f3..0627a4638 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -3,7 +3,6 @@ package messagepool import ( "context" "math/big" - "math/rand" "sort" "time" @@ -281,24 +280,6 @@ tailLoop: return result, nil } -func (mp *MessagePool) blockProbabilities(tq float64) []float64 { - // TODO FIXME fit in the actual probability distribution - // this just makes a dummy random distribution for testing purposes - bps := make([]float64, MaxBlocks) - norm := 0.0 - for i := 0; i < MaxBlocks; i++ { - p := rand.Float64() - bps[i] = p - norm += p - } - // normalize to make it a distribution - for i := 0; i < MaxBlocks; i++ { - bps[i] /= norm - } - - return bps -} - func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.SignedMessage, error) { start := time.Now() From 2057433f48a949175ae5a27e8b29715b017dc54f Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 11 Aug 2020 12:26:54 +0200 Subject: [PATCH 013/353] Add needed files Signed-off-by: Jakub Sztandera --- chain/messagepool/block_proba.go | 71 +++++++++++++++++++++++++++ chain/messagepool/block_proba_test.go | 8 +++ 2 files changed, 79 insertions(+) create mode 100644 chain/messagepool/block_proba.go create mode 100644 chain/messagepool/block_proba_test.go diff --git a/chain/messagepool/block_proba.go b/chain/messagepool/block_proba.go new file mode 100644 index 000000000..403507352 --- /dev/null +++ b/chain/messagepool/block_proba.go @@ -0,0 +1,71 @@ +package messagepool + +import "math" + +func noWinnersProb() []float64 { + poissPdf := func(x float64) float64 { + const Mu = 5 + lg, _ := math.Lgamma(x + 1) + result := math.Exp((math.Log(Mu) * x) - lg - Mu) + return result + } + + out := make([]float64, 0, MaxBlocks) + for i := 0; i < MaxBlocks; i++ { + out = append(out, poissPdf(float64(i))) + } + return out +} + +func binomialCoefficient(n, k float64) float64 { + if k > n { + return math.NaN() + } + r := 1.0 + for d := 1.0; d <= k; d++ { + r *= n + r /= d + n -= 1 + } + return r +} + +func (mp *MessagePool) blockProbabilities(tq float64) []float64 { + noWinners := noWinnersProb() // cache this + + p := 1 - tq + binoPdf := func(x, trials float64) float64 { + // based on https://github.com/atgjack/prob + if x > trials { + return 0 + } + if p == 0 { + if x == 0 { + return 1.0 + } + return 0.0 + } + if p == 1 { + if x == trials { + return 1.0 + } + return 0.0 + } + coef := binomialCoefficient(trials, x) + pow := math.Pow(p, x) * math.Pow(1-p, trials-x) + if math.IsInf(coef, 0) { + return 0 + } + return coef * pow + } + + out := make([]float64, 0, MaxBlocks) + for place := 0; place < MaxBlocks; place++ { + var pPlace float64 + for otherWinners, pCase := range noWinners { + pPlace += pCase * binoPdf(float64(place), float64(otherWinners+1)) + } + out = append(out, pPlace) + } + return out +} diff --git a/chain/messagepool/block_proba_test.go b/chain/messagepool/block_proba_test.go new file mode 100644 index 000000000..2cc2ecc2a --- /dev/null +++ b/chain/messagepool/block_proba_test.go @@ -0,0 +1,8 @@ +package messagepool + +import "testing" + +func TestBlockProbability(t *testing.T) { + mp := &MessagePool{} + t.Logf("%+v\n", mp.blockProbabilities(1-0.15)) +} From b309e80e4175685b0e6e04d16e2065e7f8b5f720 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 11 Aug 2020 13:05:04 +0200 Subject: [PATCH 014/353] Wire in Ticket Quality to MpoolSelect Signed-off-by: Jakub Sztandera --- api/api_full.go | 2 +- api/apistruct/struct.go | 12 +++++++----- cli/state.go | 2 +- cmd/lotus-shed/mpool.go | 8 +++++++- cmd/lotus/debug_advance.go | 2 +- miner/miner.go | 10 +++++++++- node/impl/full/mpool.go | 4 ++-- 7 files changed, 28 insertions(+), 12 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index 184805698..42c5017de 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -159,7 +159,7 @@ type FullNode interface { MpoolPending(context.Context, types.TipSetKey) ([]*types.SignedMessage, error) // MpoolSelect returns a list of pending messages for inclusion in the next block - MpoolSelect(context.Context, types.TipSetKey) ([]*types.SignedMessage, error) + MpoolSelect(context.Context, types.TipSetKey, float64) ([]*types.SignedMessage, error) // MpoolPush pushes a signed message to mempool. MpoolPush(context.Context, *types.SignedMessage) (cid.Cid, error) diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index a571e4564..c7f1314fd 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -97,9 +97,11 @@ type FullNodeStruct struct { SyncMarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"` SyncCheckBad func(ctx context.Context, bcid cid.Cid) (string, error) `perm:"read"` - MpoolGetConfig func(context.Context) (*types.MpoolConfig, error) `perm:"read"` - MpoolSetConfig func(context.Context, *types.MpoolConfig) error `perm:"write"` - MpoolSelect func(context.Context, types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"` + MpoolGetConfig func(context.Context) (*types.MpoolConfig, error) `perm:"read"` + MpoolSetConfig func(context.Context, *types.MpoolConfig) error `perm:"write"` + + MpoolSelect func(context.Context, types.TipSetKey, float64) ([]*types.SignedMessage, error) `perm:"read"` + MpoolPending func(context.Context, types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"` MpoolPush func(context.Context, *types.SignedMessage) (cid.Cid, error) `perm:"write"` MpoolPushMessage func(context.Context, *types.Message) (*types.SignedMessage, error) `perm:"sign"` @@ -456,8 +458,8 @@ func (c *FullNodeStruct) MpoolSetConfig(ctx context.Context, cfg *types.MpoolCon return c.Internal.MpoolSetConfig(ctx, cfg) } -func (c *FullNodeStruct) MpoolSelect(ctx context.Context, tsk types.TipSetKey) ([]*types.SignedMessage, error) { - return c.Internal.MpoolSelect(ctx, tsk) +func (c *FullNodeStruct) MpoolSelect(ctx context.Context, tsk types.TipSetKey, tq float64) ([]*types.SignedMessage, error) { + return c.Internal.MpoolSelect(ctx, tsk, tq) } func (c *FullNodeStruct) MpoolPending(ctx context.Context, tsk types.TipSetKey) ([]*types.SignedMessage, error) { diff --git a/cli/state.go b/cli/state.go index 3072d4c01..5b8a10a7a 100644 --- a/cli/state.go +++ b/cli/state.go @@ -858,7 +858,7 @@ var stateComputeStateCmd = &cli.Command{ var msgs []*types.Message if cctx.Bool("apply-mpool-messages") { - pmsgs, err := api.MpoolSelect(ctx, ts.Key()) + pmsgs, err := api.MpoolSelect(ctx, ts.Key(), 1) if err != nil { return err } diff --git a/cmd/lotus-shed/mpool.go b/cmd/lotus-shed/mpool.go index c7a2e9b39..d3660db69 100644 --- a/cmd/lotus-shed/mpool.go +++ b/cmd/lotus-shed/mpool.go @@ -20,6 +20,12 @@ var mpoolCmd = &cli.Command{ var minerSelectMsgsCmd = &cli.Command{ Name: "miner-select-msgs", + Flags: []cli.Flag{ + &cli.Float64Flag{ + Name: "ticket-quality", + Value: 1, + }, + }, Action: func(cctx *cli.Context) error { api, closer, err := lcli.GetFullNodeAPI(cctx) if err != nil { @@ -34,7 +40,7 @@ var minerSelectMsgsCmd = &cli.Command{ return err } - msgs, err := api.MpoolSelect(ctx, head.Key()) + msgs, err := api.MpoolSelect(ctx, head.Key(), cctx.Float64("ticket-quality")) if err != nil { return err } diff --git a/cmd/lotus/debug_advance.go b/cmd/lotus/debug_advance.go index 17d63b6de..72c833bb6 100644 --- a/cmd/lotus/debug_advance.go +++ b/cmd/lotus/debug_advance.go @@ -33,7 +33,7 @@ func init() { if err != nil { return err } - msgs, err := api.MpoolSelect(ctx, head.Key()) + msgs, err := api.MpoolSelect(ctx, head.Key(), 1) if err != nil { return err } diff --git a/miner/miner.go b/miner/miner.go index b8bb9e562..077e18638 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -6,10 +6,12 @@ import ( "crypto/rand" "encoding/binary" "fmt" + "math/big" "sync" "time" "github.com/filecoin-project/lotus/chain/gen/slashfilter" + "github.com/minio/blake2b-simd" "github.com/filecoin-project/go-address" "github.com/filecoin-project/specs-actors/actors/abi" @@ -390,8 +392,14 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*types.BlockMsg, return nil, xerrors.Errorf("failed to compute winning post proof: %w", err) } + ticketHash := blake2b.Sum256(ticket.VRFProof) + ticketNum := types.BigFromBytes(ticketHash[:]).Int + ticketDenu := big.NewInt(1) + ticketDenu.Lsh(ticketDenu, 256) + tq, _ := new(big.Rat).SetFrac(ticketNum, ticketDenu).Float64() + tq = 1 - tq // get pending messages early, - msgs, err := m.api.MpoolSelect(context.TODO(), base.TipSet.Key()) + msgs, err := m.api.MpoolSelect(context.TODO(), base.TipSet.Key(), tq) if err != nil { return nil, xerrors.Errorf("failed to select messages for block: %w", err) } diff --git a/node/impl/full/mpool.go b/node/impl/full/mpool.go index 346f3e2c6..20ca271c0 100644 --- a/node/impl/full/mpool.go +++ b/node/impl/full/mpool.go @@ -40,14 +40,14 @@ func (a *MpoolAPI) MpoolSetConfig(ctx context.Context, cfg *types.MpoolConfig) e return nil } -func (a *MpoolAPI) MpoolSelect(ctx context.Context, tsk types.TipSetKey) ([]*types.SignedMessage, error) { +func (a *MpoolAPI) MpoolSelect(ctx context.Context, tsk types.TipSetKey, ticketQuality float64) ([]*types.SignedMessage, error) { ts, err := a.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } // TODO FIXME compute (or pass in) the actual ticket quality! - return a.Mpool.SelectMessages(ts, 1.0) + return a.Mpool.SelectMessages(ts, ticketQuality) } func (a *MpoolAPI) MpoolPending(ctx context.Context, tsk types.TipSetKey) ([]*types.SignedMessage, error) { From 268d435ce0a675dd776d2d0e1b9951d71d523b5e Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 11 Aug 2020 14:22:01 +0300 Subject: [PATCH 015/353] add some optimal selection tests Signed-off-by: Jakub Sztandera --- chain/messagepool/selection_test.go | 233 ++++++++++++++++++++++++++-- 1 file changed, 223 insertions(+), 10 deletions(-) diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 02205d6e9..8940d3f88 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -59,7 +59,7 @@ func TestMessageChains(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeBLS) + a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -69,7 +69,7 @@ func TestMessageChains(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeBLS) + a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -297,7 +297,7 @@ func TestMessageChainSkipping(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeBLS) + a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -307,7 +307,7 @@ func TestMessageChainSkipping(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeBLS) + a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -367,7 +367,7 @@ func TestBasicMessageSelection(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeBLS) + a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -377,7 +377,7 @@ func TestBasicMessageSelection(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeBLS) + a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -511,7 +511,7 @@ func TestMessageSelectionTrimming(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeBLS) + a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -521,7 +521,7 @@ func TestMessageSelectionTrimming(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeBLS) + a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -574,7 +574,7 @@ func TestPriorityMessageSelection(t *testing.T) { t.Fatal(err) } - a1, err := w1.GenerateKey(crypto.SigTypeBLS) + a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -584,7 +584,7 @@ func TestPriorityMessageSelection(t *testing.T) { t.Fatal(err) } - a2, err := w2.GenerateKey(crypto.SigTypeBLS) + a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) if err != nil { t.Fatal(err) } @@ -643,3 +643,216 @@ func TestPriorityMessageSelection(t *testing.T) { nextNonce++ } } + +func TestOptimalMessageSelection1(t *testing.T) { + // this test uses just a single actor sending messages with a low tq + // the chain depenent merging algorithm should pick messages from the actor + // from the start + mp, tma := makeTestMpool() + + // the actors + w1, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + if err != nil { + t.Fatal(err) + } + + w2, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + if err != nil { + t.Fatal(err) + } + + block := mock.MkBlock(nil, 1, 1) + ts := mock.TipSet(block) + tma.applyBlock(t, block) + + gasLimit := gasguess.Costs[gasguess.CostKey{builtin.StorageMarketActorCodeID, 2}] + + tma.setBalance(a1, 1) // in FIL + tma.setBalance(a2, 1) // in FIL + + nMessages := int(10 * build.BlockGasLimit / gasLimit) + for i := 0; i < nMessages; i++ { + bias := (nMessages - i) / 3 + m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(1+i%3+bias)) + mustAdd(t, mp, m) + } + + msgs, err := mp.SelectMessages(ts, 0.25) + if err != nil { + t.Fatal(err) + } + + expectedMsgs := int(build.BlockGasLimit / gasLimit) + if len(msgs) != expectedMsgs { + t.Fatalf("expected %d messages, but got %d", expectedMsgs, len(msgs)) + } + + nextNonce := uint64(0) + for _, m := range msgs { + if m.Message.From != a1 { + t.Fatal("expected message from a1") + } + + if m.Message.Nonce != nextNonce { + t.Fatalf("expected nonce %d but got %d", nextNonce, m.Message.Nonce) + } + nextNonce++ + } +} + +func TestOptimalMessageSelection2(t *testing.T) { + // this test uses two actors sending messages to each other, with the first + // actor paying (much) higher gas premium than the second. + // We select with a low ticket quality; the chain depenent merging algorithm should pick + // messages from the second actor from the start + mp, tma := makeTestMpool() + + // the actors + w1, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + if err != nil { + t.Fatal(err) + } + + w2, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + if err != nil { + t.Fatal(err) + } + + block := mock.MkBlock(nil, 1, 1) + ts := mock.TipSet(block) + tma.applyBlock(t, block) + + gasLimit := gasguess.Costs[gasguess.CostKey{builtin.StorageMarketActorCodeID, 2}] + + tma.setBalance(a1, 1) // in FIL + tma.setBalance(a2, 1) // in FIL + + nMessages := int(5 * build.BlockGasLimit / gasLimit) + for i := 0; i < nMessages; i++ { + bias := (nMessages - i) / 3 + m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(10000+i%3+bias)) + mustAdd(t, mp, m) + m = makeTestMessage(w2, a2, a1, uint64(i), gasLimit, uint64(1+i%3+bias)) + mustAdd(t, mp, m) + } + + msgs, err := mp.SelectMessages(ts, 0.1) + if err != nil { + t.Fatal(err) + } + + expectedMsgs := int(build.BlockGasLimit / gasLimit) + if len(msgs) != expectedMsgs { + t.Fatalf("expected %d messages, but got %d", expectedMsgs, len(msgs)) + } + + nextNonce := uint64(0) + for _, m := range msgs { + if m.Message.From != a2 { + t.Fatal("expected message from a2") + } + + if m.Message.Nonce != nextNonce { + t.Fatalf("expected nonce %d but got %d", nextNonce, m.Message.Nonce) + } + nextNonce++ + } +} + +func TestOptimalMessageSelection3(t *testing.T) { + // this test uses 10 actors sending a block of messages to each other, with the the first + // actors paying higher gas premium than the subsequent actors. + // We select with a low ticket quality; the chain depenent merging algorithm should pick + // messages from the median actor from the start + mp, tma := makeTestMpool() + + nActors := 10 + // the actors + var actors []address.Address + var wallets []*wallet.Wallet + + for i := 0; i < nActors; i++ { + w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a, err := w.GenerateKey(crypto.SigTypeSecp256k1) + if err != nil { + t.Fatal(err) + } + + actors = append(actors, a) + wallets = append(wallets, w) + } + + block := mock.MkBlock(nil, 1, 1) + ts := mock.TipSet(block) + tma.applyBlock(t, block) + + gasLimit := gasguess.Costs[gasguess.CostKey{builtin.StorageMarketActorCodeID, 2}] + + for _, a := range actors { + tma.setBalance(a, 1) // in FIL + tma.setBalance(a, 1) // in FIL + } + + nMessages := int(build.BlockGasLimit/gasLimit) + 1 + for i := 0; i < nMessages; i++ { + for j := 0; j < nActors; j++ { + bias := (nActors-j)*nMessages + (nMessages+2-i)/(3*nActors) + i%3 + m := makeTestMessage(wallets[j], actors[j], actors[j%nActors], uint64(i), gasLimit, uint64(1+bias)) + mustAdd(t, mp, m) + } + } + + msgs, err := mp.SelectMessages(ts, 0.1) + if err != nil { + t.Fatal(err) + } + + expectedMsgs := int(build.BlockGasLimit / gasLimit) + if len(msgs) != expectedMsgs { + t.Fatalf("expected %d messages, but got %d", expectedMsgs, len(msgs)) + } + + nextNonce := uint64(0) + a := actors[len(actors)/2-1] + for _, m := range msgs { + if m.Message.From != a { + who := 0 + for i, a := range actors { + if a == m.Message.From { + who = i + break + } + } + t.Fatalf("expected message from last actor, but got from %d instead", who) + } + + if m.Message.Nonce != nextNonce { + t.Fatalf("expected nonce %d but got %d", nextNonce, m.Message.Nonce) + } + nextNonce++ + } +} From 0091f3a9cea610314bd6936915c9b5551b013b47 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 11 Aug 2020 15:05:55 +0300 Subject: [PATCH 016/353] add competitive selection test Signed-off-by: Jakub Sztandera --- chain/messagepool/selection_test.go | 107 +++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 8940d3f88..7f58ab074 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -2,6 +2,8 @@ package messagepool import ( "context" + "math/big" + "math/rand" "testing" "github.com/filecoin-project/go-address" @@ -12,6 +14,7 @@ import ( "github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" _ "github.com/filecoin-project/lotus/lib/sigs/bls" @@ -814,7 +817,6 @@ func TestOptimalMessageSelection3(t *testing.T) { for _, a := range actors { tma.setBalance(a, 1) // in FIL - tma.setBalance(a, 1) // in FIL } nMessages := int(build.BlockGasLimit/gasLimit) + 1 @@ -856,3 +858,106 @@ func TestOptimalMessageSelection3(t *testing.T) { nextNonce++ } } + +func testCompetitiveMessageSelection(t *testing.T) { + // in this test we use 100 actors and send 10 blocks of messages. + // actors send with an exponentially decreasing premium. + // a number of miners select with varying ticket quality and we compare the + // capacity and rewards of greedy selection -vs- optimal selection + + mp, tma := makeTestMpool() + + nActors := 100 + // the actors + var actors []address.Address + var wallets []*wallet.Wallet + + for i := 0; i < nActors; i++ { + w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a, err := w.GenerateKey(crypto.SigTypeSecp256k1) + if err != nil { + t.Fatal(err) + } + + actors = append(actors, a) + wallets = append(wallets, w) + } + + block := mock.MkBlock(nil, 1, 1) + ts := mock.TipSet(block) + tma.applyBlock(t, block) + + gasLimit := gasguess.Costs[gasguess.CostKey{builtin.StorageMarketActorCodeID, 2}] + baseFee := types.NewInt(0) + + for _, a := range actors { + tma.setBalance(a, 1) // in FIL + } + + nMessages := 10 * int(build.BlockGasLimit/gasLimit) + nonces := make([]uint64, nActors) + for i := 0; i < nMessages; i++ { + from := rand.Intn(nActors) + to := rand.Intn(nActors) + premium := 1 + rand.Intn(1000) + nonce := nonces[from] + nonces[from]++ + m := makeTestMessage(wallets[from], actors[from], actors[to], uint64(nonce), gasLimit, uint64(premium)) + mustAdd(t, mp, m) + } + + // 1. greedy selection + greedyMsgs, err := mp.selectMessagesGreedy(ts, ts) + if err != nil { + t.Fatal(err) + } + + // 2. optimal selection + nMiners := 10 + optMsgs := make(map[cid.Cid]*types.SignedMessage) + for i := 0; i < nMiners; i++ { + tq := rand.Float64() + msgs, err := mp.SelectMessages(ts, tq) + if err != nil { + t.Fatal(err) + } + for _, m := range msgs { + optMsgs[m.Cid()] = m + } + } + + t.Log("greedy capacity", len(greedyMsgs)) + t.Log("optimal capacity", len(optMsgs)) + if len(greedyMsgs) > len(optMsgs) { + t.Fatal("greedy capacity higher than optimal capacity; wtf") + } + + greedyReward := big.NewInt(0) + for _, m := range greedyMsgs { + greedyReward.Add(greedyReward, mp.getGasReward(m, baseFee, ts)) + } + + optReward := big.NewInt(0) + for _, m := range optMsgs { + optReward.Add(optReward, mp.getGasReward(m, baseFee, ts)) + } + + t.Log("greedy reward", greedyReward) + t.Log("optimal reward", optReward) + if greedyReward.Cmp(optReward) > 0 { + t.Fatal("greedy reward higher than optimal reward; booh") + } +} + +func TestCompetitiveMessageSelection(t *testing.T) { + seeds := []int64{1947, 1976, 2020, 2100, 10000} + for _, seed := range seeds { + t.Log("running competitve message selection with seed", seed) + rand.Seed(seed) + testCompetitiveMessageSelection(t) + } +} From 4da3aedacbb90da690189db498cacf122c085caf Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 11 Aug 2020 14:59:27 +0200 Subject: [PATCH 017/353] Work on competitve test a bit Signed-off-by: Jakub Sztandera --- chain/messagepool/selection_test.go | 44 ++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 7f58ab074..90ac0e734 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -2,6 +2,7 @@ package messagepool import ( "context" + "math" "math/big" "math/rand" "testing" @@ -859,7 +860,7 @@ func TestOptimalMessageSelection3(t *testing.T) { } } -func testCompetitiveMessageSelection(t *testing.T) { +func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) { // in this test we use 100 actors and send 10 blocks of messages. // actors send with an exponentially decreasing premium. // a number of miners select with varying ticket quality and we compare the @@ -867,7 +868,7 @@ func testCompetitiveMessageSelection(t *testing.T) { mp, tma := makeTestMpool() - nActors := 100 + nActors := 300 // the actors var actors []address.Address var wallets []*wallet.Wallet @@ -899,11 +900,12 @@ func testCompetitiveMessageSelection(t *testing.T) { } nMessages := 10 * int(build.BlockGasLimit/gasLimit) + t.Log("nMessages", nMessages) nonces := make([]uint64, nActors) for i := 0; i < nMessages; i++ { - from := rand.Intn(nActors) - to := rand.Intn(nActors) - premium := 1 + rand.Intn(1000) + from := rng.Intn(nActors) + to := rng.Intn(nActors) + premium := 20000*math.Exp(-3.*rand.Float64()) + 5000 nonce := nonces[from] nonces[from]++ m := makeTestMessage(wallets[from], actors[from], actors[to], uint64(nonce), gasLimit, uint64(premium)) @@ -917,10 +919,20 @@ func testCompetitiveMessageSelection(t *testing.T) { } // 2. optimal selection - nMiners := 10 + minersRand := rng.Float64() + winerProba := noWinnersProb() + i := 0 + for ; i < MaxBlocks && minersRand > 0; i++ { + minersRand -= winerProba[i] + } + nMiners := i + if nMiners == 0 { + nMiners = 1 + } + optMsgs := make(map[cid.Cid]*types.SignedMessage) for i := 0; i < nMiners; i++ { - tq := rand.Float64() + tq := rng.Float64() msgs, err := mp.SelectMessages(ts, tq) if err != nil { t.Fatal(err) @@ -930,8 +942,9 @@ func testCompetitiveMessageSelection(t *testing.T) { } } - t.Log("greedy capacity", len(greedyMsgs)) - t.Log("optimal capacity", len(optMsgs)) + t.Logf("nMiners: %d", nMiners) + t.Logf("greedy capacity %d, optimal capacity %d (x%.1f)", len(greedyMsgs), + len(optMsgs), float64(len(optMsgs))/float64(len(greedyMsgs))) if len(greedyMsgs) > len(optMsgs) { t.Fatal("greedy capacity higher than optimal capacity; wtf") } @@ -946,10 +959,14 @@ func testCompetitiveMessageSelection(t *testing.T) { optReward.Add(optReward, mp.getGasReward(m, baseFee, ts)) } - t.Log("greedy reward", greedyReward) - t.Log("optimal reward", optReward) + nMinersBig := big.NewInt(int64(nMiners)) + greedyAvgReward, _ := new(big.Rat).SetFrac(greedyReward, nMinersBig).Float64() + optimalAvgReward, _ := new(big.Rat).SetFrac(optReward, nMinersBig).Float64() + t.Logf("greedy reward: %f, optimal reward: %f (x%.1f)", greedyAvgReward, + optimalAvgReward, optimalAvgReward/greedyAvgReward) + if greedyReward.Cmp(optReward) > 0 { - t.Fatal("greedy reward higher than optimal reward; booh") + t.Fatal("greedy reward raw higher than optimal reward; booh") } } @@ -957,7 +974,6 @@ func TestCompetitiveMessageSelection(t *testing.T) { seeds := []int64{1947, 1976, 2020, 2100, 10000} for _, seed := range seeds { t.Log("running competitve message selection with seed", seed) - rand.Seed(seed) - testCompetitiveMessageSelection(t) + testCompetitiveMessageSelection(t, rand.New(rand.NewSource(seed))) } } From a881e58cd6dc34dc23d4d94c3374074fc23a02b2 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Tue, 11 Aug 2020 10:45:45 -0400 Subject: [PATCH 018/353] refactor: use special type for paych wait sentinel --- api/api_full.go | 14 +++--- api/apistruct/struct.go | 6 +-- api/cbor_gen.go | 96 ++++++++++++++++++++++++++-------------- api/test/paych.go | 2 +- cli/paych.go | 2 +- gen/main.go | 1 + node/impl/paych/paych.go | 19 +++----- 7 files changed, 85 insertions(+), 55 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index 184805698..a47488759 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -396,7 +396,7 @@ type FullNode interface { // The Paych methods are for interacting with and managing payment channels PaychGet(ctx context.Context, from, to address.Address, amt types.BigInt) (*ChannelInfo, error) - PaychGetWaitReady(context.Context, cid.Cid) (address.Address, error) + PaychGetWaitReady(context.Context, PaychWaitSentinel) (address.Address, error) PaychList(context.Context) ([]address.Address, error) PaychStatus(context.Context, address.Address) (*PaychStatus, error) PaychSettle(context.Context, address.Address) (cid.Cid, error) @@ -506,15 +506,17 @@ type PaychStatus struct { Direction PCHDir } +type PaychWaitSentinel cid.Cid + type ChannelInfo struct { - Channel address.Address - ChannelMessage cid.Cid + Channel address.Address + WaitSentinel PaychWaitSentinel } type PaymentInfo struct { - Channel address.Address - ChannelMessage *cid.Cid - Vouchers []*paych.SignedVoucher + Channel address.Address + WaitSentinel PaychWaitSentinel + Vouchers []*paych.SignedVoucher } type VoucherSpec struct { diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index a571e4564..d5b7f7a97 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -191,7 +191,7 @@ type FullNodeStruct struct { MarketEnsureAvailable func(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"` PaychGet func(ctx context.Context, from, to address.Address, amt types.BigInt) (*api.ChannelInfo, error) `perm:"sign"` - PaychGetWaitReady func(context.Context, cid.Cid) (address.Address, error) `perm:"sign"` + PaychGetWaitReady func(context.Context, api.PaychWaitSentinel) (address.Address, error) `perm:"sign"` PaychList func(context.Context) ([]address.Address, error) `perm:"read"` PaychStatus func(context.Context, address.Address) (*api.PaychStatus, error) `perm:"read"` PaychSettle func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"` @@ -836,8 +836,8 @@ func (c *FullNodeStruct) PaychGet(ctx context.Context, from, to address.Address, return c.Internal.PaychGet(ctx, from, to, amt) } -func (c *FullNodeStruct) PaychGetWaitReady(ctx context.Context, mcid cid.Cid) (address.Address, error) { - return c.Internal.PaychGetWaitReady(ctx, mcid) +func (c *FullNodeStruct) PaychGetWaitReady(ctx context.Context, sentinel api.PaychWaitSentinel) (address.Address, error) { + return c.Internal.PaychGetWaitReady(ctx, sentinel) } func (c *FullNodeStruct) PaychList(ctx context.Context) ([]address.Address, error) { diff --git a/api/cbor_gen.go b/api/cbor_gen.go index f06ae2a07..2d83377a4 100644 --- a/api/cbor_gen.go +++ b/api/cbor_gen.go @@ -14,6 +14,59 @@ import ( var _ = xerrors.Errorf +func (t *PaychWaitSentinel) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{160}); err != nil { + return err + } + + return nil +} + +func (t *PaychWaitSentinel) UnmarshalCBOR(r io.Reader) error { + *t = PaychWaitSentinel{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("PaychWaitSentinel: map struct too large (%d)", extra) + } + + var name string + n := extra + + for i := uint64(0); i < n; i++ { + + { + sval, err := cbg.ReadStringBuf(br, scratch) + if err != nil { + return err + } + + name = string(sval) + } + + switch name { + + default: + return fmt.Errorf("unknown struct field %d: '%s'", i, name) + } + } + + return nil +} func (t *PaymentInfo) MarshalCBOR(w io.Writer) error { if t == nil { _, err := w.Write(cbg.CborNull) @@ -41,26 +94,20 @@ func (t *PaymentInfo) MarshalCBOR(w io.Writer) error { return err } - // t.ChannelMessage (cid.Cid) (struct) - if len("ChannelMessage") > cbg.MaxLength { - return xerrors.Errorf("Value in field \"ChannelMessage\" was too long") + // t.WaitSentinel (api.PaychWaitSentinel) (struct) + if len("WaitSentinel") > cbg.MaxLength { + return xerrors.Errorf("Value in field \"WaitSentinel\" was too long") } - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("ChannelMessage"))); err != nil { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("WaitSentinel"))); err != nil { return err } - if _, err := io.WriteString(w, string("ChannelMessage")); err != nil { + if _, err := io.WriteString(w, string("WaitSentinel")); err != nil { return err } - if t.ChannelMessage == nil { - if _, err := w.Write(cbg.CborNull); err != nil { - return err - } - } else { - if err := cbg.WriteCidBuf(scratch, w, *t.ChannelMessage); err != nil { - return xerrors.Errorf("failed to write cid field t.ChannelMessage: %w", err) - } + if err := t.WaitSentinel.MarshalCBOR(w); err != nil { + return err } // t.Vouchers ([]*paych.SignedVoucher) (slice) @@ -133,28 +180,13 @@ func (t *PaymentInfo) UnmarshalCBOR(r io.Reader) error { } } - // t.ChannelMessage (cid.Cid) (struct) - case "ChannelMessage": + // t.WaitSentinel (api.PaychWaitSentinel) (struct) + case "WaitSentinel": { - pb, err := br.PeekByte() - if err != nil { - return err - } - if pb == cbg.CborNull[0] { - var nbuf [1]byte - if _, err := br.Read(nbuf[:]); err != nil { - return err - } - } else { - - c, err := cbg.ReadCid(br) - if err != nil { - return xerrors.Errorf("failed to read cid field t.ChannelMessage: %w", err) - } - - t.ChannelMessage = &c + if err := t.WaitSentinel.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.WaitSentinel: %w", err) } } diff --git a/api/test/paych.go b/api/test/paych.go index 2892b2334..85a89f18c 100644 --- a/api/test/paych.go +++ b/api/test/paych.go @@ -74,7 +74,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) { t.Fatal(err) } - channel, err := paymentCreator.PaychGetWaitReady(ctx, channelInfo.ChannelMessage) + channel, err := paymentCreator.PaychGetWaitReady(ctx, channelInfo.WaitSentinel) if err != nil { t.Fatal(err) } diff --git a/cli/paych.go b/cli/paych.go index 3fdf38972..6b7684e56 100644 --- a/cli/paych.go +++ b/cli/paych.go @@ -66,7 +66,7 @@ var paychGetCmd = &cli.Command{ } // Wait for the message to be confirmed - chAddr, err := api.PaychGetWaitReady(ctx, info.ChannelMessage) + chAddr, err := api.PaychGetWaitReady(ctx, info.WaitSentinel) if err != nil { return err } diff --git a/gen/main.go b/gen/main.go index e062f6a2e..a94f4daa1 100644 --- a/gen/main.go +++ b/gen/main.go @@ -43,6 +43,7 @@ func main() { } err = gen.WriteMapEncodersToFile("./api/cbor_gen.go", "api", + api.PaychWaitSentinel{}, api.PaymentInfo{}, api.SealedRef{}, api.SealedRefs{}, diff --git a/node/impl/paych/paych.go b/node/impl/paych/paych.go index e7f39e400..0f72e7c9e 100644 --- a/node/impl/paych/paych.go +++ b/node/impl/paych/paych.go @@ -35,13 +35,13 @@ func (a *PaychAPI) PaychGet(ctx context.Context, from, to address.Address, amt t } return &api.ChannelInfo{ - Channel: ch, - ChannelMessage: mcid, + Channel: ch, + WaitSentinel: api.PaychWaitSentinel(mcid), }, nil } -func (a *PaychAPI) PaychGetWaitReady(ctx context.Context, mcid cid.Cid) (address.Address, error) { - return a.PaychMgr.GetPaychWaitReady(ctx, mcid) +func (a *PaychAPI) PaychGetWaitReady(ctx context.Context, sentinel api.PaychWaitSentinel) (address.Address, error) { + return a.PaychMgr.GetPaychWaitReady(ctx, cid.Cid(sentinel)) } func (a *PaychAPI) PaychAllocateLane(ctx context.Context, ch address.Address) (uint64, error) { @@ -84,15 +84,10 @@ func (a *PaychAPI) PaychNewPayment(ctx context.Context, from, to address.Address svs[i] = sv } - var pchCid *cid.Cid - if ch.ChannelMessage != cid.Undef { - pchCid = &ch.ChannelMessage - } - return &api.PaymentInfo{ - Channel: ch.Channel, - ChannelMessage: pchCid, - Vouchers: svs, + Channel: ch.Channel, + WaitSentinel: ch.WaitSentinel, + Vouchers: svs, }, nil } From 56e3f7da7d7ea64bdcbeb8d66393bdd0fb8b6814 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 11 Aug 2020 17:18:46 +0200 Subject: [PATCH 019/353] Fix getGasReward and Trim Signed-off-by: Jakub Sztandera --- chain/messagepool/selection.go | 17 +++++-- chain/messagepool/selection_test.go | 75 +++++++++++++++-------------- 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 0627a4638..fdcb71c54 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -111,13 +111,14 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64 gasLimit := int64(build.BlockGasLimit) for nextChain < len(chains) { chain := chains[nextChain] - partitions[i] = append(partitions[i], chain) nextChain++ + partitions[i] = append(partitions[i], chain) gasLimit -= chain.gasLimit if gasLimit < minGas { break } } + } // 4. Compute effective performance for each chain, based on the partition they fall into @@ -606,11 +607,11 @@ func (mp *MessagePool) getPendingMessages(curTs, ts *types.TipSet) (map[address. } func (mp *MessagePool) getGasReward(msg *types.SignedMessage, baseFee types.BigInt, ts *types.TipSet) *big.Int { - gasReward := abig.Mul(msg.Message.GasPremium, types.NewInt(uint64(msg.Message.GasLimit))) - maxReward := types.BigSub(msg.Message.GasFeeCap, baseFee) - if types.BigCmp(maxReward, gasReward) < 0 { - gasReward = maxReward + maxPremium := types.BigSub(msg.Message.GasFeeCap, baseFee) + if types.BigCmp(maxPremium, msg.Message.GasPremium) < 0 { + maxPremium = msg.Message.GasPremium } + gasReward := abig.Mul(maxPremium, types.NewInt(uint64(msg.Message.GasLimit))) return gasReward.Int } @@ -795,7 +796,13 @@ func (mc *msgChain) Trim(gasLimit int64, mp *MessagePool, baseFee types.BigInt, mc.gasReward = new(big.Int).Sub(mc.gasReward, gasReward) mc.gasLimit -= mc.msgs[i].Message.GasLimit if mc.gasLimit > 0 { + bp := 1.0 + if mc.effPerf != 0 { + bp = mc.effPerf / mc.gasPerf + } + mc.gasPerf = mp.getGasPerf(mc.gasReward, mc.gasLimit) + mc.effPerf = bp * mc.gasPerf } else { mc.gasPerf = 0 } diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 90ac0e734..5e93476ab 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -20,6 +20,7 @@ import ( _ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/secp" + logging "github.com/ipfs/go-log" ) func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, gasLimit int64, gasPrice uint64) *types.SignedMessage { @@ -930,44 +931,48 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) { nMiners = 1 } - optMsgs := make(map[cid.Cid]*types.SignedMessage) - for i := 0; i < nMiners; i++ { - tq := rng.Float64() - msgs, err := mp.SelectMessages(ts, tq) - if err != nil { - t.Fatal(err) + logging.SetLogLevel("messagepool", "error") + for i := 0; i < 1; i++ { + optMsgs := make(map[cid.Cid]*types.SignedMessage) + for j := 0; j < nMiners; j++ { + tq := rng.Float64() + msgs, err := mp.SelectMessages(ts, tq) + if err != nil { + t.Fatal(err) + } + for _, m := range msgs { + optMsgs[m.Cid()] = m + } } - for _, m := range msgs { - optMsgs[m.Cid()] = m + + t.Logf("nMiners: %d", nMiners) + t.Logf("greedy capacity %d, optimal capacity %d (x%.1f)", len(greedyMsgs), + len(optMsgs), float64(len(optMsgs))/float64(len(greedyMsgs))) + if len(greedyMsgs) > len(optMsgs) { + t.Fatal("greedy capacity higher than optimal capacity; wtf") + } + + greedyReward := big.NewInt(0) + for _, m := range greedyMsgs { + greedyReward.Add(greedyReward, mp.getGasReward(m, baseFee, ts)) + } + + optReward := big.NewInt(0) + for _, m := range optMsgs { + optReward.Add(optReward, mp.getGasReward(m, baseFee, ts)) + } + + nMinersBig := big.NewInt(int64(nMiners)) + greedyAvgReward, _ := new(big.Rat).SetFrac(greedyReward, nMinersBig).Float64() + optimalAvgReward, _ := new(big.Rat).SetFrac(optReward, nMinersBig).Float64() + t.Logf("greedy reward: %.0f, optimal reward: %.0f (x%.1f)", greedyAvgReward, + optimalAvgReward, optimalAvgReward/greedyAvgReward) + + if greedyReward.Cmp(optReward) > 0 { + t.Fatal("greedy reward raw higher than optimal reward; booh") } } - - t.Logf("nMiners: %d", nMiners) - t.Logf("greedy capacity %d, optimal capacity %d (x%.1f)", len(greedyMsgs), - len(optMsgs), float64(len(optMsgs))/float64(len(greedyMsgs))) - if len(greedyMsgs) > len(optMsgs) { - t.Fatal("greedy capacity higher than optimal capacity; wtf") - } - - greedyReward := big.NewInt(0) - for _, m := range greedyMsgs { - greedyReward.Add(greedyReward, mp.getGasReward(m, baseFee, ts)) - } - - optReward := big.NewInt(0) - for _, m := range optMsgs { - optReward.Add(optReward, mp.getGasReward(m, baseFee, ts)) - } - - nMinersBig := big.NewInt(int64(nMiners)) - greedyAvgReward, _ := new(big.Rat).SetFrac(greedyReward, nMinersBig).Float64() - optimalAvgReward, _ := new(big.Rat).SetFrac(optReward, nMinersBig).Float64() - t.Logf("greedy reward: %f, optimal reward: %f (x%.1f)", greedyAvgReward, - optimalAvgReward, optimalAvgReward/greedyAvgReward) - - if greedyReward.Cmp(optReward) > 0 { - t.Fatal("greedy reward raw higher than optimal reward; booh") - } + logging.SetLogLevel("messagepool", "info") } func TestCompetitiveMessageSelection(t *testing.T) { From d3baf2b9ebbff68f7e6ff6317ec5c30ee863e9c9 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 11 Aug 2020 19:32:28 +0300 Subject: [PATCH 020/353] fix edge case in chain creation --- chain/messagepool/selection.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index fdcb71c54..64d845e02 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -693,7 +693,7 @@ func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint6 } // check we have a sane set of messages to construct the chains - if i > 0 { + if i > skip { msgs = msgs[skip:i] } else { return nil From 2aaf14b5588aa9fc1917c32f1edde6cbe1dd6fbb Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 11 Aug 2020 20:00:51 +0300 Subject: [PATCH 021/353] mute timing logs if they are under 1ms --- chain/messagepool/selection.go | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 64d845e02..4d84df2fe 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -90,7 +90,9 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64 next := mp.createMessageChains(actor, mset, baseFee, ts) chains = append(chains, next...) } - log.Infow("create message chains done", "took", time.Since(startChains)) + if dt := time.Since(startChains); dt > time.Millisecond { + log.Infow("create message chains done", "took", dt) + } // 2. Sort the chains sort.Slice(chains, func(i, j int) bool { @@ -187,7 +189,9 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64 last = i break } - log.Infow("merge message chains done", "took", time.Since(startMerge)) + if dt := time.Since(startMerge); dt > time.Millisecond { + log.Infow("merge message chains done", "took", dt) + } // 7. We have reached the edge of what can fit wholesale; if we still hae available // gasLimit to pack some more chains, then trim the last chain and push it down. @@ -276,7 +280,9 @@ tailLoop: // gas to spare; end the loop. break } - log.Infow("pack tail chains done", "took", time.Since(startTail)) + if dt := time.Since(startTail); dt > time.Millisecond { + log.Infow("pack tail chains done", "took", dt) + } return result, nil } @@ -321,7 +327,9 @@ func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.S next := mp.createMessageChains(actor, mset, baseFee, ts) chains = append(chains, next...) } - log.Infow("create message chains done", "took", time.Since(startChains)) + if dt := time.Since(startChains); dt > time.Millisecond { + log.Infow("create message chains done", "took", dt) + } // 2. Sort the chains sort.Slice(chains, func(i, j int) bool { @@ -354,7 +362,9 @@ func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.S last = i break } - log.Infow("merge message chains done", "took", time.Since(startMerge)) + if dt := time.Since(startMerge); dt > time.Millisecond { + log.Infow("merge message chains done", "took", dt) + } // 4. We have reached the edge of what we can fit wholesale; if we still have available gasLimit // to pack some more chains, then trim the last chain and push it down. @@ -406,7 +416,9 @@ tailLoop: // gas to spare; end the loop break } - log.Infow("pack tail chains done", "took", time.Since(startTail)) + if dt := time.Since(startTail); dt > time.Millisecond { + log.Infow("pack tail chains done", "took", dt) + } return result, nil } @@ -414,7 +426,9 @@ tailLoop: func (mp *MessagePool) selectPriorityMessages(pending map[address.Address]map[uint64]*types.SignedMessage, baseFee types.BigInt, ts *types.TipSet) ([]*types.SignedMessage, int64) { start := time.Now() defer func() { - log.Infow("select priority messages done", "took", time.Since(start)) + if dt := time.Since(start); dt > time.Millisecond { + log.Infow("select priority messages done", "took", dt) + } }() result := make([]*types.SignedMessage, 0, mp.cfg.SizeLimitLow) @@ -502,8 +516,8 @@ func (mp *MessagePool) getPendingMessages(curTs, ts *types.TipSet) (map[address. result := make(map[address.Address]map[uint64]*types.SignedMessage) haveCids := make(map[cid.Cid]struct{}) defer func() { - if time.Since(start) > time.Millisecond { - log.Infow("get pending messages done", "took", time.Since(start)) + if dt := time.Since(start); dt > time.Millisecond { + log.Infow("get pending messages done", "took", dt) } }() From f857ee159ed4b75560a76fa0968d21e008256587 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Tue, 11 Aug 2020 10:20:05 -0400 Subject: [PATCH 022/353] refactor: unify manager interfaces for easier mocks --- paychmgr/manager.go | 49 ++++--- paychmgr/mock_test.go | 180 +++++++++++++++++++++++++ paychmgr/paych.go | 12 +- paychmgr/paych_test.go | 104 ++++----------- paychmgr/paychget_test.go | 267 +++++++++++--------------------------- paychmgr/settle_test.go | 11 +- paychmgr/simple.go | 7 - paychmgr/state.go | 2 +- 8 files changed, 319 insertions(+), 313 deletions(-) create mode 100644 paychmgr/mock_test.go diff --git a/paychmgr/manager.go b/paychmgr/manager.go index a75c79515..96dd11f7a 100644 --- a/paychmgr/manager.go +++ b/paychmgr/manager.go @@ -27,62 +27,71 @@ import ( var log = logging.Logger("paych") -type ManagerApi struct { +// PaychAPI is used by dependency injection to pass the consituent APIs to NewManager() +type PaychAPI struct { fx.In full.MpoolAPI - full.WalletAPI full.StateAPI } -type StateManagerApi interface { +// stateManagerAPI defines the methods needed from StateManager +type stateManagerAPI interface { LoadActorState(ctx context.Context, a address.Address, out interface{}, ts *types.TipSet) (*types.Actor, error) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) } +// paychAPI defines the API methods needed by the payment channel manager +type paychAPI interface { + StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) + MpoolPushMessage(ctx context.Context, msg *types.Message) (*types.SignedMessage, error) +} + +// managerAPI defines all methods needed by the manager +type managerAPI interface { + stateManagerAPI + paychAPI +} + +// managerAPIImpl is used to create a composite that implements managerAPI +type managerAPIImpl struct { + stateManagerAPI + paychAPI +} + type Manager struct { // The Manager context is used to terminate wait operations on shutdown ctx context.Context shutdown context.CancelFunc store *Store - sm StateManagerApi sa *stateAccessor - pchapi paychApi + pchapi managerAPI lk sync.RWMutex channels map[string]*channelAccessor - - mpool full.MpoolAPI - wallet full.WalletAPI - state full.StateAPI } -func NewManager(mctx helpers.MetricsCtx, lc fx.Lifecycle, sm *stmgr.StateManager, pchstore *Store, api ManagerApi) *Manager { +func NewManager(mctx helpers.MetricsCtx, lc fx.Lifecycle, sm *stmgr.StateManager, pchstore *Store, api PaychAPI) *Manager { ctx := helpers.LifecycleCtx(mctx, lc) ctx, shutdown := context.WithCancel(ctx) + impl := &managerAPIImpl{stateManagerAPI: sm, paychAPI: &api} return &Manager{ ctx: ctx, shutdown: shutdown, store: pchstore, - sm: sm, - sa: &stateAccessor{sm: sm}, + sa: &stateAccessor{sm: impl}, channels: make(map[string]*channelAccessor), - pchapi: &api, - - mpool: api.MpoolAPI, - wallet: api.WalletAPI, - state: api.StateAPI, + pchapi: impl, } } // newManager is used by the tests to supply mocks -func newManager(sm StateManagerApi, pchstore *Store, pchapi paychApi) (*Manager, error) { +func newManager(pchstore *Store, pchapi managerAPI) (*Manager, error) { pm := &Manager{ store: pchstore, - sm: sm, - sa: &stateAccessor{sm: sm}, + sa: &stateAccessor{sm: pchapi}, channels: make(map[string]*channelAccessor), pchapi: pchapi, } diff --git a/paychmgr/mock_test.go b/paychmgr/mock_test.go new file mode 100644 index 000000000..6db357ecb --- /dev/null +++ b/paychmgr/mock_test.go @@ -0,0 +1,180 @@ +package paychmgr + +import ( + "context" + "fmt" + "sync" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/specs-actors/actors/builtin/account" + "github.com/filecoin-project/specs-actors/actors/builtin/paych" + "github.com/ipfs/go-cid" +) + +type mockManagerAPI struct { + *mockStateManager + *mockPaychAPI +} + +func newMockManagerAPI() *mockManagerAPI { + return &mockManagerAPI{ + mockStateManager: newMockStateManager(), + mockPaychAPI: newMockPaychAPI(), + } +} + +type mockPchState struct { + actor *types.Actor + state paych.State +} + +type mockStateManager struct { + lk sync.Mutex + accountState map[address.Address]account.State + paychState map[address.Address]mockPchState + response *api.InvocResult +} + +func newMockStateManager() *mockStateManager { + return &mockStateManager{ + accountState: make(map[address.Address]account.State), + paychState: make(map[address.Address]mockPchState), + } +} + +func (sm *mockStateManager) setAccountState(a address.Address, state account.State) { + sm.lk.Lock() + defer sm.lk.Unlock() + sm.accountState[a] = state +} + +func (sm *mockStateManager) setPaychState(a address.Address, actor *types.Actor, state paych.State) { + sm.lk.Lock() + defer sm.lk.Unlock() + sm.paychState[a] = mockPchState{actor, state} +} + +func (sm *mockStateManager) LoadActorState(ctx context.Context, a address.Address, out interface{}, ts *types.TipSet) (*types.Actor, error) { + sm.lk.Lock() + defer sm.lk.Unlock() + + if outState, ok := out.(*account.State); ok { + *outState = sm.accountState[a] + return nil, nil + } + if outState, ok := out.(*paych.State); ok { + info := sm.paychState[a] + *outState = info.state + return info.actor, nil + } + panic(fmt.Sprintf("unexpected state type %v", out)) +} + +func (sm *mockStateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) { + return sm.response, nil +} + +type waitingCall struct { + response chan types.MessageReceipt +} + +type waitingResponse struct { + receipt types.MessageReceipt + done chan struct{} +} + +type mockPaychAPI struct { + lk sync.Mutex + messages map[cid.Cid]*types.SignedMessage + waitingCalls map[cid.Cid]*waitingCall + waitingResponses map[cid.Cid]*waitingResponse +} + +func newMockPaychAPI() *mockPaychAPI { + return &mockPaychAPI{ + messages: make(map[cid.Cid]*types.SignedMessage), + waitingCalls: make(map[cid.Cid]*waitingCall), + waitingResponses: make(map[cid.Cid]*waitingResponse), + } +} + +func (pchapi *mockPaychAPI) StateWaitMsg(ctx context.Context, mcid cid.Cid, confidence uint64) (*api.MsgLookup, error) { + pchapi.lk.Lock() + + response := make(chan types.MessageReceipt) + + if response, ok := pchapi.waitingResponses[mcid]; ok { + defer pchapi.lk.Unlock() + defer func() { + go close(response.done) + }() + + delete(pchapi.waitingResponses, mcid) + return &api.MsgLookup{Receipt: response.receipt}, nil + } + + pchapi.waitingCalls[mcid] = &waitingCall{response: response} + pchapi.lk.Unlock() + + receipt := <-response + return &api.MsgLookup{Receipt: receipt}, nil +} + +func (pchapi *mockPaychAPI) receiveMsgResponse(mcid cid.Cid, receipt types.MessageReceipt) { + pchapi.lk.Lock() + + if call, ok := pchapi.waitingCalls[mcid]; ok { + defer pchapi.lk.Unlock() + + delete(pchapi.waitingCalls, mcid) + call.response <- receipt + return + } + + done := make(chan struct{}) + pchapi.waitingResponses[mcid] = &waitingResponse{receipt: receipt, done: done} + + pchapi.lk.Unlock() + + <-done +} + +// Send success response for any waiting calls +func (pchapi *mockPaychAPI) close() { + pchapi.lk.Lock() + defer pchapi.lk.Unlock() + + success := types.MessageReceipt{ + ExitCode: 0, + Return: []byte{}, + } + for mcid, call := range pchapi.waitingCalls { + delete(pchapi.waitingCalls, mcid) + call.response <- success + } +} + +func (pchapi *mockPaychAPI) MpoolPushMessage(ctx context.Context, msg *types.Message) (*types.SignedMessage, error) { + pchapi.lk.Lock() + defer pchapi.lk.Unlock() + + smsg := &types.SignedMessage{Message: *msg} + pchapi.messages[smsg.Cid()] = smsg + return smsg, nil +} + +func (pchapi *mockPaychAPI) pushedMessages(c cid.Cid) *types.SignedMessage { + pchapi.lk.Lock() + defer pchapi.lk.Unlock() + + return pchapi.messages[c] +} + +func (pchapi *mockPaychAPI) pushedMessageCount() int { + pchapi.lk.Lock() + defer pchapi.lk.Unlock() + + return len(pchapi.messages) +} diff --git a/paychmgr/paych.go b/paychmgr/paych.go index f0d347e0b..2f518c2f9 100644 --- a/paychmgr/paych.go +++ b/paychmgr/paych.go @@ -24,9 +24,8 @@ type channelAccessor struct { // waitCtx is used by processes that wait for things to be confirmed // on chain waitCtx context.Context - sm StateManagerApi sa *stateAccessor - api paychApi + api managerAPI store *Store lk *channelLock fundsReqQueue []*fundsReq @@ -36,8 +35,7 @@ type channelAccessor struct { func newChannelAccessor(pm *Manager) *channelAccessor { return &channelAccessor{ lk: &channelLock{globalLock: &pm.lk}, - sm: pm.sm, - sa: &stateAccessor{sm: pm.sm}, + sa: pm.sa, api: pm.pchapi, store: pm.store, msgListeners: newMsgListeners(), @@ -70,7 +68,7 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add } var actState account.State - _, err = ca.sm.LoadActorState(ctx, pchState.From, &actState, nil) + _, err = ca.api.LoadActorState(ctx, pchState.From, &actState, nil) if err != nil { return nil, err } @@ -181,7 +179,7 @@ func (ca *channelAccessor) checkVoucherSpendable(ctx context.Context, ch address return false, err } - ret, err := ca.sm.Call(ctx, &types.Message{ + ret, err := ca.api.Call(ctx, &types.Message{ From: recipient, To: ch, Method: builtin.MethodsPaych.UpdateChannelState, @@ -200,7 +198,7 @@ func (ca *channelAccessor) checkVoucherSpendable(ctx context.Context, ch address func (ca *channelAccessor) getPaychRecipient(ctx context.Context, ch address.Address) (address.Address, error) { var state paych.State - if _, err := ca.sm.LoadActorState(ctx, ch, &state, nil); err != nil { + if _, err := ca.api.LoadActorState(ctx, ch, &state, nil); err != nil { return address.Address{}, err } diff --git a/paychmgr/paych_test.go b/paychmgr/paych_test.go index 9c28fdcb8..69aa39119 100644 --- a/paychmgr/paych_test.go +++ b/paychmgr/paych_test.go @@ -2,8 +2,6 @@ package paychmgr import ( "context" - "fmt" - "sync" "testing" "github.com/filecoin-project/specs-actors/actors/builtin" @@ -24,64 +22,12 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin/account" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types" ds "github.com/ipfs/go-datastore" ds_sync "github.com/ipfs/go-datastore/sync" ) -type testPchState struct { - actor *types.Actor - state paych.State -} - -type mockStateManager struct { - lk sync.Mutex - accountState map[address.Address]account.State - paychState map[address.Address]testPchState - response *api.InvocResult -} - -func newMockStateManager() *mockStateManager { - return &mockStateManager{ - accountState: make(map[address.Address]account.State), - paychState: make(map[address.Address]testPchState), - } -} - -func (sm *mockStateManager) setAccountState(a address.Address, state account.State) { - sm.lk.Lock() - defer sm.lk.Unlock() - sm.accountState[a] = state -} - -func (sm *mockStateManager) setPaychState(a address.Address, actor *types.Actor, state paych.State) { - sm.lk.Lock() - defer sm.lk.Unlock() - sm.paychState[a] = testPchState{actor, state} -} - -func (sm *mockStateManager) LoadActorState(ctx context.Context, a address.Address, out interface{}, ts *types.TipSet) (*types.Actor, error) { - sm.lk.Lock() - defer sm.lk.Unlock() - - if outState, ok := out.(*account.State); ok { - *outState = sm.accountState[a] - return nil, nil - } - if outState, ok := out.(*paych.State); ok { - info := sm.paychState[a] - *outState = info.state - return info.actor, nil - } - panic(fmt.Sprintf("unexpected state type %v", out)) -} - -func (sm *mockStateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) { - return sm.response, nil -} - func TestPaychOutbound(t *testing.T) { ctx := context.Background() store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore())) @@ -92,10 +38,10 @@ func TestPaychOutbound(t *testing.T) { fromAcct := tutils.NewIDAddr(t, 201) toAcct := tutils.NewIDAddr(t, 202) - sm := newMockStateManager() - sm.setAccountState(fromAcct, account.State{Address: from}) - sm.setAccountState(toAcct, account.State{Address: to}) - sm.setPaychState(ch, nil, paych.State{ + mock := newMockManagerAPI() + mock.setAccountState(fromAcct, account.State{Address: from}) + mock.setAccountState(toAcct, account.State{Address: to}) + mock.setPaychState(ch, nil, paych.State{ From: fromAcct, To: toAcct, ToSend: big.NewInt(0), @@ -104,7 +50,7 @@ func TestPaychOutbound(t *testing.T) { LaneStates: []*paych.LaneState{}, }) - mgr, err := newManager(sm, store, nil) + mgr, err := newManager(store, mock) require.NoError(t, err) err = mgr.TrackOutboundChannel(ctx, ch) @@ -130,10 +76,10 @@ func TestPaychInbound(t *testing.T) { fromAcct := tutils.NewIDAddr(t, 201) toAcct := tutils.NewIDAddr(t, 202) - sm := newMockStateManager() - sm.setAccountState(fromAcct, account.State{Address: from}) - sm.setAccountState(toAcct, account.State{Address: to}) - sm.setPaychState(ch, nil, paych.State{ + mock := newMockManagerAPI() + mock.setAccountState(fromAcct, account.State{Address: from}) + mock.setAccountState(toAcct, account.State{Address: to}) + mock.setPaychState(ch, nil, paych.State{ From: fromAcct, To: toAcct, ToSend: big.NewInt(0), @@ -142,7 +88,7 @@ func TestPaychInbound(t *testing.T) { LaneStates: []*paych.LaneState{}, }) - mgr, err := newManager(sm, store, nil) + mgr, err := newManager(store, mock) require.NoError(t, err) err = mgr.TrackInboundChannel(ctx, ch) @@ -170,9 +116,9 @@ func TestCheckVoucherValid(t *testing.T) { fromAcct := tutils.NewActorAddr(t, "fromAct") toAcct := tutils.NewActorAddr(t, "toAct") - sm := newMockStateManager() - sm.setAccountState(fromAcct, account.State{Address: from}) - sm.setAccountState(toAcct, account.State{Address: to}) + mock := newMockManagerAPI() + mock.setAccountState(fromAcct, account.State{Address: from}) + mock.setAccountState(toAcct, account.State{Address: to}) tcases := []struct { name string @@ -316,7 +262,7 @@ func TestCheckVoucherValid(t *testing.T) { Nonce: 0, Balance: tcase.actorBalance, } - sm.setPaychState(ch, act, paych.State{ + mock.setPaychState(ch, act, paych.State{ From: fromAcct, To: toAcct, ToSend: tcase.toSend, @@ -325,7 +271,7 @@ func TestCheckVoucherValid(t *testing.T) { LaneStates: tcase.laneStates, }) - mgr, err := newManager(sm, store, nil) + mgr, err := newManager(store, mock) require.NoError(t, err) err = mgr.TrackInboundChannel(ctx, ch) @@ -355,9 +301,9 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) { toAcct := tutils.NewActorAddr(t, "toAct") minDelta := big.NewInt(0) - sm := newMockStateManager() - sm.setAccountState(fromAcct, account.State{Address: from}) - sm.setAccountState(toAcct, account.State{Address: to}) + mock := newMockManagerAPI() + mock.setAccountState(fromAcct, account.State{Address: from}) + mock.setAccountState(toAcct, account.State{Address: to}) store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore())) @@ -379,7 +325,7 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) { Nonce: 0, Balance: actorBalance, } - sm.setPaychState(ch, act, paych.State{ + mock.setPaychState(ch, act, paych.State{ From: fromAcct, To: toAcct, ToSend: toSend, @@ -388,7 +334,7 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) { LaneStates: laneStates, }) - mgr, err := newManager(sm, store, nil) + mgr, err := newManager(store, mock) require.NoError(t, err) err = mgr.TrackInboundChannel(ctx, ch) @@ -678,9 +624,9 @@ func testSetupMgrWithChannel(ctx context.Context, t *testing.T) (*Manager, addre fromAcct := tutils.NewActorAddr(t, "fromAct") toAcct := tutils.NewActorAddr(t, "toAct") - sm := newMockStateManager() - sm.setAccountState(fromAcct, account.State{Address: from}) - sm.setAccountState(toAcct, account.State{Address: to}) + mock := newMockManagerAPI() + mock.setAccountState(fromAcct, account.State{Address: from}) + mock.setAccountState(toAcct, account.State{Address: to}) act := &types.Actor{ Code: builtin.AccountActorCodeID, @@ -688,7 +634,7 @@ func testSetupMgrWithChannel(ctx context.Context, t *testing.T) (*Manager, addre Nonce: 0, Balance: big.NewInt(20), } - sm.setPaychState(ch, act, paych.State{ + mock.setPaychState(ch, act, paych.State{ From: fromAcct, To: toAcct, ToSend: big.NewInt(0), @@ -698,7 +644,7 @@ func testSetupMgrWithChannel(ctx context.Context, t *testing.T) (*Manager, addre }) store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore())) - mgr, err := newManager(sm, store, nil) + mgr, err := newManager(store, mock) require.NoError(t, err) err = mgr.TrackInboundChannel(ctx, ch) diff --git a/paychmgr/paychget_test.go b/paychmgr/paychget_test.go index ab4c65c77..64ef6f9d7 100644 --- a/paychmgr/paychget_test.go +++ b/paychmgr/paychget_test.go @@ -12,7 +12,6 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/go-address" @@ -26,109 +25,6 @@ import ( "github.com/stretchr/testify/require" ) -type waitingCall struct { - response chan types.MessageReceipt -} - -type waitingResponse struct { - receipt types.MessageReceipt - done chan struct{} -} - -type mockPaychAPI struct { - lk sync.Mutex - messages map[cid.Cid]*types.SignedMessage - waitingCalls map[cid.Cid]*waitingCall - waitingResponses map[cid.Cid]*waitingResponse -} - -func newMockPaychAPI() *mockPaychAPI { - return &mockPaychAPI{ - messages: make(map[cid.Cid]*types.SignedMessage), - waitingCalls: make(map[cid.Cid]*waitingCall), - waitingResponses: make(map[cid.Cid]*waitingResponse), - } -} - -func (pchapi *mockPaychAPI) StateWaitMsg(ctx context.Context, mcid cid.Cid, confidence uint64) (*api.MsgLookup, error) { - pchapi.lk.Lock() - - response := make(chan types.MessageReceipt) - - if response, ok := pchapi.waitingResponses[mcid]; ok { - defer pchapi.lk.Unlock() - defer func() { - go close(response.done) - }() - - delete(pchapi.waitingResponses, mcid) - return &api.MsgLookup{Receipt: response.receipt}, nil - } - - pchapi.waitingCalls[mcid] = &waitingCall{response: response} - pchapi.lk.Unlock() - - receipt := <-response - return &api.MsgLookup{Receipt: receipt}, nil -} - -func (pchapi *mockPaychAPI) receiveMsgResponse(mcid cid.Cid, receipt types.MessageReceipt) { - pchapi.lk.Lock() - - if call, ok := pchapi.waitingCalls[mcid]; ok { - defer pchapi.lk.Unlock() - - delete(pchapi.waitingCalls, mcid) - call.response <- receipt - return - } - - done := make(chan struct{}) - pchapi.waitingResponses[mcid] = &waitingResponse{receipt: receipt, done: done} - - pchapi.lk.Unlock() - - <-done -} - -// Send success response for any waiting calls -func (pchapi *mockPaychAPI) close() { - pchapi.lk.Lock() - defer pchapi.lk.Unlock() - - success := types.MessageReceipt{ - ExitCode: 0, - Return: []byte{}, - } - for mcid, call := range pchapi.waitingCalls { - delete(pchapi.waitingCalls, mcid) - call.response <- success - } -} - -func (pchapi *mockPaychAPI) MpoolPushMessage(ctx context.Context, msg *types.Message) (*types.SignedMessage, error) { - pchapi.lk.Lock() - defer pchapi.lk.Unlock() - - smsg := &types.SignedMessage{Message: *msg} - pchapi.messages[smsg.Cid()] = smsg - return smsg, nil -} - -func (pchapi *mockPaychAPI) pushedMessages(c cid.Cid) *types.SignedMessage { - pchapi.lk.Lock() - defer pchapi.lk.Unlock() - - return pchapi.messages[c] -} - -func (pchapi *mockPaychAPI) pushedMessageCount() int { - pchapi.lk.Lock() - defer pchapi.lk.Unlock() - - return len(pchapi.messages) -} - func testChannelResponse(t *testing.T, ch address.Address) types.MessageReceipt { createChannelRet := init_.ExecReturn{ IDAddress: ch, @@ -152,11 +48,10 @@ func TestPaychGetCreateChannelMsg(t *testing.T) { from := tutils.NewIDAddr(t, 101) to := tutils.NewIDAddr(t, 102) - sm := newMockStateManager() - pchapi := newMockPaychAPI() - defer pchapi.close() + mock := newMockManagerAPI() + defer mock.close() - mgr, err := newManager(sm, store, pchapi) + mgr, err := newManager(store, mock) require.NoError(t, err) amt := big.NewInt(10) @@ -164,7 +59,7 @@ func TestPaychGetCreateChannelMsg(t *testing.T) { require.NoError(t, err) require.Equal(t, address.Undef, ch) - pushedMsg := pchapi.pushedMessages(mcid) + pushedMsg := mock.pushedMessages(mcid) require.Equal(t, from, pushedMsg.Message.From) require.Equal(t, builtin.InitActorAddr, pushedMsg.Message.To) require.Equal(t, amt, pushedMsg.Message.Value) @@ -180,11 +75,10 @@ func TestPaychGetCreateChannelThenAddFunds(t *testing.T) { from := tutils.NewIDAddr(t, 101) to := tutils.NewIDAddr(t, 102) - sm := newMockStateManager() - pchapi := newMockPaychAPI() - defer pchapi.close() + mock := newMockManagerAPI() + defer mock.close() - mgr, err := newManager(sm, store, pchapi) + mgr, err := newManager(store, mock) require.NoError(t, err) // Send create message for a channel with value 10 @@ -234,7 +128,7 @@ func TestPaychGetCreateChannelThenAddFunds(t *testing.T) { require.Nil(t, ci.CreateMsg) // Trigger add funds confirmation - pchapi.receiveMsgResponse(addFundsMsgCid, types.MessageReceipt{ExitCode: 0}) + mock.receiveMsgResponse(addFundsMsgCid, types.MessageReceipt{ExitCode: 0}) // Wait for add funds confirmation to be processed by manager _, err = mgr.GetPaychWaitReady(ctx, addFundsMsgCid) @@ -255,7 +149,7 @@ func TestPaychGetCreateChannelThenAddFunds(t *testing.T) { }() // 3. Send create channel response - pchapi.receiveMsgResponse(createMsgCid, response) + mock.receiveMsgResponse(createMsgCid, response) <-done } @@ -270,11 +164,10 @@ func TestPaychGetCreateChannelWithErrorThenCreateAgain(t *testing.T) { from := tutils.NewIDAddr(t, 101) to := tutils.NewIDAddr(t, 102) - sm := newMockStateManager() - pchapi := newMockPaychAPI() - defer pchapi.close() + mock := newMockManagerAPI() + defer mock.close() - mgr, err := newManager(sm, store, pchapi) + mgr, err := newManager(store, mock) require.NoError(t, err) // Send create message for a channel @@ -304,7 +197,7 @@ func TestPaychGetCreateChannelWithErrorThenCreateAgain(t *testing.T) { // 4. Send a success response ch := tutils.NewIDAddr(t, 100) successResponse := testChannelResponse(t, ch) - pchapi.receiveMsgResponse(mcid2, successResponse) + mock.receiveMsgResponse(mcid2, successResponse) _, err = mgr.GetPaychWaitReady(ctx, mcid2) require.NoError(t, err) @@ -321,7 +214,7 @@ func TestPaychGetCreateChannelWithErrorThenCreateAgain(t *testing.T) { }() // 3. Send error response to first channel create - pchapi.receiveMsgResponse(mcid1, errResponse) + mock.receiveMsgResponse(mcid1, errResponse) <-done } @@ -336,11 +229,10 @@ func TestPaychGetRecoverAfterError(t *testing.T) { from := tutils.NewIDAddr(t, 101) to := tutils.NewIDAddr(t, 102) - sm := newMockStateManager() - pchapi := newMockPaychAPI() - defer pchapi.close() + mock := newMockManagerAPI() + defer mock.close() - mgr, err := newManager(sm, store, pchapi) + mgr, err := newManager(store, mock) require.NoError(t, err) // Send create message for a channel @@ -349,7 +241,7 @@ func TestPaychGetRecoverAfterError(t *testing.T) { require.NoError(t, err) // Send error create channel response - pchapi.receiveMsgResponse(mcid, types.MessageReceipt{ + mock.receiveMsgResponse(mcid, types.MessageReceipt{ ExitCode: 1, // error Return: []byte{}, }) @@ -361,7 +253,7 @@ func TestPaychGetRecoverAfterError(t *testing.T) { // Send success create channel response response := testChannelResponse(t, ch) - pchapi.receiveMsgResponse(mcid2, response) + mock.receiveMsgResponse(mcid2, response) _, err = mgr.GetPaychWaitReady(ctx, mcid2) require.NoError(t, err) @@ -389,11 +281,10 @@ func TestPaychGetRecoverAfterAddFundsError(t *testing.T) { from := tutils.NewIDAddr(t, 101) to := tutils.NewIDAddr(t, 102) - sm := newMockStateManager() - pchapi := newMockPaychAPI() - defer pchapi.close() + mock := newMockManagerAPI() + defer mock.close() - mgr, err := newManager(sm, store, pchapi) + mgr, err := newManager(store, mock) require.NoError(t, err) // Send create message for a channel @@ -403,7 +294,7 @@ func TestPaychGetRecoverAfterAddFundsError(t *testing.T) { // Send success create channel response response := testChannelResponse(t, ch) - pchapi.receiveMsgResponse(mcid1, response) + mock.receiveMsgResponse(mcid1, response) // Send add funds message for channel amt2 := big.NewInt(5) @@ -411,7 +302,7 @@ func TestPaychGetRecoverAfterAddFundsError(t *testing.T) { require.NoError(t, err) // Send error add funds response - pchapi.receiveMsgResponse(mcid2, types.MessageReceipt{ + mock.receiveMsgResponse(mcid2, types.MessageReceipt{ ExitCode: 1, // error Return: []byte{}, }) @@ -438,7 +329,7 @@ func TestPaychGetRecoverAfterAddFundsError(t *testing.T) { require.NoError(t, err) // Send success add funds response - pchapi.receiveMsgResponse(mcid3, types.MessageReceipt{ + mock.receiveMsgResponse(mcid3, types.MessageReceipt{ ExitCode: 0, Return: []byte{}, }) @@ -472,10 +363,9 @@ func TestPaychGetRestartAfterCreateChannelMsg(t *testing.T) { from := tutils.NewIDAddr(t, 101) to := tutils.NewIDAddr(t, 102) - sm := newMockStateManager() - pchapi := newMockPaychAPI() + mock := newMockManagerAPI() - mgr, err := newManager(sm, store, pchapi) + mgr, err := newManager(store, mock) require.NoError(t, err) // Send create message for a channel with value 10 @@ -484,14 +374,13 @@ func TestPaychGetRestartAfterCreateChannelMsg(t *testing.T) { require.NoError(t, err) // Simulate shutting down system - pchapi.close() + mock.close() // Create a new manager with the same datastore - sm2 := newMockStateManager() - pchapi2 := newMockPaychAPI() - defer pchapi2.close() + mock2 := newMockManagerAPI() + defer mock2.close() - mgr2, err := newManager(sm2, store, pchapi2) + mgr2, err := newManager(store, mock2) require.NoError(t, err) // Should have no channels yet (message sent but channel not created) @@ -537,7 +426,7 @@ func TestPaychGetRestartAfterCreateChannelMsg(t *testing.T) { }() // 3. Send create channel response - pchapi2.receiveMsgResponse(createMsgCid, response) + mock2.receiveMsgResponse(createMsgCid, response) <-done } @@ -553,10 +442,9 @@ func TestPaychGetRestartAfterAddFundsMsg(t *testing.T) { from := tutils.NewIDAddr(t, 101) to := tutils.NewIDAddr(t, 102) - sm := newMockStateManager() - pchapi := newMockPaychAPI() + mock := newMockManagerAPI() - mgr, err := newManager(sm, store, pchapi) + mgr, err := newManager(store, mock) require.NoError(t, err) // Send create message for a channel @@ -566,7 +454,7 @@ func TestPaychGetRestartAfterAddFundsMsg(t *testing.T) { // Send success create channel response response := testChannelResponse(t, ch) - pchapi.receiveMsgResponse(mcid1, response) + mock.receiveMsgResponse(mcid1, response) // Send add funds message for channel amt2 := big.NewInt(5) @@ -574,18 +462,17 @@ func TestPaychGetRestartAfterAddFundsMsg(t *testing.T) { require.NoError(t, err) // Simulate shutting down system - pchapi.close() + mock.close() // Create a new manager with the same datastore - sm2 := newMockStateManager() - pchapi2 := newMockPaychAPI() - defer pchapi2.close() + mock2 := newMockManagerAPI() + defer mock2.close() - mgr2, err := newManager(sm2, store, pchapi2) + mgr2, err := newManager(store, mock2) require.NoError(t, err) // Send success add funds response - pchapi2.receiveMsgResponse(mcid2, types.MessageReceipt{ + mock2.receiveMsgResponse(mcid2, types.MessageReceipt{ ExitCode: 0, Return: []byte{}, }) @@ -617,11 +504,10 @@ func TestPaychGetWait(t *testing.T) { from := tutils.NewIDAddr(t, 101) to := tutils.NewIDAddr(t, 102) - sm := newMockStateManager() - pchapi := newMockPaychAPI() - defer pchapi.close() + mock := newMockManagerAPI() + defer mock.close() - mgr, err := newManager(sm, store, pchapi) + mgr, err := newManager(store, mock) require.NoError(t, err) // 1. Get @@ -633,7 +519,7 @@ func TestPaychGetWait(t *testing.T) { go func() { // 3. Send response response := testChannelResponse(t, expch) - pchapi.receiveMsgResponse(createMsgCid, response) + mock.receiveMsgResponse(createMsgCid, response) }() // 2. Wait till ready @@ -658,7 +544,7 @@ func TestPaychGetWait(t *testing.T) { ExitCode: 0, Return: []byte{}, } - pchapi.receiveMsgResponse(addFundsMsgCid, addFundsResponse) + mock.receiveMsgResponse(addFundsMsgCid, addFundsResponse) }() // 5. Wait for add funds @@ -675,11 +561,10 @@ func TestPaychGetWaitErr(t *testing.T) { from := tutils.NewIDAddr(t, 101) to := tutils.NewIDAddr(t, 102) - sm := newMockStateManager() - pchapi := newMockPaychAPI() - defer pchapi.close() + mock := newMockManagerAPI() + defer mock.close() - mgr, err := newManager(sm, store, pchapi) + mgr, err := newManager(store, mock) require.NoError(t, err) // 1. Create channel @@ -709,7 +594,7 @@ func TestPaychGetWaitErr(t *testing.T) { ExitCode: 1, // error Return: []byte{}, } - pchapi.receiveMsgResponse(mcid, response) + mock.receiveMsgResponse(mcid, response) <-done } @@ -723,11 +608,10 @@ func TestPaychGetWaitCtx(t *testing.T) { from := tutils.NewIDAddr(t, 101) to := tutils.NewIDAddr(t, 102) - sm := newMockStateManager() - pchapi := newMockPaychAPI() - defer pchapi.close() + mock := newMockManagerAPI() + defer mock.close() - mgr, err := newManager(sm, store, pchapi) + mgr, err := newManager(store, mock) require.NoError(t, err) amt := big.NewInt(10) @@ -754,11 +638,10 @@ func TestPaychGetMergeAddFunds(t *testing.T) { from := tutils.NewIDAddr(t, 101) to := tutils.NewIDAddr(t, 102) - sm := newMockStateManager() - pchapi := newMockPaychAPI() - defer pchapi.close() + mock := newMockManagerAPI() + defer mock.close() - mgr, err := newManager(sm, store, pchapi) + mgr, err := newManager(store, mock) require.NoError(t, err) // Send create message for a channel with value 10 @@ -800,7 +683,7 @@ func TestPaychGetMergeAddFunds(t *testing.T) { // Send create channel response response := testChannelResponse(t, ch) - pchapi.receiveMsgResponse(createMsgCid, response) + mock.receiveMsgResponse(createMsgCid, response) // Wait for create channel response chres, err := mgr.GetPaychWaitReady(ctx, createMsgCid) @@ -817,7 +700,7 @@ func TestPaychGetMergeAddFunds(t *testing.T) { require.Equal(t, addFundsMcid1, addFundsMcid2) // Send success add funds response - pchapi.receiveMsgResponse(addFundsMcid1, types.MessageReceipt{ + mock.receiveMsgResponse(addFundsMcid1, types.MessageReceipt{ ExitCode: 0, Return: []byte{}, }) @@ -829,17 +712,17 @@ func TestPaychGetMergeAddFunds(t *testing.T) { // Make sure that one create channel message and one add funds message was // sent - require.Equal(t, 2, pchapi.pushedMessageCount()) + require.Equal(t, 2, mock.pushedMessageCount()) // Check create message amount is correct - createMsg := pchapi.pushedMessages(createMsgCid) + createMsg := mock.pushedMessages(createMsgCid) require.Equal(t, from, createMsg.Message.From) require.Equal(t, builtin.InitActorAddr, createMsg.Message.To) require.Equal(t, createAmt, createMsg.Message.Value) // Check merged add funds amount is the sum of the individual // amounts - addFundsMsg := pchapi.pushedMessages(addFundsMcid1) + addFundsMsg := mock.pushedMessages(addFundsMcid1) require.Equal(t, from, addFundsMsg.Message.From) require.Equal(t, ch, addFundsMsg.Message.To) require.Equal(t, types.BigAdd(addFundsAmt1, addFundsAmt2), addFundsMsg.Message.Value) @@ -855,11 +738,10 @@ func TestPaychGetMergeAddFundsCtxCancelOne(t *testing.T) { from := tutils.NewIDAddr(t, 101) to := tutils.NewIDAddr(t, 102) - sm := newMockStateManager() - pchapi := newMockPaychAPI() - defer pchapi.close() + mock := newMockManagerAPI() + defer mock.close() - mgr, err := newManager(sm, store, pchapi) + mgr, err := newManager(store, mock) require.NoError(t, err) // Send create message for a channel with value 10 @@ -899,7 +781,7 @@ func TestPaychGetMergeAddFundsCtxCancelOne(t *testing.T) { // Send create channel response response := testChannelResponse(t, ch) - pchapi.receiveMsgResponse(createMsgCid, response) + mock.receiveMsgResponse(createMsgCid, response) // Wait for create channel response chres, err := mgr.GetPaychWaitReady(ctx, createMsgCid) @@ -914,7 +796,7 @@ func TestPaychGetMergeAddFundsCtxCancelOne(t *testing.T) { require.Equal(t, ch, addFundsCh2) // Send success add funds response - pchapi.receiveMsgResponse(addFundsMcid2, types.MessageReceipt{ + mock.receiveMsgResponse(addFundsMcid2, types.MessageReceipt{ ExitCode: 0, Return: []byte{}, }) @@ -926,17 +808,17 @@ func TestPaychGetMergeAddFundsCtxCancelOne(t *testing.T) { // Make sure that one create channel message and one add funds message was // sent - require.Equal(t, 2, pchapi.pushedMessageCount()) + require.Equal(t, 2, mock.pushedMessageCount()) // Check create message amount is correct - createMsg := pchapi.pushedMessages(createMsgCid) + createMsg := mock.pushedMessages(createMsgCid) require.Equal(t, from, createMsg.Message.From) require.Equal(t, builtin.InitActorAddr, createMsg.Message.To) require.Equal(t, createAmt, createMsg.Message.Value) // Check merged add funds amount only includes the second add funds amount // (because first was cancelled) - addFundsMsg := pchapi.pushedMessages(addFundsMcid2) + addFundsMsg := mock.pushedMessages(addFundsMcid2) require.Equal(t, from, addFundsMsg.Message.From) require.Equal(t, ch, addFundsMsg.Message.To) require.Equal(t, addFundsAmt2, addFundsMsg.Message.Value) @@ -952,11 +834,10 @@ func TestPaychGetMergeAddFundsCtxCancelAll(t *testing.T) { from := tutils.NewIDAddr(t, 101) to := tutils.NewIDAddr(t, 102) - sm := newMockStateManager() - pchapi := newMockPaychAPI() - defer pchapi.close() + mock := newMockManagerAPI() + defer mock.close() - mgr, err := newManager(sm, store, pchapi) + mgr, err := newManager(store, mock) require.NoError(t, err) // Send create message for a channel with value 10 @@ -995,7 +876,7 @@ func TestPaychGetMergeAddFundsCtxCancelAll(t *testing.T) { // Send create channel response response := testChannelResponse(t, ch) - pchapi.receiveMsgResponse(createMsgCid, response) + mock.receiveMsgResponse(createMsgCid, response) // Wait for create channel response chres, err := mgr.GetPaychWaitReady(ctx, createMsgCid) @@ -1009,10 +890,10 @@ func TestPaychGetMergeAddFundsCtxCancelAll(t *testing.T) { require.NotNil(t, addFundsErr2) // Make sure that just the create channel message was sent - require.Equal(t, 1, pchapi.pushedMessageCount()) + require.Equal(t, 1, mock.pushedMessageCount()) // Check create message amount is correct - createMsg := pchapi.pushedMessages(createMsgCid) + createMsg := mock.pushedMessages(createMsgCid) require.Equal(t, from, createMsg.Message.From) require.Equal(t, builtin.InitActorAddr, createMsg.Message.To) require.Equal(t, createAmt, createMsg.Message.Value) diff --git a/paychmgr/settle_test.go b/paychmgr/settle_test.go index a9e10ed9e..f922dcccb 100644 --- a/paychmgr/settle_test.go +++ b/paychmgr/settle_test.go @@ -22,11 +22,10 @@ func TestPaychSettle(t *testing.T) { from := tutils.NewIDAddr(t, 101) to := tutils.NewIDAddr(t, 102) - sm := newMockStateManager() - pchapi := newMockPaychAPI() - defer pchapi.close() + mock := newMockManagerAPI() + defer mock.close() - mgr, err := newManager(sm, store, pchapi) + mgr, err := newManager(store, mock) require.NoError(t, err) amt := big.NewInt(10) @@ -35,7 +34,7 @@ func TestPaychSettle(t *testing.T) { // Send channel create response response := testChannelResponse(t, expch) - pchapi.receiveMsgResponse(mcid, response) + mock.receiveMsgResponse(mcid, response) // Get the channel address ch, err := mgr.GetPaychWaitReady(ctx, mcid) @@ -56,7 +55,7 @@ func TestPaychSettle(t *testing.T) { // Send new channel create response response2 := testChannelResponse(t, expch2) - pchapi.receiveMsgResponse(mcid2, response2) + mock.receiveMsgResponse(mcid2, response2) // Make sure the new channel is different from the old channel ch2, err := mgr.GetPaychWaitReady(ctx, mcid2) diff --git a/paychmgr/simple.go b/paychmgr/simple.go index ea65b48b2..2c92d7ccb 100644 --- a/paychmgr/simple.go +++ b/paychmgr/simple.go @@ -8,8 +8,6 @@ import ( "golang.org/x/sync/errgroup" - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin" @@ -25,11 +23,6 @@ import ( "github.com/filecoin-project/lotus/chain/types" ) -type paychApi interface { - StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) - MpoolPushMessage(ctx context.Context, msg *types.Message) (*types.SignedMessage, error) -} - // paychFundsRes is the response to a create channel or add funds request type paychFundsRes struct { channel address.Address diff --git a/paychmgr/state.go b/paychmgr/state.go index 9ba2740e6..1502cc8cb 100644 --- a/paychmgr/state.go +++ b/paychmgr/state.go @@ -12,7 +12,7 @@ import ( ) type stateAccessor struct { - sm StateManagerApi + sm stateManagerAPI } func (ca *stateAccessor) loadPaychState(ctx context.Context, ch address.Address) (*types.Actor, *paych.State, error) { From a467deede6e18411b2189fffb2cb83983a953e74 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 11 Aug 2020 20:20:59 +0300 Subject: [PATCH 023/353] fix typos in comment --- chain/messagepool/selection.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 4d84df2fe..bed084aad 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -58,8 +58,8 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64 return nil, xerrors.Errorf("computing basefee: %w", err) } - // 0. Load messages from the targeti tipset; if it is the same as the current tipset in - // the mpoll, then this is just the pending messages + // 0. Load messages from the target tipset; if it is the same as the current tipset in + // the mpool, then this is just the pending messages pending, err := mp.getPendingMessages(curTs, ts) if err != nil { return nil, err From a45febc06566ea460ad48c620ef2d32849500a12 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 11 Aug 2020 19:32:31 +0200 Subject: [PATCH 024/353] Fix MpoolLocker Signed-off-by: Jakub Sztandera --- node/builder.go | 1 + node/impl/full/mpool.go | 31 ++++++------------------------- node/modules/dtypes/mpool.go | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 25 deletions(-) create mode 100644 node/modules/dtypes/mpool.go diff --git a/node/builder.go b/node/builder.go index 671170e53..aa0a18626 100644 --- a/node/builder.go +++ b/node/builder.go @@ -255,6 +255,7 @@ func Online() Option { Override(new(*peermgr.PeerMgr), peermgr.NewPeerMgr), Override(new(dtypes.Graphsync), modules.Graphsync), + Override(new(*dtypes.MpoolLocker), new(dtypes.MpoolLocker)), Override(RunHelloKey, modules.RunHello), Override(RunBlockSyncKey, modules.RunBlockSync), diff --git a/node/impl/full/mpool.go b/node/impl/full/mpool.go index 20ca271c0..b1d9a58cb 100644 --- a/node/impl/full/mpool.go +++ b/node/impl/full/mpool.go @@ -2,7 +2,6 @@ package full import ( "context" - "sync" "github.com/ipfs/go-cid" "go.uber.org/fx" @@ -13,6 +12,7 @@ import ( "github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/modules/dtypes" ) type MpoolAPI struct { @@ -25,10 +25,7 @@ type MpoolAPI struct { Mpool *messagepool.MessagePool - PushLocks struct { - m map[address.Address]chan struct{} - sync.Mutex - } `name:"verymuchunique" optional:"true"` + PushLocks *dtypes.MpoolLocker } func (a *MpoolAPI) MpoolGetConfig(context.Context) (*types.MpoolConfig, error) { @@ -118,27 +115,11 @@ func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message) (*t if err != nil { return nil, xerrors.Errorf("getting key address: %w", err) } - - a.PushLocks.Lock() - if a.PushLocks.m == nil { - a.PushLocks.m = make(map[address.Address]chan struct{}) + done, err := a.PushLocks.TakeLock(ctx, fromA) + if err != nil { + return nil, xerrors.Errorf("taking lock: %w", err) } - lk, ok := a.PushLocks.m[fromA] - if !ok { - lk = make(chan struct{}, 1) - a.PushLocks.m[msg.From] = lk - } - a.PushLocks.Unlock() - - select { - case lk <- struct{}{}: - case <-ctx.Done(): - return nil, ctx.Err() - } - - defer func() { - <-lk - }() + defer done() } if msg.Nonce != 0 { diff --git a/node/modules/dtypes/mpool.go b/node/modules/dtypes/mpool.go new file mode 100644 index 000000000..1c64449f8 --- /dev/null +++ b/node/modules/dtypes/mpool.go @@ -0,0 +1,35 @@ +package dtypes + +import ( + "context" + "sync" + + "github.com/filecoin-project/go-address" +) + +type MpoolLocker struct { + m map[address.Address]chan struct{} + lk sync.Mutex +} + +func (ml *MpoolLocker) TakeLock(ctx context.Context, a address.Address) (func(), error) { + ml.lk.Lock() + if ml.m == nil { + ml.m = make(map[address.Address]chan struct{}) + } + lk, ok := ml.m[a] + if !ok { + lk = make(chan struct{}, 1) + ml.m[a] = lk + } + ml.lk.Unlock() + + select { + case lk <- struct{}{}: + case <-ctx.Done(): + return nil, ctx.Err() + } + return func() { + <-lk + }, nil +} From 9032163c5a080a15167cbe3a0d5ae632173ba8d1 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 11 Aug 2020 20:47:50 +0300 Subject: [PATCH 025/353] turn probability eyeballing into an actual test --- chain/messagepool/block_proba_test.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/chain/messagepool/block_proba_test.go b/chain/messagepool/block_proba_test.go index 2cc2ecc2a..b39ea587e 100644 --- a/chain/messagepool/block_proba_test.go +++ b/chain/messagepool/block_proba_test.go @@ -4,5 +4,12 @@ import "testing" func TestBlockProbability(t *testing.T) { mp := &MessagePool{} - t.Logf("%+v\n", mp.blockProbabilities(1-0.15)) + bp := mp.blockProbabilities(1 - 0.15) + t.Logf("%+v\n", bp) + for i := 0; i < len(bp)-1; i++ { + if bp[i] < bp[i+1] { + t.Fatalf("expected decreasing block probabilities for this quality: %d %f %f", + i, bp[i], bp[i+1]) + } + } } From 53e06f358a037e71b8dc96fb89fd0fed767251c6 Mon Sep 17 00:00:00 2001 From: Ingar Shu Date: Tue, 11 Aug 2020 13:04:00 -0700 Subject: [PATCH 026/353] client retrieval logging --- api/api_full.go | 3 +- api/apistruct/struct.go | 31 ++++++++--------- api/test/deals.go | 14 ++++++-- cli/client.go | 29 +++++++++++++--- markets/loggers/loggers.go | 9 +++++ node/impl/client/client.go | 69 +++++++++++++++++++++++++++++--------- 6 files changed, 116 insertions(+), 39 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index 654a8620f..2775946de 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -21,6 +21,7 @@ import ( "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/lotus/chain/types" + marketevents "github.com/filecoin-project/lotus/markets/loggers" "github.com/filecoin-project/lotus/node/modules/dtypes" ) @@ -236,7 +237,7 @@ type FullNode interface { // ClientMinerQueryOffer returns a QueryOffer for the specific miner and file. ClientMinerQueryOffer(ctx context.Context, miner address.Address, root cid.Cid, piece *cid.Cid) (QueryOffer, error) // ClientRetrieve initiates the retrieval of a file, as specified in the order. - ClientRetrieve(ctx context.Context, order RetrievalOrder, ref *FileRef) error + ClientRetrieve(ctx context.Context, order RetrievalOrder, ref *FileRef) (<-chan marketevents.RetrievalEvent, error) // ClientQueryAsk returns a signed StorageAsk from the specified miner. ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) // ClientCalcCommP calculates the CommP for a specified file, based on the sector size of the provided miner. diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index a571e4564..a0f50f752 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -15,6 +15,7 @@ import ( "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-jsonrpc/auth" "github.com/filecoin-project/go-multistore" + marketevents "github.com/filecoin-project/lotus/markets/loggers" "github.com/filecoin-project/sector-storage/fsutil" "github.com/filecoin-project/sector-storage/sealtasks" "github.com/filecoin-project/sector-storage/stores" @@ -122,20 +123,20 @@ type FullNodeStruct struct { WalletImport func(context.Context, *types.KeyInfo) (address.Address, error) `perm:"admin"` WalletDelete func(context.Context, address.Address) error `perm:"write"` - ClientImport func(ctx context.Context, ref api.FileRef) (*api.ImportRes, error) `perm:"admin"` - ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"` - ClientRemoveImport func(ctx context.Context, importID multistore.StoreID) error `perm:"admin"` - ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, error) `perm:"write"` - ClientFindData func(ctx context.Context, root cid.Cid, piece *cid.Cid) ([]api.QueryOffer, error) `perm:"read"` - ClientMinerQueryOffer func(ctx context.Context, miner address.Address, root cid.Cid, piece *cid.Cid) (api.QueryOffer, error) `perm:"read"` - ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"` - ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"` - ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"` - ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error `perm:"admin"` - ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"` - ClientCalcCommP func(ctx context.Context, inpath string, miner address.Address) (*api.CommPRet, error) `perm:"read"` - ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"` - ClientDealSize func(ctx context.Context, root cid.Cid) (api.DataSize, error) `perm:"read"` + ClientImport func(ctx context.Context, ref api.FileRef) (*api.ImportRes, error) `perm:"admin"` + ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"` + ClientRemoveImport func(ctx context.Context, importID multistore.StoreID) error `perm:"admin"` + ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, error) `perm:"write"` + ClientFindData func(ctx context.Context, root cid.Cid, piece *cid.Cid) ([]api.QueryOffer, error) `perm:"read"` + ClientMinerQueryOffer func(ctx context.Context, miner address.Address, root cid.Cid, piece *cid.Cid) (api.QueryOffer, error) `perm:"read"` + ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"` + ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"` + ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"` + ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) `perm:"admin"` + ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"` + ClientCalcCommP func(ctx context.Context, inpath string, miner address.Address) (*api.CommPRet, error) `perm:"read"` + ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"` + ClientDealSize func(ctx context.Context, root cid.Cid) (api.DataSize, error) `perm:"read"` StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"` StateMinerSectors func(context.Context, address.Address, *abi.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"` @@ -415,7 +416,7 @@ func (c *FullNodeStruct) ClientListDeals(ctx context.Context) ([]api.DealInfo, e return c.Internal.ClientListDeals(ctx) } -func (c *FullNodeStruct) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error { +func (c *FullNodeStruct) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) { return c.Internal.ClientRetrieve(ctx, order, ref) } diff --git a/api/test/deals.go b/api/test/deals.go index 37ff780f7..0abc0a419 100644 --- a/api/test/deals.go +++ b/api/test/deals.go @@ -398,9 +398,17 @@ func testRetrieval(t *testing.T, ctx context.Context, err error, client *impl.Fu Path: filepath.Join(rpath, "ret"), IsCAR: carExport, } - err = client.ClientRetrieve(ctx, offers[0].Order(caddr), ref) - if err != nil { - t.Fatalf("%+v", err) + updates, err := client.ClientRetrieve(ctx, offers[0].Order(caddr), ref) + for { + select { + case update, ok := <-updates: + if !ok { + break + } + if update.Err != nil { + t.Fatalf("%+v", err) + } + } } rdata, err := ioutil.ReadFile(filepath.Join(rpath, "ret")) diff --git a/cli/client.go b/cli/client.go index e35344977..97db9bfe5 100644 --- a/cli/client.go +++ b/cli/client.go @@ -12,6 +12,7 @@ import ( "github.com/docker/go-units" "github.com/fatih/color" + "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/ipfs/go-cid" "github.com/ipfs/go-cidutil/cidenc" "github.com/libp2p/go-libp2p-core/peer" @@ -837,12 +838,32 @@ var clientRetrieveCmd = &cli.Command{ Path: cctx.Args().Get(1), IsCAR: cctx.Bool("car"), } - if err := fapi.ClientRetrieve(ctx, offer.Order(payer), ref); err != nil { - return xerrors.Errorf("Retrieval Failed: %w", err) + updates, err := fapi.ClientRetrieve(ctx, offer.Order(payer), ref) + if err != nil { + return xerrors.Errorf("error setting up retrieval: %w", err) } - fmt.Println("Success") - return nil + for { + select { + case evt, chOpen := <-updates: + + fmt.Printf("Retrieval Event: %s, State: %s, BytesReceived: %d, PaymentSent: %s\n", + retrievalmarket.ClientEvents[evt.Event], + retrievalmarket.DealStatuses[evt.Status], + evt.BytesReceived, + evt.FundsSpent.String(), + ) + + if !chOpen { + fmt.Println("Success") + return nil + } + + if evt.Err != nil { + return xerrors.Errorf("Retrieval Failed: %w", err) + } + } + } }, } diff --git a/markets/loggers/loggers.go b/markets/loggers/loggers.go index 8ebf54fd2..58dc6d97d 100644 --- a/markets/loggers/loggers.go +++ b/markets/loggers/loggers.go @@ -3,6 +3,7 @@ package marketevents import ( "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/specs-actors/actors/abi" logging "github.com/ipfs/go-log/v2" ) @@ -27,3 +28,11 @@ func RetrievalClientLogger(event retrievalmarket.ClientEvent, deal retrievalmark func RetrievalProviderLogger(event retrievalmarket.ProviderEvent, deal retrievalmarket.ProviderDealState) { log.Infow("retrieval event", "name", retrievalmarket.ProviderEvents[event], "deal ID", deal.ID, "receiver", deal.Receiver, "state", retrievalmarket.DealStatuses[deal.Status], "message", deal.Message) } + +type RetrievalEvent struct { + Event retrievalmarket.ClientEvent + Status retrievalmarket.DealStatus + BytesReceived uint64 + FundsSpent abi.TokenAmount + Err error +} diff --git a/node/impl/client/client.go b/node/impl/client/client.go index cf13c2bfb..befcae0b1 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -35,11 +35,13 @@ import ( "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-multistore" "github.com/filecoin-project/go-padreader" - "github.com/filecoin-project/sector-storage/ffiwrapper" "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin/miner" + marketevents "github.com/filecoin-project/lotus/markets/loggers" + "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/store" @@ -398,11 +400,24 @@ func (a *API) ClientListImports(ctx context.Context) ([]api.Import, error) { return out, nil } -func (a *API) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error { +func (a *API) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) { + events := make(chan marketevents.RetrievalEvent) + go a.clientRetrieve(ctx, order, ref, events) + return events, nil +} + +func (a *API) clientRetrieve(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef, events chan marketevents.RetrievalEvent) { + defer close(events) + + finish := func(e error) { + events <- marketevents.RetrievalEvent{Err: e} + } + if order.MinerPeer.ID == "" { mi, err := a.StateMinerInfo(ctx, order.Miner, types.EmptyTSK) if err != nil { - return err + finish(err) + return } order.MinerPeer = retrievalmarket.RetrievalPeer{ @@ -412,7 +427,8 @@ func (a *API) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref } if order.Size == 0 { - return xerrors.Errorf("cannot make retrieval deal for zero bytes") + finish(xerrors.Errorf("cannot make retrieval deal for zero bytes")) + return } /*id, st, err := a.imgr().NewStore() @@ -427,6 +443,14 @@ func (a *API) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref unsubscribe := a.Retrieval.SubscribeToEvents(func(event rm.ClientEvent, state rm.ClientDealState) { if state.PayloadCID.Equals(order.Root) { + + events <- marketevents.RetrievalEvent{ + Event: event, + Status: state.Status, + BytesReceived: state.TotalReceived, + FundsSpent: state.FundsSpent, + } + switch state.Status { case rm.DealStatusCompleted: retrievalResult <- nil @@ -444,12 +468,14 @@ func (a *API) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref params, err := rm.NewParamsV1(ppb, order.PaymentInterval, order.PaymentIntervalIncrease, shared.AllSelector(), order.Piece, order.UnsealPrice) if err != nil { - return xerrors.Errorf("Error in retrieval params: %s", err) + finish(xerrors.Errorf("Error in retrieval params: %s", err)) + return } store, err := a.RetrievalStoreMgr.NewStore() if err != nil { - return xerrors.Errorf("Error setting up new store: %w", err) + finish(xerrors.Errorf("Error setting up new store: %w", err)) + return } defer func() { @@ -467,14 +493,18 @@ func (a *API) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref store.StoreID()) if err != nil { - return xerrors.Errorf("Retrieve failed: %w", err) + finish(xerrors.Errorf("Retrieve failed: %w", err)) + return } + select { case <-ctx.Done(): - return xerrors.New("Retrieval Timed Out") + finish(xerrors.New("Retrieval Timed Out")) + return case err := <-retrievalResult: if err != nil { - return xerrors.Errorf("Retrieve: %w", err) + finish(xerrors.Errorf("Retrieve: %w", err)) + return } } @@ -482,7 +512,8 @@ func (a *API) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref // If ref is nil, it only fetches the data into the configured blockstore. if ref == nil { - return nil + finish(nil) + return } rdag := store.DAGService() @@ -490,24 +521,30 @@ func (a *API) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref if ref.IsCAR { f, err := os.OpenFile(ref.Path, os.O_CREATE|os.O_WRONLY, 0644) if err != nil { - return err + finish(err) + return } err = car.WriteCar(ctx, rdag, []cid.Cid{order.Root}, f) if err != nil { - return err + finish(err) + return } - return f.Close() + finish(f.Close()) + return } nd, err := rdag.Get(ctx, order.Root) if err != nil { - return xerrors.Errorf("ClientRetrieve: %w", err) + finish(xerrors.Errorf("ClientRetrieve: %w", err)) + return } file, err := unixfile.NewUnixfsFile(ctx, rdag, nd) if err != nil { - return xerrors.Errorf("ClientRetrieve: %w", err) + finish(xerrors.Errorf("ClientRetrieve: %w", err)) + return } - return files.WriteTo(file, ref.Path) + finish(files.WriteTo(file, ref.Path)) + return } func (a *API) ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) { From f018e870dc4348ba7940e11faa5916930adbb38e Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 11 Aug 2020 23:35:06 +0200 Subject: [PATCH 027/353] Address review Signed-off-by: Jakub Sztandera --- chain/types/blockheader.go | 10 ++++++++++ miner/miner.go | 10 +--------- node/impl/full/mpool.go | 1 - 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/chain/types/blockheader.go b/chain/types/blockheader.go index 8950fd91a..36b43c012 100644 --- a/chain/types/blockheader.go +++ b/chain/types/blockheader.go @@ -22,6 +22,16 @@ type Ticket struct { VRFProof []byte } +func (t *Ticket) Quality() float64 { + ticketHash := blake2b.Sum256(t.VRFProof) + ticketNum := BigFromBytes(ticketHash[:]).Int + ticketDenu := big.NewInt(1) + ticketDenu.Lsh(ticketDenu, 256) + tv, _ := new(big.Rat).SetFrac(ticketNum, ticketDenu).Float64() + tq := 1 - tv + return tq +} + type BeaconEntry struct { Round uint64 Data []byte diff --git a/miner/miner.go b/miner/miner.go index 077e18638..27d3c040d 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -6,12 +6,10 @@ import ( "crypto/rand" "encoding/binary" "fmt" - "math/big" "sync" "time" "github.com/filecoin-project/lotus/chain/gen/slashfilter" - "github.com/minio/blake2b-simd" "github.com/filecoin-project/go-address" "github.com/filecoin-project/specs-actors/actors/abi" @@ -392,14 +390,8 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*types.BlockMsg, return nil, xerrors.Errorf("failed to compute winning post proof: %w", err) } - ticketHash := blake2b.Sum256(ticket.VRFProof) - ticketNum := types.BigFromBytes(ticketHash[:]).Int - ticketDenu := big.NewInt(1) - ticketDenu.Lsh(ticketDenu, 256) - tq, _ := new(big.Rat).SetFrac(ticketNum, ticketDenu).Float64() - tq = 1 - tq // get pending messages early, - msgs, err := m.api.MpoolSelect(context.TODO(), base.TipSet.Key(), tq) + msgs, err := m.api.MpoolSelect(context.TODO(), base.TipSet.Key(), ticket.Quality()) if err != nil { return nil, xerrors.Errorf("failed to select messages for block: %w", err) } diff --git a/node/impl/full/mpool.go b/node/impl/full/mpool.go index b1d9a58cb..cd6adef6d 100644 --- a/node/impl/full/mpool.go +++ b/node/impl/full/mpool.go @@ -43,7 +43,6 @@ func (a *MpoolAPI) MpoolSelect(ctx context.Context, tsk types.TipSetKey, ticketQ return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - // TODO FIXME compute (or pass in) the actual ticket quality! return a.Mpool.SelectMessages(ts, ticketQuality) } From 02b0c8dd94f06dfa772922e14d0fa0df36a9e162 Mon Sep 17 00:00:00 2001 From: Ingar Shu Date: Tue, 11 Aug 2020 13:48:56 -0700 Subject: [PATCH 028/353] Watch context for completion also --- api/test/deals.go | 12 +++--------- cli/client.go | 4 +++- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/api/test/deals.go b/api/test/deals.go index 0abc0a419..5b5f04e41 100644 --- a/api/test/deals.go +++ b/api/test/deals.go @@ -399,15 +399,9 @@ func testRetrieval(t *testing.T, ctx context.Context, err error, client *impl.Fu IsCAR: carExport, } updates, err := client.ClientRetrieve(ctx, offers[0].Order(caddr), ref) - for { - select { - case update, ok := <-updates: - if !ok { - break - } - if update.Err != nil { - t.Fatalf("%+v", err) - } + for update := range updates { + if update.Err != nil { + t.Fatalf("%+v", err) } } diff --git a/cli/client.go b/cli/client.go index 97db9bfe5..5c2574364 100644 --- a/cli/client.go +++ b/cli/client.go @@ -860,8 +860,10 @@ var clientRetrieveCmd = &cli.Command{ } if evt.Err != nil { - return xerrors.Errorf("Retrieval Failed: %w", err) + return xerrors.Errorf("retrieval failed: %w", err) } + case <-ctx.Done(): + return xerrors.Errorf("retrieval timed out") } } }, From 2efb18f6775bd32e6370bed29ba98b91df0ff7ee Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 11 Aug 2020 23:55:06 +0200 Subject: [PATCH 029/353] Small fixes to mpool Trim Signed-off-by: Jakub Sztandera --- chain/messagepool/selection.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index bed084aad..7bfaaf811 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -811,12 +811,15 @@ func (mc *msgChain) Trim(gasLimit int64, mp *MessagePool, baseFee types.BigInt, mc.gasLimit -= mc.msgs[i].Message.GasLimit if mc.gasLimit > 0 { bp := 1.0 - if mc.effPerf != 0 { + if mc.gasPerf != 0 { // prevent div by 0 bp = mc.effPerf / mc.gasPerf } mc.gasPerf = mp.getGasPerf(mc.gasReward, mc.gasLimit) - mc.effPerf = bp * mc.gasPerf + + if mc.effPerf != 0 { // keep effPerf 0 if it is 0 + mc.effPerf = bp * mc.gasPerf + } } else { mc.gasPerf = 0 } From 1fc768fb32d1d9cfd9046540441bc6739ef6ccc3 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 11 Aug 2020 15:07:17 -0700 Subject: [PATCH 030/353] add env vars to configure chain store cache sizes --- chain/store/index.go | 17 ++++++++++++++++- chain/store/store.go | 15 ++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/chain/store/index.go b/chain/store/index.go index 7edbf251f..8f3e88417 100644 --- a/chain/store/index.go +++ b/chain/store/index.go @@ -2,6 +2,8 @@ package store import ( "context" + "os" + "strconv" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/specs-actors/actors/abi" @@ -9,6 +11,19 @@ import ( "golang.org/x/xerrors" ) +var DefaultChainIndexCacheSize = 32 << 10 + +func init() { + if s := os.Getenv("LOTUS_CHAIN_INDEX_CACHE"); s != "" { + lcic, err := strconv.Atoi(s) + if err != nil { + log.Errorf("failed to parse 'LOTUS_CHAIN_INDEX_CACHE' env var: %s", err) + } + DefaultChainIndexCacheSize = lcic + } + +} + type ChainIndex struct { skipCache *lru.ARCCache @@ -19,7 +34,7 @@ type ChainIndex struct { type loadTipSetFunc func(types.TipSetKey) (*types.TipSet, error) func NewChainIndex(lts loadTipSetFunc) *ChainIndex { - sc, _ := lru.NewARC(8192) + sc, _ := lru.NewARC(DefaultChainIndexCacheSize) return &ChainIndex{ skipCache: sc, loadTipSet: lts, diff --git a/chain/store/store.go b/chain/store/store.go index f2ebf2b41..af7deb4d0 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -7,6 +7,7 @@ import ( "encoding/json" "io" "os" + "strconv" "sync" "github.com/filecoin-project/specs-actors/actors/crypto" @@ -50,6 +51,18 @@ var log = logging.Logger("chainstore") var chainHeadKey = dstore.NewKey("head") var blockValidationCacheKeyPrefix = dstore.NewKey("blockValidation") +var DefaultTipSetCacheSize = 8192 + +func init() { + if s := os.Getenv("LOTUS_CHAIN_TIPSET_CACHE"); s != "" { + tscs, err := strconv.Atoi(s) + if err != nil { + log.Errorf("failed to parse 'LOTUS_CHAIN_TIPSET_CACHE' env var: %s", err) + } + DefaultTipSetCacheSize = tscs + } +} + // ReorgNotifee represents a callback that gets called upon reorgs. type ReorgNotifee func(rev, app []*types.TipSet) error @@ -88,7 +101,7 @@ type ChainStore struct { func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls runtime.Syscalls) *ChainStore { c, _ := lru.NewARC(2048) - tsc, _ := lru.NewARC(4096) + tsc, _ := lru.NewARC(DefaultTipSetCacheSize) cs := &ChainStore{ bs: bs, ds: ds, From f537c48f93d059e30f9d1c8164671fefcade7923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 11 Aug 2020 23:26:53 +0200 Subject: [PATCH 031/353] v28 Proofs --- build/proof-params/parameters.json | 182 ++++++++++++++--------------- extern/filecoin-ffi | 2 +- go.sum | 29 +++++ 3 files changed, 121 insertions(+), 92 deletions(-) diff --git a/build/proof-params/parameters.json b/build/proof-params/parameters.json index b632c17e8..1d4584454 100644 --- a/build/proof-params/parameters.json +++ b/build/proof-params/parameters.json @@ -1,152 +1,152 @@ { - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.params": { - "cid": "QmeDRyxek34F1H6xJY6AkFdWvPsy5F6dKTrebV3ZtWT4ky", - "digest": "f5827f2d8801c62c831e0f972f6dc8bb", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.params": { + "cid": "QmVxjFRyhmyQaZEtCh7nk2abc7LhFkzhnRX4rcHqCCpikR", + "digest": "7610b9f82bfc88405b7a832b651ce2f6", "sector_size": 2048 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.vk": { - "cid": "QmUw1ZmG4BBbX19MsbH3zAEGKUc42iFJc5ZAyomDHeJTsA", - "digest": "398fecdb4b2de445125852bc3c080b35", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0170db1f394b35d995252228ee359194b13199d259380541dc529fb0099096b0.vk": { + "cid": "QmcS5JZs8X3TdtkEBpHAdUYjdNDqcL7fWQFtQz69mpnu2X", + "digest": "0e0958009936b9d5e515ec97b8cb792d", "sector_size": 2048 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.params": { - "cid": "QmUeNKp9YZpiAFm81RV5KuxH1FDGJx2DuwcbU2XNSZLLSv", - "digest": "2b6d2972ac9e862e8134d98fb695b0c5", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.params": { + "cid": "QmUiRx71uxfmUE8V3H9sWAsAXoM88KR4eo1ByvvcFNeTLR", + "digest": "1a7d4a9c8a502a497ed92a54366af33f", "sector_size": 536870912 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.vk": { - "cid": "QmQaQmTXX995Akd66ggtJY5bNx6Gkxk8P34JTdMMq8393G", - "digest": "3688c9eb256b7b17f411dad78d5ef74a", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-0cfb4f178bbb71cf2ecfcd42accce558b27199ab4fb59cb78f2483fe21ef36d9.vk": { + "cid": "QmfCeddjFpWtavzfEzZpJfzSajGNwfL4RjFXWAvA9TSnTV", + "digest": "4dae975de4f011f101f5a2f86d1daaba", "sector_size": 536870912 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.params": { - "cid": "QmfEYTMSkwGJTumQx26iKXGNKiYh3mmAC4SkdybZpJCj5p", - "digest": "09bff16aed893349d94485cfae366a9c", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.params": { + "cid": "QmcSTqDcFVLGGVYz1njhUZ7B6fkKtBumsLUwx4nkh22TzS", + "digest": "82c88066be968bb550a05e30ff6c2413", "sector_size": 2048 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.vk": { - "cid": "QmP4ThPieSUJyRanjibWpT5R5cCMzMAU4j8Y7kBn7CSW1Q", - "digest": "142f2f7e8f1b1779290315cabfd2c803", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-3ea05428c9d11689f23529cde32fd30aabd50f7d2c93657c1d3650bca3e8ea9e.vk": { + "cid": "QmSTCXF2ipGA3f6muVo6kHc2URSx6PzZxGUqu7uykaH5KU", + "digest": "ffd79788d614d27919ae5bd2d94eacb6", "sector_size": 2048 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.params": { - "cid": "QmcAixrHsz29DgvtZiMc2kQjvPRvWxYUp36QYmRDZbmREm", - "digest": "8f987f64d434365562180b96ec12e299", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.params": { + "cid": "QmU9SBzJNrcjRFDiFc4GcApqdApN6z9X7MpUr66mJ2kAJP", + "digest": "700171ecf7334e3199437c930676af82", "sector_size": 8388608 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.vk": { - "cid": "QmT4iFnbL6r4txS5PXsiV7NTzbhCxHy54PvdkJJGV2VFXb", - "digest": "94b6c24ac01924f4feeecedd16b5d77d", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-50c7368dea9593ed0989e70974d28024efa9d156d585b7eea1be22b2e753f331.vk": { + "cid": "QmbmUMa3TbbW3X5kFhExs6WgC4KeWT18YivaVmXDkB6ANG", + "digest": "79ebb55f56fda427743e35053edad8fc", "sector_size": 8388608 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.params": { - "cid": "QmbjFst6SFCK1KsTQrfwPdxf3VTNa1raed574tEZZ9PoyQ", - "digest": "2c245fe8179839dd6c6cdea207c67ae8", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.params": { + "cid": "QmdNEL2RtqL52GQNuj8uz6mVj5Z34NVnbaJ1yMyh1oXtBx", + "digest": "c49499bb76a0762884896f9683403f55", "sector_size": 8388608 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.vk": { - "cid": "QmQJKmvZN1a5cQ1Nw6CDyXs3nuRPzvyU5NvCFMUL2BfcZC", - "digest": "56ae47bfda53bb8d22981ed8d8d27d72", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-5294475db5237a2e83c3e52fd6c2b03859a1831d45ed08c4f35dbf9a803165a9.vk": { + "cid": "QmUiVYCQUgr6Y13pZFr8acWpSM4xvTXUdcvGmxyuHbKhsc", + "digest": "34d4feeacd9abf788d69ef1bb4d8fd00", "sector_size": 8388608 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.params": { - "cid": "QmQCABxeTpdvXTyjDyk7nPBxkQzCh7MXfGztWnSXEPKMLW", - "digest": "7e6b2eb5ecbb11ac651ad66ebbb2075a", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.params": { + "cid": "QmVgCsJFRXKLuuUhT3aMYwKVGNA9rDeR6DCrs7cAe8riBT", + "digest": "827359440349fe8f5a016e7598993b79", "sector_size": 536870912 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.vk": { - "cid": "QmPBweyugh5Sx4umk8ULhgEGbjY8xmWLfU6M7EMpc8Mad6", - "digest": "94a8d9e25a9ab9674d339833664eba25", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-0-0-7d739b8cf60f1b0709eeebee7730e297683552e4b69cab6984ec0285663c5781.vk": { + "cid": "QmfA31fbCWojSmhSGvvfxmxaYCpMoXP95zEQ9sLvBGHNaN", + "digest": "bd2cd62f65c1ab84f19ca27e97b7c731", "sector_size": 536870912 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.params": { - "cid": "QmY5yax1E9KymBnCeHksE9Zi8NieZbmwcpoDGoabkeeb9h", - "digest": "c909ea9e3fe25ab9b391a64593afdbba", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.params": { + "cid": "QmaUmfcJt6pozn8ndq1JVBzLRjRJdHMTPd4foa8iw5sjBZ", + "digest": "2cf49eb26f1fee94c85781a390ddb4c8", "sector_size": 34359738368 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.vk": { - "cid": "QmXnPo4yH5mwMguwrvqgRfduSttbmPrXtbBfbwU21wQWHt", - "digest": "caf900461e988bbf86dbcaca087b7864", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-0377ded656c6f524f1618760bffe4e0a1c51d5a70c4509eedae8a27555733edc.vk": { + "cid": "QmR9i9KL3vhhAqTBGj1bPPC7LvkptxrH9RvxJxLN1vvsBE", + "digest": "0f8ec542485568fa3468c066e9fed82b", "sector_size": 34359738368 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.params": { - "cid": "QmZtzzPWwmZEgR7MSMvXRbt9KVK8k4XZ5RLWHybHJW9SdE", - "digest": "a2844f0703f186d143a06146a04577d8", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.params": { + "cid": "Qmdtczp7p4wrbDofmHdGhiixn9irAcN77mV9AEHZBaTt1i", + "digest": "d84f79a16fe40e9e25a36e2107bb1ba0", "sector_size": 34359738368 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.vk": { - "cid": "QmWxEA7EdQCUJTzjNpxg5XTF45D2uVyYnN1QRUb5TRYU8M", - "digest": "2306247a1e616dbe07f01b88196c2044", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-0-559e581f022bb4e4ec6e719e563bf0e026ad6de42e56c18714a2c692b1b88d7e.vk": { + "cid": "QmZCvxKcKP97vDAk8Nxs9R1fWtqpjQrAhhfXPoCi1nkDoF", + "digest": "fc02943678dd119e69e7fab8420e8819", "sector_size": 34359738368 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.params": { - "cid": "QmP676KwuvyF9Y64uJnXvLtvD1xcuWQ6wD23RzYtQ6dd4f", - "digest": "215b1c667a4f46a1d0178338df568615", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.params": { + "cid": "QmeAN4vuANhXsF8xP2Lx5j2L6yMSdogLzpcvqCJThRGK1V", + "digest": "3810b7780ac0e299b22ae70f1f94c9bc", "sector_size": 68719476736 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.vk": { - "cid": "QmPvPwbJtcSGyqB1rQJhSF5yvFbX9ZBSsHVej5F8JUyHUJ", - "digest": "0c9c423b28b1455fcbc329a1045fd4dd", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-2627e4006b67f99cef990c0a47d5426cb7ab0a0ad58fc1061547bf2d28b09def.vk": { + "cid": "QmWV8rqZLxs1oQN9jxNWmnT1YdgLwCcscv94VARrhHf1T7", + "digest": "59d2bf1857adc59a4f08fcf2afaa916b", "sector_size": 68719476736 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.params": { - "cid": "QmUxPQfvckzm1t6MFRdDZ1fDK5UJzAjK7pTZ97cwyachdr", - "digest": "965132f51ae445b0e6d32692b7561995", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.params": { + "cid": "QmVkrXc1SLcpgcudK5J25HH93QvR9tNsVhVTYHm5UymXAz", + "digest": "2170a91ad5bae22ea61f2ea766630322", "sector_size": 68719476736 }, - "v27-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.vk": { - "cid": "QmTxq2EBnQWb5R8tS4MHdchj4vNfLYGoSXxwJFvs5xgW4K", - "digest": "fc8c3d26e0e56373ad96cb41520d55a6", + "v28-proof-of-spacetime-fallback-merkletree-poseidon_hasher-8-8-2-b62098629d07946e9028127e70295ed996fe3ed25b0f9f88eb610a0ab4385a3c.vk": { + "cid": "QmbfQjPD7EpzjhWGmvWAsyN2mAZ4PcYhsf3ujuhU9CSuBm", + "digest": "6d3789148fb6466d07ee1e24d6292fd6", "sector_size": 68719476736 }, - "v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.params": { - "cid": "QmRjgZHERgqGoRagR788Kh6ybi26csVYa8mqbqhmZm57Jx", - "digest": "cfc7b0897d1eee48c586f7beb89e67f7", + "v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.params": { + "cid": "QmWceMgnWYLopMuM4AoGMvGEau7tNe5UK83XFjH5V9B17h", + "digest": "434fb1338ecfaf0f59256f30dde4968f", "sector_size": 2048 }, - "v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.vk": { - "cid": "QmNjvnvFP7KgovHUddULoB19fBHT81iz7NcUbzEHZUUPsm", - "digest": "fb59bd061c987eac7068008c44de346b", + "v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-032d3138d22506ec0082ed72b2dcba18df18477904e35bafee82b3793b06832f.vk": { + "cid": "QmamahpFCstMUqHi2qGtVoDnRrsXhid86qsfvoyCTKJqHr", + "digest": "dc1ade9929ade1708238f155343044ac", "sector_size": 2048 }, - "v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.params": { - "cid": "QmTpRPBA4dt8fgGpcVzi4L1KA1U2eBHCE8WVmS2GUygMvT", - "digest": "36d465915b0afbf96bd08e7915e00952", + "v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.params": { + "cid": "QmYBpTt7LWNAWr1JXThV5VxX7wsQFLd1PHrGYVbrU1EZjC", + "digest": "6c77597eb91ab936c1cef4cf19eba1b3", "sector_size": 536870912 }, - "v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.vk": { - "cid": "QmRzDyVfQCLsxspoVsed5bcQRsG6KiktngJfcNBL3TJPZe", - "digest": "99d16df0eb6a7e227a4f4570c4f6b6f1", + "v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-6babf46ce344ae495d558e7770a585b2382d54f225af8ed0397b8be7c3fcd472.vk": { + "cid": "QmWionkqH2B6TXivzBSQeSyBxojaiAFbzhjtwYRrfwd8nH", + "digest": "065179da19fbe515507267677f02823e", "sector_size": 536870912 }, - "v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.params": { - "cid": "QmV8ZjTSGzDUWmFvsq9NSyPBR7eDDUcvCPNgj2yE7HMAFu", - "digest": "34f3ddf1d1c9f41c0cd73b91e8b4bc27", + "v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.params": { + "cid": "QmPXAPPuQtuQz7Zz3MHMAMEtsYwqM1o9H1csPLeiMUQwZH", + "digest": "09e612e4eeb7a0eb95679a88404f960c", "sector_size": 8388608 }, - "v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.vk": { - "cid": "QmTa3VbjTiqJWU6r4WKayaQrUaaBsrpp5UDqYvPDd2C5hs", - "digest": "ec62d59651daa5631d3d1e9c782dd940", + "v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-0-0-sha256_hasher-ecd683648512ab1765faa2a5f14bab48f676e633467f0aa8aad4b55dcb0652bb.vk": { + "cid": "QmYCuipFyvVW1GojdMrjK1JnMobXtT4zRCZs1CGxjizs99", + "digest": "b687beb9adbd9dabe265a7e3620813e4", "sector_size": 8388608 }, - "v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.params": { - "cid": "Qmf8ngfArxrv9tFWDqBcNegdBMymvuakwyHKd1pbW3pbsb", - "digest": "a16d6f4c6424fb280236739f84b24f97", + "v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.params": { + "cid": "QmengpM684XLQfG8754ToonszgEg2bQeAGUan5uXTHUQzJ", + "digest": "6a388072a518cf46ebd661f5cc46900a", "sector_size": 34359738368 }, - "v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.vk": { - "cid": "QmfQgVFerArJ6Jupwyc9tKjLD9n1J9ajLHBdpY465tRM7M", - "digest": "7a139d82b8a02e35279d657e197f5c1f", + "v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-0-sha256_hasher-82a357d2f2ca81dc61bb45f4a762807aedee1b0a53fd6c4e77b46a01bfef7820.vk": { + "cid": "Qmf93EMrADXAK6CyiSfE8xx45fkMfR3uzKEPCvZC1n2kzb", + "digest": "0c7b4aac1c40fdb7eb82bc355b41addf", "sector_size": 34359738368 }, - "v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.params": { - "cid": "QmfDha8271nXJn14Aq3qQeghjMBWbs6HNSGa6VuzCVk4TW", - "digest": "5d3cd3f107a3bea8a96d1189efd2965c", + "v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.params": { + "cid": "QmS7ye6Ri2MfFzCkcUJ7FQ6zxDKuJ6J6B8k5PN7wzSR9sX", + "digest": "1801f8a6e1b00bceb00cc27314bb5ce3", "sector_size": 68719476736 }, - "v27-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.vk": { - "cid": "QmRVtTtiFzHJTHurYzaCvetGAchux9cktixT4aGHthN6Zt", - "digest": "62c366405404e60f171e661492740b1c", + "v28-stacked-proof-of-replication-merkletree-poseidon_hasher-8-8-2-sha256_hasher-96f1b4a04c5c51e4759bbf224bbc2ef5a42c7100f16ec0637123f16a845ddfb2.vk": { + "cid": "QmehSmC6BhrgRZakPDta2ewoH9nosNzdjCqQRXsNFNUkLN", + "digest": "a89884252c04c298d0b3c81bfd884164", "sector_size": 68719476736 } -} \ No newline at end of file +} diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index cddc56607..d70d49a74 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit cddc56607e1d851ea6d09d49404bd7db70cb3c2e +Subproject commit d70d49a742cde20bda233dbc63abebda0e8e4406 diff --git a/go.sum b/go.sum index ca9f0df33..887010d29 100644 --- a/go.sum +++ b/go.sum @@ -1230,6 +1230,8 @@ github.com/prometheus/procfs v0.1.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/raulk/clock v1.1.0 h1:dpb29+UKMbLqiU/jqIJptgLR1nn23HLgMY0sTCDza5Y= github.com/raulk/clock v1.1.0/go.mod h1:3MpVxdZ/ODBQDxbN+kzshf5OSZwPjtMDx6BBXBmOeY0= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -1327,6 +1329,8 @@ github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFd github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g= +github.com/tj/go-spin v1.1.0 h1:lhdWZsvImxvZ3q1C5OIB7d72DuOwP4O2NdBg9PyzNds= +github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-client-go v2.23.1+incompatible h1:uArBYHQR0HqLFFAypI7RsWTzPSj/bDpmZZuQjMLSg1A= @@ -1395,11 +1399,16 @@ github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1: github.com/whyrusleeping/yamux v1.1.5/go.mod h1:E8LnQQ8HKx5KD29HZFUwM1PxCOdPRzGwur1mcYhXcD8= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/c-for-go v0.0.0-20200718154222-87b0065af829 h1:wb7xrDzfkLgPHsSEBm+VSx6aDdi64VtV0xvP0E6j8bk= +github.com/xlab/c-for-go v0.0.0-20200718154222-87b0065af829/go.mod h1:h/1PEBwj7Ym/8kOuMWvO2ujZ6Lt+TMbySEXNhjjR87I= +github.com/xlab/pkgconfig v0.0.0-20170226114623-cea12a0fd245 h1:Sw125DKxZhPUI4JLlWugkzsrlB50jR9v2khiD9FxuSo= +github.com/xlab/pkgconfig v0.0.0-20170226114623-cea12a0fd245/go.mod h1:C+diUUz7pxhNY6KAoLgrTYARGWnt82zWTylZlxT92vk= github.com/xorcare/golden v0.6.0/go.mod h1:7T39/ZMvaSEZlBPoYfVFmsBLmUl3uz9IuzWj/U6FtvQ= github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 h1:oWgZJmC1DorFZDpfMfWg7xk29yEOZiXmo/wZl+utTI8= github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542/go.mod h1:7T39/ZMvaSEZlBPoYfVFmsBLmUl3uz9IuzWj/U6FtvQ= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw= go.dedis.ch/kyber/v3 v3.0.4/go.mod h1:OzvaEnPvKlyrWyp3kGXlFdp7ap1VC6RkZDTaPikqhsQ= @@ -1482,6 +1491,8 @@ golang.org/x/crypto v0.0.0-20200427165652-729f1e841bcc/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1515,6 +1526,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1557,6 +1570,8 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200519113804-d87ec0cfa476/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1695,6 +1710,8 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200318150045-ba25ddc85566/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4 h1:kDtqNkeBrZb8B+atrj50B5XLHpzXXqcCdZPP/ApQ5NY= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200711155855-7342f9734a7d h1:F3OmlXCzYtG9YE6tXDnUOlJBzVzHF8EcmZ1yTJlcgIk= +golang.org/x/tools v0.0.0-20200711155855-7342f9734a7d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= @@ -1808,6 +1825,8 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= @@ -1825,6 +1844,16 @@ howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqp howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= +modernc.org/cc v1.0.0 h1:nPibNuDEx6tvYrUAtvDTTw98rx5juGsa5zuDnKwEEQQ= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0 h1:wWpDlbK8ejRfSyi0frMyhilD3JBvtcx2AdGDnU+JtsE= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.1.1 h1:FeylZSVX8S+58VsyJlkEj2bcpdytmp9MmDKZkKx8OIE= +modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/strutil v1.1.0 h1:+1/yCzZxY2pZwwrsbH+4T7BQMoLQ9QiBshRC9eicYsc= +modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0 h1:7ccXrupWZIS3twbUGrtKmHS2DXY6xegFua+6O3xgAFU= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From 922d568e12bc65a9b97858eab050208e51a90237 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Tue, 11 Aug 2020 18:59:12 -0400 Subject: [PATCH 032/353] Add checks to ValidForBlockInclusion --- chain/types/message.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/chain/types/message.go b/chain/types/message.go index aab3020d5..b806fa9e4 100644 --- a/chain/types/message.go +++ b/chain/types/message.go @@ -142,6 +142,10 @@ func (m *Message) ValidForBlockInclusion(minGas int64) error { return xerrors.New("'From' address cannot be empty") } + if m.Value.Int == nil { + return xerrors.New("'Value' cannot be nil") + } + if m.Value.LessThan(big.Zero()) { return xerrors.New("'Value' field cannot be negative") } @@ -150,10 +154,18 @@ func (m *Message) ValidForBlockInclusion(minGas int64) error { return xerrors.New("'Value' field cannot be greater than total filecoin supply") } + if m.GasFeeCap.Int == nil { + return xerrors.New("'GasFeeCap' cannot be nil") + } + if m.GasFeeCap.LessThan(big.Zero()) { return xerrors.New("'GasFeeCap' field cannot be negative") } + if m.GasPremium.Int == nil { + return xerrors.New("'GasPremium' cannot be nil") + } + if m.GasPremium.LessThan(big.Zero()) { return xerrors.New("'GasPremium' field cannot be negative") } From 42951d05a58d3243c1d8285d93a164d300f5c380 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 10 Aug 2020 10:07:44 +0300 Subject: [PATCH 033/353] refactor messagepool provider out of the main messagepool implementation --- chain/messagepool/messagepool.go | 65 --------------------------- chain/messagepool/provider.go | 76 ++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 65 deletions(-) create mode 100644 chain/messagepool/provider.go diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 0d47e488e..fe4011629 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -18,7 +18,6 @@ import ( "github.com/ipfs/go-datastore/namespace" "github.com/ipfs/go-datastore/query" logging "github.com/ipfs/go-log/v2" - pubsub "github.com/libp2p/go-libp2p-pubsub" lps "github.com/whyrusleeping/pubsub" "go.uber.org/multierr" "golang.org/x/xerrors" @@ -27,7 +26,6 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/lib/sigs" @@ -147,69 +145,6 @@ func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool) (bool, error) { return !has, nil } -type Provider interface { - SubscribeHeadChanges(func(rev, app []*types.TipSet) error) *types.TipSet - PutMessage(m types.ChainMsg) (cid.Cid, error) - PubSubPublish(string, []byte) error - StateGetActor(address.Address, *types.TipSet) (*types.Actor, error) - StateAccountKey(context.Context, address.Address, *types.TipSet) (address.Address, error) - MessagesForBlock(*types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) - MessagesForTipset(*types.TipSet) ([]types.ChainMsg, error) - LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) - ChainComputeBaseFee(ctx context.Context, ts *types.TipSet) (types.BigInt, error) -} - -type mpoolProvider struct { - sm *stmgr.StateManager - ps *pubsub.PubSub -} - -func NewProvider(sm *stmgr.StateManager, ps *pubsub.PubSub) Provider { - return &mpoolProvider{sm: sm, ps: ps} -} - -func (mpp *mpoolProvider) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet { - mpp.sm.ChainStore().SubscribeHeadChanges(cb) - return mpp.sm.ChainStore().GetHeaviestTipSet() -} - -func (mpp *mpoolProvider) PutMessage(m types.ChainMsg) (cid.Cid, error) { - return mpp.sm.ChainStore().PutMessage(m) -} - -func (mpp *mpoolProvider) PubSubPublish(k string, v []byte) error { - return mpp.ps.Publish(k, v) -} - -func (mpp *mpoolProvider) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) { - var act types.Actor - return &act, mpp.sm.WithParentState(ts, mpp.sm.WithActor(addr, stmgr.GetActor(&act))) -} - -func (mpp *mpoolProvider) StateAccountKey(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { - return mpp.sm.ResolveToKeyAddress(ctx, addr, ts) -} - -func (mpp *mpoolProvider) MessagesForBlock(h *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) { - return mpp.sm.ChainStore().MessagesForBlock(h) -} - -func (mpp *mpoolProvider) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) { - return mpp.sm.ChainStore().MessagesForTipset(ts) -} - -func (mpp *mpoolProvider) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) { - return mpp.sm.ChainStore().LoadTipSet(tsk) -} - -func (mpp *mpoolProvider) ChainComputeBaseFee(ctx context.Context, ts *types.TipSet) (types.BigInt, error) { - baseFee, err := mpp.sm.ChainStore().ComputeBaseFee(ctx, ts) - if err != nil { - return types.NewInt(0), xerrors.Errorf("computing base fee at %s: %w", ts, err) - } - return baseFee, nil -} - func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*MessagePool, error) { cache, _ := lru.New2Q(build.BlsSignatureCacheSize) verifcache, _ := lru.New2Q(build.VerifSigCacheSize) diff --git a/chain/messagepool/provider.go b/chain/messagepool/provider.go new file mode 100644 index 000000000..a6aa79ef6 --- /dev/null +++ b/chain/messagepool/provider.go @@ -0,0 +1,76 @@ +package messagepool + +import ( + "context" + + "github.com/ipfs/go-cid" + pubsub "github.com/libp2p/go-libp2p-pubsub" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/types" +) + +type Provider interface { + SubscribeHeadChanges(func(rev, app []*types.TipSet) error) *types.TipSet + PutMessage(m types.ChainMsg) (cid.Cid, error) + PubSubPublish(string, []byte) error + StateGetActor(address.Address, *types.TipSet) (*types.Actor, error) + StateAccountKey(context.Context, address.Address, *types.TipSet) (address.Address, error) + MessagesForBlock(*types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) + MessagesForTipset(*types.TipSet) ([]types.ChainMsg, error) + LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) + ChainComputeBaseFee(ctx context.Context, ts *types.TipSet) (types.BigInt, error) +} + +type mpoolProvider struct { + sm *stmgr.StateManager + ps *pubsub.PubSub +} + +func NewProvider(sm *stmgr.StateManager, ps *pubsub.PubSub) Provider { + return &mpoolProvider{sm: sm, ps: ps} +} + +func (mpp *mpoolProvider) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet { + mpp.sm.ChainStore().SubscribeHeadChanges(cb) + return mpp.sm.ChainStore().GetHeaviestTipSet() +} + +func (mpp *mpoolProvider) PutMessage(m types.ChainMsg) (cid.Cid, error) { + return mpp.sm.ChainStore().PutMessage(m) +} + +func (mpp *mpoolProvider) PubSubPublish(k string, v []byte) error { + return mpp.ps.Publish(k, v) +} + +func (mpp *mpoolProvider) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) { + var act types.Actor + return &act, mpp.sm.WithParentState(ts, mpp.sm.WithActor(addr, stmgr.GetActor(&act))) +} + +func (mpp *mpoolProvider) StateAccountKey(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { + return mpp.sm.ResolveToKeyAddress(ctx, addr, ts) +} + +func (mpp *mpoolProvider) MessagesForBlock(h *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) { + return mpp.sm.ChainStore().MessagesForBlock(h) +} + +func (mpp *mpoolProvider) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) { + return mpp.sm.ChainStore().MessagesForTipset(ts) +} + +func (mpp *mpoolProvider) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) { + return mpp.sm.ChainStore().LoadTipSet(tsk) +} + +func (mpp *mpoolProvider) ChainComputeBaseFee(ctx context.Context, ts *types.TipSet) (types.BigInt, error) { + baseFee, err := mpp.sm.ChainStore().ComputeBaseFee(ctx, ts) + if err != nil { + return types.NewInt(0), xerrors.Errorf("computing base fee at %s: %w", ts, err) + } + return baseFee, nil +} From e876617c8279d8edf42378cb3ea5332bdb63d26a Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 10 Aug 2020 11:07:36 +0300 Subject: [PATCH 034/353] new message republishing logic --- chain/messagepool/messagepool.go | 63 +----------------- chain/messagepool/repub.go | 106 +++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 61 deletions(-) create mode 100644 chain/messagepool/repub.go diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index fe4011629..2a889c68d 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -19,7 +19,6 @@ import ( "github.com/ipfs/go-datastore/query" logging "github.com/ipfs/go-log/v2" lps "github.com/whyrusleeping/pubsub" - "go.uber.org/multierr" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" @@ -38,8 +37,6 @@ var log = logging.Logger("messagepool") const futureDebug = false -const repubMsgLimit = 5 - const RbfDenom = 256 var ( @@ -217,63 +214,8 @@ func (mp *MessagePool) runLoop() { for { select { case <-mp.repubTk.C: - mp.lk.Lock() - - msgsForAddr := make(map[address.Address][]*types.SignedMessage) - for a := range mp.localAddrs { - msgsForAddr[a] = mp.pendingFor(a) - } - - mp.lk.Unlock() - - var errout error - outputMsgs := []*types.SignedMessage{} - - for a, msgs := range msgsForAddr { - a, err := mp.api.StateGetActor(a, nil) - if err != nil { - errout = multierr.Append(errout, xerrors.Errorf("could not get actor state: %w", err)) - continue - } - - curNonce := a.Nonce - for _, m := range msgs { - if m.Message.Nonce < curNonce { - continue - } - if m.Message.Nonce != curNonce { - break - } - outputMsgs = append(outputMsgs, m) - curNonce++ - } - - } - - if len(outputMsgs) != 0 { - log.Infow("republishing local messages", "n", len(outputMsgs)) - } - - if len(outputMsgs) > repubMsgLimit { - outputMsgs = outputMsgs[:repubMsgLimit] - } - - for _, msg := range outputMsgs { - msgb, err := msg.Serialize() - if err != nil { - errout = multierr.Append(errout, xerrors.Errorf("could not serialize: %w", err)) - continue - } - - err = mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb) - if err != nil { - errout = multierr.Append(errout, xerrors.Errorf("could not publish: %w", err)) - continue - } - } - - if errout != nil { - log.Errorf("errors while republishing: %+v", errout) + if err := mp.republishPendingMessages(); err != nil { + log.Errorf("error while republishing messages: %s", err) } case <-mp.pruneTrigger: if err := mp.pruneExcessMessages(); err != nil { @@ -284,7 +226,6 @@ func (mp *MessagePool) runLoop() { return } } - } func (mp *MessagePool) addLocal(m *types.SignedMessage, msgb []byte) error { diff --git a/chain/messagepool/repub.go b/chain/messagepool/repub.go new file mode 100644 index 000000000..935ff17ec --- /dev/null +++ b/chain/messagepool/repub.go @@ -0,0 +1,106 @@ +package messagepool + +import ( + "context" + "sort" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" +) + +const repubMsgLimit = 5 + +func (mp *MessagePool) republishPendingMessages() error { + mp.curTsLk.Lock() + ts := mp.curTs + mp.curTsLk.Unlock() + + baseFee, err := mp.api.ChainComputeBaseFee(context.TODO(), ts) + if err != nil { + return xerrors.Errorf("computing basefee: %w", err) + } + + pending := make(map[address.Address]map[uint64]*types.SignedMessage) + mp.lk.Lock() + for actor := range mp.localAddrs { + mset, ok := mp.pending[actor] + if !ok { + continue + } + if len(mset.msgs) == 0 { + continue + } + // we need to copy this while holding the lock to avoid races with concurrent modification + pend := make(map[uint64]*types.SignedMessage, len(mset.msgs)) + for nonce, m := range mset.msgs { + pend[nonce] = m + } + pending[actor] = pend + } + mp.lk.Unlock() + + if len(pending) == 0 { + return nil + } + + var chains []*msgChain + for actor, mset := range pending { + next := mp.createMessageChains(actor, mset, baseFee, ts) + chains = append(chains, next...) + } + + if len(chains) == 0 { + return nil + } + + sort.Slice(chains, func(i, j int) bool { + return chains[i].Before(chains[j]) + }) + + // we don't republish negative performing chains; this is an error that will be screamed + // at the user + if chains[0].gasPerf < 0 { + return xerrors.Errorf("skipping republish: all message chains have negative gas performance; best gas performance: %f", chains[0].gasPerf) + } + + gasLimit := int64(build.BlockGasLimit) + var msgs []*types.SignedMessage + for _, chain := range chains { + // we can exceed this if we have picked (some) longer chain already + if len(msgs) > repubMsgLimit { + break + } + + // we don't republish negative performing chains, as they won't be included in + // a block anyway + if chain.gasPerf < 0 { + break + } + + // we don't exceed the block gasLimit in our republish endeavor + if chain.gasLimit > gasLimit { + break + } + + gasLimit -= chain.gasLimit + msgs = append(msgs, chain.msgs...) + } + + log.Infof("republishing %d messages", len(msgs)) + for _, m := range msgs { + mb, err := m.Serialize() + if err != nil { + return xerrors.Errorf("cannot serialize message: %w", err) + } + + err = mp.api.PubSubPublish(build.MessagesTopic(mp.netName), mb) + if err != nil { + return xerrors.Errorf("cannot publish: %w", err) + } + } + + return nil +} From 7396212c896d8d5a3f786a6d6463ca3e91e85d43 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 10 Aug 2020 11:18:12 +0300 Subject: [PATCH 035/353] slightly increase the replublish interval to include the propagation delay as well --- chain/messagepool/messagepool.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 2a889c68d..3d3477ff0 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -39,6 +39,8 @@ const futureDebug = false const RbfDenom = 256 +var RepublishInterval = time.Duration(build.BlockDelaySecs+build.PropagationDelaySecs) * time.Second + var ( ErrMessageTooBig = errors.New("message too big") @@ -156,7 +158,7 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa mp := &MessagePool{ ds: ds, closer: make(chan struct{}), - repubTk: build.Clock.Ticker(time.Duration(build.BlockDelaySecs) * time.Second), + repubTk: build.Clock.Ticker(RepublishInterval), localAddrs: make(map[address.Address]struct{}), pending: make(map[address.Address]*msgSet), minGasPrice: types.NewInt(0), From cf34fe5cc3ba042ae36f588b2710149d992d9ef7 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 10 Aug 2020 19:53:56 +0300 Subject: [PATCH 036/353] extend the republish interval to something more reasonable pubsub timecache duration + 5 blocks + propagation delay --- chain/messagepool/messagepool.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 3d3477ff0..c18f5f5ae 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -18,6 +18,7 @@ import ( "github.com/ipfs/go-datastore/namespace" "github.com/ipfs/go-datastore/query" logging "github.com/ipfs/go-log/v2" + pubsub "github.com/libp2p/go-libp2p-pubsub" lps "github.com/whyrusleeping/pubsub" "golang.org/x/xerrors" @@ -39,7 +40,7 @@ const futureDebug = false const RbfDenom = 256 -var RepublishInterval = time.Duration(build.BlockDelaySecs+build.PropagationDelaySecs) * time.Second +var RepublishInterval = pubsub.TimeCacheDuration + time.Duration(5*build.BlockDelaySecs+build.PropagationDelaySecs)*time.Second var ( ErrMessageTooBig = errors.New("message too big") From 47f81f1ad6a9e42971161078e8bf962788fac33a Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 11 Aug 2020 14:26:06 +0300 Subject: [PATCH 037/353] increase repub message limit to 30 --- chain/messagepool/repub.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/messagepool/repub.go b/chain/messagepool/repub.go index 935ff17ec..d0604e4dd 100644 --- a/chain/messagepool/repub.go +++ b/chain/messagepool/repub.go @@ -11,7 +11,7 @@ import ( "github.com/filecoin-project/lotus/chain/types" ) -const repubMsgLimit = 5 +const repubMsgLimit = 30 func (mp *MessagePool) republishPendingMessages() error { mp.curTsLk.Lock() From 7b16fe3792c8af177bc84b15c2b5b74f5d4daf30 Mon Sep 17 00:00:00 2001 From: vyzo Date: Wed, 12 Aug 2020 09:18:04 +0300 Subject: [PATCH 038/353] hold ts lock longer --- chain/messagepool/repub.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chain/messagepool/repub.go b/chain/messagepool/repub.go index d0604e4dd..bb043a784 100644 --- a/chain/messagepool/repub.go +++ b/chain/messagepool/repub.go @@ -16,10 +16,10 @@ const repubMsgLimit = 30 func (mp *MessagePool) republishPendingMessages() error { mp.curTsLk.Lock() ts := mp.curTs - mp.curTsLk.Unlock() baseFee, err := mp.api.ChainComputeBaseFee(context.TODO(), ts) if err != nil { + mp.curTsLk.Unlock() return xerrors.Errorf("computing basefee: %w", err) } @@ -41,6 +41,7 @@ func (mp *MessagePool) republishPendingMessages() error { pending[actor] = pend } mp.lk.Unlock() + mp.curTsLk.Unlock() if len(pending) == 0 { return nil From 472e502218c16f18cd1e5c7f03bc679f87cb69b5 Mon Sep 17 00:00:00 2001 From: vyzo Date: Wed, 12 Aug 2020 09:41:02 +0300 Subject: [PATCH 039/353] fix republishing chain selection to account for edge case of inordinately long chains --- chain/messagepool/repub.go | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/chain/messagepool/repub.go b/chain/messagepool/repub.go index bb043a784..a55bc4f3f 100644 --- a/chain/messagepool/repub.go +++ b/chain/messagepool/repub.go @@ -8,6 +8,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/messagepool/gasguess" "github.com/filecoin-project/lotus/chain/types" ) @@ -68,26 +69,50 @@ func (mp *MessagePool) republishPendingMessages() error { } gasLimit := int64(build.BlockGasLimit) + minGas := int64(gasguess.MinGas) var msgs []*types.SignedMessage - for _, chain := range chains { + for i := 0; i < len(chains); { + chain := chains[i] + // we can exceed this if we have picked (some) longer chain already if len(msgs) > repubMsgLimit { break } + // there is not enough gas for any message + if gasLimit <= minGas { + break + } + // we don't republish negative performing chains, as they won't be included in // a block anyway if chain.gasPerf < 0 { break } - // we don't exceed the block gasLimit in our republish endeavor - if chain.gasLimit > gasLimit { - break + // has the chain been invalidated? + if !chain.valid { + i++ + continue } - gasLimit -= chain.gasLimit - msgs = append(msgs, chain.msgs...) + // does it fit in a block? + if chain.gasLimit <= gasLimit { + gasLimit -= chain.gasLimit + msgs = append(msgs, chain.msgs...) + i++ + continue + } + + // we can't fit the current chain but there is gas to spare + // trim it and push it down + chain.Trim(gasLimit, mp, baseFee, ts, false) + for j := i; j < len(chains)-1; j++ { + if chains[j].Before(chains[j+1]) { + break + } + chains[j], chains[j+1] = chains[j+1], chains[j] + } } log.Infof("republishing %d messages", len(msgs)) From 7be18df6ea70674a8b23d06816b68ffa26d71498 Mon Sep 17 00:00:00 2001 From: vyzo Date: Wed, 12 Aug 2020 10:38:40 +0300 Subject: [PATCH 040/353] add semaphore in push and friends to reduce lock contention --- chain/messagepool/messagepool.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index c18f5f5ae..b8e2bd324 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -68,6 +68,8 @@ type MessagePool struct { ds dtypes.MetadataDS + addSema chan struct{} + closer chan struct{} repubTk *clock.Ticker @@ -158,6 +160,7 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa mp := &MessagePool{ ds: ds, + addSema: make(chan struct{}, 1), closer: make(chan struct{}), repubTk: build.Clock.Ticker(RepublishInterval), localAddrs: make(map[address.Address]struct{}), @@ -251,6 +254,12 @@ func (mp *MessagePool) verifyMsgBeforePush(m *types.SignedMessage, epoch abi.Cha } func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) { + // serialize push access to reduce lock contention + mp.addSema <- struct{}{} + defer func() { + <-mp.addSema + }() + mp.curTsLk.Lock() epoch := mp.curTs.Height() mp.curTsLk.Unlock() @@ -296,6 +305,12 @@ func (mp *MessagePool) Add(m *types.SignedMessage) error { return err } + // serialize push access to reduce lock contention + mp.addSema <- struct{}{} + defer func() { + <-mp.addSema + }() + mp.curTsLk.Lock() defer mp.curTsLk.Unlock() return mp.addTs(m, mp.curTs) @@ -494,6 +509,12 @@ func (mp *MessagePool) getStateBalance(addr address.Address, ts *types.TipSet) ( } func (mp *MessagePool) PushWithNonce(ctx context.Context, addr address.Address, cb func(address.Address, uint64) (*types.SignedMessage, error)) (*types.SignedMessage, error) { + // serialize push access to reduce lock contention + mp.addSema <- struct{}{} + defer func() { + <-mp.addSema + }() + mp.curTsLk.Lock() defer mp.curTsLk.Unlock() From 5169785c91dea43fdd9bf78a43f994cd38e50be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sami=20M=C3=A4kel=C3=A4?= Date: Wed, 12 Aug 2020 14:15:03 +0300 Subject: [PATCH 041/353] merge --- cmd/lotus-storage-miner/market.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/cmd/lotus-storage-miner/market.go b/cmd/lotus-storage-miner/market.go index 8ab74b7ae..f8fcc54fc 100644 --- a/cmd/lotus-storage-miner/market.go +++ b/cmd/lotus-storage-miner/market.go @@ -194,11 +194,7 @@ var setAskCmd = &cli.Command{ defer closer() pri := types.NewInt(cctx.Uint64("price")) -<<<<<<< HEAD - verifiedPri := types.NewInt(cctx.Uint64("verified-price")) -======= vpri := types.NewInt(cctx.Uint64("verified-price")) ->>>>>>> e2c6cc6c6deb4620cbf3b05fb7600b8743d15564 dur, err := time.ParseDuration(cctx.String("duration")) if err != nil { @@ -241,11 +237,7 @@ var setAskCmd = &cli.Command{ return xerrors.Errorf("max piece size (w/bit-padding) %s cannot exceed miner sector size %s", types.SizeStr(types.NewInt(uint64(max))), types.SizeStr(types.NewInt(uint64(smax)))) } -<<<<<<< HEAD - return api.MarketSetAsk(ctx, pri, verifiedPri, abi.ChainEpoch(qty), abi.PaddedPieceSize(min), abi.PaddedPieceSize(max)) -======= return api.MarketSetAsk(ctx, pri, vpri, abi.ChainEpoch(qty), abi.PaddedPieceSize(min), abi.PaddedPieceSize(max)) ->>>>>>> e2c6cc6c6deb4620cbf3b05fb7600b8743d15564 }, } From 8367e79279e9a05300fd619ea49b741811753626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sami=20M=C3=A4kel=C3=A4?= Date: Wed, 12 Aug 2020 17:36:07 +0300 Subject: [PATCH 042/353] now working --- cmd/lotus-storage-miner/market.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/lotus-storage-miner/market.go b/cmd/lotus-storage-miner/market.go index f8fcc54fc..352330c81 100644 --- a/cmd/lotus-storage-miner/market.go +++ b/cmd/lotus-storage-miner/market.go @@ -289,7 +289,7 @@ var getAskCmd = &cli.Command{ rem = (time.Second * time.Duration(int64(dlt)*int64(build.BlockDelaySecs))).String() } - fmt.Fprintf(w, "%s\t%s\t%s\t%d\t%s\t%d\n", ask.Price, ask.VerifiedPrice, types.SizeStr(types.NewInt(uint64(ask.MinPieceSize))), types.SizeStr(types.NewInt(uint64(ask.MaxPieceSize))), ask.Expiry, rem, ask.SeqNo) + fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%d\t%s\t%d\n", ask.Price, ask.VerifiedPrice, types.SizeStr(types.NewInt(uint64(ask.MinPieceSize))), types.SizeStr(types.NewInt(uint64(ask.MaxPieceSize))), ask.Expiry, rem, ask.SeqNo) return w.Flush() }, From f2e89e6b168a757ada276e5d5877b3af80af4457 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Wed, 12 Aug 2020 16:38:32 +0200 Subject: [PATCH 043/353] Set charset to UTF-8 in compute state output Signed-off-by: Jakub Sztandera --- cli/state.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cli/state.go b/cli/state.go index 5b8a10a7a..71bf236c7 100644 --- a/cli/state.go +++ b/cli/state.go @@ -913,6 +913,7 @@ func printInternalExecutions(prefix string, trace []types.ExecutionTrace) { var compStateTemplate = ` +