From 5702ea236cc125153a3d74fa7078a3d58b9dd696 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Thu, 13 Aug 2020 20:19:47 -0400 Subject: [PATCH 01/53] Do not include the burnt funds actor as a genesis account actor --- chain/stmgr/stmgr.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index a3bd9e023..24d7509bf 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -856,15 +856,17 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error { return xerrors.Errorf("decoding address: %w", err) } - kid, err := sTree.LookupID(kaddr) - if err != nil { - return xerrors.Errorf("resolving address: %w", err) - } + if kaddr != builtin.BurntFundsActorAddr { + kid, err := sTree.LookupID(kaddr) + if err != nil { + return xerrors.Errorf("resolving address: %w", err) + } - gi.genesisActors = append(gi.genesisActors, genesisActor{ - addr: kid, - initBal: act.Balance, - }) + gi.genesisActors = append(gi.genesisActors, genesisActor{ + addr: kid, + initBal: act.Balance, + }) + } } return nil }) From f5b0c306336a835795ddfaad2d726f9b2def5d31 Mon Sep 17 00:00:00 2001 From: David Dias Date: Mon, 17 Aug 2020 15:21:27 +0100 Subject: [PATCH 02/53] docs: add badgers --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 23a1d7eb1..cd7edad5e 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,14 @@

Project Lotus - 莲

+

+ + + + +
+

+ Lotus is an implementation of the Filecoin Distributed Storage Network. For more details about Filecoin, check out the [Filecoin Spec](https://spec.filecoin.io). ## Building & Documentation From 5040623a12c3b93c27c3949c74c6cb64922c3ea8 Mon Sep 17 00:00:00 2001 From: Travis Person Date: Mon, 17 Aug 2020 18:52:02 +0000 Subject: [PATCH 03/53] lotus-pcr: refund provecommit sectors --- cmd/lotus-pcr/main.go | 244 ++++++++++++++++++++++++++++++++---------- 1 file changed, 185 insertions(+), 59 deletions(-) diff --git a/cmd/lotus-pcr/main.go b/cmd/lotus-pcr/main.go index fe75349a2..440c0163b 100644 --- a/cmd/lotus-pcr/main.go +++ b/cmd/lotus-pcr/main.go @@ -10,6 +10,7 @@ import ( "os" "path/filepath" "strconv" + "time" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" @@ -20,6 +21,7 @@ import ( "golang.org/x/xerrors" "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" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" @@ -70,16 +72,24 @@ func main() { EnvVars: []string{"LOTUS_PCR_PATH"}, Value: "~/.lotuspcr", // TODO: Consider XDG_DATA_HOME }, + &cli.StringFlag{ + Name: "log-level", + EnvVars: []string{"LOTUS_PCR_LOG_LEVEL"}, + Hidden: true, + Value: "info", + }, + }, + Before: func(cctx *cli.Context) error { + return logging.SetLogLevel("main", cctx.String("log-level")) }, - Commands: local, } if err := app.Run(os.Args); err != nil { - log.Warn(err) + log.Errorw("exit in error", "err", err) + os.Exit(1) return } - } var versionCmd = &cli.Command{ @@ -90,6 +100,7 @@ var versionCmd = &cli.Command{ return nil }, } + var runCmd = &cli.Command{ Name: "run", Usage: "Start message reimpursement", @@ -97,19 +108,36 @@ var runCmd = &cli.Command{ &cli.StringFlag{ Name: "from", EnvVars: []string{"LOTUS_PCR_FROM"}, + Usage: "wallet address to send refund from", }, &cli.BoolFlag{ Name: "no-sync", EnvVars: []string{"LOTUS_PCR_NO_SYNC"}, + Usage: "do not wait for chain sync to complete", }, &cli.IntFlag{ - Name: "percent-extra", - Value: 3, + Name: "percent-extra", + EnvVars: []string{"LOTUS_PCR_PERCENT_EXTRA"}, + Usage: "extra funds to send above the refund", + Value: 3, }, &cli.IntFlag{ - Name: "head-delay", - Usage: "the number of tipsets to delay message processing to smooth chain reorgs", - Value: int(build.MessageConfidence), + Name: "max-message-queue", + EnvVars: []string{"LOTUS_PCR_MAX_MESSAGE_QUEUE"}, + Usage: "set the maximum number of messages that can be queue in the mpool", + Value: 3000, + }, + &cli.BoolFlag{ + Name: "dry-run", + EnvVars: []string{"LOTUS_PCR_DRY_RUN"}, + Usage: "do not send any messages", + Value: false, + }, + &cli.IntFlag{ + Name: "head-delay", + EnvVars: []string{"LOTUS_PCR_HEAD_DELAY"}, + Usage: "the number of tipsets to delay message processing to smooth chain reorgs", + Value: int(build.MessageConfidence), }, }, Action: func(cctx *cli.Context) error { @@ -150,15 +178,52 @@ var runCmd = &cli.Command{ } percentExtra := cctx.Int("percent-extra") + maxMessageQueue := cctx.Int("max-message-queue") + dryRun := cctx.Bool("dry-run") + + rf := &refunder{ + api: api, + wallet: from, + percentExtra: percentExtra, + dryRun: dryRun, + } for tipset := range tipsetsCh { - if err := ProcessTipset(ctx, api, tipset, from, percentExtra); err != nil { + refunds, err := rf.ProcessTipset(ctx, tipset) + if err != nil { + return err + } + + if err := rf.Refund(ctx, tipset, refunds); err != nil { return err } if err := r.SetHeight(tipset.Height()); err != nil { return err } + + for { + msgs, err := api.MpoolPending(ctx, types.EmptyTSK) + if err != nil { + log.Warnw("failed to fetch pending messages", "err", err) + time.Sleep(time.Duration(int64(time.Second) * int64(build.BlockDelaySecs))) + continue + } + + count := 0 + for _, msg := range msgs { + if msg.Message.From == from { + count = count + 1 + } + } + + if count < maxMessageQueue { + break + } + + log.Warnw("messages in mpool over max message queue", "message_count", count, "max_message_queue", maxMessageQueue) + time.Sleep(time.Duration(int64(time.Second) * int64(build.BlockDelaySecs))) + } } return nil @@ -167,6 +232,7 @@ var runCmd = &cli.Command{ type MinersRefund struct { refunds map[address.Address]types.BigInt + count int } func NewMinersRefund() *MinersRefund { @@ -180,11 +246,13 @@ func (m *MinersRefund) Track(addr address.Address, value types.BigInt) { m.refunds[addr] = types.NewInt(0) } + m.count = m.count + 1 + m.refunds[addr] = types.BigAdd(m.refunds[addr], value) } func (m *MinersRefund) Count() int { - return len(m.refunds) + return m.count } func (m *MinersRefund) Miners() []address.Address { @@ -200,50 +268,58 @@ func (m *MinersRefund) GetRefund(addr address.Address) types.BigInt { return m.refunds[addr] } -type processTipSetApi interface { +type refunderNodeApi interface { ChainGetParentMessages(ctx context.Context, blockCid cid.Cid) ([]api.Message, error) ChainGetParentReceipts(ctx context.Context, blockCid cid.Cid) ([]*types.MessageReceipt, error) + ChainGetTipSetByHeight(ctx context.Context, epoch abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) StateMinerInitialPledgeCollateral(ctx context.Context, addr address.Address, precommitInfo miner.SectorPreCommitInfo, tsk types.TipSetKey) (types.BigInt, error) + StateSectorPreCommitInfo(ctx context.Context, addr address.Address, sector abi.SectorNumber, tsk types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) MpoolPushMessage(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec) (*types.SignedMessage, error) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) WalletBalance(ctx context.Context, addr address.Address) (types.BigInt, error) } -func ProcessTipset(ctx context.Context, api processTipSetApi, tipset *types.TipSet, wallet address.Address, percentExtra int) error { - log.Infow("processing tipset", "height", tipset.Height(), "key", tipset.Key().String()) +type refunder struct { + api refunderNodeApi + wallet address.Address + percentExtra int + dryRun bool +} +func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet) (*MinersRefund, error) { cids := tipset.Cids() if len(cids) == 0 { - return fmt.Errorf("no cids in tipset") + log.Errorw("no cids in tipset", "height", tipset.Height(), "key", tipset.Key()) + return nil, fmt.Errorf("no cids in tipset") } - msgs, err := api.ChainGetParentMessages(ctx, cids[0]) + msgs, err := r.api.ChainGetParentMessages(ctx, cids[0]) if err != nil { - log.Errorw("failed to get tipset parent messages", "err", err) - return nil + log.Errorw("failed to get tipset parent messages", "err", err, "height", tipset.Height(), "key", tipset.Key()) + return nil, nil } - recps, err := api.ChainGetParentReceipts(ctx, cids[0]) + recps, err := r.api.ChainGetParentReceipts(ctx, cids[0]) if err != nil { - log.Errorw("failed to get tipset parent receipts", "err", err) - return nil + log.Errorw("failed to get tipset parent receipts", "err", err, "height", tipset.Height(), "key", tipset.Key()) + return nil, nil } if len(msgs) != len(recps) { - log.Errorw("message length does not match receipts length", "messages", len(msgs), "receipts", len(recps)) - return nil + log.Errorw("message length does not match receipts length", "height", tipset.Height(), "key", tipset.Key(), "messages", len(msgs), "receipts", len(recps)) + return nil, nil } refunds := NewMinersRefund() - count := 0 + refundValue := types.NewInt(0) for i, msg := range msgs { m := msg.Message - a, err := api.StateGetActor(ctx, m.To, tipset.Key()) + a, err := r.api.StateGetActor(ctx, m.To, tipset.Key()) if err != nil { - log.Warnw("failed to look up state actor", "actor", m.To) + log.Warnw("failed to look up state actor", "height", tipset.Height(), "key", tipset.Key(), "actor", m.To) continue } @@ -251,39 +327,87 @@ func ProcessTipset(ctx context.Context, api processTipSetApi, tipset *types.TipS continue } - // we only care to look at PreCommitSector messages - if m.Method != builtin.MethodsMiner.PreCommitSector { + var messageMethod string + + switch m.Method { + case builtin.MethodsMiner.ProveCommitSector: + messageMethod = "ProveCommitSector" + if recps[i].ExitCode != exitcode.Ok { + log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recps[i].ExitCode) + continue + } + + var proveCommitSector miner.ProveCommitSectorParams + if err := proveCommitSector.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil { + log.Warnw("failed to decode provecommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To) + continue + } + + // We use the parent tipset key because precommit information is removed when ProveCommitSector is executed + precommitChainInfo, err := r.api.StateSectorPreCommitInfo(ctx, m.To, proveCommitSector.SectorNumber, tipset.Parents()) + if err != nil { + log.Warnw("failed to get precommit info for sector", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", proveCommitSector.SectorNumber) + continue + } + + precommitTipset, err := r.api.ChainGetTipSetByHeight(ctx, precommitChainInfo.PreCommitEpoch, tipset.Key()) + if err != nil { + log.Warnf("failed to lookup precommit epoch", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", proveCommitSector.SectorNumber) + continue + } + + collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitChainInfo.Info, precommitTipset.Key()) + if err != nil { + log.Warnw("failed to get initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", proveCommitSector.SectorNumber) + } + + collateral = big.Sub(collateral, precommitChainInfo.PreCommitDeposit) + if collateral.LessThan(big.Zero()) { + log.Debugw("skipping zero pledge collateral difference", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", proveCommitSector.SectorNumber) + continue + } + + refundValue = collateral + case builtin.MethodsMiner.PreCommitSector: + messageMethod = "PreCommitSector" + + if recps[i].ExitCode != exitcode.Ok { + log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recps[i].ExitCode) + continue + } + + var precommitInfo miner.SectorPreCommitInfo + if err := precommitInfo.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil { + log.Warnw("failed to decode precommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To) + continue + } + + collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitInfo, tipset.Key()) + if err != nil { + log.Warnw("failed to calculate initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", precommitInfo.SectorNumber) + continue + } + + refundValue = collateral + default: continue } - if recps[i].ExitCode != exitcode.Ok { - log.Debugw("skipping non-ok exitcode message", "cid", msg.Cid.String(), "exitcode", recps[i].ExitCode) + if r.percentExtra > 0 { + refundValue = types.BigAdd(refundValue, types.BigDiv(types.BigMul(refundValue, types.NewInt(100)), types.NewInt(uint64(r.percentExtra)))) } - var precommitInfo miner.SectorPreCommitInfo - if err := precommitInfo.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil { - log.Warnw("failed to decode precommit params", "err", err) - continue - } + log.Debugw("processing message", "method", messageMethod, "cid", msg.Cid, "from", m.From, "to", m.To, "value", m.Value, "gas_fee_cap", m.GasFeeCap, "gas_premium", m.GasPremium, "gas_used", recps[i].GasUsed, "refund", refundValue) - refundValue, err := api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitInfo, tipset.Key()) - if err != nil { - log.Warnw("failed to calculate", "err", err) - continue - } - - if percentExtra > 0 { - refundValue = types.BigAdd(refundValue, types.BigDiv(refundValue, types.NewInt(100*uint64(percentExtra)))) - } - - log.Infow("processing message", "from", m.From, "to", m.To, "value", m.Value.String(), "gas_fee_cap", m.GasFeeCap.String(), "gas_premium", m.GasPremium.String(), "gas_used", fmt.Sprintf("%d", recps[i].GasUsed), "refund", refundValue.String()) - - count = count + 1 refunds.Track(m.From, refundValue) } + return refunds, nil +} + +func (r *refunder) Refund(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund) error { if refunds.Count() == 0 { - log.Debugw("no messages to refund in tipset") + log.Debugw("no messages to refund in tipset", "height", tipset.Height(), "key", tipset.Key()) return nil } @@ -294,15 +418,15 @@ func ProcessTipset(ctx context.Context, api processTipSetApi, tipset *types.TipS refundValue := refunds.GetRefund(maddr) // We want to try and ensure these messages get mined quickly - gasPremium, err := api.GasEstimateGasPremium(ctx, 0, wallet, 0, tipset.Key()) + gasPremium, err := r.api.GasEstimateGasPremium(ctx, 0, r.wallet, 0, tipset.Key()) if err != nil { - log.Warnw("failed to estimate gas premium", "err", err) + log.Warnw("failed to estimate gas premium", "err", err, "height", tipset.Height(), "key", tipset.Key()) continue } msg := &types.Message{ Value: refundValue, - From: wallet, + From: r.wallet, To: maddr, GasPremium: gasPremium, @@ -312,32 +436,34 @@ func ProcessTipset(ctx context.Context, api processTipSetApi, tipset *types.TipS messages = append(messages, msg) } - balance, err := api.WalletBalance(ctx, wallet) + balance, err := r.api.WalletBalance(ctx, r.wallet) if err != nil { + log.Errorw("failed to get wallet balance", "err", err, "height", tipset.Height(), "key", tipset.Key()) return xerrors.Errorf("failed to get wallet balance :%w", err) } // Calculate the minimum balance as the total refund we need to issue plus 5% to cover fees minBalance := types.BigAdd(refundSum, types.BigDiv(refundSum, types.NewInt(500))) if balance.LessThan(minBalance) { - log.Errorw("not sufficent funds to cover refunds", "balance", balance.String(), "refund_sum", refundSum.String(), "minimum_required", minBalance.String()) + log.Errorw("not sufficent funds to cover refunds", "balance", balance, "refund_sum", refundSum, "minimum_required", minBalance) return xerrors.Errorf("wallet does not have enough balance to cover refund") } failures := 0 refundSum.SetUint64(0) for _, msg := range messages { - if _, err = api.MpoolPushMessage(ctx, msg, nil); err != nil { - log.Errorw("failed to MpoolPushMessage", "err", err, "msg", msg) - failures = failures + 1 - continue + if !r.dryRun { + if _, err = r.api.MpoolPushMessage(ctx, msg, nil); err != nil { + log.Errorw("failed to MpoolPushMessage", "err", err, "msg", msg) + failures = failures + 1 + continue + } } refundSum = types.BigAdd(refundSum, msg.Value) } - log.Infow("tipset stats", "messages_sent", len(messages)-failures, "refund_sum", refundSum.String(), "messages_failures", failures) - + log.Infow("tipset stats", "height", tipset.Height(), "key", tipset.Key(), "messages_sent", len(messages)-failures, "refund_sum", refundSum, "messages_failures", failures, "messages_processed", refunds.Count()) return nil } From 13e5b72cdbbe4a02f3863c04f9ecb69c21c3f80f Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 17 Aug 2020 18:54:49 -0700 Subject: [PATCH 04/53] proper genesis block history Commit hash originally stamped into the ethereum blockchain: https://etherscan.io/tx/0xe8f51c9eefb682cd866f059462577b6dd3d2685ff4b6437f6c940ff4f4aaf067 --- chain/gen/gen.go | 3 ++- chain/gen/genesis/genblock.go | 41 +++++++++++++++++++++++++++++ chain/gen/genesis/genesis.go | 16 ++++++++++- chain/stmgr/stmgr.go | 5 ++-- chain/store/store.go | 13 ++++++--- cmd/lotus-chainwatch/syncer/sync.go | 2 +- node/impl/full/gas.go | 2 +- 7 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 chain/gen/genesis/genblock.go diff --git a/chain/gen/gen.go b/chain/gen/gen.go index bcf9c4f10..d86b00ce1 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -304,7 +304,8 @@ func (cg *ChainGen) GenesisCar() ([]byte, error) { func CarWalkFunc(nd format.Node) (out []*format.Link, err error) { for _, link := range nd.Links() { - if link.Cid.Prefix().Codec == cid.FilCommitmentSealed || link.Cid.Prefix().Codec == cid.FilCommitmentUnsealed { + pref := link.Cid.Prefix() + if pref.Codec == cid.FilCommitmentSealed || pref.Codec == cid.FilCommitmentUnsealed { continue } out = append(out, link) diff --git a/chain/gen/genesis/genblock.go b/chain/gen/genesis/genblock.go new file mode 100644 index 000000000..f26659cdf --- /dev/null +++ b/chain/gen/genesis/genblock.go @@ -0,0 +1,41 @@ +package genesis + +import ( + "encoding/hex" + + blocks "github.com/ipfs/go-block-format" + "github.com/ipfs/go-cid" + "github.com/multiformats/go-multihash" +) + +const genesisMultihashString = "1220107d821c25dc0735200249df94a8bebc9c8e489744f86a4ca8919e81f19dcd72" +const genesisBlockHex = "a5684461746574696d6573323031372d30352d30352030313a32373a3531674e6574776f726b6846696c65636f696e65546f6b656e6846696c65636f696e6c546f6b656e416d6f756e7473a36b546f74616c537570706c796d322c3030302c3030302c303030664d696e6572736d312c3430302c3030302c3030306c50726f746f636f6c4c616273a36b446576656c6f706d656e746b3330302c3030302c3030306b46756e6472616973696e676b3230302c3030302c3030306a466f756e646174696f6e6b3130302c3030302c303030674d657373616765784854686973206973207468652047656e6573697320426c6f636b206f66207468652046696c65636f696e20446563656e7472616c697a65642053746f72616765204e6574776f726b2e" + +var cidBuilder = cid.V1Builder{Codec: cid.DagCBOR, MhType: multihash.SHA2_256} + +func expectedCid() cid.Cid { + mh, err := multihash.FromHexString(genesisMultihashString) + if err != nil { + panic(err) + } + return cid.NewCidV1(cidBuilder.Codec, mh) +} + +func getGenesisBlock() (blocks.Block, error) { + genesisBlockData, err := hex.DecodeString(genesisBlockHex) + if err != nil { + return nil, err + } + + genesisCid, err := cidBuilder.Sum(genesisBlockData) + if err != nil { + return nil, err + } + + block, err := blocks.NewBlockWithCid(genesisBlockData, genesisCid) + if err != nil { + return nil, err + } + + return block, nil +} diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index bb6fc467d..ca912fa82 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -434,10 +434,24 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallB VRFProof: []byte("vrf proof0000000vrf proof0000000"), } + filecoinGenesisCid, err := cid.Decode("bafyreiaqpwbbyjo4a42saasj36kkrpv4tsherf2e7bvezkert2a7dhonoi") + if err != nil { + return nil, xerrors.Errorf("failed to decode filecoin genesis block CID: %w", err) + } + + gblk, err := getGenesisBlock() + if err != nil { + return nil, xerrors.Errorf("failed to construct filecoin genesis block: %w", err) + } + + if err := bs.Put(gblk); err != nil { + return nil, xerrors.Errorf("failed writing filecoin genesis block to blockstore: %w", err) + } + b := &types.BlockHeader{ Miner: builtin.SystemActorAddr, Ticket: genesisticket, - Parents: []cid.Cid{}, + Parents: []cid.Cid{filecoinGenesisCid}, Height: 0, ParentWeight: types.NewInt(0), ParentStateRoot: stateroot, diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index f4943cba3..30c71087a 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -3,9 +3,10 @@ package stmgr import ( "context" "fmt" - "github.com/filecoin-project/specs-actors/actors/builtin/power" "sync" + "github.com/filecoin-project/specs-actors/actors/builtin/power" + "github.com/filecoin-project/specs-actors/actors/builtin/multisig" "github.com/filecoin-project/go-address" @@ -323,7 +324,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, ts *types.TipSet var parentEpoch abi.ChainEpoch pstate := blks[0].ParentStateRoot - if len(blks[0].Parents) > 0 { + if blks[0].Height > 0 { parent, err := sm.cs.GetBlock(blks[0].Parents[0]) if err != nil { return cid.Undef, cid.Undef, xerrors.Errorf("getting parent block: %w", err) diff --git a/chain/store/store.go b/chain/store/store.go index 24d8c408b..9c424dc3b 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -1177,15 +1177,20 @@ func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, w io.Writer) return xerrors.Errorf("unmarshaling block header (cid=%s): %w", blk, err) } - for _, p := range b.Parents { - blocksToWalk = append(blocksToWalk, p) - } - cids, err := recurseLinks(cs.bs, b.Messages, []cid.Cid{b.Messages}) if err != nil { return xerrors.Errorf("recursing messages failed: %w", err) } + if b.Height > 0 { + for _, p := range b.Parents { + blocksToWalk = append(blocksToWalk, p) + } + } else { + // include the genesis block + cids = append(cids, b.Parents...) + } + out := cids if b.Height == 0 { diff --git a/cmd/lotus-chainwatch/syncer/sync.go b/cmd/lotus-chainwatch/syncer/sync.go index 5e559b42a..69195b536 100644 --- a/cmd/lotus-chainwatch/syncer/sync.go +++ b/cmd/lotus-chainwatch/syncer/sync.go @@ -239,7 +239,7 @@ func (s *Syncer) unsyncedBlocks(ctx context.Context, head *types.TipSet, since t log.Debugw("To visit", "toVisit", toVisit.Len(), "toSync", len(toSync), "current_height", bh.Height) } - if len(bh.Parents) == 0 { + if bh.Height == 0 { continue } diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index d501af2f7..0e140c7a1 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -77,7 +77,7 @@ func (a *GasAPI) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, ts := a.Chain.GetHeaviestTipSet() for i := uint64(0); i < nblocksincl*2; i++ { - if len(ts.Parents().Cids()) == 0 { + if ts.Height() == 0 { break // genesis } From 64e18131c13b483da7f92f11f9ad2a3fd43eb47a Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 17 Aug 2020 23:38:58 -0700 Subject: [PATCH 05/53] place the remainder of unallocated funds in a 'remainder' account --- chain/gen/genesis/genesis.go | 24 +++++++++++++++++++++++- chain/gen/genesis/t01_init.go | 1 + genesis/types.go | 3 ++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index bb6fc467d..434b727be 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -258,11 +258,33 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge Balance: types.NewInt(0), Head: verifierState, }) - if err != nil { return nil, nil, xerrors.Errorf("setting account from actmap: %w", err) } + totalFilAllocated := big.Zero() + err = state.ForEach(func(addr address.Address, act *types.Actor) error { + totalFilAllocated = big.Add(totalFilAllocated, act.Balance) + return nil + }) + if err != nil { + return nil, nil, xerrors.Errorf("summing account balances in state tree: %w", err) + } + + totalFil := big.Mul(big.NewInt(int64(build.FilBase)), big.NewInt(int64(build.FilecoinPrecision))) + remainingFil := big.Sub(totalFil, totalFilAllocated) + + template.RemainderAccount.Balance = remainingFil + + remAccKey, err := address.NewIDAddress(90) + if err != nil { + return nil, nil, err + } + + if err := createAccount(ctx, bs, cst, state, remAccKey, template.RemainderAccount); err != nil { + return nil, nil, err + } + return state, keyIDs, nil } diff --git a/chain/gen/genesis/t01_init.go b/chain/gen/genesis/t01_init.go index 3cf0d66be..c3708329b 100644 --- a/chain/gen/genesis/t01_init.go +++ b/chain/gen/genesis/t01_init.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/specs-actors/actors/builtin" diff --git a/genesis/types.go b/genesis/types.go index 7d401fd0e..468a09067 100644 --- a/genesis/types.go +++ b/genesis/types.go @@ -79,5 +79,6 @@ type Template struct { NetworkName string Timestamp uint64 `json:",omitempty"` - VerifregRootKey Actor + VerifregRootKey Actor + RemainderAccount Actor } From add56c8b81544bdb16620284cc431e16c15b9e88 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Tue, 18 Aug 2020 05:49:56 -0400 Subject: [PATCH 06/53] Create eventless version of ClientRetrieve --- api/api_full.go | 5 ++++- api/apistruct/struct.go | 35 ++++++++++++++++++++--------------- api/test/deals.go | 2 +- cli/client.go | 2 +- node/impl/client/client.go | 8 +++++++- 5 files changed, 33 insertions(+), 19 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index 2a1d830ed..6feeb12cf 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -244,7 +244,10 @@ 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) (<-chan marketevents.RetrievalEvent, error) + ClientRetrieve(ctx context.Context, order RetrievalOrder, ref *FileRef) error + // ClientRetrieveWithEvents initiates the retrieval of a file, as specified in the order, and provides a channel + // of status updates. + ClientRetrieveWithEvents(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 diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index eabf4fa26..8fb8e68ed 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -127,20 +127,21 @@ 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) (<-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) (*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) error `perm:"admin"` + ClientRetrieveWithEvents 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) (*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"` @@ -425,10 +426,14 @@ 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) (<-chan marketevents.RetrievalEvent, error) { +func (c *FullNodeStruct) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error { return c.Internal.ClientRetrieve(ctx, order, ref) } +func (c *FullNodeStruct) ClientRetrieveWithEvents(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) { + return c.Internal.ClientRetrieveWithEvents(ctx, order, ref) +} + func (c *FullNodeStruct) ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) { return c.Internal.ClientQueryAsk(ctx, p, miner) } diff --git a/api/test/deals.go b/api/test/deals.go index f30b5b8ac..054f26b8a 100644 --- a/api/test/deals.go +++ b/api/test/deals.go @@ -398,7 +398,7 @@ func testRetrieval(t *testing.T, ctx context.Context, err error, client *impl.Fu Path: filepath.Join(rpath, "ret"), IsCAR: carExport, } - updates, err := client.ClientRetrieve(ctx, offers[0].Order(caddr), ref) + updates, err := client.ClientRetrieveWithEvents(ctx, offers[0].Order(caddr), ref) for update := range updates { if update.Err != "" { t.Fatalf("%v", err) diff --git a/cli/client.go b/cli/client.go index c0d5972b0..3320f5b5e 100644 --- a/cli/client.go +++ b/cli/client.go @@ -847,7 +847,7 @@ var clientRetrieveCmd = &cli.Command{ Path: cctx.Args().Get(1), IsCAR: cctx.Bool("car"), } - updates, err := fapi.ClientRetrieve(ctx, offer.Order(payer), ref) + updates, err := fapi.ClientRetrieveWithEvents(ctx, offer.Order(payer), ref) if err != nil { return xerrors.Errorf("error setting up retrieval: %w", err) } diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 70cd770f4..1d9216d46 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -400,7 +400,13 @@ 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) (<-chan marketevents.RetrievalEvent, error) { +func (a *API) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error { + events := make(chan marketevents.RetrievalEvent) + go a.clientRetrieve(ctx, order, ref, events) + return nil +} + +func (a *API) ClientRetrieveWithEvents(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 From 8942c02f28634adcad2117564711284fde8dbf20 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Tue, 18 Aug 2020 06:01:48 -0400 Subject: [PATCH 07/53] Add a reminder comment --- chain/stmgr/stmgr.go | 1 + 1 file changed, 1 insertion(+) diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index f4943cba3..662a860d1 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -850,6 +850,7 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error { } } else if act.Code == builtin.AccountActorCodeID { + // should exclude burnt funds actor and "remainder account actor" // should only ever be "faucet" accounts in testnets kaddr, err := address.NewFromBytes([]byte(k)) if err != nil { From 88fbc044b3832a795647938fbd426bd4b29a1f40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sami=20M=C3=A4kel=C3=A4?= Date: Tue, 18 Aug 2020 13:23:28 +0300 Subject: [PATCH 08/53] adding actors for genesis msig addresses --- chain/gen/genesis/genesis.go | 22 ++++++++++++--- chain/gen/genesis/t01_init.go | 50 ++++++++++++++++++++++++++++++++--- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index bb6fc467d..c142db73c 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -211,7 +211,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge return nil, nil, err } - if err = createAccount(ctx, bs, cst, state, ida, info); err != nil { + if err = createAccount(ctx, bs, cst, state, ida, info, keyIDs); err != nil { return nil, nil, err } @@ -222,7 +222,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge return nil, nil, err } - if err = createAccount(ctx, bs, cst, state, vregroot, template.VerifregRootKey); err != nil { + if err = createAccount(ctx, bs, cst, state, vregroot, template.VerifregRootKey, keyIDs); err != nil { return nil, nil, err } @@ -266,7 +266,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge return state, keyIDs, nil } -func createAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.IpldStore, state *state.StateTree, ida address.Address, info genesis.Actor) error { +func createAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.IpldStore, state *state.StateTree, ida address.Address, info genesis.Actor, keyIDs map[address.Address]address.Address) error { if info.Type == genesis.TAccount { var ainfo genesis.AccountMeta if err := json.Unmarshal(info.Meta, &ainfo); err != nil { @@ -294,6 +294,22 @@ func createAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.IpldStore return xerrors.Errorf("failed to create empty map: %v", err) } + for _, e := range ainfo.Signers { + idAddress, _ := keyIDs[e] + st, err := cst.Put(ctx, &account.State{Address: e}) + if err != nil { + return err + } + err = state.SetActor(idAddress, &types.Actor{ + Code: builtin.AccountActorCodeID, + Balance: types.NewInt(0), + Head: st, + }) + if err != nil { + return xerrors.Errorf("setting account from actmap: %w", err) + } + } + st, err := cst.Put(ctx, &multisig.State{ Signers: ainfo.Signers, NumApprovalsThreshold: uint64(ainfo.Threshold), diff --git a/chain/gen/genesis/t01_init.go b/chain/gen/genesis/t01_init.go index 3cf0d66be..7d00601f2 100644 --- a/chain/gen/genesis/t01_init.go +++ b/chain/gen/genesis/t01_init.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/specs-actors/actors/builtin" @@ -33,8 +34,30 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi keyToId := map[address.Address]address.Address{} - for i, a := range initialActors { + counter := int64(AccountStart) + + for _, a := range initialActors { if a.Type == genesis.TMultisig { + var ainfo genesis.MultisigMeta + if err := json.Unmarshal(a.Meta, &ainfo); err != nil { + return nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err) + } + for _, e := range ainfo.Signers { + fmt.Printf("init set %s t0%d\n", e, counter) + + value := cbg.CborInt(counter) + if err := amap.Put(adt.AddrKey(e), &value); err != nil { + return nil, nil, err + } + counter = counter + 1 + var err error + keyToId[e], err = address.NewIDAddress(uint64(value)) + if err != nil { + return nil, nil, err + } + + } + // Need to add actors for all multisigs too continue } @@ -47,12 +70,13 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi return nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err) } - fmt.Printf("init set %s t0%d\n", ainfo.Owner, AccountStart+int64(i)) + fmt.Printf("init set %s t0%d\n", ainfo.Owner, counter) - value := cbg.CborInt(AccountStart + int64(i)) + value := cbg.CborInt(counter) if err := amap.Put(adt.AddrKey(ainfo.Owner), &value); err != nil { return nil, nil, err } + counter = counter + 1 var err error keyToId[ainfo.Owner], err = address.NewIDAddress(uint64(value)) @@ -70,6 +94,26 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi if err := amap.Put(adt.AddrKey(ainfo.Owner), &value); err != nil { return nil, nil, err } + } else if rootVerifier.Type == genesis.TMultisig { + var ainfo genesis.MultisigMeta + if err := json.Unmarshal(rootVerifier.Meta, &ainfo); err != nil { + return nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err) + } + for _, e := range ainfo.Signers { + fmt.Printf("init set %s t0%d\n", e, counter) + + value := cbg.CborInt(counter) + if err := amap.Put(adt.AddrKey(e), &value); err != nil { + return nil, nil, err + } + counter = counter + 1 + var err error + keyToId[e], err = address.NewIDAddress(uint64(value)) + if err != nil { + return nil, nil, err + } + + } } amapaddr, err := amap.Root() From 4ae02ef1b9c3b3960819d6dc9cbaea6e6676059e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sami=20M=C3=A4kel=C3=A4?= Date: Tue, 18 Aug 2020 13:33:11 +0300 Subject: [PATCH 09/53] looks like it's working --- chain/gen/genesis/genesis.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index c142db73c..4d059a3a2 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -294,6 +294,8 @@ func createAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.IpldStore return xerrors.Errorf("failed to create empty map: %v", err) } + var signers []address.Address + for _, e := range ainfo.Signers { idAddress, _ := keyIDs[e] st, err := cst.Put(ctx, &account.State{Address: e}) @@ -308,10 +310,11 @@ func createAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.IpldStore if err != nil { return xerrors.Errorf("setting account from actmap: %w", err) } + signers = append(signers, idAddress) } st, err := cst.Put(ctx, &multisig.State{ - Signers: ainfo.Signers, + Signers: signers, NumApprovalsThreshold: uint64(ainfo.Threshold), StartEpoch: abi.ChainEpoch(ainfo.VestingStart), UnlockDuration: abi.ChainEpoch(ainfo.VestingDuration), From 36d87eb8e91e6decb490b98b1cbee7def97cb0dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 18 Aug 2020 15:04:31 +0200 Subject: [PATCH 10/53] more checks around genesis CID --- chain/gen/genesis/genesis.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index ca912fa82..2bc8ec27d 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -439,11 +439,19 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallB return nil, xerrors.Errorf("failed to decode filecoin genesis block CID: %w", err) } + if !expectedCid().Equals(filecoinGenesisCid) { + return nil, xerrors.Errorf("expectedCid != filecoinGenesisCid") + } + gblk, err := getGenesisBlock() if err != nil { return nil, xerrors.Errorf("failed to construct filecoin genesis block: %w", err) } + if !filecoinGenesisCid.Equals(gblk.Cid()) { + return nil, xerrors.Errorf("filecoinGenesisCid != gblk.Cid") + } + if err := bs.Put(gblk); err != nil { return nil, xerrors.Errorf("failed writing filecoin genesis block to blockstore: %w", err) } From 4cd56b3b99ff85230d1fc0e6498382deb40b3d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 18 Aug 2020 15:27:56 +0200 Subject: [PATCH 11/53] impl: wait in ClientRetrieve --- cli/client.go | 2 +- node/impl/client/client.go | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cli/client.go b/cli/client.go index 3320f5b5e..777073292 100644 --- a/cli/client.go +++ b/cli/client.go @@ -868,7 +868,7 @@ var clientRetrieveCmd = &cli.Command{ } if evt.Err != "" { - return xerrors.Errorf("retrieval failed: %v", err) + return xerrors.Errorf("retrieval failed: %s", evt.Err) } case <-ctx.Done(): return xerrors.Errorf("retrieval timed out") diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 1d9216d46..3b992fe54 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -403,7 +403,21 @@ func (a *API) ClientListImports(ctx context.Context) ([]api.Import, error) { func (a *API) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error { events := make(chan marketevents.RetrievalEvent) go a.clientRetrieve(ctx, order, ref, events) - return nil + + for { + select { + case evt, ok := <-events: + if !ok { // done successfully + return nil + } + + if evt.Err != "" { + return xerrors.Errorf("retrieval failed: %s", evt.Err) + } + case <-ctx.Done(): + return xerrors.Errorf("retrieval timed out") + } + } } func (a *API) ClientRetrieveWithEvents(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) { From c841f26256e2abcb3f0a555699773de09c9d89cc Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 18 Aug 2020 15:19:24 +0200 Subject: [PATCH 12/53] Basefee change depends on unique messages not all messages Signed-off-by: Jakub Sztandera --- build/params_shared_vals.go | 3 +++ chain/store/basefee.go | 34 +++++++++++++++++++++++++++++++--- chain/store/basefee_test.go | 6 +++--- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/build/params_shared_vals.go b/build/params_shared_vals.go index cfcab0140..2fce61ee7 100644 --- a/build/params_shared_vals.go +++ b/build/params_shared_vals.go @@ -89,11 +89,14 @@ const VerifSigCacheSize = 32000 // TODO: If this is gonna stay, it should move to specs-actors const BlockMessageLimit = 10000 + const BlockGasLimit = 10_000_000_000 const BlockGasTarget = BlockGasLimit / 2 const BaseFeeMaxChangeDenom = 8 // 12.5% const InitialBaseFee = 100e6 const MinimumBaseFee = 100 +const PackingEfficiencyNum = 4 +const PackingEfficiencyDenom = 5 // Actor consts // TODO: Pull from actors when its made not private diff --git a/chain/store/basefee.go b/chain/store/basefee.go index 7148ff9ba..3873f3945 100644 --- a/chain/store/basefee.go +++ b/chain/store/basefee.go @@ -7,11 +7,26 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" ) func computeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int) types.BigInt { - delta := gasLimitUsed/int64(noOfBlocks) - build.BlockGasTarget + // deta := 1/PackingEfficiency * gasLimitUsed/noOfBlocks - build.BlockGasTarget + // change := baseFee * deta / BlockGasTarget / BaseFeeMaxChangeDenom + // nextBaseFee = baseFee + change + // nextBaseFee = max(nextBaseFee, build.MinimumBaseFee) + + delta := build.PackingEfficiencyDenom * gasLimitUsed / int64(noOfBlocks*build.PackingEfficiencyNum) + delta -= build.BlockGasTarget + + // cap change at 12.5% (BaseFeeMaxChangeDenom) by capping delta + if delta > build.BlockGasTarget { + delta = build.BlockGasTarget + } + if delta < -build.BlockGasTarget { + delta = -build.BlockGasTarget + } change := big.Mul(baseFee, big.NewInt(delta)) change = big.Div(change, big.NewInt(build.BlockGasTarget)) @@ -26,17 +41,30 @@ func computeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int func (cs *ChainStore) ComputeBaseFee(ctx context.Context, ts *types.TipSet) (abi.TokenAmount, error) { zero := abi.NewTokenAmount(0) + + // totalLimit is sum of GasLimits of unique messages in a tipset totalLimit := int64(0) + + seen := make(map[cid.Cid]struct{}) + for _, b := range ts.Blocks() { msg1, msg2, err := cs.MessagesForBlock(b) if err != nil { return zero, xerrors.Errorf("error getting messages for: %s: %w", b.Cid(), err) } for _, m := range msg1 { - totalLimit += m.GasLimit + c := m.Cid() + if _, ok := seen[c]; !ok { + totalLimit += m.GasLimit + seen[c] = struct{}{} + } } for _, m := range msg2 { - totalLimit += m.Message.GasLimit + c := m.Cid() + if _, ok := seen[c]; !ok { + totalLimit += m.Message.GasLimit + seen[c] = struct{}{} + } } } parentBaseFee := ts.Blocks()[0].ParentBaseFee diff --git a/chain/store/basefee_test.go b/chain/store/basefee_test.go index c2186a711..7a7cae911 100644 --- a/chain/store/basefee_test.go +++ b/chain/store/basefee_test.go @@ -18,10 +18,10 @@ func TestBaseFee(t *testing.T) { }{ {100e6, 0, 1, 87.5e6}, {100e6, 0, 5, 87.5e6}, - {100e6, build.BlockGasTarget, 1, 100e6}, - {100e6, build.BlockGasTarget * 2, 2, 100e6}, + {100e6, build.BlockGasTarget, 1, 103.125e6}, + {100e6, build.BlockGasTarget * 2, 2, 103.125e6}, {100e6, build.BlockGasLimit * 2, 2, 112.5e6}, - {100e6, build.BlockGasLimit * 1.5, 2, 106.25e6}, + {100e6, build.BlockGasLimit * 1.5, 2, 110937500}, } for _, test := range tests { From 65ffde9e4b909310011cdf1ce36d7a6d90b05e0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 18 Aug 2020 16:20:31 +0200 Subject: [PATCH 13/53] fsm: Config for max WaitDeals sectors --- extern/storage-sealing/fsm.go | 6 +- extern/storage-sealing/sealing.go | 109 +++++++++++++++++++++++------- extern/storage-sealing/types.go | 4 +- node/builder.go | 4 +- node/config/def.go | 21 ++++-- node/impl/storminer.go | 19 ++++-- node/modules/dtypes/miner.go | 5 +- node/modules/storageminer.go | 26 ++++--- storage/miner.go | 14 ++-- 9 files changed, 151 insertions(+), 57 deletions(-) diff --git a/extern/storage-sealing/fsm.go b/extern/storage-sealing/fsm.go index fd9ff2d29..ddfebad24 100644 --- a/extern/storage-sealing/fsm.go +++ b/extern/storage-sealing/fsm.go @@ -328,7 +328,7 @@ func (m *Sealing) restartSectors(ctx context.Context) error { log.Errorf("loading sector list: %+v", err) } - sd, err := m.getSealDelay() + cfg, err := m.getConfig() if err != nil { return xerrors.Errorf("getting the sealing delay: %w", err) } @@ -339,8 +339,8 @@ func (m *Sealing) restartSectors(ctx context.Context) error { } if sector.State == WaitDeals { - if sd > 0 { - timer := time.NewTimer(sd) + if cfg.WaitDealsDelay > 0 { + timer := time.NewTimer(cfg.WaitDealsDelay) go func() { <-timer.C m.StartPacking(sector.SectorNumber) diff --git a/extern/storage-sealing/sealing.go b/extern/storage-sealing/sealing.go index eca387da3..7ae2e5163 100644 --- a/extern/storage-sealing/sealing.go +++ b/extern/storage-sealing/sealing.go @@ -3,6 +3,7 @@ package sealing import ( "context" "io" + "math" "sync" "time" @@ -33,6 +34,16 @@ type SectorLocation struct { Partition uint64 } +type Config struct { + // 0 = no limit + MaxWaitDealsSectors uint64 + + // includes failed, 0 = no limit + MaxSealingSectors uint64 + + WaitDealsDelay time.Duration +} + type SealingAPI interface { StateWaitMsg(context.Context, cid.Cid) (MsgLookup, error) StateComputeDataCommitment(ctx context.Context, maddr address.Address, sectorType abi.RegisteredSealProof, deals []abi.DealID, tok TipSetToken) (cid.Cid, error) @@ -70,7 +81,7 @@ type Sealing struct { upgradeLk sync.Mutex toUpgrade map[abi.SectorNumber]struct{} - getSealDelay GetSealingDelayFunc + getConfig GetSealingConfigFunc } type FeeConfig struct { @@ -80,7 +91,7 @@ type FeeConfig struct { type UnsealedSectorMap struct { infos map[abi.SectorNumber]UnsealedSectorInfo - mux sync.Mutex + lk sync.Mutex } type UnsealedSectorInfo struct { @@ -90,7 +101,7 @@ type UnsealedSectorInfo struct { pieceSizes []abi.UnpaddedPieceSize } -func New(api SealingAPI, fc FeeConfig, events Events, maddr address.Address, ds datastore.Batching, sealer sectorstorage.SectorManager, sc SectorIDCounter, verif ffiwrapper.Verifier, pcp PreCommitPolicy, gsd GetSealingDelayFunc) *Sealing { +func New(api SealingAPI, fc FeeConfig, events Events, maddr address.Address, ds datastore.Batching, sealer sectorstorage.SectorManager, sc SectorIDCounter, verif ffiwrapper.Verifier, pcp PreCommitPolicy, gc GetSealingConfigFunc) *Sealing { s := &Sealing{ api: api, feeCfg: fc, @@ -103,11 +114,11 @@ func New(api SealingAPI, fc FeeConfig, events Events, maddr address.Address, ds pcp: pcp, unsealedInfoMap: UnsealedSectorMap{ infos: make(map[abi.SectorNumber]UnsealedSectorInfo), - mux: sync.Mutex{}, + lk: sync.Mutex{}, }, - toUpgrade: map[abi.SectorNumber]struct{}{}, - getSealDelay: gsd, + toUpgrade: map[abi.SectorNumber]struct{}{}, + getConfig: gc, } s.sectors = statemachine.New(namespace.Wrap(ds, datastore.NewKey(SectorStorePrefix)), s, SectorInfo{}) @@ -137,18 +148,18 @@ func (m *Sealing) AddPieceToAnySector(ctx context.Context, size abi.UnpaddedPiec return 0, 0, xerrors.Errorf("piece cannot fit into a sector") } - m.unsealedInfoMap.mux.Lock() + m.unsealedInfoMap.lk.Lock() sid, pads, err := m.getSectorAndPadding(size) if err != nil { - m.unsealedInfoMap.mux.Unlock() + m.unsealedInfoMap.lk.Unlock() return 0, 0, xerrors.Errorf("getting available sector: %w", err) } for _, p := range pads { err = m.addPiece(ctx, sid, p.Unpadded(), NewNullReader(p.Unpadded()), nil) if err != nil { - m.unsealedInfoMap.mux.Unlock() + m.unsealedInfoMap.lk.Unlock() return 0, 0, xerrors.Errorf("writing pads: %w", err) } } @@ -157,12 +168,15 @@ func (m *Sealing) AddPieceToAnySector(ctx context.Context, size abi.UnpaddedPiec err = m.addPiece(ctx, sid, size, r, &d) if err != nil { - m.unsealedInfoMap.mux.Unlock() + m.unsealedInfoMap.lk.Unlock() return 0, 0, xerrors.Errorf("adding piece to sector: %w", err) } - m.unsealedInfoMap.mux.Unlock() - if m.unsealedInfoMap.infos[sid].numDeals == getDealPerSectorLimit(m.sealer.SectorSize()) { + startPacking := m.unsealedInfoMap.infos[sid].numDeals >= getDealPerSectorLimit(m.sealer.SectorSize()) + + m.unsealedInfoMap.lk.Unlock() + + if startPacking { if err := m.StartPacking(sid); err != nil { return 0, 0, xerrors.Errorf("start packing: %w", err) } @@ -171,7 +185,7 @@ func (m *Sealing) AddPieceToAnySector(ctx context.Context, size abi.UnpaddedPiec return sid, offset, nil } -// Caller should hold m.unsealedInfoMap.mux +// Caller should hold m.unsealedInfoMap.lk func (m *Sealing) addPiece(ctx context.Context, sectorID abi.SectorNumber, size abi.UnpaddedPieceSize, r io.Reader, di *DealInfo) error { log.Infof("Adding piece to sector %d", sectorID) ppi, err := m.sealer.AddPiece(sectorstorage.WithPriority(ctx, DealSectorPriority), m.minerSector(sectorID), m.unsealedInfoMap.infos[sectorID].pieceSizes, size, r) @@ -206,7 +220,7 @@ func (m *Sealing) Remove(ctx context.Context, sid abi.SectorNumber) error { return m.sectors.Send(uint64(sid), SectorRemove{}) } -// Caller should NOT hold m.unsealedInfoMap.mux +// Caller should NOT hold m.unsealedInfoMap.lk func (m *Sealing) StartPacking(sectorID abi.SectorNumber) error { log.Infof("Starting packing sector %d", sectorID) err := m.sectors.Send(uint64(sectorID), SectorStartPacking{}) @@ -214,14 +228,14 @@ func (m *Sealing) StartPacking(sectorID abi.SectorNumber) error { return err } - m.unsealedInfoMap.mux.Lock() + m.unsealedInfoMap.lk.Lock() delete(m.unsealedInfoMap.infos, sectorID) - m.unsealedInfoMap.mux.Unlock() + m.unsealedInfoMap.lk.Unlock() return nil } -// Caller should hold m.unsealedInfoMap.mux +// Caller should hold m.unsealedInfoMap.lk func (m *Sealing) getSectorAndPadding(size abi.UnpaddedPieceSize) (abi.SectorNumber, []abi.PaddedPieceSize, error) { ss := abi.PaddedPieceSize(m.sealer.SectorSize()) for k, v := range m.unsealedInfoMap.infos { @@ -231,7 +245,7 @@ func (m *Sealing) getSectorAndPadding(size abi.UnpaddedPieceSize) (abi.SectorNum } } - ns, err := m.newSector() + ns, err := m.newDealSector() if err != nil { return 0, nil, err } @@ -245,8 +259,57 @@ func (m *Sealing) getSectorAndPadding(size abi.UnpaddedPieceSize) (abi.SectorNum return ns, nil, nil } -// newSector creates a new sector for deal storage -func (m *Sealing) newSector() (abi.SectorNumber, error) { +// newDealSector creates a new sector for deal storage +func (m *Sealing) newDealSector() (abi.SectorNumber, error) { + // First make sure we don't have too many 'open' sectors + + cfg, err := m.getConfig() + if err != nil { + return 0, xerrors.Errorf("getting config: %w", err) + } + + if cfg.MaxWaitDealsSectors > 0 { + // run in a loop because we have to drop the map lock here for a bit + tries := 0 + + for uint64(len(m.unsealedInfoMap.infos)) >= cfg.MaxWaitDealsSectors { + if tries > 10 { + // whatever... + break + } + + if tries > 0 { + m.unsealedInfoMap.lk.Unlock() + time.Sleep(time.Second) + m.unsealedInfoMap.lk.Lock() + } + + tries++ + var mostStored abi.PaddedPieceSize = math.MaxUint64 + var best abi.SectorNumber = math.MaxUint64 + + for sn, info := range m.unsealedInfoMap.infos { + if info.stored + 1 > mostStored + 1 { // 18446744073709551615 + 1 = 0 + best = sn + } + } + + if best == math.MaxUint64 { + // probably not possible, but who knows + break + } + + m.unsealedInfoMap.lk.Unlock() + if err := m.StartPacking(best); err != nil { + log.Error("newDealSector StartPacking error: %+v", err) + continue // let's pretend this is fine + } + m.unsealedInfoMap.lk.Lock() + } + } + + // Now actually create a new sector + sid, err := m.sc.Next() if err != nil { return 0, xerrors.Errorf("getting sector number: %w", err) @@ -272,13 +335,13 @@ func (m *Sealing) newSector() (abi.SectorNumber, error) { return 0, xerrors.Errorf("starting the sector fsm: %w", err) } - sd, err := m.getSealDelay() + cf, err := m.getConfig() if err != nil { return 0, xerrors.Errorf("getting the sealing delay: %w", err) } - if sd > 0 { - timer := time.NewTimer(sd) + if cf.WaitDealsDelay > 0 { + timer := time.NewTimer(cf.WaitDealsDelay) go func() { <-timer.C m.StartPacking(sid) diff --git a/extern/storage-sealing/types.go b/extern/storage-sealing/types.go index 45993bb82..1e7c9f76c 100644 --- a/extern/storage-sealing/types.go +++ b/extern/storage-sealing/types.go @@ -3,8 +3,6 @@ package sealing import ( "bytes" "context" - "time" - "github.com/ipfs/go-cid" "github.com/filecoin-project/specs-actors/actors/abi" @@ -188,7 +186,7 @@ type MessageReceipt struct { GasUsed int64 } -type GetSealingDelayFunc func() (time.Duration, error) +type GetSealingConfigFunc func() (Config, error) func (mr *MessageReceipt) Equals(o *MessageReceipt) bool { return mr.ExitCode == o.ExitCode && bytes.Equal(mr.Return, o.Return) && mr.GasUsed == o.GasUsed diff --git a/node/builder.go b/node/builder.go index 7f1247084..cf07a660a 100644 --- a/node/builder.go +++ b/node/builder.go @@ -328,8 +328,8 @@ func Online() Option { Override(new(dtypes.SetConsiderOfflineStorageDealsConfigFunc), modules.NewSetConsideringOfflineStorageDealsFunc), Override(new(dtypes.ConsiderOfflineRetrievalDealsConfigFunc), modules.NewConsiderOfflineRetrievalDealsConfigFunc), Override(new(dtypes.SetConsiderOfflineRetrievalDealsConfigFunc), modules.NewSetConsiderOfflineRetrievalDealsConfigFunc), - Override(new(dtypes.SetSealingDelayFunc), modules.NewSetSealDelayFunc), - Override(new(dtypes.GetSealingDelayFunc), modules.NewGetSealDelayFunc), + Override(new(dtypes.SetSealingConfigFunc), modules.NewSetSealConfigFunc), + Override(new(dtypes.GetSealingConfigFunc), modules.NewGetSealConfigFunc), Override(new(dtypes.SetExpectedSealDurationFunc), modules.NewSetExpectedSealDurationFunc), Override(new(dtypes.GetExpectedSealDurationFunc), modules.NewGetExpectedSealDurationFunc), ), diff --git a/node/config/def.go b/node/config/def.go index 436935916..fcddf73ba 100644 --- a/node/config/def.go +++ b/node/config/def.go @@ -31,10 +31,9 @@ type StorageMiner struct { Common Dealmaking DealmakingConfig + Sealing SealingConfig Storage sectorstorage.SealerConfig Fees MinerFeeConfig - - SealingDelay Duration } type DealmakingConfig struct { @@ -48,6 +47,16 @@ type DealmakingConfig struct { Filter string } +type SealingConfig struct { + // 0 = no limit + MaxWaitDealsSectors uint64 + + // includes failed, 0 = no limit + MaxSealingSectors uint64 + + WaitDealsDelay Duration +} + type MinerFeeConfig struct { MaxPreCommitGasFee types.FIL MaxCommitGasFee types.FIL @@ -130,6 +139,12 @@ func DefaultFullNode() *FullNode { func DefaultStorageMiner() *StorageMiner { cfg := &StorageMiner{ Common: defCommon(), + + Sealing: SealingConfig{ + MaxWaitDealsSectors: 2, // 64G with 32G sectors + MaxSealingSectors: 0, + WaitDealsDelay: Duration(time.Hour), + }, Storage: sectorstorage.SealerConfig{ AllowAddPiece: true, @@ -158,8 +173,6 @@ func DefaultStorageMiner() *StorageMiner { MaxCommitGasFee: types.FIL(types.BigDiv(types.FromFil(1), types.NewInt(20))), MaxWindowPoStGasFee: types.FIL(types.FromFil(50)), }, - - SealingDelay: Duration(time.Hour), } cfg.Common.API.ListenAddress = "/ip4/127.0.0.1/tcp/2345/http" cfg.Common.API.RemoteListenAddress = "127.0.0.1:2345" diff --git a/node/impl/storminer.go b/node/impl/storminer.go index e302f7051..77052164b 100644 --- a/node/impl/storminer.go +++ b/node/impl/storminer.go @@ -62,8 +62,8 @@ type StorageMinerAPI struct { SetConsiderOfflineStorageDealsConfigFunc dtypes.SetConsiderOfflineStorageDealsConfigFunc ConsiderOfflineRetrievalDealsConfigFunc dtypes.ConsiderOfflineRetrievalDealsConfigFunc SetConsiderOfflineRetrievalDealsConfigFunc dtypes.SetConsiderOfflineRetrievalDealsConfigFunc - SetSealingDelayFunc dtypes.SetSealingDelayFunc - GetSealingDelayFunc dtypes.GetSealingDelayFunc + SetSealingConfigFunc dtypes.SetSealingConfigFunc + GetSealingConfigFunc dtypes.GetSealingConfigFunc GetExpectedSealDurationFunc dtypes.GetExpectedSealDurationFunc SetExpectedSealDurationFunc dtypes.SetExpectedSealDurationFunc } @@ -232,11 +232,22 @@ func (sm *StorageMinerAPI) SectorStartSealing(ctx context.Context, number abi.Se } func (sm *StorageMinerAPI) SectorSetSealDelay(ctx context.Context, delay time.Duration) error { - return sm.SetSealingDelayFunc(delay) + cfg, err := sm.GetSealingConfigFunc() + if err != nil { + return xerrors.Errorf("get config: %w", err) + } + + cfg.WaitDealsDelay = delay + + return sm.SetSealingConfigFunc(cfg) } func (sm *StorageMinerAPI) SectorGetSealDelay(ctx context.Context) (time.Duration, error) { - return sm.GetSealingDelayFunc() + cfg, err := sm.GetSealingConfigFunc() + if err != nil { + return 0, err + } + return cfg.WaitDealsDelay, nil } func (sm *StorageMinerAPI) SectorSetExpectedSealDuration(ctx context.Context, delay time.Duration) error { diff --git a/node/modules/dtypes/miner.go b/node/modules/dtypes/miner.go index 34911df5e..600d19dc7 100644 --- a/node/modules/dtypes/miner.go +++ b/node/modules/dtypes/miner.go @@ -8,6 +8,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-fil-markets/storagemarket" + sealing "github.com/filecoin-project/lotus/extern/storage-sealing" "github.com/filecoin-project/specs-actors/actors/abi" ) @@ -56,10 +57,10 @@ type ConsiderOfflineRetrievalDealsConfigFunc func() (bool, error) type SetConsiderOfflineRetrievalDealsConfigFunc func(bool) error // SetSealingDelay sets how long a sector waits for more deals before sealing begins. -type SetSealingDelayFunc func(time.Duration) error +type SetSealingConfigFunc func(sealing.Config) error // GetSealingDelay returns how long a sector waits for more deals before sealing begins. -type GetSealingDelayFunc func() (time.Duration, error) +type GetSealingConfigFunc func() (sealing.Config, error) // SetExpectedSealDurationFunc is a function which is used to set how long sealing is expected to take. // Deals that would need to start earlier than this duration will be rejected. diff --git a/node/modules/storageminer.go b/node/modules/storageminer.go index 7aec09482..e0cbb434e 100644 --- a/node/modules/storageminer.go +++ b/node/modules/storageminer.go @@ -141,8 +141,8 @@ func SectorIDCounter(ds dtypes.MetadataDS) sealing.SectorIDCounter { return &sidsc{sc} } -func StorageMiner(fc config.MinerFeeConfig) func(mctx helpers.MetricsCtx, lc fx.Lifecycle, api lapi.FullNode, h host.Host, ds dtypes.MetadataDS, sealer sectorstorage.SectorManager, sc sealing.SectorIDCounter, verif ffiwrapper.Verifier, gsd dtypes.GetSealingDelayFunc) (*storage.Miner, error) { - return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, api lapi.FullNode, h host.Host, ds dtypes.MetadataDS, sealer sectorstorage.SectorManager, sc sealing.SectorIDCounter, verif ffiwrapper.Verifier, gsd dtypes.GetSealingDelayFunc) (*storage.Miner, error) { +func StorageMiner(fc config.MinerFeeConfig) func(mctx helpers.MetricsCtx, lc fx.Lifecycle, api lapi.FullNode, h host.Host, ds dtypes.MetadataDS, sealer sectorstorage.SectorManager, sc sealing.SectorIDCounter, verif ffiwrapper.Verifier, gsd dtypes.GetSealingConfigFunc) (*storage.Miner, error) { + return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, api lapi.FullNode, h host.Host, ds dtypes.MetadataDS, sealer sectorstorage.SectorManager, sc sealing.SectorIDCounter, verif ffiwrapper.Verifier, gsd dtypes.GetSealingConfigFunc) (*storage.Miner, error) { maddr, err := minerAddrFromDS(ds) if err != nil { return nil, err @@ -593,19 +593,27 @@ func NewSetConsiderOfflineRetrievalDealsConfigFunc(r repo.LockedRepo) (dtypes.Se }, nil } -func NewSetSealDelayFunc(r repo.LockedRepo) (dtypes.SetSealingDelayFunc, error) { - return func(delay time.Duration) (err error) { - err = mutateCfg(r, func(cfg *config.StorageMiner) { - cfg.SealingDelay = config.Duration(delay) +func NewSetSealConfigFunc(r repo.LockedRepo) (dtypes.SetSealingConfigFunc, error) { + return func(cfg sealing.Config) (err error) { + err = mutateCfg(r, func(c *config.StorageMiner) { + c.Sealing = config.SealingConfig{ + MaxWaitDealsSectors: cfg.MaxWaitDealsSectors, + MaxSealingSectors: cfg.MaxSealingSectors, + WaitDealsDelay: config.Duration(cfg.WaitDealsDelay), + } }) return }, nil } -func NewGetSealDelayFunc(r repo.LockedRepo) (dtypes.GetSealingDelayFunc, error) { - return func() (out time.Duration, err error) { +func NewGetSealConfigFunc(r repo.LockedRepo) (dtypes.GetSealingConfigFunc, error) { + return func() (out sealing.Config, err error) { err = readCfg(r, func(cfg *config.StorageMiner) { - out = time.Duration(cfg.SealingDelay) + out = sealing.Config{ + MaxWaitDealsSectors: cfg.Sealing.MaxWaitDealsSectors, + MaxSealingSectors: cfg.Sealing.MaxSealingSectors, + WaitDealsDelay: time.Duration(cfg.Sealing.WaitDealsDelay), + } }) return }, nil diff --git a/storage/miner.go b/storage/miner.go index f8a6691f4..803556cdf 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -43,8 +43,8 @@ type Miner struct { maddr address.Address worker address.Address - getSealDelay dtypes.GetSealingDelayFunc - sealing *sealing.Sealing + getSealConfig dtypes.GetSealingConfigFunc + sealing *sealing.Sealing } type storageMinerApi interface { @@ -84,7 +84,7 @@ type storageMinerApi interface { WalletHas(context.Context, address.Address) (bool, error) } -func NewMiner(api storageMinerApi, maddr, worker address.Address, h host.Host, ds datastore.Batching, sealer sectorstorage.SectorManager, sc sealing.SectorIDCounter, verif ffiwrapper.Verifier, gsd dtypes.GetSealingDelayFunc, feeCfg config.MinerFeeConfig) (*Miner, error) { +func NewMiner(api storageMinerApi, maddr, worker address.Address, h host.Host, ds datastore.Batching, sealer sectorstorage.SectorManager, sc sealing.SectorIDCounter, verif ffiwrapper.Verifier, gsd dtypes.GetSealingConfigFunc, feeCfg config.MinerFeeConfig) (*Miner, error) { m := &Miner{ api: api, feeCfg: feeCfg, @@ -94,9 +94,9 @@ func NewMiner(api storageMinerApi, maddr, worker address.Address, h host.Host, d sc: sc, verif: verif, - maddr: maddr, - worker: worker, - getSealDelay: gsd, + maddr: maddr, + worker: worker, + getSealConfig: gsd, } return m, nil @@ -120,7 +120,7 @@ func (m *Miner) Run(ctx context.Context) error { evts := events.NewEvents(ctx, m.api) adaptedAPI := NewSealingAPIAdapter(m.api) pcp := sealing.NewBasicPreCommitPolicy(adaptedAPI, miner.MaxSectorExpirationExtension-(miner.WPoStProvingPeriod*2), md.PeriodStart%miner.WPoStProvingPeriod) - m.sealing = sealing.New(adaptedAPI, fc, NewEventsAdapter(evts), m.maddr, m.ds, m.sealer, m.sc, m.verif, &pcp, sealing.GetSealingDelayFunc(m.getSealDelay)) + m.sealing = sealing.New(adaptedAPI, fc, NewEventsAdapter(evts), m.maddr, m.ds, m.sealer, m.sc, m.verif, &pcp, sealing.GetSealingConfigFunc(m.getSealConfig)) go m.sealing.Run(ctx) //nolint:errcheck // logged intside the function From 6a49bd6d8e4a2200d49bbb28f4b9d0878f1a9fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 18 Aug 2020 16:54:05 +0200 Subject: [PATCH 14/53] fsm: Config for limiting max sealing sectors --- extern/storage-sealing/fsm.go | 2 ++ extern/storage-sealing/sealing.go | 19 +++++++++++ extern/storage-sealing/sector_state.go | 11 +++++++ extern/storage-sealing/stats.go | 45 ++++++++++++++++++++++++++ 4 files changed, 77 insertions(+) create mode 100644 extern/storage-sealing/stats.go diff --git a/extern/storage-sealing/fsm.go b/extern/storage-sealing/fsm.go index ddfebad24..4842e6023 100644 --- a/extern/storage-sealing/fsm.go +++ b/extern/storage-sealing/fsm.go @@ -225,6 +225,8 @@ func (m *Sealing) plan(events []statemachine.Event, state *SectorInfo) (func(sta */ + m.stats.updateSector(m.minerSector(state.SectorNumber), state.State) + switch state.State { // Happy path case Empty: diff --git a/extern/storage-sealing/sealing.go b/extern/storage-sealing/sealing.go index 7ae2e5163..3ae75e189 100644 --- a/extern/storage-sealing/sealing.go +++ b/extern/storage-sealing/sealing.go @@ -81,6 +81,8 @@ type Sealing struct { upgradeLk sync.Mutex toUpgrade map[abi.SectorNumber]struct{} + stats SectorStats + getConfig GetSealingConfigFunc } @@ -268,6 +270,12 @@ func (m *Sealing) newDealSector() (abi.SectorNumber, error) { return 0, xerrors.Errorf("getting config: %w", err) } + if cfg.MaxSealingSectors > 0 { + if m.stats.curSealing() > cfg.MaxSealingSectors { + return 0, xerrors.Errorf("too many sectors sealing") + } + } + if cfg.MaxWaitDealsSectors > 0 { // run in a loop because we have to drop the map lock here for a bit tries := 0 @@ -353,6 +361,17 @@ func (m *Sealing) newDealSector() (abi.SectorNumber, error) { // newSectorCC accepts a slice of pieces with no deal (junk data) func (m *Sealing) newSectorCC(sid abi.SectorNumber, pieces []Piece) error { + cfg, err := m.getConfig() + if err != nil { + return xerrors.Errorf("getting config: %w", err) + } + + if cfg.MaxSealingSectors > 0 { + if m.stats.curSealing() > cfg.MaxSealingSectors { + return xerrors.Errorf("too many sectors sealing (curSealing: %d, max: %d)", m.stats.curSealing(), cfg.MaxSealingSectors) + } + } + rt, err := ffiwrapper.SealProofTypeFromSectorSize(m.sealer.SectorSize()) if err != nil { return xerrors.Errorf("bad sector size: %w", err) diff --git a/extern/storage-sealing/sector_state.go b/extern/storage-sealing/sector_state.go index f2801c9fc..2f57d83e8 100644 --- a/extern/storage-sealing/sector_state.go +++ b/extern/storage-sealing/sector_state.go @@ -36,3 +36,14 @@ const ( RemoveFailed SectorState = "RemoveFailed" Removed SectorState = "Removed" ) + +func toStatState(st SectorState) statSectorState { + switch st { + case Empty, WaitDeals, Packing, PreCommit1, PreCommit2, PreCommitting, PreCommitWait, WaitSeed, Committing, CommitWait, FinalizeSector: + return sstSealing + case Proving, Removed, Removing: + return sstProving + } + + return sstFailed +} diff --git a/extern/storage-sealing/stats.go b/extern/storage-sealing/stats.go new file mode 100644 index 000000000..3d31a39ff --- /dev/null +++ b/extern/storage-sealing/stats.go @@ -0,0 +1,45 @@ +package sealing + +import ( + "sync" + + "github.com/filecoin-project/specs-actors/actors/abi" +) + +type statSectorState int +const ( + sstSealing statSectorState = iota + sstFailed + sstProving + nsst +) + +type SectorStats struct { + lk sync.Mutex + + bySector map[abi.SectorID]statSectorState + totals [nsst]uint64 +} + +func (ss *SectorStats) updateSector(id abi.SectorID, st SectorState) { + ss.lk.Lock() + defer ss.lk.Unlock() + + oldst, found := ss.bySector[id] + if found { + ss.totals[oldst]-- + } + + sst := toStatState(st) + ss.bySector[id] = sst + ss.totals[sst]++ +} + + +// return the number of sectors currently in the sealing pipeline +func (ss *SectorStats) curSealing() uint64 { + ss.lk.Lock() + defer ss.lk.Unlock() + + return ss.totals[sstSealing] + ss.totals[sstFailed] +} From c9fdd4bee279a05d9364ca4ef71dfb1683ac6ed4 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 18 Aug 2020 17:40:53 +0200 Subject: [PATCH 15/53] Fix testgrounds build Signed-off-by: Jakub Sztandera --- build/params_testground.go | 3 +++ chain/store/basefee.go | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/build/params_testground.go b/build/params_testground.go index ffd5ac9a4..bdd56fbb1 100644 --- a/build/params_testground.go +++ b/build/params_testground.go @@ -66,4 +66,7 @@ var ( // Actor consts // TODO: Pull from actors when its made not private MinDealDuration = abi.ChainEpoch(180 * builtin.EpochsInDay) + + PackingEfficiencyNum int64 = 4 + PackingEfficiencyDenom int64 = 5 ) diff --git a/chain/store/basefee.go b/chain/store/basefee.go index 3873f3945..de3f90a8f 100644 --- a/chain/store/basefee.go +++ b/chain/store/basefee.go @@ -17,7 +17,7 @@ func computeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int // nextBaseFee = baseFee + change // nextBaseFee = max(nextBaseFee, build.MinimumBaseFee) - delta := build.PackingEfficiencyDenom * gasLimitUsed / int64(noOfBlocks*build.PackingEfficiencyNum) + delta := build.PackingEfficiencyDenom * gasLimitUsed / (int64(noOfBlocks) * build.PackingEfficiencyNum) delta -= build.BlockGasTarget // cap change at 12.5% (BaseFeeMaxChangeDenom) by capping delta From 886d9cd5eb9ccb4fdb821d27d584bc30ca271c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 18 Aug 2020 18:02:13 +0200 Subject: [PATCH 16/53] fsm: handle already-precommitted CommitFailed sectors correctly --- extern/storage-sealing/checks.go | 15 +++++++++++++++ extern/storage-sealing/fsm.go | 3 +++ extern/storage-sealing/fsm_events.go | 4 ++++ extern/storage-sealing/sealing.go | 10 ++++++++++ extern/storage-sealing/states_failed.go | 12 ++++++++++++ extern/storage-sealing/states_sealing.go | 18 ++++++++++++++++++ storage/adapter_storage_miner.go | 23 ++++++++++++++++++++++- storage/miner.go | 1 + 8 files changed, 85 insertions(+), 1 deletion(-) diff --git a/extern/storage-sealing/checks.go b/extern/storage-sealing/checks.go index 95ef101fa..af62b9548 100644 --- a/extern/storage-sealing/checks.go +++ b/extern/storage-sealing/checks.go @@ -26,10 +26,12 @@ type ErrBadCommD struct{ error } type ErrExpiredTicket struct{ error } type ErrBadTicket struct{ error } type ErrPrecommitOnChain struct{ error } +type ErrSectorNumberAllocated struct{ error } type ErrBadSeed struct{ error } type ErrInvalidProof struct{ error } type ErrNoPrecommit struct{ error } +type ErrCommitWaitFailed struct{ error } func checkPieces(ctx context.Context, si SectorInfo, api SealingAPI) error { tok, height, err := api.ChainHead(ctx) @@ -87,6 +89,9 @@ func checkPrecommit(ctx context.Context, maddr address.Address, si SectorInfo, t pci, err := api.StateSectorPreCommitInfo(ctx, maddr, si.SectorNumber, tok) if err != nil { + if err == ErrSectorAllocated { + return &ErrSectorNumberAllocated{err} + } return &ErrApi{xerrors.Errorf("getting precommit info: %w", err)} } @@ -106,6 +111,16 @@ func (m *Sealing) checkCommit(ctx context.Context, si SectorInfo, proof []byte, } pci, err := m.api.StateSectorPreCommitInfo(ctx, m.maddr, si.SectorNumber, tok) + if err == ErrSectorAllocated { + // not much more we can check here, basically try to wait for commit, + // and hope that this will work + + if si.CommitMessage != nil { + return &ErrCommitWaitFailed{err} + } + + return err + } if err != nil { return xerrors.Errorf("getting precommit info: %w", err) } diff --git a/extern/storage-sealing/fsm.go b/extern/storage-sealing/fsm.go index 4842e6023..d9648a99d 100644 --- a/extern/storage-sealing/fsm.go +++ b/extern/storage-sealing/fsm.go @@ -108,6 +108,7 @@ var fsmPlanners = map[SectorState]func(events []statemachine.Event, state *Secto on(SectorRetryPreCommitWait{}, PreCommitWait), on(SectorChainPreCommitFailed{}, PreCommitFailed), on(SectorRetryPreCommit{}, PreCommitting), + on(SectorRetryCommitWait{}, CommitWait), ), FinalizeFailed: planOne( on(SectorRetryFinalize{}, FinalizeSector), @@ -317,6 +318,8 @@ func planCommitting(events []statemachine.Event, state *SectorInfo) error { state.State = SealPreCommit1Failed case SectorCommitFailed: state.State = CommitFailed + case SectorRetryCommitWait: + state.State = CommitWait default: return xerrors.Errorf("planCommitting got event of unknown type %T, events: %+v", event.User, events) } diff --git a/extern/storage-sealing/fsm_events.go b/extern/storage-sealing/fsm_events.go index c4278991e..f270b3668 100644 --- a/extern/storage-sealing/fsm_events.go +++ b/extern/storage-sealing/fsm_events.go @@ -252,6 +252,10 @@ func (evt SectorRetryInvalidProof) apply(state *SectorInfo) { state.InvalidProofs++ } +type SectorRetryCommitWait struct{} + +func (evt SectorRetryCommitWait) apply(state *SectorInfo) {} + // Faults type SectorFaulty struct{} diff --git a/extern/storage-sealing/sealing.go b/extern/storage-sealing/sealing.go index 3ae75e189..3a6bb8e5f 100644 --- a/extern/storage-sealing/sealing.go +++ b/extern/storage-sealing/sealing.go @@ -2,6 +2,7 @@ package sealing import ( "context" + "errors" "io" "math" "sync" @@ -44,9 +45,14 @@ type Config struct { WaitDealsDelay time.Duration } +var ErrSectorAllocated = errors.New("sectorNumber is allocated, but PreCommit info wasn't found on chain") + type SealingAPI interface { StateWaitMsg(context.Context, cid.Cid) (MsgLookup, error) + StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error) StateComputeDataCommitment(ctx context.Context, maddr address.Address, sectorType abi.RegisteredSealProof, deals []abi.DealID, tok TipSetToken) (cid.Cid, error) + + // Can return ErrSectorAllocated in case precommit info wasn't found, but the sector number is marked as allocated StateSectorPreCommitInfo(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok TipSetToken) (*miner.SectorPreCommitOnChainInfo, error) StateSectorGetInfo(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok TipSetToken) (*miner.SectorOnChainInfo, error) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok TipSetToken) (*SectorLocation, error) @@ -121,6 +127,10 @@ func New(api SealingAPI, fc FeeConfig, events Events, maddr address.Address, ds toUpgrade: map[abi.SectorNumber]struct{}{}, getConfig: gc, + + stats: SectorStats{ + bySector: map[abi.SectorID]statSectorState{}, + }, } s.sectors = statemachine.New(namespace.Wrap(ds, datastore.NewKey(SectorStorePrefix)), s, SectorInfo{}) diff --git a/extern/storage-sealing/states_failed.go b/extern/storage-sealing/states_failed.go index e208a8cca..cf829f44f 100644 --- a/extern/storage-sealing/states_failed.go +++ b/extern/storage-sealing/states_failed.go @@ -85,6 +85,10 @@ func (m *Sealing) handlePreCommitFailed(ctx statemachine.Context, sector SectorI return ctx.Send(SectorRetryPreCommit{}) case *ErrPrecommitOnChain: // noop + case *ErrSectorNumberAllocated: + log.Errorf("handlePreCommitFailed: sector number already allocated, not proceeding: %+v", err) + // TODO: check if the sector is committed (not sure how we'd end up here) + return nil default: return xerrors.Errorf("checkPrecommit sanity check error: %w", err) } @@ -158,6 +162,8 @@ func (m *Sealing) handleCommitFailed(ctx statemachine.Context, sector SectorInfo return ctx.Send(SectorChainPreCommitFailed{xerrors.Errorf("no precommit: %w", err)}) case *ErrPrecommitOnChain: // noop, this is expected + case *ErrSectorNumberAllocated: + // noop, already committed? default: return xerrors.Errorf("checkPrecommit sanity check error (%T): %w", err, err) } @@ -186,6 +192,12 @@ func (m *Sealing) handleCommitFailed(ctx statemachine.Context, sector SectorInfo return ctx.Send(SectorRetryPreCommitWait{}) case *ErrNoPrecommit: return ctx.Send(SectorRetryPreCommit{}) + case *ErrCommitWaitFailed: + if err := failedCooldown(ctx, sector); err != nil { + return err + } + + return ctx.Send(SectorRetryCommitWait{}) default: return xerrors.Errorf("checkCommit sanity check error (%T): %w", err, err) } diff --git a/extern/storage-sealing/states_sealing.go b/extern/storage-sealing/states_sealing.go index 2178ce0b4..110a73ac0 100644 --- a/extern/storage-sealing/states_sealing.go +++ b/extern/storage-sealing/states_sealing.go @@ -149,6 +149,10 @@ func (m *Sealing) handlePreCommitting(ctx statemachine.Context, sector SectorInf return ctx.Send(SectorSealPreCommit1Failed{xerrors.Errorf("bad ticket: %w", err)}) case *ErrPrecommitOnChain: return ctx.Send(SectorPreCommitLanded{TipSet: tok}) // we re-did precommit + case *ErrSectorNumberAllocated: + log.Errorf("handlePreCommitFailed: sector number already allocated, not proceeding: %+v", err) + // TODO: check if the sector is committed (not sure how we'd end up here) + return nil default: return xerrors.Errorf("checkPrecommit sanity check error: %w", err) } @@ -275,6 +279,20 @@ func (m *Sealing) handleWaitSeed(ctx statemachine.Context, sector SectorInfo) er } func (m *Sealing) handleCommitting(ctx statemachine.Context, sector SectorInfo) error { + if sector.CommitMessage != nil { + log.Warnf("sector %d entered committing state with a commit message cid", sector.SectorNumber) + + ml, err := m.api.StateSearchMsg(ctx.Context(), *sector.CommitMessage) + if err != nil { + log.Warnf("sector %d searching existing commit message %s: %+v", sector.SectorNumber, *sector.CommitMessage, err) + } + + if ml != nil { + // some weird retry paths can lead here + return ctx.Send(SectorRetryCommitWait{}) + } + } + log.Info("scheduling seal proof computation...") log.Infof("KOMIT %d %x(%d); %x(%d); %v; r:%x; d:%x", sector.SectorNumber, sector.TicketValue, sector.TicketEpoch, sector.SeedValue, sector.SeedEpoch, sector.pieceInfos(), sector.CommR, sector.CommD) diff --git a/storage/adapter_storage_miner.go b/storage/adapter_storage_miner.go index 8881e599e..1890a369f 100644 --- a/storage/adapter_storage_miner.go +++ b/storage/adapter_storage_miner.go @@ -108,6 +108,27 @@ func (s SealingAPIAdapter) StateWaitMsg(ctx context.Context, mcid cid.Cid) (seal }, nil } +func (s SealingAPIAdapter) StateSearchMsg(ctx context.Context, c cid.Cid) (*sealing.MsgLookup, error) { + wmsg, err := s.delegate.StateSearchMsg(ctx, c) + if err != nil { + return nil, err + } + + if wmsg == nil { + return nil, nil + } + + return &sealing.MsgLookup{ + Receipt: sealing.MessageReceipt{ + ExitCode: wmsg.Receipt.ExitCode, + Return: wmsg.Receipt.Return, + GasUsed: wmsg.Receipt.GasUsed, + }, + TipSetTok: wmsg.TipSet.Bytes(), + Height: wmsg.Height, + }, nil +} + func (s SealingAPIAdapter) StateComputeDataCommitment(ctx context.Context, maddr address.Address, sectorType abi.RegisteredSealProof, deals []abi.DealID, tok sealing.TipSetToken) (cid.Cid, error) { tsk, err := types.TipSetKeyFromBytes(tok) if err != nil { @@ -186,7 +207,7 @@ func (s SealingAPIAdapter) StateSectorPreCommitInfo(ctx context.Context, maddr a return nil, xerrors.Errorf("checking if sector is allocated: %w", err) } if set { - return nil, xerrors.Errorf("sectorNumber is allocated") + return nil, sealing.ErrSectorAllocated } return nil, nil diff --git a/storage/miner.go b/storage/miner.go index 803556cdf..7baffee30 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -60,6 +60,7 @@ type storageMinerApi interface { StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error) StateMinerPreCommitDepositForPower(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error) StateMinerInitialPledgeCollateral(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error) + StateSearchMsg(context.Context, cid.Cid) (*api.MsgLookup, error) StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) // TODO: removeme eventually StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) From baf91f08a12962067d3235c75705025fb3699752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 18 Aug 2020 18:27:18 +0200 Subject: [PATCH 17/53] Unbreak tests --- extern/storage-sealing/fsm_test.go | 26 +++++++++++++++++++--- extern/storage-sealing/sealiface/config.go | 16 +++++++++++++ extern/storage-sealing/sealing.go | 10 --------- extern/storage-sealing/types.go | 3 ++- node/modules/dtypes/miner.go | 7 +++--- node/modules/storageminer.go | 7 +++--- 6 files changed, 49 insertions(+), 20 deletions(-) create mode 100644 extern/storage-sealing/sealiface/config.go diff --git a/extern/storage-sealing/fsm_test.go b/extern/storage-sealing/fsm_test.go index b1e53133c..474ea1966 100644 --- a/extern/storage-sealing/fsm_test.go +++ b/extern/storage-sealing/fsm_test.go @@ -3,6 +3,8 @@ package sealing import ( "testing" + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/abi" logging "github.com/ipfs/go-log/v2" "github.com/stretchr/testify/require" @@ -25,8 +27,14 @@ type test struct { } func TestHappyPath(t *testing.T) { + ma, _ := address.NewIDAddress(55151) m := test{ - s: &Sealing{}, + s: &Sealing{ + maddr: ma, + stats: SectorStats{ + bySector: map[abi.SectorID]statSectorState{}, + }, + }, t: t, state: &SectorInfo{State: Packing}, } @@ -60,8 +68,14 @@ func TestHappyPath(t *testing.T) { } func TestSeedRevert(t *testing.T) { + ma, _ := address.NewIDAddress(55151) m := test{ - s: &Sealing{}, + s: &Sealing{ + maddr: ma, + stats: SectorStats{ + bySector: map[abi.SectorID]statSectorState{}, + }, + }, t: t, state: &SectorInfo{State: Packing}, } @@ -101,8 +115,14 @@ func TestSeedRevert(t *testing.T) { } func TestPlanCommittingHandlesSectorCommitFailed(t *testing.T) { + ma, _ := address.NewIDAddress(55151) m := test{ - s: &Sealing{}, + s: &Sealing{ + maddr: ma, + stats: SectorStats{ + bySector: map[abi.SectorID]statSectorState{}, + }, + }, t: t, state: &SectorInfo{State: Committing}, } diff --git a/extern/storage-sealing/sealiface/config.go b/extern/storage-sealing/sealiface/config.go new file mode 100644 index 000000000..ad0b12c40 --- /dev/null +++ b/extern/storage-sealing/sealiface/config.go @@ -0,0 +1,16 @@ +package sealiface + +import "time" + +// this has to be in a separate package to not make lotus API depend on filecoin-ffi + +type Config struct { + // 0 = no limit + MaxWaitDealsSectors uint64 + + // includes failed, 0 = no limit + MaxSealingSectors uint64 + + WaitDealsDelay time.Duration +} + diff --git a/extern/storage-sealing/sealing.go b/extern/storage-sealing/sealing.go index 3a6bb8e5f..006118e58 100644 --- a/extern/storage-sealing/sealing.go +++ b/extern/storage-sealing/sealing.go @@ -35,16 +35,6 @@ type SectorLocation struct { Partition uint64 } -type Config struct { - // 0 = no limit - MaxWaitDealsSectors uint64 - - // includes failed, 0 = no limit - MaxSealingSectors uint64 - - WaitDealsDelay time.Duration -} - var ErrSectorAllocated = errors.New("sectorNumber is allocated, but PreCommit info wasn't found on chain") type SealingAPI interface { diff --git a/extern/storage-sealing/types.go b/extern/storage-sealing/types.go index 1e7c9f76c..a9c2a7203 100644 --- a/extern/storage-sealing/types.go +++ b/extern/storage-sealing/types.go @@ -12,6 +12,7 @@ import ( "github.com/filecoin-project/specs-storage/storage" sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" + "github.com/filecoin-project/lotus/extern/storage-sealing/sealiface" ) // Piece is a tuple of piece and deal info @@ -186,7 +187,7 @@ type MessageReceipt struct { GasUsed int64 } -type GetSealingConfigFunc func() (Config, error) +type GetSealingConfigFunc func() (sealiface.Config, error) func (mr *MessageReceipt) Equals(o *MessageReceipt) bool { return mr.ExitCode == o.ExitCode && bytes.Equal(mr.Return, o.Return) && mr.GasUsed == o.GasUsed diff --git a/node/modules/dtypes/miner.go b/node/modules/dtypes/miner.go index 600d19dc7..d559a2de1 100644 --- a/node/modules/dtypes/miner.go +++ b/node/modules/dtypes/miner.go @@ -8,8 +8,9 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-fil-markets/storagemarket" - sealing "github.com/filecoin-project/lotus/extern/storage-sealing" "github.com/filecoin-project/specs-actors/actors/abi" + + "github.com/filecoin-project/lotus/extern/storage-sealing/sealiface" ) type MinerAddress address.Address @@ -57,10 +58,10 @@ type ConsiderOfflineRetrievalDealsConfigFunc func() (bool, error) type SetConsiderOfflineRetrievalDealsConfigFunc func(bool) error // SetSealingDelay sets how long a sector waits for more deals before sealing begins. -type SetSealingConfigFunc func(sealing.Config) error +type SetSealingConfigFunc func(sealiface.Config) error // GetSealingDelay returns how long a sector waits for more deals before sealing begins. -type GetSealingConfigFunc func() (sealing.Config, error) +type GetSealingConfigFunc func() (sealiface.Config, error) // SetExpectedSealDurationFunc is a function which is used to set how long sealing is expected to take. // Deals that would need to start earlier than this duration will be rejected. diff --git a/node/modules/storageminer.go b/node/modules/storageminer.go index e0cbb434e..3be869f0f 100644 --- a/node/modules/storageminer.go +++ b/node/modules/storageminer.go @@ -48,6 +48,7 @@ import ( "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" "github.com/filecoin-project/lotus/extern/sector-storage/stores" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" + "github.com/filecoin-project/lotus/extern/storage-sealing/sealiface" lapi "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" @@ -594,7 +595,7 @@ func NewSetConsiderOfflineRetrievalDealsConfigFunc(r repo.LockedRepo) (dtypes.Se } func NewSetSealConfigFunc(r repo.LockedRepo) (dtypes.SetSealingConfigFunc, error) { - return func(cfg sealing.Config) (err error) { + return func(cfg sealiface.Config) (err error) { err = mutateCfg(r, func(c *config.StorageMiner) { c.Sealing = config.SealingConfig{ MaxWaitDealsSectors: cfg.MaxWaitDealsSectors, @@ -607,9 +608,9 @@ func NewSetSealConfigFunc(r repo.LockedRepo) (dtypes.SetSealingConfigFunc, error } func NewGetSealConfigFunc(r repo.LockedRepo) (dtypes.GetSealingConfigFunc, error) { - return func() (out sealing.Config, err error) { + return func() (out sealiface.Config, err error) { err = readCfg(r, func(cfg *config.StorageMiner) { - out = sealing.Config{ + out = sealiface.Config{ MaxWaitDealsSectors: cfg.Sealing.MaxWaitDealsSectors, MaxSealingSectors: cfg.Sealing.MaxSealingSectors, WaitDealsDelay: time.Duration(cfg.Sealing.WaitDealsDelay), From e7d65be90a5832afb4fd3e82c336ed27f477d4f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 18 Aug 2020 18:27:28 +0200 Subject: [PATCH 18/53] gofmt --- cli/pprof.go | 5 ++--- cmd/lotus-storage-miner/config.go | 2 +- extern/storage-sealing/fsm_test.go | 24 +++++++++++----------- extern/storage-sealing/sealiface/config.go | 1 - extern/storage-sealing/sealing.go | 2 +- extern/storage-sealing/stats.go | 4 ++-- node/config/def.go | 4 ++-- 7 files changed, 20 insertions(+), 22 deletions(-) diff --git a/cli/pprof.go b/cli/pprof.go index dff089e7f..50a67ef86 100644 --- a/cli/pprof.go +++ b/cli/pprof.go @@ -13,7 +13,7 @@ import ( ) var pprofCmd = &cli.Command{ - Name: "pprof", + Name: "pprof", Hidden: true, Subcommands: []*cli.Command{ PprofGoroutines, @@ -42,7 +42,7 @@ var PprofGoroutines = &cli.Command{ return err } - addr = "http://" + addr + "/debug/pprof/goroutine?debug=2" + addr = "http://" + addr + "/debug/pprof/goroutine?debug=2" r, err := http.Get(addr) if err != nil { @@ -56,4 +56,3 @@ var PprofGoroutines = &cli.Command{ return r.Body.Close() }, } - diff --git a/cmd/lotus-storage-miner/config.go b/cmd/lotus-storage-miner/config.go index 0c843fe23..e5e4fc4c4 100644 --- a/cmd/lotus-storage-miner/config.go +++ b/cmd/lotus-storage-miner/config.go @@ -9,7 +9,7 @@ import ( ) var configCmd = &cli.Command{ - Name: "config", + Name: "config", Usage: "Output default configuration", Action: func(cctx *cli.Context) error { comm, err := config.ConfigComment(config.DefaultStorageMiner()) diff --git a/extern/storage-sealing/fsm_test.go b/extern/storage-sealing/fsm_test.go index 474ea1966..f41d8c535 100644 --- a/extern/storage-sealing/fsm_test.go +++ b/extern/storage-sealing/fsm_test.go @@ -70,12 +70,12 @@ func TestHappyPath(t *testing.T) { func TestSeedRevert(t *testing.T) { ma, _ := address.NewIDAddress(55151) m := test{ - s: &Sealing{ - maddr: ma, - stats: SectorStats{ - bySector: map[abi.SectorID]statSectorState{}, - }, - }, + s: &Sealing{ + maddr: ma, + stats: SectorStats{ + bySector: map[abi.SectorID]statSectorState{}, + }, + }, t: t, state: &SectorInfo{State: Packing}, } @@ -117,12 +117,12 @@ func TestSeedRevert(t *testing.T) { func TestPlanCommittingHandlesSectorCommitFailed(t *testing.T) { ma, _ := address.NewIDAddress(55151) m := test{ - s: &Sealing{ - maddr: ma, - stats: SectorStats{ - bySector: map[abi.SectorID]statSectorState{}, - }, - }, + s: &Sealing{ + maddr: ma, + stats: SectorStats{ + bySector: map[abi.SectorID]statSectorState{}, + }, + }, t: t, state: &SectorInfo{State: Committing}, } diff --git a/extern/storage-sealing/sealiface/config.go b/extern/storage-sealing/sealiface/config.go index ad0b12c40..36fa7edad 100644 --- a/extern/storage-sealing/sealiface/config.go +++ b/extern/storage-sealing/sealiface/config.go @@ -13,4 +13,3 @@ type Config struct { WaitDealsDelay time.Duration } - diff --git a/extern/storage-sealing/sealing.go b/extern/storage-sealing/sealing.go index 006118e58..43c8973db 100644 --- a/extern/storage-sealing/sealing.go +++ b/extern/storage-sealing/sealing.go @@ -297,7 +297,7 @@ func (m *Sealing) newDealSector() (abi.SectorNumber, error) { var best abi.SectorNumber = math.MaxUint64 for sn, info := range m.unsealedInfoMap.infos { - if info.stored + 1 > mostStored + 1 { // 18446744073709551615 + 1 = 0 + if info.stored+1 > mostStored+1 { // 18446744073709551615 + 1 = 0 best = sn } } diff --git a/extern/storage-sealing/stats.go b/extern/storage-sealing/stats.go index 3d31a39ff..871c962c1 100644 --- a/extern/storage-sealing/stats.go +++ b/extern/storage-sealing/stats.go @@ -7,6 +7,7 @@ import ( ) type statSectorState int + const ( sstSealing statSectorState = iota sstFailed @@ -18,7 +19,7 @@ type SectorStats struct { lk sync.Mutex bySector map[abi.SectorID]statSectorState - totals [nsst]uint64 + totals [nsst]uint64 } func (ss *SectorStats) updateSector(id abi.SectorID, st SectorState) { @@ -35,7 +36,6 @@ func (ss *SectorStats) updateSector(id abi.SectorID, st SectorState) { ss.totals[sst]++ } - // return the number of sectors currently in the sealing pipeline func (ss *SectorStats) curSealing() uint64 { ss.lk.Lock() diff --git a/node/config/def.go b/node/config/def.go index fcddf73ba..f3b33f5aa 100644 --- a/node/config/def.go +++ b/node/config/def.go @@ -139,11 +139,11 @@ func DefaultFullNode() *FullNode { func DefaultStorageMiner() *StorageMiner { cfg := &StorageMiner{ Common: defCommon(), - + Sealing: SealingConfig{ MaxWaitDealsSectors: 2, // 64G with 32G sectors MaxSealingSectors: 0, - WaitDealsDelay: Duration(time.Hour), + WaitDealsDelay: Duration(time.Hour), }, Storage: sectorstorage.SealerConfig{ From 6a7d72c030435523cabc7b3b775ecc92c39d4088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 18 Aug 2020 19:26:17 +0200 Subject: [PATCH 19/53] fsm: fail early on too-many-sealing-sectors in pledge --- extern/storage-sealing/garbage.go | 11 +++++++++++ extern/storage-sealing/sealing.go | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/extern/storage-sealing/garbage.go b/extern/storage-sealing/garbage.go index d8cdb4248..4b95c1b67 100644 --- a/extern/storage-sealing/garbage.go +++ b/extern/storage-sealing/garbage.go @@ -31,6 +31,17 @@ func (m *Sealing) pledgeSector(ctx context.Context, sectorID abi.SectorID, exist } func (m *Sealing) PledgeSector() error { + cfg, err := m.getConfig() + if err != nil { + return xerrors.Errorf("getting config: %w", err) + } + + if cfg.MaxSealingSectors > 0 { + if m.stats.curSealing() > cfg.MaxSealingSectors { + return xerrors.Errorf("too many sectors sealing (curSealing: %d, max: %d)", m.stats.curSealing(), cfg.MaxSealingSectors) + } + } + go func() { ctx := context.TODO() // we can't use the context from command which invokes // this, as we run everything here async, and it's cancelled when the diff --git a/extern/storage-sealing/sealing.go b/extern/storage-sealing/sealing.go index 43c8973db..d52f2d731 100644 --- a/extern/storage-sealing/sealing.go +++ b/extern/storage-sealing/sealing.go @@ -361,17 +361,6 @@ func (m *Sealing) newDealSector() (abi.SectorNumber, error) { // newSectorCC accepts a slice of pieces with no deal (junk data) func (m *Sealing) newSectorCC(sid abi.SectorNumber, pieces []Piece) error { - cfg, err := m.getConfig() - if err != nil { - return xerrors.Errorf("getting config: %w", err) - } - - if cfg.MaxSealingSectors > 0 { - if m.stats.curSealing() > cfg.MaxSealingSectors { - return xerrors.Errorf("too many sectors sealing (curSealing: %d, max: %d)", m.stats.curSealing(), cfg.MaxSealingSectors) - } - } - rt, err := ffiwrapper.SealProofTypeFromSectorSize(m.sealer.SectorSize()) if err != nil { return xerrors.Errorf("bad sector size: %w", err) From 214eeccb18c185146041b25eb7dc579f670cf2d3 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Mon, 17 Aug 2020 23:44:56 -0400 Subject: [PATCH 20/53] Create a testnet version of setupGenesisActors --- chain/stmgr/stmgr.go | 83 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index f4943cba3..513dfbeab 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -787,7 +787,7 @@ type genesisActor struct { initBal abi.TokenAmount } -// sets up information about the non-multisig actors in the genesis state +// sets up information about the actors in the genesis state func (sm *StateManager) setupGenesisActors(ctx context.Context) error { gi := genesisInfo{} @@ -888,6 +888,83 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error { return nil } +// sets up information about the actors in the genesis state +// For testnet we use a hardcoded set of multisig states, instead of what's actually in the genesis multisigs +// We also do not consider ANY account actors (including the faucet) +func (sm *StateManager) setupGenesisActorsTestnet(ctx context.Context) error { + + gi := genesisInfo{} + + gb, err := sm.cs.GetGenesis() + if err != nil { + return xerrors.Errorf("getting genesis block: %w", err) + } + + gts, err := types.NewTipSet([]*types.BlockHeader{gb}) + if err != nil { + return xerrors.Errorf("getting genesis tipset: %w", err) + } + + st, _, err := sm.TipSetState(ctx, gts) + if err != nil { + return xerrors.Errorf("getting genesis tipset state: %w", err) + } + + cst := cbor.NewCborStore(sm.cs.Blockstore()) + sTree, err := state.LoadStateTree(cst, st) + if err != nil { + return xerrors.Errorf("loading state tree: %w", err) + } + + gi.genesisMarketFunds, err = getFilMarketLocked(ctx, sTree) + if err != nil { + return xerrors.Errorf("setting up genesis market funds: %w", err) + } + + gi.genesisPledge, err = getFilPowerLocked(ctx, sTree) + if err != nil { + return xerrors.Errorf("setting up genesis pledge: %w", err) + } + + totalsByEpoch := make(map[abi.ChainEpoch]abi.TokenAmount) + + // 6 months + sixMonths := abi.ChainEpoch(183 * builtin.EpochsInDay) + totalsByEpoch[sixMonths] = big.NewInt(49_929_341) + totalsByEpoch[sixMonths] = big.Add(totalsByEpoch[sixMonths], big.NewInt(32_787_700)) + + // 1 year + oneYear := abi.ChainEpoch(365 * builtin.EpochsInDay) + totalsByEpoch[oneYear] = big.NewInt(22_421_712) + + // 2 years + twoYears := abi.ChainEpoch(2 * 365 * builtin.EpochsInDay) + totalsByEpoch[twoYears] = big.NewInt(7_223_364) + + // 3 years + threeYears := abi.ChainEpoch(3 * 365 * builtin.EpochsInDay) + totalsByEpoch[threeYears] = big.NewInt(87_637_883) + + // 6 years + sixYears := abi.ChainEpoch(6 * 365 * builtin.EpochsInDay) + totalsByEpoch[sixYears] = big.NewInt(100_000_000) + totalsByEpoch[sixYears] = big.Add(totalsByEpoch[sixYears], big.NewInt(300_000_000)) + + gi.genesisMsigs = make([]multisig.State, 0, len(totalsByEpoch)) + for k, v := range totalsByEpoch { + ns := multisig.State{ + InitialBalance: v, + UnlockDuration: k, + PendingTxns: cid.Undef, + } + gi.genesisMsigs = append(gi.genesisMsigs, ns) + } + + sm.genInfo = &gi + + return nil +} + // GetVestedFunds returns all funds that have "left" actors that are in the genesis state: // - For Multisigs, it counts the actual amounts that have vested at the given epoch // - For Accounts, it counts max(currentBalance - genesisBalance, 0). @@ -898,7 +975,7 @@ func (sm *StateManager) GetFilVested(ctx context.Context, height abi.ChainEpoch, vf = big.Add(vf, au) } - // these should only ever be "faucet" accounts in testnets + // there should not be any such accounts in testnet (and also none in mainnet?) for _, v := range sm.genInfo.genesisActors { act, err := st.GetActor(v.addr) if err != nil { @@ -988,7 +1065,7 @@ func (sm *StateManager) GetCirculatingSupplyDetailed(ctx context.Context, height sm.genesisMsigLk.Lock() defer sm.genesisMsigLk.Unlock() if sm.genInfo == nil { - err := sm.setupGenesisActors(ctx) + err := sm.setupGenesisActorsTestnet(ctx) if err != nil { return api.CirculatingSupply{}, xerrors.Errorf("failed to setup genesis information: %w", err) } From 42730bcf1c2ad756d511bc13b8618ec8903419f2 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 18 Aug 2020 10:56:54 -0700 Subject: [PATCH 21/53] handle potential overallocation --- chain/gen/genesis/genesis.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 434b727be..80cf6f247 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -273,6 +273,9 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge totalFil := big.Mul(big.NewInt(int64(build.FilBase)), big.NewInt(int64(build.FilecoinPrecision))) remainingFil := big.Sub(totalFil, totalFilAllocated) + if remainingFil.Sign() < 0 { + return nil, nil, xerrors.Errorf("somehow overallocated filecoin (allocated = %s)", types.FIL(totalFilAllocated)) + } template.RemainderAccount.Balance = remainingFil From 446a4f62721bb26fcf83139dd56932355c944d94 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Tue, 18 Aug 2020 13:35:46 -0400 Subject: [PATCH 22/53] Update to specs-actors v0.9.3 --- chain/gen/genesis/miners.go | 4 ++++ go.mod | 2 +- go.sum | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index 0491371d3..cc649c84c 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -262,6 +262,8 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid return cid.Undef, xerrors.Errorf("getting current total power: %w", err) } + pcd := miner.PreCommitDepositForPower(epochReward.ThisEpochRewardSmoothed, tpow.QualityAdjPowerSmoothed, sectorWeight) + pledge := miner.InitialPledgeForPower( sectorWeight, epochReward.ThisEpochBaselinePower, @@ -271,6 +273,8 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid circSupply(ctx, vm, minerInfos[i].maddr), ) + pledge = big.Add(pcd, pledge) + fmt.Println(types.FIL(pledge)) _, err = doExecValue(ctx, vm, minerInfos[i].maddr, m.Worker, pledge, builtin.MethodsMiner.PreCommitSector, mustEnc(params)) if err != nil { diff --git a/go.mod b/go.mod index ab239ebc9..aeb96ffbd 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require ( github.com/filecoin-project/go-statestore v0.1.0 github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0 // indirect - github.com/filecoin-project/specs-actors v0.9.2 + github.com/filecoin-project/specs-actors v0.9.3 github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401 github.com/filecoin-project/storage-fsm v0.0.0-20200805013058-9d9ea4e6331f github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 diff --git a/go.sum b/go.sum index 2f3da883a..26966c505 100644 --- a/go.sum +++ b/go.sum @@ -276,6 +276,8 @@ github.com/filecoin-project/specs-actors v0.8.7-0.20200811203034-272d022c1923 h1 github.com/filecoin-project/specs-actors v0.8.7-0.20200811203034-272d022c1923/go.mod h1:hukRu6vKQrrS7Nt+fC/ql4PqWLSfmAWNshD/VDtARZU= github.com/filecoin-project/specs-actors v0.9.2 h1:0JG0QLHw8pO6BPqPRe9eQxQW60biHAQsx1rlQ9QbzZ0= github.com/filecoin-project/specs-actors v0.9.2/go.mod h1:YasnVUOUha0DN5wB+twl+V8LlDKVNknRG00kTJpsfFA= +github.com/filecoin-project/specs-actors v0.9.3 h1:Fi75G/UQ7R4eiIwnN+S6bBQ9LqKivyJdw62jJzTi6aE= +github.com/filecoin-project/specs-actors v0.9.3/go.mod h1:YasnVUOUha0DN5wB+twl+V8LlDKVNknRG00kTJpsfFA= github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea h1:iixjULRQFPn7Q9KlIqfwLJnlAXO10bbkI+xy5GKGdLY= github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401 h1:jLzN1hwO5WpKPu8ASbW8fs1FUCsOWNvoBXzQhv+8/E8= From 02d21c28336251f46f2a5d724cad64666373bdea Mon Sep 17 00:00:00 2001 From: Peter Rabbitson Date: Tue, 18 Aug 2020 21:08:20 +0200 Subject: [PATCH 23/53] Missing error argument --- storage/wdpost_sched.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/wdpost_sched.go b/storage/wdpost_sched.go index dc21f38c0..2645b3702 100644 --- a/storage/wdpost_sched.go +++ b/storage/wdpost_sched.go @@ -88,7 +88,7 @@ func (s *WindowPoStScheduler) Run(ctx context.Context) { if notifs == nil { notifs, err = s.api.ChainNotify(ctx) if err != nil { - log.Errorf("ChainNotify error: %+v") + log.Errorf("ChainNotify error: %+v", err) build.Clock.Sleep(10 * time.Second) continue From 8acd92663640da21eec78cf49f07a44ff69255b3 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 18 Aug 2020 19:18:53 +0200 Subject: [PATCH 24/53] Use conditional probability for noWinners, fix tests Signed-off-by: Jakub Sztandera --- chain/messagepool/block_proba.go | 24 +++++++++++++++++++++++- chain/messagepool/selection_test.go | 24 ++++++++++++++---------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/chain/messagepool/block_proba.go b/chain/messagepool/block_proba.go index 7304bd3ce..f3432fa36 100644 --- a/chain/messagepool/block_proba.go +++ b/chain/messagepool/block_proba.go @@ -26,6 +26,28 @@ func noWinnersProb() []float64 { return noWinnersProbCache } +var noWinnersProbAssumingCache []float64 +var noWinnersProbAssumingOnce sync.Once + +func noWinnersProbAssumingMoreThanOne() []float64 { + noWinnersProbAssumingOnce.Do(func() { + cond := math.Log(-1 + math.Exp(5)) + poissPdf := func(x float64) float64 { + const Mu = 5 + lg, _ := math.Lgamma(x + 1) + result := math.Exp((math.Log(Mu) * x) - lg - cond) + return result + } + + out := make([]float64, 0, MaxBlocks) + for i := 0; i < MaxBlocks; i++ { + out = append(out, poissPdf(float64(i+1))) + } + noWinnersProbAssumingCache = out + }) + return noWinnersProbAssumingCache +} + func binomialCoefficient(n, k float64) float64 { if k > n { return math.NaN() @@ -40,7 +62,7 @@ func binomialCoefficient(n, k float64) float64 { } func (mp *MessagePool) blockProbabilities(tq float64) []float64 { - noWinners := noWinnersProb() // cache this + noWinners := noWinnersProbAssumingMoreThanOne() p := 1 - tq binoPdf := func(x, trials float64) float64 { diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 29a613256..a1a287c25 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -934,9 +934,11 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu t.Fatal(err) } - capacityBoost := 0.0 - rewardBoost := 0.0 - const runs = 1 + totalGreedyCapacity := 0.0 + totalGreedyReward := 0.0 + totalOptimalCapacity := 0.0 + totalOptimalReward := 0.0 + const runs = 50 for i := 0; i < runs; i++ { // 2. optimal selection minersRand := rng.Float64() @@ -945,8 +947,8 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu for ; i < MaxBlocks && minersRand > 0; i++ { minersRand -= winerProba[i] } - nMiners := i - if nMiners == 0 { + nMiners := i - 1 + if nMiners < 1 { nMiners = 1 } @@ -962,14 +964,15 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu } } + totalGreedyCapacity += float64(len(greedyMsgs)) + totalOptimalCapacity += float64(len(optMsgs)) boost := float64(len(optMsgs)) / float64(len(greedyMsgs)) - capacityBoost += boost t.Logf("nMiners: %d", nMiners) t.Logf("greedy capacity %d, optimal capacity %d (x %.1f )", len(greedyMsgs), len(optMsgs), boost) if len(greedyMsgs) > len(optMsgs) { - t.Fatal("greedy capacity higher than optimal capacity; wtf") + t.Errorf("greedy capacity higher than optimal capacity; wtf") } greedyReward := big.NewInt(0) @@ -984,17 +987,18 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu nMinersBig := big.NewInt(int64(nMiners)) greedyAvgReward, _ := new(big.Rat).SetFrac(greedyReward, nMinersBig).Float64() + totalGreedyReward += greedyAvgReward optimalAvgReward, _ := new(big.Rat).SetFrac(optReward, nMinersBig).Float64() + totalOptimalReward += optimalAvgReward boost = optimalAvgReward / greedyAvgReward - rewardBoost += boost t.Logf("greedy reward: %.0f, optimal reward: %.0f (x %.1f )", greedyAvgReward, optimalAvgReward, boost) } - capacityBoost /= runs - rewardBoost /= runs + capacityBoost := totalOptimalCapacity / totalGreedyCapacity + rewardBoost := totalOptimalReward / totalGreedyReward t.Logf("Average capacity boost: %f", capacityBoost) t.Logf("Average reward boost: %f", rewardBoost) From 9c98cf8bc1a3f0f75d123a7f93a267708fec3ffe Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 18 Aug 2020 19:24:49 +0200 Subject: [PATCH 25/53] Fix blockProbabilities Signed-off-by: Jakub Sztandera --- chain/messagepool/block_proba.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/messagepool/block_proba.go b/chain/messagepool/block_proba.go index f3432fa36..6634f5b46 100644 --- a/chain/messagepool/block_proba.go +++ b/chain/messagepool/block_proba.go @@ -94,7 +94,7 @@ func (mp *MessagePool) blockProbabilities(tq float64) []float64 { for place := 0; place < MaxBlocks; place++ { var pPlace float64 for otherWinners, pCase := range noWinners { - pPlace += pCase * binoPdf(float64(place), float64(otherWinners+1)) + pPlace += pCase * binoPdf(float64(place), float64(otherWinners)) } out = append(out, pPlace) } From 8bca545cab858eadb670cfaf390a1cc32fbb8d10 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 18 Aug 2020 19:42:43 +0200 Subject: [PATCH 26/53] Add test for winnerProba Signed-off-by: Jakub Sztandera --- chain/messagepool/block_proba_test.go | 30 ++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/chain/messagepool/block_proba_test.go b/chain/messagepool/block_proba_test.go index b39ea587e..93f51e887 100644 --- a/chain/messagepool/block_proba_test.go +++ b/chain/messagepool/block_proba_test.go @@ -1,6 +1,11 @@ package messagepool -import "testing" +import ( + "math" + "math/rand" + "testing" + "time" +) func TestBlockProbability(t *testing.T) { mp := &MessagePool{} @@ -13,3 +18,26 @@ func TestBlockProbability(t *testing.T) { } } } + +func TestWinnerProba(t *testing.T) { + rand.Seed(time.Now().UnixNano()) + const N = 1000000 + winnerProba := noWinnersProb() + sum := 0 + for i := 0; i < N; i++ { + minersRand := rand.Float64() + j := 0 + for ; j < MaxBlocks; j++ { + minersRand -= winnerProba[j] + if minersRand < 0 { + break + } + } + sum += j + } + + if avg := float64(sum) / N; math.Abs(avg-5) > 0.01 { + t.Fatalf("avg too far off: %f", avg) + } + +} From 8d4427a8bc1276cb4f186d4c71bcc3da6f4939b7 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 18 Aug 2020 20:19:17 +0200 Subject: [PATCH 27/53] add best ticket reward to tests Signed-off-by: Jakub Sztandera --- chain/messagepool/selection_test.go | 33 +++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index a1a287c25..e714fb77e 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -874,7 +874,7 @@ func TestOptimalMessageSelection3(t *testing.T) { } } -func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium func() uint64) (float64, float64) { +func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium func() uint64) (float64, float64, float64) { // in this test we use 300 actors and send 10 blocks of messages. // actors send with an randomly distributed premium dictated by the getPremium function. // a number of miners select with varying ticket quality and we compare the @@ -938,6 +938,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu totalGreedyReward := 0.0 totalOptimalCapacity := 0.0 totalOptimalReward := 0.0 + totalBestTQReward := 0.0 const runs = 50 for i := 0; i < runs; i++ { // 2. optimal selection @@ -953,12 +954,18 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu } optMsgs := make(map[cid.Cid]*types.SignedMessage) + bestTq := 0.0 + var bestMsgs []*types.SignedMessage for j := 0; j < nMiners; j++ { tq := rng.Float64() msgs, err := mp.SelectMessages(ts, tq) if err != nil { t.Fatal(err) } + if tq > bestTq { + bestMsgs = msgs + } + for _, m := range msgs { optMsgs[m.Cid()] = m } @@ -985,6 +992,13 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu optReward.Add(optReward, mp.getGasReward(m, baseFee, ts)) } + bestTqReward := big.NewInt(0) + for _, m := range bestMsgs { + bestTqReward.Add(bestTqReward, mp.getGasReward(m, baseFee, ts)) + } + + totalBestTQReward += float64(bestTqReward.Uint64()) + nMinersBig := big.NewInt(int64(nMiners)) greedyAvgReward, _ := new(big.Rat).SetFrac(greedyReward, nMinersBig).Float64() totalGreedyReward += greedyAvgReward @@ -1001,10 +1015,11 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu rewardBoost := totalOptimalReward / totalGreedyReward t.Logf("Average capacity boost: %f", capacityBoost) t.Logf("Average reward boost: %f", rewardBoost) + t.Logf("Average best tq reward: %f", totalBestTQReward/runs/1e18) logging.SetLogLevel("messagepool", "info") - return capacityBoost, rewardBoost + return capacityBoost, rewardBoost, totalBestTQReward / runs / 1e18 } func makeExpPremiumDistribution(rng *rand.Rand) func() uint64 { @@ -1022,35 +1037,41 @@ func makeZipfPremiumDistribution(rng *rand.Rand) func() uint64 { } func TestCompetitiveMessageSelectionExp(t *testing.T) { - var capacityBoost, rewardBoost float64 + var capacityBoost, rewardBoost, tqReward float64 seeds := []int64{1947, 1976, 2020, 2100, 10000, 143324, 432432, 131, 32, 45} for _, seed := range seeds { t.Log("running competitive message selection with Exponential premium distribution and seed", seed) rng := rand.New(rand.NewSource(seed)) - cb, rb := testCompetitiveMessageSelection(t, rng, makeExpPremiumDistribution(rng)) + cb, rb, tqR := testCompetitiveMessageSelection(t, rng, makeExpPremiumDistribution(rng)) capacityBoost += cb rewardBoost += rb + tqReward += tqR } capacityBoost /= float64(len(seeds)) rewardBoost /= float64(len(seeds)) + tqReward /= float64(len(seeds)) t.Logf("Average capacity boost across all seeds: %f", capacityBoost) t.Logf("Average reward boost across all seeds: %f", rewardBoost) + t.Logf("Average reward of best ticket across all seeds: %f", tqReward) } func TestCompetitiveMessageSelectionZipf(t *testing.T) { - var capacityBoost, rewardBoost float64 + var capacityBoost, rewardBoost, tqReward float64 seeds := []int64{1947, 1976, 2020, 2100, 10000, 143324, 432432, 131, 32, 45} for _, seed := range seeds { t.Log("running competitive message selection with Zipf premium distribution and seed", seed) rng := rand.New(rand.NewSource(seed)) - cb, rb := testCompetitiveMessageSelection(t, rng, makeZipfPremiumDistribution(rng)) + cb, rb, tqR := testCompetitiveMessageSelection(t, rng, makeZipfPremiumDistribution(rng)) capacityBoost += cb rewardBoost += rb + tqReward += tqR } + tqReward /= float64(len(seeds)) capacityBoost /= float64(len(seeds)) rewardBoost /= float64(len(seeds)) t.Logf("Average capacity boost across all seeds: %f", capacityBoost) t.Logf("Average reward boost across all seeds: %f", rewardBoost) + t.Logf("Average reward of best ticket across all seeds: %f", tqReward) } From 4d01cbfb625dcbe641363aabadafbd18a5fc1b91 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 18 Aug 2020 20:27:25 +0200 Subject: [PATCH 28/53] Increase precision of output Signed-off-by: Jakub Sztandera --- chain/messagepool/selection_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index e714fb77e..58eae3a92 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -1015,11 +1015,11 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu rewardBoost := totalOptimalReward / totalGreedyReward t.Logf("Average capacity boost: %f", capacityBoost) t.Logf("Average reward boost: %f", rewardBoost) - t.Logf("Average best tq reward: %f", totalBestTQReward/runs/1e18) + t.Logf("Average best tq reward: %f", totalBestTQReward/runs/1e12) logging.SetLogLevel("messagepool", "info") - return capacityBoost, rewardBoost, totalBestTQReward / runs / 1e18 + return capacityBoost, rewardBoost, totalBestTQReward / runs / 1e12 } func makeExpPremiumDistribution(rng *rand.Rand) func() uint64 { From e0b72ba0498b2927da87b7eccb980d441adc993e Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 18 Aug 2020 21:08:57 +0200 Subject: [PATCH 29/53] Reduce number of runs to 1 Signed-off-by: Jakub Sztandera --- chain/messagepool/selection_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 58eae3a92..0fd9b7406 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -939,7 +939,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu totalOptimalCapacity := 0.0 totalOptimalReward := 0.0 totalBestTQReward := 0.0 - const runs = 50 + const runs = 1 for i := 0; i < runs; i++ { // 2. optimal selection minersRand := rng.Float64() From 6d9707c784e112c891b1c6b5d33b06d51e9ef290 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 18 Aug 2020 22:24:07 +0300 Subject: [PATCH 30/53] fix OptimalSelection3 test --- chain/messagepool/selection_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 0fd9b7406..0032db23c 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -834,7 +834,7 @@ func TestOptimalMessageSelection3(t *testing.T) { nMessages := int(build.BlockGasLimit/gasLimit) + 1 for i := 0; i < nMessages; i++ { for j := 0; j < nActors; j++ { - premium := 500000 + 20000*(nActors-j) + (nMessages+2-i)/(3*nActors) + i%3 + premium := 500000 + 10000*(nActors-j) + (nMessages+2-i)/(30*nActors) + i%3 m := makeTestMessage(wallets[j], actors[j], actors[j%nActors], uint64(i), gasLimit, uint64(premium)) mustAdd(t, mp, m) } From a03192a39b0f1bb30cda4347ef03bcfa9eff495c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 18 Aug 2020 19:52:20 +0200 Subject: [PATCH 31/53] Separate concurrent sealing sector limit for deals --- extern/storage-sealing/sealiface/config.go | 3 +++ extern/storage-sealing/sealing.go | 7 +++++-- node/config/def.go | 10 +++++++--- node/modules/storageminer.go | 7 ++++--- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/extern/storage-sealing/sealiface/config.go b/extern/storage-sealing/sealiface/config.go index 36fa7edad..945565562 100644 --- a/extern/storage-sealing/sealiface/config.go +++ b/extern/storage-sealing/sealiface/config.go @@ -11,5 +11,8 @@ type Config struct { // includes failed, 0 = no limit MaxSealingSectors uint64 + // includes failed, 0 = no limit + MaxSealingSectorsForDeals uint64 + WaitDealsDelay time.Duration } diff --git a/extern/storage-sealing/sealing.go b/extern/storage-sealing/sealing.go index d52f2d731..062ade2a3 100644 --- a/extern/storage-sealing/sealing.go +++ b/extern/storage-sealing/sealing.go @@ -270,8 +270,8 @@ func (m *Sealing) newDealSector() (abi.SectorNumber, error) { return 0, xerrors.Errorf("getting config: %w", err) } - if cfg.MaxSealingSectors > 0 { - if m.stats.curSealing() > cfg.MaxSealingSectors { + if cfg.MaxSealingSectorsForDeals > 0 { + if m.stats.curSealing() > cfg.MaxSealingSectorsForDeals { return 0, xerrors.Errorf("too many sectors sealing") } } @@ -280,6 +280,9 @@ func (m *Sealing) newDealSector() (abi.SectorNumber, error) { // run in a loop because we have to drop the map lock here for a bit tries := 0 + // we have to run in a loop as we're dropping unsealedInfoMap.lk + // to actually call StartPacking. When we do that, another entry can + // get added to unsealedInfoMap. for uint64(len(m.unsealedInfoMap.infos)) >= cfg.MaxWaitDealsSectors { if tries > 10 { // whatever... diff --git a/node/config/def.go b/node/config/def.go index f3b33f5aa..d10810998 100644 --- a/node/config/def.go +++ b/node/config/def.go @@ -54,6 +54,9 @@ type SealingConfig struct { // includes failed, 0 = no limit MaxSealingSectors uint64 + // includes failed, 0 = no limit + MaxSealingSectorsForDeals uint64 + WaitDealsDelay Duration } @@ -141,9 +144,10 @@ func DefaultStorageMiner() *StorageMiner { Common: defCommon(), Sealing: SealingConfig{ - MaxWaitDealsSectors: 2, // 64G with 32G sectors - MaxSealingSectors: 0, - WaitDealsDelay: Duration(time.Hour), + MaxWaitDealsSectors: 2, // 64G with 32G sectors + MaxSealingSectors: 0, + MaxSealingSectorsForDeals: 0, + WaitDealsDelay: Duration(time.Hour), }, Storage: sectorstorage.SealerConfig{ diff --git a/node/modules/storageminer.go b/node/modules/storageminer.go index 3be869f0f..ce2427f2c 100644 --- a/node/modules/storageminer.go +++ b/node/modules/storageminer.go @@ -611,9 +611,10 @@ func NewGetSealConfigFunc(r repo.LockedRepo) (dtypes.GetSealingConfigFunc, error return func() (out sealiface.Config, err error) { err = readCfg(r, func(cfg *config.StorageMiner) { out = sealiface.Config{ - MaxWaitDealsSectors: cfg.Sealing.MaxWaitDealsSectors, - MaxSealingSectors: cfg.Sealing.MaxSealingSectors, - WaitDealsDelay: time.Duration(cfg.Sealing.WaitDealsDelay), + MaxWaitDealsSectors: cfg.Sealing.MaxWaitDealsSectors, + MaxSealingSectors: cfg.Sealing.MaxSealingSectors, + MaxSealingSectorsForDeals: cfg.Sealing.MaxSealingSectorsForDeals, + WaitDealsDelay: time.Duration(cfg.Sealing.WaitDealsDelay), } }) return From 8675ca561d1fd1ddbce02bb1879d925ecbe39f2d Mon Sep 17 00:00:00 2001 From: Mike Greenberg Date: Tue, 18 Aug 2020 14:17:06 -0400 Subject: [PATCH 32/53] fix(api): Filter malformed peer ID before RPC marshaling --- api/types.go | 9 +++++++-- cli/client.go | 6 +++--- cmd/lotus-chainwatch/processor/miner.go | 6 +++++- markets/storageadapter/client.go | 2 +- node/impl/client/client.go | 6 +++--- 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/api/types.go b/api/types.go index 8e8c32122..8a682db17 100644 --- a/api/types.go +++ b/api/types.go @@ -50,7 +50,7 @@ type MinerInfo struct { Worker address.Address // Must be an ID-address. NewWorker address.Address // Must be an ID-address. WorkerChangeEpoch abi.ChainEpoch - PeerId peer.ID + PeerId *peer.ID Multiaddrs []abi.Multiaddrs SealProofType abi.RegisteredSealProof SectorSize abi.SectorSize @@ -58,12 +58,17 @@ type MinerInfo struct { } func NewApiMinerInfo(info *miner.MinerInfo) MinerInfo { + var pid *peer.ID + if peerID, err := peer.IDFromBytes(info.PeerId); err == nil { + pid = &peerID + } + mi := MinerInfo{ Owner: info.Owner, Worker: info.Worker, NewWorker: address.Undef, WorkerChangeEpoch: -1, - PeerId: peer.ID(info.PeerId), + PeerId: pid, Multiaddrs: info.Multiaddrs, SealProofType: info.SealProofType, SectorSize: info.SectorSize, diff --git a/cli/client.go b/cli/client.go index 777073292..519d11e5a 100644 --- a/cli/client.go +++ b/cli/client.go @@ -550,7 +550,7 @@ func interactiveDeal(cctx *cli.Context) error { continue } - a, err := api.ClientQueryAsk(ctx, mi.PeerId, maddr) + a, err := api.ClientQueryAsk(ctx, *mi.PeerId, maddr) if err != nil { printErr(xerrors.Errorf("failed to query ask: %w", err)) state = "miner" @@ -926,11 +926,11 @@ var clientQueryAskCmd = &cli.Command{ return xerrors.Errorf("failed to get peerID for miner: %w", err) } - if peer.ID(mi.PeerId) == peer.ID("SETME") { + if peer.ID(*mi.PeerId) == peer.ID("SETME") { return fmt.Errorf("the miner hasn't initialized yet") } - pid = peer.ID(mi.PeerId) + pid = peer.ID(*mi.PeerId) } ask, err := api.ClientQueryAsk(ctx, pid, maddr) diff --git a/cmd/lotus-chainwatch/processor/miner.go b/cmd/lotus-chainwatch/processor/miner.go index 6d60f401d..19fa3da95 100644 --- a/cmd/lotus-chainwatch/processor/miner.go +++ b/cmd/lotus-chainwatch/processor/miner.go @@ -879,11 +879,15 @@ func (p *Processor) storeMinersActorInfoState(ctx context.Context, miners []mine return err } } + var pid string + if mi.PeerId != nil { + pid = mi.PeerId.String() + } if _, err := stmt.Exec( m.common.addr.String(), mi.Owner.String(), mi.Worker.String(), - mi.PeerId.String(), + pid, mi.SectorSize.ShortString(), ); err != nil { log.Errorw("failed to store miner state", "state", m.state, "info", m.state.Info, "error", err) diff --git a/markets/storageadapter/client.go b/markets/storageadapter/client.go index a9794f607..576a0e98a 100644 --- a/markets/storageadapter/client.go +++ b/markets/storageadapter/client.go @@ -514,7 +514,7 @@ func (c *ClientNodeAdapter) GetMinerInfo(ctx context.Context, addr address.Addre return nil, err } - out := utils.NewStorageProviderInfo(addr, mi.Worker, mi.SectorSize, mi.PeerId, mi.Multiaddrs) + out := utils.NewStorageProviderInfo(addr, mi.Worker, mi.SectorSize, *mi.PeerId, mi.Multiaddrs) return &out, nil } diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 3b992fe54..d9ece2d9e 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -137,7 +137,7 @@ func (a *API) ClientStartDeal(ctx context.Context, params *api.StartDealParams) return nil, xerrors.New("data doesn't fit in a sector") } - providerInfo := utils.NewStorageProviderInfo(params.Miner, mi.Worker, mi.SectorSize, mi.PeerId, mi.Multiaddrs) + providerInfo := utils.NewStorageProviderInfo(params.Miner, mi.Worker, mi.SectorSize, *mi.PeerId, mi.Multiaddrs) dealStart := params.DealStartEpoch if dealStart <= 0 { // unset, or explicitly 'epoch undefined' @@ -255,7 +255,7 @@ func (a *API) ClientMinerQueryOffer(ctx context.Context, miner address.Address, } rp := rm.RetrievalPeer{ Address: miner, - ID: mi.PeerId, + ID: *mi.PeerId, } return a.makeRetrievalQuery(ctx, rp, root, piece, rm.QueryParams{}), nil } @@ -443,7 +443,7 @@ func (a *API) clientRetrieve(ctx context.Context, order api.RetrievalOrder, ref } order.MinerPeer = retrievalmarket.RetrievalPeer{ - ID: mi.PeerId, + ID: *mi.PeerId, Address: order.Miner, } } From 574a22de6cecba62e9d3aabb9738d09e8ac7077a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 18 Aug 2020 22:45:43 +0200 Subject: [PATCH 33/53] genesis: Set remainder account balance correctly --- chain/gen/genesis/genesis.go | 16 ++++++++++++---- genesis/types.go | 3 +-- node/node_test.go | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 80cf6f247..5d0a1cbfb 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -263,6 +263,11 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge } totalFilAllocated := big.Zero() + + // flush as ForEach works on the HAMT + if _, err := state.Flush(ctx); err != nil { + return nil, nil, err + } err = state.ForEach(func(addr address.Address, act *types.Actor) error { totalFilAllocated = big.Add(totalFilAllocated, act.Balance) return nil @@ -277,15 +282,18 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge return nil, nil, xerrors.Errorf("somehow overallocated filecoin (allocated = %s)", types.FIL(totalFilAllocated)) } - template.RemainderAccount.Balance = remainingFil - remAccKey, err := address.NewIDAddress(90) if err != nil { return nil, nil, err } - if err := createAccount(ctx, bs, cst, state, remAccKey, template.RemainderAccount); err != nil { - return nil, nil, err + err = state.SetActor(remAccKey, &types.Actor{ + Code: builtin.AccountActorCodeID, + Balance: remainingFil, + Head: emptyobject, + }) + if err != nil { + return nil, nil, xerrors.Errorf("set burnt funds account actor: %w", err) } return state, keyIDs, nil diff --git a/genesis/types.go b/genesis/types.go index 468a09067..7d401fd0e 100644 --- a/genesis/types.go +++ b/genesis/types.go @@ -79,6 +79,5 @@ type Template struct { NetworkName string Timestamp uint64 `json:",omitempty"` - VerifregRootKey Actor - RemainderAccount Actor + VerifregRootKey Actor } diff --git a/node/node_test.go b/node/node_test.go index 770ce1f5b..f2df15ffd 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -351,7 +351,7 @@ func mockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test genaccs = append(genaccs, genesis.Actor{ Type: genesis.TAccount, - Balance: big.Mul(big.NewInt(400_000_000_000), types.NewInt(build.FilecoinPrecision)), + Balance: big.Mul(big.NewInt(400_000_000), types.NewInt(build.FilecoinPrecision)), Meta: (&genesis.AccountMeta{Owner: wk.Address}).ActorMeta(), }) From abca69b4760f4e45a7483a6180559dd129fd734c Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 18 Aug 2020 14:30:49 -0700 Subject: [PATCH 34/53] configurable remainder account --- chain/gen/gen.go | 18 +++++++++++++++--- chain/gen/genesis/genesis.go | 8 +++++++- genesis/types.go | 3 ++- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/chain/gen/gen.go b/chain/gen/gen.go index bcf9c4f10..4d1a0e2ab 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -107,6 +107,17 @@ var DefaultVerifregRootkeyActor = genesis.Actor{ Meta: rootkeyMultisig.ActorMeta(), } +var remAccTestKey, _ = address.NewFromString("t1ceb34gnsc6qk5dt6n7xg6ycwzasjhbxm3iylkiy") +var remAccMeta = genesis.AccountMeta{ + Owner: remAccTestKey, +} + +var DefaultRemainderAccountActor = genesis.Actor{ + Type: genesis.TAccount, + Balance: big.NewInt(0), + Meta: remAccMeta.ActorMeta(), +} + func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) { saminer.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ abi.RegisteredSealProof_StackedDrg2KiBV1: {}, @@ -210,9 +221,10 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) { *genm1, *genm2, }, - VerifregRootKey: DefaultVerifregRootkeyActor, - NetworkName: "", - Timestamp: uint64(build.Clock.Now().Add(-500 * time.Duration(build.BlockDelaySecs) * time.Second).Unix()), + VerifregRootKey: DefaultVerifregRootkeyActor, + RemainderAccount: DefaultRemainderAccountActor, + NetworkName: "", + Timestamp: uint64(build.Clock.Now().Add(-500 * time.Duration(build.BlockDelaySecs) * time.Second).Unix()), } genb, err := genesis2.MakeGenesisBlock(context.TODO(), bs, sys, tpl) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 5d0a1cbfb..8c0a2632c 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -3,6 +3,7 @@ package genesis import ( "context" "encoding/json" + "fmt" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" @@ -287,6 +288,9 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge return nil, nil, err } + if err := createAccount(ctx, bs, cst, state, remAccKey, template.RemainderAccount); err != nil { + return nil, nil, err + } err = state.SetActor(remAccKey, &types.Actor{ Code: builtin.AccountActorCodeID, Balance: remainingFil, @@ -317,6 +321,7 @@ func createAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.IpldStore if err != nil { return xerrors.Errorf("setting account from actmap: %w", err) } + return nil } else if info.Type == genesis.TMultisig { var ainfo genesis.MultisigMeta if err := json.Unmarshal(info.Meta, &ainfo); err != nil { @@ -346,9 +351,10 @@ func createAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.IpldStore if err != nil { return xerrors.Errorf("setting account from actmap: %w", err) } + return nil } - return nil + return fmt.Errorf("failed to create account") } func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot cid.Cid, template genesis.Template, keyIDs map[address.Address]address.Address) (cid.Cid, error) { diff --git a/genesis/types.go b/genesis/types.go index 7d401fd0e..468a09067 100644 --- a/genesis/types.go +++ b/genesis/types.go @@ -79,5 +79,6 @@ type Template struct { NetworkName string Timestamp uint64 `json:",omitempty"` - VerifregRootKey Actor + VerifregRootKey Actor + RemainderAccount Actor } From 916bebadefe61c1a50cdd58671cbb232c1a7714f Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 18 Aug 2020 14:34:35 -0700 Subject: [PATCH 35/53] setup proper template defaults --- cmd/lotus-seed/genesis.go | 9 +++++---- node/node_test.go | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/cmd/lotus-seed/genesis.go b/cmd/lotus-seed/genesis.go index 3a9545d2d..f2bff4d6e 100644 --- a/cmd/lotus-seed/genesis.go +++ b/cmd/lotus-seed/genesis.go @@ -48,10 +48,11 @@ var genesisNewCmd = &cli.Command{ return xerrors.New("seed genesis new [genesis.json]") } out := genesis.Template{ - Accounts: []genesis.Actor{}, - Miners: []genesis.Miner{}, - VerifregRootKey: gen.DefaultVerifregRootkeyActor, - NetworkName: cctx.String("network-name"), + Accounts: []genesis.Actor{}, + Miners: []genesis.Miner{}, + VerifregRootKey: gen.DefaultVerifregRootkeyActor, + RemainderAccount: gen.DefaultRemainderAccountActor, + NetworkName: cctx.String("network-name"), } if out.NetworkName == "" { out.NetworkName = "localnet-" + uuid.New().String() diff --git a/node/node_test.go b/node/node_test.go index f2df15ffd..102fcc912 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -212,10 +212,11 @@ func builder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestN genms = append(genms, *genm) } templ := &genesis.Template{ - Accounts: genaccs, - Miners: genms, - Timestamp: uint64(time.Now().Unix() - 10000), // some time sufficiently far in the past - VerifregRootKey: gen.DefaultVerifregRootkeyActor, + Accounts: genaccs, + Miners: genms, + Timestamp: uint64(time.Now().Unix() - 10000), // some time sufficiently far in the past + VerifregRootKey: gen.DefaultVerifregRootkeyActor, + RemainderAccount: gen.DefaultRemainderAccountActor, } // END PRESEAL SECTION @@ -362,10 +363,11 @@ func mockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test genms = append(genms, *genm) } templ := &genesis.Template{ - Accounts: genaccs, - Miners: genms, - Timestamp: uint64(time.Now().Unix()) - (build.BlockDelaySecs * 20000), - VerifregRootKey: gen.DefaultVerifregRootkeyActor, + Accounts: genaccs, + Miners: genms, + Timestamp: uint64(time.Now().Unix()) - (build.BlockDelaySecs * 20000), + VerifregRootKey: gen.DefaultVerifregRootkeyActor, + RemainderAccount: gen.DefaultRemainderAccountActor, } // END PRESEAL SECTION From 98f00b510f774144e61cc21c273784a8c8c42985 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Tue, 18 Aug 2020 18:53:56 -0400 Subject: [PATCH 36/53] re-mark replaced sectors as for upgrade if precommit fails --- extern/storage-sealing/states_sealing.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/extern/storage-sealing/states_sealing.go b/extern/storage-sealing/states_sealing.go index 110a73ac0..791aba290 100644 --- a/extern/storage-sealing/states_sealing.go +++ b/extern/storage-sealing/states_sealing.go @@ -123,6 +123,14 @@ func (m *Sealing) handlePreCommit2(ctx statemachine.Context, sector SectorInfo) }) } +// TODO: We should probably invoke this method in most (if not all) state transition failures after handlePreCommitting +func (m *Sealing) remarkForUpgrade(sid abi.SectorNumber) { + err := m.MarkForUpgrade(sid) + if err != nil { + log.Errorf("error re-marking sector %d as for upgrade: %+v", sid, err) + } +} + func (m *Sealing) handlePreCommitting(ctx statemachine.Context, sector SectorInfo) error { tok, height, err := m.api.ChainHead(ctx.Context()) if err != nil { @@ -197,6 +205,9 @@ func (m *Sealing) handlePreCommitting(ctx statemachine.Context, sector SectorInf log.Infof("submitting precommit for sector %d (deposit: %s): ", sector.SectorNumber, deposit) mcid, err := m.api.SendMsg(ctx.Context(), waddr, m.maddr, builtin.MethodsMiner.PreCommitSector, deposit, m.feeCfg.MaxPreCommitGasFee, enc.Bytes()) if err != nil { + if params.ReplaceSectorDeadline > 0 { + m.remarkForUpgrade(params.ReplaceSectorNumber) + } return ctx.Send(SectorChainPreCommitFailed{xerrors.Errorf("pushing message to mpool: %w", err)}) } @@ -208,7 +219,7 @@ func (m *Sealing) handlePreCommitWait(ctx statemachine.Context, sector SectorInf return ctx.Send(SectorChainPreCommitFailed{xerrors.Errorf("precommit message was nil")}) } - // would be ideal to just use the events.Called handler, but it wouldnt be able to handle individual message timeouts + // would be ideal to just use the events.Called handler, but it wouldn't be able to handle individual message timeouts log.Info("Sector precommitted: ", sector.SectorNumber) mw, err := m.api.StateWaitMsg(ctx.Context(), *sector.PreCommitMessage) if err != nil { From 7de7e65dbc5c13347c4f0e82d0bd8ae6162e356a Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Tue, 18 Aug 2020 18:55:18 -0400 Subject: [PATCH 37/53] Calculate depositMinimum for upgrading as replaced sector's Initialpledge --- extern/storage-sealing/states_sealing.go | 2 +- extern/storage-sealing/upgrade_queue.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/extern/storage-sealing/states_sealing.go b/extern/storage-sealing/states_sealing.go index 791aba290..1ac22e20f 100644 --- a/extern/storage-sealing/states_sealing.go +++ b/extern/storage-sealing/states_sealing.go @@ -205,7 +205,7 @@ func (m *Sealing) handlePreCommitting(ctx statemachine.Context, sector SectorInf log.Infof("submitting precommit for sector %d (deposit: %s): ", sector.SectorNumber, deposit) mcid, err := m.api.SendMsg(ctx.Context(), waddr, m.maddr, builtin.MethodsMiner.PreCommitSector, deposit, m.feeCfg.MaxPreCommitGasFee, enc.Bytes()) if err != nil { - if params.ReplaceSectorDeadline > 0 { + if params.ReplaceCapacity { m.remarkForUpgrade(params.ReplaceSectorNumber) } return ctx.Send(SectorChainPreCommitFailed{xerrors.Errorf("pushing message to mpool: %w", err)}) diff --git a/extern/storage-sealing/upgrade_queue.go b/extern/storage-sealing/upgrade_queue.go index ed60e55d4..bb7bccd13 100644 --- a/extern/storage-sealing/upgrade_queue.go +++ b/extern/storage-sealing/upgrade_queue.go @@ -57,18 +57,18 @@ func (m *Sealing) tryUpgradeSector(ctx context.Context, params *miner.SectorPreC params.ReplaceSectorDeadline = loc.Deadline params.ReplaceSectorPartition = loc.Partition - ri, err := m.GetSectorInfo(*replace) + ri, err := m.api.StateSectorGetInfo(ctx, m.maddr, *replace, nil) if err != nil { - log.Errorf("error calling GetSectorInfo for replaced sector: %+v", err) + log.Errorf("error calling StateSectorGetInfo for replaced sector: %+v", err) return big.Zero() } - if params.Expiration < ri.PreCommitInfo.Expiration { + if params.Expiration < ri.Expiration { // TODO: Some limit on this - params.Expiration = ri.PreCommitInfo.Expiration + params.Expiration = ri.Expiration } - return ri.PreCommitDeposit + return ri.InitialPledge } return big.Zero() From f511cc188af48b9e97d6abafd4f218f3ec0140c4 Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Tue, 18 Aug 2020 16:26:21 -0700 Subject: [PATCH 38/53] feat(cli): data transfer command add command to monitor data transfers --- api/api_full.go | 3 +- api/apistruct/struct.go | 5 ++ api/types.go | 15 ++++++ cli/client.go | 103 +++++++++++++++++++++++++++++++++++++ node/impl/client/client.go | 38 ++++++++++++++ 5 files changed, 163 insertions(+), 1 deletion(-) diff --git a/api/api_full.go b/api/api_full.go index 6feeb12cf..3e2683241 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -256,7 +256,8 @@ type FullNode interface { ClientGenCar(ctx context.Context, ref FileRef, outpath string) error // ClientDealSize calculates real deal data size ClientDealSize(ctx context.Context, root cid.Cid) (DataSize, error) - + // ClientListTransfers returns the status of all ongoing transfers of data + ClientListDataTransfers(ctx context.Context) ([]DataTransferChannel, error) // ClientUnimport removes references to the specified file from filestore //ClientUnimport(path string) diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index 8fb8e68ed..ffa28be90 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -142,6 +142,7 @@ type FullNodeStruct struct { ClientCalcCommP func(ctx context.Context, inpath string) (*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"` + ClientListDataTransfers func(ctx context.Context) ([]api.DataTransferChannel, error) `perm:"write"` 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"` @@ -449,6 +450,10 @@ func (c *FullNodeStruct) ClientDealSize(ctx context.Context, root cid.Cid) (api. return c.Internal.ClientDealSize(ctx, root) } +func (c *FullNodeStruct) ClientListDataTransfers(ctx context.Context) ([]api.DataTransferChannel, error) { + return c.Internal.ClientListDataTransfers(ctx) +} + func (c *FullNodeStruct) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) { return c.Internal.GasEstimateGasPremium(ctx, nblocksincl, sender, gaslimit, tsk) diff --git a/api/types.go b/api/types.go index 8a682db17..4b707dc9f 100644 --- a/api/types.go +++ b/api/types.go @@ -2,10 +2,13 @@ package api import ( "encoding/json" + "github.com/filecoin-project/go-address" + datatransfer "github.com/filecoin-project/go-data-transfer" "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" + "github.com/ipfs/go-cid" "github.com/libp2p/go-libp2p-core/peer" pubsub "github.com/libp2p/go-libp2p-pubsub" @@ -98,3 +101,15 @@ func (ms *MessageSendSpec) Get() MessageSendSpec { return *ms } + +type DataTransferChannel struct { + TransferID datatransfer.TransferID + Status datatransfer.Status + BaseCID cid.Cid + IsInitiator bool + IsSender bool + VoucherJSON string + Message string + OtherPeer peer.ID + Transferred uint64 +} diff --git a/cli/client.go b/cli/client.go index 519d11e5a..fe4ed8c1f 100644 --- a/cli/client.go +++ b/cli/client.go @@ -12,6 +12,7 @@ import ( "github.com/docker/go-units" "github.com/fatih/color" + datatransfer "github.com/filecoin-project/go-data-transfer" "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/ipfs/go-cid" "github.com/ipfs/go-cidutil/cidenc" @@ -76,6 +77,7 @@ var clientCmd = &cli.Command{ WithCategory("util", clientCommPCmd), WithCategory("util", clientCarGenCmd), WithCategory("util", clientInfoCmd), + WithCategory("util", clientListTransfers), }, } @@ -1203,3 +1205,104 @@ var clientInfoCmd = &cli.Command{ return nil }, } + +var clientListTransfers = &cli.Command{ + Name: "list-transfers", + Usage: "Monitor ongoing data transfers for deals", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "color", + Usage: "use color in display output", + Value: true, + }, + }, + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + channels, err := api.ClientListDataTransfers(ctx) + if err != nil { + return err + } + + sort.Slice(channels, func(i, j int) bool { + return channels[i].TransferID < channels[j].TransferID + }) + + var receivingChannels, sendingChannels []lapi.DataTransferChannel + for _, channel := range channels { + if channel.IsSender { + sendingChannels = append(sendingChannels, channel) + } else { + receivingChannels = append(receivingChannels, channel) + } + } + + color := cctx.Bool("color") + + fmt.Fprintf(os.Stdout, "Sending Channels\n\n") + w := tablewriter.New(tablewriter.Col("ID"), + tablewriter.Col("Status"), + tablewriter.Col("Other Party"), + tablewriter.Col("Root Cid"), + tablewriter.Col("Initiated?"), + tablewriter.Col("Transferred"), + tablewriter.NewLineCol("Voucher"), + tablewriter.NewLineCol("Message")) + for _, channel := range sendingChannels { + w.Write(toChannelOutput(color, channel)) + } + w.Flush(os.Stdout) + + fmt.Fprintf(os.Stdout, "\nReceiving Channels\n\n") + for _, channel := range receivingChannels { + + w.Write(toChannelOutput(color, channel)) + } + return w.Flush(os.Stdout) + }, +} + +func channelStatusString(useColor bool, status datatransfer.Status) string { + s := datatransfer.Statuses[status] + if !useColor { + return s + } + + switch status { + case datatransfer.Failed, datatransfer.Cancelled: + return color.RedString(s) + case datatransfer.Completed: + return color.GreenString(s) + default: + return s + } +} + +func toChannelOutput(useColor bool, channel api.DataTransferChannel) map[string]interface{} { + rootCid := channel.BaseCID.String() + rootCid = "..." + rootCid[len(rootCid)-8:] + + otherParty := channel.OtherPeer.String() + otherParty = "..." + otherParty[len(otherParty)-8:] + + initiated := "N" + if channel.IsInitiator { + initiated = "Y" + } + + return map[string]interface{}{ + "ID": channel.TransferID, + "Status": channelStatusString(useColor, channel.Status), + "Other Party": otherParty, + "Root Cid": rootCid, + "Initiated?": initiated, + "Transferred": channel.Transferred, + "Voucher": channel.VoucherJSON, + "Message": channel.Message, + } +} diff --git a/node/impl/client/client.go b/node/impl/client/client.go index d9ece2d9e..38696431b 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -2,6 +2,7 @@ package client import ( "context" + "encoding/json" "fmt" "io" "os" @@ -24,6 +25,7 @@ import ( basicnode "github.com/ipld/go-ipld-prime/node/basic" "github.com/ipld/go-ipld-prime/traversal/selector" "github.com/ipld/go-ipld-prime/traversal/selector/builder" + "github.com/libp2p/go-libp2p-core/host" "github.com/libp2p/go-libp2p-core/peer" mh "github.com/multiformats/go-multihash" "go.uber.org/fx" @@ -74,6 +76,8 @@ type API struct { CombinedBstore dtypes.ClientBlockstore // TODO: try to remove RetrievalStoreMgr dtypes.ClientRetrievalStoreManager + DataTransfer dtypes.ClientDataTransfer + Host host.Host } func calcDealExpiration(minDuration uint64, md *miner.DeadlineInfo, startEpoch abi.ChainEpoch) abi.ChainEpoch { @@ -755,3 +759,37 @@ func (a *API) clientImport(ctx context.Context, ref api.FileRef, store *multisto return nd.Cid(), nil } + +func (a *API) ClientListDataTransfers(ctx context.Context) ([]api.DataTransferChannel, error) { + inProgressChannels, err := a.DataTransfer.InProgressChannels(ctx) + if err != nil { + return nil, err + } + + apiChannels := make([]api.DataTransferChannel, 0, len(inProgressChannels)) + for channelID, channelState := range inProgressChannels { + channel := api.DataTransferChannel{ + TransferID: channelState.TransferID(), + Status: channelState.Status(), + BaseCID: channelState.BaseCID(), + IsInitiator: channelID.Initiator == a.Host.ID(), + IsSender: channelState.Sender() == a.Host.ID(), + Message: channelState.Message(), + } + voucherJSON, err := json.Marshal(channelState.Voucher()) + if err != nil { + return nil, err + } + channel.VoucherJSON = string(voucherJSON) + if channel.IsSender { + channel.Transferred = channelState.Sent() + channel.OtherPeer = channelState.Recipient() + } else { + channel.Transferred = channelState.Received() + channel.OtherPeer = channelState.Sender() + } + apiChannels = append(apiChannels, channel) + } + + return apiChannels, nil +} From d2d72c76e0949f3c2eaab8a085d1b147923b835a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 13 Aug 2020 10:47:28 +0200 Subject: [PATCH 39/53] docs: Expand sealing issue template --- .github/ISSUE_TEMPLATE/sealingfailed.md | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/sealingfailed.md b/.github/ISSUE_TEMPLATE/sealingfailed.md index d58664415..ae14c3262 100644 --- a/.github/ISSUE_TEMPLATE/sealingfailed.md +++ b/.github/ISSUE_TEMPLATE/sealingfailed.md @@ -17,18 +17,27 @@ A brief description of the problem you encountered while proving (sealing) a sec Including what commands you ran, and a description of your setup, is very helpful. -**Sectors list** - -The output of `./lotus-storage-miner sectors list`. - **Sectors status** -The output of `./lotus-storage-miner sectors status --log ` for the failed sector(s). +The output of `lotus-miner sectors status --log ` for the failed sector(s). -**Lotus storage miner logs** +**Lotus miner logs** -Please go through the logs of your storage miner, and include screenshots of any error-like messages you find. +Please go through the logs of your miner, and include screenshots of any error-like messages you find. + +Alternatively please upload full log files and share a link here + +**Lotus miner diagnostic info** + +Please collect the following diagnostic information, and share a link here + +* lotus-miner diagnostic info `lotus-miner info all > allinfo` + +** Code modifications ** + +If you have modified parts of lotus, please describe which areas were modified, +and the scope of those modifications **Version** -The output of `./lotus --version`. +The output of `lotus --version`. From ef7f7375e70a9377f2d15f81676460f3764e8953 Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Tue, 18 Aug 2020 16:43:05 -0700 Subject: [PATCH 40/53] fix(cli): cleanup data-transfers cleanup output for data transfers. --- cli/client.go | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/cli/client.go b/cli/client.go index fe4ed8c1f..fac891530 100644 --- a/cli/client.go +++ b/cli/client.go @@ -1247,21 +1247,29 @@ var clientListTransfers = &cli.Command{ fmt.Fprintf(os.Stdout, "Sending Channels\n\n") w := tablewriter.New(tablewriter.Col("ID"), tablewriter.Col("Status"), - tablewriter.Col("Other Party"), + tablewriter.Col("Sending To"), tablewriter.Col("Root Cid"), tablewriter.Col("Initiated?"), tablewriter.Col("Transferred"), - tablewriter.NewLineCol("Voucher"), + tablewriter.Col("Voucher"), tablewriter.NewLineCol("Message")) for _, channel := range sendingChannels { - w.Write(toChannelOutput(color, channel)) + w.Write(toChannelOutput(color, "Sending To", channel)) } w.Flush(os.Stdout) fmt.Fprintf(os.Stdout, "\nReceiving Channels\n\n") + w = tablewriter.New(tablewriter.Col("ID"), + tablewriter.Col("Status"), + tablewriter.Col("Receiving From"), + tablewriter.Col("Root Cid"), + tablewriter.Col("Initiated?"), + tablewriter.Col("Transferred"), + tablewriter.Col("Voucher"), + tablewriter.NewLineCol("Message")) for _, channel := range receivingChannels { - w.Write(toChannelOutput(color, channel)) + w.Write(toChannelOutput(color, "Receiving From", channel)) } return w.Flush(os.Stdout) }, @@ -1283,7 +1291,7 @@ func channelStatusString(useColor bool, status datatransfer.Status) string { } } -func toChannelOutput(useColor bool, channel api.DataTransferChannel) map[string]interface{} { +func toChannelOutput(useColor bool, otherPartyColumn string, channel api.DataTransferChannel) map[string]interface{} { rootCid := channel.BaseCID.String() rootCid = "..." + rootCid[len(rootCid)-8:] @@ -1295,14 +1303,19 @@ func toChannelOutput(useColor bool, channel api.DataTransferChannel) map[string] initiated = "Y" } + voucher := channel.VoucherJSON + if len(voucher) > 40 { + voucher = "..." + voucher[len(voucher)-37:] + } + return map[string]interface{}{ - "ID": channel.TransferID, - "Status": channelStatusString(useColor, channel.Status), - "Other Party": otherParty, - "Root Cid": rootCid, - "Initiated?": initiated, - "Transferred": channel.Transferred, - "Voucher": channel.VoucherJSON, - "Message": channel.Message, + "ID": channel.TransferID, + "Status": channelStatusString(useColor, channel.Status), + otherPartyColumn: otherParty, + "Root Cid": rootCid, + "Initiated?": initiated, + "Transferred": channel.Transferred, + "Voucher": voucher, + "Message": channel.Message, } } From d0f6804283f2cacd25bcc7421c944f6e6c2239c7 Mon Sep 17 00:00:00 2001 From: David Dias Date: Mon, 17 Aug 2020 15:21:27 +0100 Subject: [PATCH 41/53] docs: add badgers --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 23a1d7eb1..cd7edad5e 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,14 @@

Project Lotus - 莲

+

+ + + + +
+

+ Lotus is an implementation of the Filecoin Distributed Storage Network. For more details about Filecoin, check out the [Filecoin Spec](https://spec.filecoin.io). ## Building & Documentation From 2dfc15c67d7ee944b36262b729a0d27510640661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Wed, 19 Aug 2020 01:57:57 +0200 Subject: [PATCH 42/53] docs: Expand sealing issue template --- .github/ISSUE_TEMPLATE/sealingfailed.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/sealingfailed.md b/.github/ISSUE_TEMPLATE/sealingfailed.md index 2084b8dd4..ae14c3262 100644 --- a/.github/ISSUE_TEMPLATE/sealingfailed.md +++ b/.github/ISSUE_TEMPLATE/sealingfailed.md @@ -17,18 +17,27 @@ A brief description of the problem you encountered while proving (sealing) a sec Including what commands you ran, and a description of your setup, is very helpful. -**Sectors list** - -The output of `./lotus-miner sectors list`. - **Sectors status** -The output of `./lotus-miner sectors status --log ` for the failed sector(s). +The output of `lotus-miner sectors status --log ` for the failed sector(s). **Lotus miner logs** Please go through the logs of your miner, and include screenshots of any error-like messages you find. +Alternatively please upload full log files and share a link here + +**Lotus miner diagnostic info** + +Please collect the following diagnostic information, and share a link here + +* lotus-miner diagnostic info `lotus-miner info all > allinfo` + +** Code modifications ** + +If you have modified parts of lotus, please describe which areas were modified, +and the scope of those modifications + **Version** -The output of `./lotus --version`. +The output of `lotus --version`. From 66ac7c195cb74646943ea8fb9b32e069ffa5517f Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Tue, 18 Aug 2020 17:36:22 -0700 Subject: [PATCH 43/53] feat(cli): add updates to data transfer Add an API to get data transfer updates and add modify the CLI to be an ongoing monitoring plan --- api/api_full.go | 2 + api/apistruct/struct.go | 37 ++++++----- api/types.go | 2 +- cli/client.go | 124 +++++++++++++++++++++++++------------ go.mod | 1 + go.sum | 2 + node/impl/client/client.go | 81 +++++++++++++++++------- 7 files changed, 168 insertions(+), 81 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index 3e2683241..72799c846 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -258,6 +258,8 @@ type FullNode interface { ClientDealSize(ctx context.Context, root cid.Cid) (DataSize, error) // ClientListTransfers returns the status of all ongoing transfers of data ClientListDataTransfers(ctx context.Context) ([]DataTransferChannel, error) + ClientDataTransferUpdates(ctx context.Context) (<-chan DataTransferChannel, error) + // ClientUnimport removes references to the specified file from filestore //ClientUnimport(path string) diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index ffa28be90..282dd3116 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -127,22 +127,23 @@ 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"` - ClientRetrieveWithEvents 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) (*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"` - ClientListDataTransfers func(ctx context.Context) ([]api.DataTransferChannel, 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"` + ClientRetrieveWithEvents 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) (*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"` + ClientListDataTransfers func(ctx context.Context) ([]api.DataTransferChannel, error) `perm:"write"` + ClientDataTransferUpdates func(ctx context.Context) (<-chan api.DataTransferChannel, error) `perm:"write"` 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"` @@ -454,6 +455,10 @@ func (c *FullNodeStruct) ClientListDataTransfers(ctx context.Context) ([]api.Dat return c.Internal.ClientListDataTransfers(ctx) } +func (c *FullNodeStruct) ClientDataTransferUpdates(ctx context.Context) (<-chan api.DataTransferChannel, error) { + return c.Internal.ClientDataTransferUpdates(ctx) +} + func (c *FullNodeStruct) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) { return c.Internal.GasEstimateGasPremium(ctx, nblocksincl, sender, gaslimit, tsk) diff --git a/api/types.go b/api/types.go index 4b707dc9f..9a874d1c2 100644 --- a/api/types.go +++ b/api/types.go @@ -108,7 +108,7 @@ type DataTransferChannel struct { BaseCID cid.Cid IsInitiator bool IsSender bool - VoucherJSON string + Voucher string Message string OtherPeer peer.ID Transferred uint64 diff --git a/cli/client.go b/cli/client.go index fac891530..1b1072edd 100644 --- a/cli/client.go +++ b/cli/client.go @@ -10,6 +10,7 @@ import ( "text/tabwriter" "time" + tm "github.com/buger/goterm" "github.com/docker/go-units" "github.com/fatih/color" datatransfer "github.com/filecoin-project/go-data-transfer" @@ -1215,6 +1216,10 @@ var clientListTransfers = &cli.Command{ Usage: "use color in display output", Value: true, }, + &cli.BoolFlag{ + Name: "completed", + Usage: "show completed data transfers", + }, }, Action: func(cctx *cli.Context) error { api, closer, err := GetFullNodeAPI(cctx) @@ -1229,49 +1234,86 @@ var clientListTransfers = &cli.Command{ return err } - sort.Slice(channels, func(i, j int) bool { - return channels[i].TransferID < channels[j].TransferID - }) + channelUpdates, err := api.ClientDataTransferUpdates(ctx) + if err != nil { + return err + } - var receivingChannels, sendingChannels []lapi.DataTransferChannel - for _, channel := range channels { - if channel.IsSender { - sendingChannels = append(sendingChannels, channel) - } else { - receivingChannels = append(receivingChannels, channel) + for { + tm.Clear() // Clear current screen + + tm.MoveCursor(1, 1) + + sort.Slice(channels, func(i, j int) bool { + return channels[i].TransferID < channels[j].TransferID + }) + + completed := cctx.Bool("completed") + var receivingChannels, sendingChannels []lapi.DataTransferChannel + for _, channel := range channels { + if !completed && channel.Status == datatransfer.Completed { + continue + } + if channel.IsSender { + sendingChannels = append(sendingChannels, channel) + } else { + receivingChannels = append(receivingChannels, channel) + } + } + + color := cctx.Bool("color") + + tm.Printf("Sending Channels\n\n") + w := tablewriter.New(tablewriter.Col("ID"), + tablewriter.Col("Status"), + tablewriter.Col("Sending To"), + tablewriter.Col("Root Cid"), + tablewriter.Col("Initiated?"), + tablewriter.Col("Transferred"), + tablewriter.Col("Voucher"), + tablewriter.NewLineCol("Message")) + for _, channel := range sendingChannels { + w.Write(toChannelOutput(color, "Sending To", channel)) + } + w.Flush(tm.Screen) + + fmt.Fprintf(os.Stdout, "\nReceiving Channels\n\n") + w = tablewriter.New(tablewriter.Col("ID"), + tablewriter.Col("Status"), + tablewriter.Col("Receiving From"), + tablewriter.Col("Root Cid"), + tablewriter.Col("Initiated?"), + tablewriter.Col("Transferred"), + tablewriter.Col("Voucher"), + tablewriter.NewLineCol("Message")) + for _, channel := range receivingChannels { + + w.Write(toChannelOutput(color, "Receiving From", channel)) + } + w.Flush(tm.Screen) + + tm.Flush() + + select { + case <-ctx.Done(): + return nil + case channelUpdate := <-channelUpdates: + var found bool + for i, existing := range channels { + if existing.TransferID == channelUpdate.TransferID && + existing.OtherPeer == channelUpdate.OtherPeer && + existing.IsSender == channelUpdate.IsSender && + existing.IsInitiator == channelUpdate.IsInitiator { + channels[i] = channelUpdate + found = true + break + } + } + if !found { + channels = append(channels, channelUpdate) + } } } - - color := cctx.Bool("color") - - fmt.Fprintf(os.Stdout, "Sending Channels\n\n") - w := tablewriter.New(tablewriter.Col("ID"), - tablewriter.Col("Status"), - tablewriter.Col("Sending To"), - tablewriter.Col("Root Cid"), - tablewriter.Col("Initiated?"), - tablewriter.Col("Transferred"), - tablewriter.Col("Voucher"), - tablewriter.NewLineCol("Message")) - for _, channel := range sendingChannels { - w.Write(toChannelOutput(color, "Sending To", channel)) - } - w.Flush(os.Stdout) - - fmt.Fprintf(os.Stdout, "\nReceiving Channels\n\n") - w = tablewriter.New(tablewriter.Col("ID"), - tablewriter.Col("Status"), - tablewriter.Col("Receiving From"), - tablewriter.Col("Root Cid"), - tablewriter.Col("Initiated?"), - tablewriter.Col("Transferred"), - tablewriter.Col("Voucher"), - tablewriter.NewLineCol("Message")) - for _, channel := range receivingChannels { - - w.Write(toChannelOutput(color, "Receiving From", channel)) - } - return w.Flush(os.Stdout) }, } @@ -1303,7 +1345,7 @@ func toChannelOutput(useColor bool, otherPartyColumn string, channel api.DataTra initiated = "Y" } - voucher := channel.VoucherJSON + voucher := channel.Voucher if len(voucher) > 40 { voucher = "..." + voucher[len(voucher)-37:] } diff --git a/go.mod b/go.mod index aeb96ffbd..d3c945c38 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d + github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 github.com/coreos/go-systemd/v22 v22.0.0 github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e github.com/dgraph-io/badger/v2 v2.0.3 diff --git a/go.sum b/go.sum index 26966c505..a916c6074 100644 --- a/go.sum +++ b/go.sum @@ -112,6 +112,8 @@ github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVa github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 h1:gfAMKE626QEuKG3si0pdTRcr/YEbBoxY+3GOH3gWvl4= +github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129/go.mod h1:u9UyCz2eTrSGy6fbupqJ54eY5c4IC8gREQ1053dK12U= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 38696431b..248b9ec6a 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -7,6 +7,7 @@ import ( "io" "os" + datatransfer "github.com/filecoin-project/go-data-transfer" "github.com/filecoin-project/specs-actors/actors/abi/big" "golang.org/x/xerrors" @@ -470,11 +471,15 @@ 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{ + select { + case <-ctx.Done(): + return + case events <- marketevents.RetrievalEvent{ Event: event, Status: state.Status, BytesReceived: state.TotalReceived, FundsSpent: state.FundsSpent, + }: } switch state.Status { @@ -767,29 +772,59 @@ func (a *API) ClientListDataTransfers(ctx context.Context) ([]api.DataTransferCh } apiChannels := make([]api.DataTransferChannel, 0, len(inProgressChannels)) - for channelID, channelState := range inProgressChannels { - channel := api.DataTransferChannel{ - TransferID: channelState.TransferID(), - Status: channelState.Status(), - BaseCID: channelState.BaseCID(), - IsInitiator: channelID.Initiator == a.Host.ID(), - IsSender: channelState.Sender() == a.Host.ID(), - Message: channelState.Message(), - } - voucherJSON, err := json.Marshal(channelState.Voucher()) - if err != nil { - return nil, err - } - channel.VoucherJSON = string(voucherJSON) - if channel.IsSender { - channel.Transferred = channelState.Sent() - channel.OtherPeer = channelState.Recipient() - } else { - channel.Transferred = channelState.Received() - channel.OtherPeer = channelState.Sender() - } - apiChannels = append(apiChannels, channel) + for _, channelState := range inProgressChannels { + apiChannels = append(apiChannels, toAPIChannel(a.Host.ID(), channelState)) } return apiChannels, nil } + +func (a *API) ClientDataTransferUpdates(ctx context.Context) (<-chan api.DataTransferChannel, error) { + channels := make(chan api.DataTransferChannel) + + unsub := a.DataTransfer.SubscribeToEvents(func(evt datatransfer.Event, channelState datatransfer.ChannelState) { + channel := toAPIChannel(a.Host.ID(), channelState) + select { + case <-ctx.Done(): + case channels <- channel: + } + }) + + go func() { + defer unsub() + <-ctx.Done() + }() + + return channels, nil +} + +func toAPIChannel(hostID peer.ID, channelState datatransfer.ChannelState) api.DataTransferChannel { + channel := api.DataTransferChannel{ + TransferID: channelState.TransferID(), + Status: channelState.Status(), + BaseCID: channelState.BaseCID(), + IsSender: channelState.Sender() == hostID, + Message: channelState.Message(), + } + stringer, ok := channelState.Voucher().(fmt.Stringer) + if ok { + channel.Voucher = stringer.String() + } else { + voucherJSON, err := json.Marshal(channelState.Voucher()) + if err != nil { + channel.Voucher = fmt.Errorf("Voucher Serialization: %w", err).Error() + } else { + channel.Voucher = string(voucherJSON) + } + } + if channel.IsSender { + channel.IsInitiator = !channelState.IsPull() + channel.Transferred = channelState.Sent() + channel.OtherPeer = channelState.Recipient() + } else { + channel.IsInitiator = channelState.IsPull() + channel.Transferred = channelState.Received() + channel.OtherPeer = channelState.Sender() + } + return channel +} From 4fc5f9fe9f832c7dc362436e1040443a7ef11b66 Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Tue, 18 Aug 2020 18:23:29 -0700 Subject: [PATCH 44/53] feat(cli): data transfer watch option make watching data transfer CLI updates only an option --- cli/client.go | 153 +++++++++++++++++++++++++++----------------------- 1 file changed, 83 insertions(+), 70 deletions(-) diff --git a/cli/client.go b/cli/client.go index 1b1072edd..b3ee6220b 100644 --- a/cli/client.go +++ b/cli/client.go @@ -3,6 +3,7 @@ package cli import ( "encoding/json" "fmt" + "io" "os" "path/filepath" "sort" @@ -1209,7 +1210,7 @@ var clientInfoCmd = &cli.Command{ var clientListTransfers = &cli.Command{ Name: "list-transfers", - Usage: "Monitor ongoing data transfers for deals", + Usage: "List ongoing data transfers for deals", Flags: []cli.Flag{ &cli.BoolFlag{ Name: "color", @@ -1220,6 +1221,10 @@ var clientListTransfers = &cli.Command{ Name: "completed", Usage: "show completed data transfers", }, + &cli.BoolFlag{ + Name: "watch", + Usage: "watch deal updates in real-time, rather than a one time list", + }, }, Action: func(cctx *cli.Context) error { api, closer, err := GetFullNodeAPI(cctx) @@ -1234,89 +1239,97 @@ var clientListTransfers = &cli.Command{ return err } - channelUpdates, err := api.ClientDataTransferUpdates(ctx) - if err != nil { - return err - } + completed := cctx.Bool("completed") + color := cctx.Bool("color") + watch := cctx.Bool("watch") - for { - tm.Clear() // Clear current screen - - tm.MoveCursor(1, 1) - - sort.Slice(channels, func(i, j int) bool { - return channels[i].TransferID < channels[j].TransferID - }) - - completed := cctx.Bool("completed") - var receivingChannels, sendingChannels []lapi.DataTransferChannel - for _, channel := range channels { - if !completed && channel.Status == datatransfer.Completed { - continue - } - if channel.IsSender { - sendingChannels = append(sendingChannels, channel) - } else { - receivingChannels = append(receivingChannels, channel) - } + if watch { + channelUpdates, err := api.ClientDataTransferUpdates(ctx) + if err != nil { + return err } - color := cctx.Bool("color") + for { + tm.Clear() // Clear current screen - tm.Printf("Sending Channels\n\n") - w := tablewriter.New(tablewriter.Col("ID"), - tablewriter.Col("Status"), - tablewriter.Col("Sending To"), - tablewriter.Col("Root Cid"), - tablewriter.Col("Initiated?"), - tablewriter.Col("Transferred"), - tablewriter.Col("Voucher"), - tablewriter.NewLineCol("Message")) - for _, channel := range sendingChannels { - w.Write(toChannelOutput(color, "Sending To", channel)) - } - w.Flush(tm.Screen) + tm.MoveCursor(1, 1) - fmt.Fprintf(os.Stdout, "\nReceiving Channels\n\n") - w = tablewriter.New(tablewriter.Col("ID"), - tablewriter.Col("Status"), - tablewriter.Col("Receiving From"), - tablewriter.Col("Root Cid"), - tablewriter.Col("Initiated?"), - tablewriter.Col("Transferred"), - tablewriter.Col("Voucher"), - tablewriter.NewLineCol("Message")) - for _, channel := range receivingChannels { + outputChannels(tm.Screen, channels, completed, color) - w.Write(toChannelOutput(color, "Receiving From", channel)) - } - w.Flush(tm.Screen) + tm.Flush() - tm.Flush() - - select { - case <-ctx.Done(): - return nil - case channelUpdate := <-channelUpdates: - var found bool - for i, existing := range channels { - if existing.TransferID == channelUpdate.TransferID && - existing.OtherPeer == channelUpdate.OtherPeer && - existing.IsSender == channelUpdate.IsSender && - existing.IsInitiator == channelUpdate.IsInitiator { - channels[i] = channelUpdate - found = true - break + select { + case <-ctx.Done(): + return nil + case channelUpdate := <-channelUpdates: + var found bool + for i, existing := range channels { + if existing.TransferID == channelUpdate.TransferID && + existing.OtherPeer == channelUpdate.OtherPeer && + existing.IsSender == channelUpdate.IsSender && + existing.IsInitiator == channelUpdate.IsInitiator { + channels[i] = channelUpdate + found = true + break + } + } + if !found { + channels = append(channels, channelUpdate) } } - if !found { - channels = append(channels, channelUpdate) - } } } + outputChannels(os.Stdout, channels, completed, color) + return nil }, } +func outputChannels(out io.Writer, channels []api.DataTransferChannel, completed bool, color bool) { + sort.Slice(channels, func(i, j int) bool { + return channels[i].TransferID < channels[j].TransferID + }) + + var receivingChannels, sendingChannels []lapi.DataTransferChannel + for _, channel := range channels { + if !completed && channel.Status == datatransfer.Completed { + continue + } + if channel.IsSender { + sendingChannels = append(sendingChannels, channel) + } else { + receivingChannels = append(receivingChannels, channel) + } + } + + fmt.Fprintf(out, "Sending Channels\n\n") + w := tablewriter.New(tablewriter.Col("ID"), + tablewriter.Col("Status"), + tablewriter.Col("Sending To"), + tablewriter.Col("Root Cid"), + tablewriter.Col("Initiated?"), + tablewriter.Col("Transferred"), + tablewriter.Col("Voucher"), + tablewriter.NewLineCol("Message")) + for _, channel := range sendingChannels { + w.Write(toChannelOutput(color, "Sending To", channel)) + } + w.Flush(out) + + fmt.Fprintf(out, "\nReceiving Channels\n\n") + w = tablewriter.New(tablewriter.Col("ID"), + tablewriter.Col("Status"), + tablewriter.Col("Receiving From"), + tablewriter.Col("Root Cid"), + tablewriter.Col("Initiated?"), + tablewriter.Col("Transferred"), + tablewriter.Col("Voucher"), + tablewriter.NewLineCol("Message")) + for _, channel := range receivingChannels { + w.Write(toChannelOutput(color, "Receiving From", channel)) + } + w.Flush(out) +} + func channelStatusString(useColor bool, status datatransfer.Status) string { s := datatransfer.Statuses[status] if !useColor { From 63ad6bc325e7a60ef3430a443aeda0b391cc670d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sami=20M=C3=A4kel=C3=A4?= Date: Wed, 19 Aug 2020 12:25:38 +0300 Subject: [PATCH 45/53] need to merge --- chain/gen/genesis/genesis.go | 5 +++++ chain/gen/genesis/t01_init.go | 5 +++++ go.sum | 1 + 3 files changed, 11 insertions(+) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 4d059a3a2..de4a1a989 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -298,6 +298,11 @@ func createAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.IpldStore for _, e := range ainfo.Signers { idAddress, _ := keyIDs[e] + // Check if actor already exists + _, err := state.GetActor(e) + if err == nil { + continue + } st, err := cst.Put(ctx, &account.State{Address: e}) if err != nil { return err diff --git a/chain/gen/genesis/t01_init.go b/chain/gen/genesis/t01_init.go index 7d00601f2..b15ada470 100644 --- a/chain/gen/genesis/t01_init.go +++ b/chain/gen/genesis/t01_init.go @@ -43,6 +43,11 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi return nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err) } for _, e := range ainfo.Signers { + + if _, ok := keyToId[e]; ok { + continue + } + fmt.Printf("init set %s t0%d\n", e, counter) value := cbg.CborInt(counter) diff --git a/go.sum b/go.sum index 2f3da883a..e792431f5 100644 --- a/go.sum +++ b/go.sum @@ -276,6 +276,7 @@ github.com/filecoin-project/specs-actors v0.8.7-0.20200811203034-272d022c1923 h1 github.com/filecoin-project/specs-actors v0.8.7-0.20200811203034-272d022c1923/go.mod h1:hukRu6vKQrrS7Nt+fC/ql4PqWLSfmAWNshD/VDtARZU= github.com/filecoin-project/specs-actors v0.9.2 h1:0JG0QLHw8pO6BPqPRe9eQxQW60biHAQsx1rlQ9QbzZ0= github.com/filecoin-project/specs-actors v0.9.2/go.mod h1:YasnVUOUha0DN5wB+twl+V8LlDKVNknRG00kTJpsfFA= +github.com/filecoin-project/specs-actors v0.9.3 h1:Fi75G/UQ7R4eiIwnN+S6bBQ9LqKivyJdw62jJzTi6aE= github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea h1:iixjULRQFPn7Q9KlIqfwLJnlAXO10bbkI+xy5GKGdLY= github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401 h1:jLzN1hwO5WpKPu8ASbW8fs1FUCsOWNvoBXzQhv+8/E8= From 99e71badbf07a3560a80c7247e612d7f297eb263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sami=20M=C3=A4kel=C3=A4?= Date: Wed, 19 Aug 2020 13:03:59 +0300 Subject: [PATCH 46/53] check that accounts aren't overwritten --- chain/gen/genesis/genesis.go | 2 +- chain/gen/genesis/t01_init.go | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 651b909b4..3ff38218c 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -288,7 +288,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge return nil, nil, err } - if err := createAccount(ctx, bs, cst, state, remAccKey, template.RemainderAccount); err != nil { + if err := createAccount(ctx, bs, cst, state, remAccKey, template.RemainderAccount, keyIDs); err != nil { return nil, nil, err } err = state.SetActor(remAccKey, &types.Actor{ diff --git a/chain/gen/genesis/t01_init.go b/chain/gen/genesis/t01_init.go index b15ada470..095f275fd 100644 --- a/chain/gen/genesis/t01_init.go +++ b/chain/gen/genesis/t01_init.go @@ -33,7 +33,6 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi amap := adt.MakeEmptyMap(store) keyToId := map[address.Address]address.Address{} - counter := int64(AccountStart) for _, a := range initialActors { @@ -105,6 +104,9 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi return nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err) } for _, e := range ainfo.Signers { + if _, ok := keyToId[e]; ok { + continue + } fmt.Printf("init set %s t0%d\n", e, counter) value := cbg.CborInt(counter) From 74f35c88ad10e647c307c23421c24bf275b2287c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sami=20M=C3=A4kel=C3=A4?= Date: Wed, 19 Aug 2020 15:27:50 +0300 Subject: [PATCH 47/53] checking verifreg handling --- node/impl/full/state.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/node/impl/full/state.go b/node/impl/full/state.go index ceea2e813..f5421e2ba 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -1092,6 +1092,12 @@ func (a *StateAPI) StateVerifiedClientStatus(ctx context.Context, addr address.A return nil, err } + aid, err := a.StateLookupID(ctx, addr, tsk) + if err != nil { + log.Warnf("lookup failure %v", err) + return nil, err + } + store := a.StateManager.ChainStore().Store(ctx) var st verifreg.State @@ -1105,7 +1111,7 @@ func (a *StateAPI) StateVerifiedClientStatus(ctx context.Context, addr address.A } var dcap verifreg.DataCap - if found, err := vh.Get(adt.AddrKey(addr), &dcap); err != nil { + if found, err := vh.Get(adt.AddrKey(aid), &dcap); err != nil { return nil, err } else if !found { return nil, nil From 6c5a91735a504b5949964809d5daa0b4d289fe25 Mon Sep 17 00:00:00 2001 From: vyzo Date: Wed, 19 Aug 2020 18:45:31 +0300 Subject: [PATCH 48/53] fix drand topic first message delivery cap --- node/modules/lp2p/pubsub.go | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/node/modules/lp2p/pubsub.go b/node/modules/lp2p/pubsub.go index 95596b7d5..bea5437ce 100644 --- a/node/modules/lp2p/pubsub.go +++ b/node/modules/lp2p/pubsub.go @@ -130,12 +130,12 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { TimeInMeshQuantum: time.Second, TimeInMeshCap: 1, - // deliveries decay after 1 hour, cap at 100 blocks - FirstMessageDeliveriesWeight: 5, // max value is 500 + // deliveries decay after 1 hour, cap at 25 beacons + FirstMessageDeliveriesWeight: 5, // max value is 125 FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), - FirstMessageDeliveriesCap: 100, // 100 blocks in an hour + FirstMessageDeliveriesCap: 25, // the maximum expected in an hour is ~26, including the decay - // Mesh Delivery Failure is currently turned off for blocks + // Mesh Delivery Failure is currently turned off for beacons // This is on purpose as // - the traffic is very low for meaningful distribution of incoming edges. // - the reaction time needs to be very slow -- in the order of 10 min at least @@ -144,19 +144,6 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { // - the network is too small, so large asymmetries can be expected between mesh // edges. // We should revisit this once the network grows. - // - // // tracks deliveries in the last minute - // // penalty activates at 1 minute and expects ~0.4 blocks - // MeshMessageDeliveriesWeight: -576, // max penalty is -100 - // MeshMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Minute), - // MeshMessageDeliveriesCap: 10, // 10 blocks in a minute - // MeshMessageDeliveriesThreshold: 0.41666, // 10/12/2 blocks/min - // MeshMessageDeliveriesWindow: 10 * time.Millisecond, - // MeshMessageDeliveriesActivation: time.Minute, - // - // // decays after 15 min - // MeshFailurePenaltyWeight: -576, - // MeshFailurePenaltyDecay: pubsub.ScoreParameterDecay(15 * time.Minute), // invalid messages decay after 1 hour InvalidMessageDeliveriesWeight: -1000, From f1632376e7561d60e4c898bf32f6bca7a9095693 Mon Sep 17 00:00:00 2001 From: Travis Person Date: Wed, 19 Aug 2020 19:18:36 +0000 Subject: [PATCH 49/53] lotus-shed: add simple jwt creation support --- cmd/lotus-shed/jwt.go | 89 +++++++++++++++++++++++++++++++++++++++ cmd/lotus-shed/keyinfo.go | 2 +- cmd/lotus-shed/main.go | 1 + node/modules/core.go | 7 +-- 4 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 cmd/lotus-shed/jwt.go diff --git a/cmd/lotus-shed/jwt.go b/cmd/lotus-shed/jwt.go new file mode 100644 index 000000000..d37359f71 --- /dev/null +++ b/cmd/lotus-shed/jwt.go @@ -0,0 +1,89 @@ +package main + +import ( + "crypto/rand" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + + "github.com/gbrlsnchs/jwt/v3" + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/lotus/api/apistruct" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/modules" +) + +var jwtCmd = &cli.Command{ + Name: "jwt", + Usage: "work with lotus jwt secrets and tokens", + Description: `The subcommands of jwt provide helpful tools for working with jwt files without + having to run the lotus daemon.`, + Subcommands: []*cli.Command{ + jwtNewCmd, + }, +} + +var jwtNewCmd = &cli.Command{ + Name: "new", + Usage: "create a new jwt secret and token for lotus", + ArgsUsage: "", + Description: `Jwt tokens are used to authenticate api requests to the lotus daemon. + + The created jwt token have full privileges and should not be shared.`, + Flags: []cli.Flag{}, + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return fmt.Errorf("please specify a name") + } + + keyName := cctx.Args().First() + + sk, err := ioutil.ReadAll(io.LimitReader(rand.Reader, 32)) + if err != nil { + return err + } + + keyInfo := types.KeyInfo{ + Type: modules.KTJwtHmacSecret, + PrivateKey: sk, + } + + p := modules.JwtPayload{ + Allow: apistruct.AllPermissions, + } + + token, err := jwt.Sign(&p, jwt.NewHS256(keyInfo.PrivateKey)) + if err != nil { + return err + } + + filename := fmt.Sprintf("jwt-%s.jwts", keyName) + file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + return err + } + + defer func() { + if err := file.Close(); err != nil { + log.Warnf("failed to close output file: %w", err) + } + }() + + bytes, err := json.Marshal(keyInfo) + if err != nil { + return err + } + + encoded := hex.EncodeToString(bytes) + if _, err := file.Write([]byte(encoded)); err != nil { + return err + } + + filenameToken := fmt.Sprintf("jwt-%s.token", keyName) + return ioutil.WriteFile(filenameToken, token, 0600) + }, +} diff --git a/cmd/lotus-shed/keyinfo.go b/cmd/lotus-shed/keyinfo.go index 028ead413..0f608d858 100644 --- a/cmd/lotus-shed/keyinfo.go +++ b/cmd/lotus-shed/keyinfo.go @@ -325,7 +325,7 @@ var keyinfoNewCmd = &cli.Command{ filename = strings.ReplaceAll(filename, "", keyAddr) filename = strings.ReplaceAll(filename, "", keyType) - file, err := os.Create(filename) + file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { return err } diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index c37b93a42..4126fa649 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -19,6 +19,7 @@ func main() { base16Cmd, bitFieldCmd, keyinfoCmd, + jwtCmd, noncefix, bigIntParseCmd, staterootStatsCmd, diff --git a/node/modules/core.go b/node/modules/core.go index 84179bd63..1f21f2720 100644 --- a/node/modules/core.go +++ b/node/modules/core.go @@ -37,8 +37,9 @@ func RecordValidator(ps peerstore.Peerstore) record.Validator { } const JWTSecretName = "auth-jwt-private" //nolint:gosec +const KTJwtHmacSecret = "jwt-hmac-secret" -type jwtPayload struct { +type JwtPayload struct { Allow []auth.Permission } @@ -54,7 +55,7 @@ func APISecret(keystore types.KeyStore, lr repo.LockedRepo) (*dtypes.APIAlg, err } key = types.KeyInfo{ - Type: "jwt-hmac-secret", + Type: KTJwtHmacSecret, PrivateKey: sk, } @@ -63,7 +64,7 @@ func APISecret(keystore types.KeyStore, lr repo.LockedRepo) (*dtypes.APIAlg, err } // TODO: make this configurable - p := jwtPayload{ + p := JwtPayload{ Allow: apistruct.AllPermissions, } From 2ab202a03de9ca48251a6316a855054cf3f0b20f Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Wed, 19 Aug 2020 12:54:33 -0700 Subject: [PATCH 50/53] fixup ID allocation and a few other things --- chain/gen/genesis/genesis.go | 234 +++++++++++++++++++--------------- chain/gen/genesis/miners.go | 4 +- chain/gen/genesis/t01_init.go | 34 ++--- chain/gen/genesis/util.go | 2 +- cmd/lotus-seed/seed/seed.go | 1 + genesis/types.go | 1 + node/impl/full/multisig.go | 8 ++ 7 files changed, 162 insertions(+), 122 deletions(-) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 3ff38218c..c915c77e0 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -135,7 +135,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge // Create init actor - initact, keyIDs, err := SetupInitActor(bs, template.NetworkName, template.Accounts, template.VerifregRootKey) + idStart, initact, keyIDs, err := SetupInitActor(bs, template.NetworkName, template.Accounts, template.VerifregRootKey) if err != nil { return nil, nil, xerrors.Errorf("setup init actor: %w", err) } @@ -202,29 +202,39 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge } // Create accounts - for id, info := range template.Accounts { - if info.Type != genesis.TAccount && info.Type != genesis.TMultisig { + for _, info := range template.Accounts { + + switch info.Type { + case genesis.TAccount: + if err := createAccountActor(ctx, cst, state, info, keyIDs); err != nil { + return nil, nil, xerrors.Errorf("failed to create account actor: %w", err) + } + + case genesis.TMultisig: + + ida, err := address.NewIDAddress(uint64(idStart)) + if err != nil { + return nil, nil, err + } + idStart++ + + if err := createMultisigAccount(ctx, bs, cst, state, ida, info, keyIDs); err != nil { + return nil, nil, err + } + default: return nil, nil, xerrors.New("unsupported account type") } - ida, err := address.NewIDAddress(uint64(AccountStart + id)) - if err != nil { - return nil, nil, err - } - - if err = createAccount(ctx, bs, cst, state, ida, info, keyIDs); err != nil { - return nil, nil, err - } - } vregroot, err := address.NewIDAddress(80) if err != nil { return nil, nil, err } + _ = vregroot - if err = createAccount(ctx, bs, cst, state, vregroot, template.VerifregRootKey, keyIDs); err != nil { - return nil, nil, err + if err = createMultisigAccount(ctx, bs, cst, state, vregroot, template.VerifregRootKey, keyIDs); err != nil { + return nil, nil, xerrors.Errorf("failed to set up verified registry signer: %w", err) } // Setup the first verifier as ID-address 81 @@ -265,6 +275,8 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge totalFilAllocated := big.Zero() + fmt.Println("finished basic setup, time for remainder") + // flush as ForEach works on the HAMT if _, err := state.Flush(ctx); err != nil { return nil, nil, err @@ -288,97 +300,105 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge return nil, nil, err } - if err := createAccount(ctx, bs, cst, state, remAccKey, template.RemainderAccount, keyIDs); err != nil { - return nil, nil, err - } - err = state.SetActor(remAccKey, &types.Actor{ - Code: builtin.AccountActorCodeID, - Balance: remainingFil, - Head: emptyobject, - }) - if err != nil { - return nil, nil, xerrors.Errorf("set burnt funds account actor: %w", err) + if err := createMultisigAccount(ctx, bs, cst, state, remAccKey, template.RemainderAccount, keyIDs); err != nil { + return nil, nil, xerrors.Errorf("failed to set up remainder account: %w", err) } return state, keyIDs, nil } -func createAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.IpldStore, state *state.StateTree, ida address.Address, info genesis.Actor, keyIDs map[address.Address]address.Address) error { - if info.Type == genesis.TAccount { - var ainfo genesis.AccountMeta - if err := json.Unmarshal(info.Meta, &ainfo); err != nil { - return xerrors.Errorf("unmarshaling account meta: %w", err) - } - st, err := cst.Put(ctx, &account.State{Address: ainfo.Owner}) - if err != nil { - return err - } - err = state.SetActor(ida, &types.Actor{ - Code: builtin.AccountActorCodeID, - Balance: info.Balance, - Head: st, - }) - if err != nil { - return xerrors.Errorf("setting account from actmap: %w", err) - } - return nil - } else if info.Type == genesis.TMultisig { - var ainfo genesis.MultisigMeta - if err := json.Unmarshal(info.Meta, &ainfo); err != nil { - return xerrors.Errorf("unmarshaling account meta: %w", err) - } - pending, err := adt.MakeEmptyMap(adt.WrapStore(ctx, cst)).Root() - if err != nil { - return xerrors.Errorf("failed to create empty map: %v", err) - } - - var signers []address.Address - - for _, e := range ainfo.Signers { - idAddress, _ := keyIDs[e] - // Check if actor already exists - _, err := state.GetActor(e) - if err == nil { - continue - } - st, err := cst.Put(ctx, &account.State{Address: e}) - if err != nil { - return err - } - err = state.SetActor(idAddress, &types.Actor{ - Code: builtin.AccountActorCodeID, - Balance: types.NewInt(0), - Head: st, - }) - if err != nil { - return xerrors.Errorf("setting account from actmap: %w", err) - } - signers = append(signers, idAddress) - } - - st, err := cst.Put(ctx, &multisig.State{ - Signers: signers, - NumApprovalsThreshold: uint64(ainfo.Threshold), - StartEpoch: abi.ChainEpoch(ainfo.VestingStart), - UnlockDuration: abi.ChainEpoch(ainfo.VestingDuration), - PendingTxns: pending, - InitialBalance: info.Balance, - }) - if err != nil { - return err - } - err = state.SetActor(ida, &types.Actor{ - Code: builtin.MultisigActorCodeID, - Balance: info.Balance, - Head: st, - }) - if err != nil { - return xerrors.Errorf("setting account from actmap: %w", err) - } - return nil +func createAccountActor(ctx context.Context, cst cbor.IpldStore, state *state.StateTree, info genesis.Actor, keyIDs map[address.Address]address.Address) error { + var ainfo genesis.AccountMeta + if err := json.Unmarshal(info.Meta, &ainfo); err != nil { + return xerrors.Errorf("unmarshaling account meta: %w", err) + } + fmt.Println("Creating account: ", ainfo.Owner, keyIDs[ainfo.Owner]) + st, err := cst.Put(ctx, &account.State{Address: ainfo.Owner}) + if err != nil { + return err } - return fmt.Errorf("failed to create account") + ida, ok := keyIDs[ainfo.Owner] + if !ok { + return fmt.Errorf("no registered ID for account actor: %s", ainfo.Owner) + } + + err = state.SetActor(ida, &types.Actor{ + Code: builtin.AccountActorCodeID, + Balance: info.Balance, + Head: st, + }) + if err != nil { + return xerrors.Errorf("setting account from actmap: %w", err) + } + return nil +} + +func createMultisigAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.IpldStore, state *state.StateTree, ida address.Address, info genesis.Actor, keyIDs map[address.Address]address.Address) error { + if info.Type != genesis.TMultisig { + return fmt.Errorf("can only call createMultisigAccount with multisig Actor info") + } + var ainfo genesis.MultisigMeta + if err := json.Unmarshal(info.Meta, &ainfo); err != nil { + return xerrors.Errorf("unmarshaling account meta: %w", err) + } + pending, err := adt.MakeEmptyMap(adt.WrapStore(ctx, cst)).Root() + if err != nil { + return xerrors.Errorf("failed to create empty map: %v", err) + } + + var signers []address.Address + + fmt.Println("setting up multisig signers") + for _, e := range ainfo.Signers { + fmt.Println("Signer: ", e) + idAddress, ok := keyIDs[e] + fmt.Println("keyIDs map: ", idAddress, ok) + + // Check if actor already exists + _, err := state.GetActor(e) + if err == nil { + fmt.Println("continue signer: ", idAddress) + signers = append(signers, idAddress) + continue + } + + fmt.Println("Creating account actor for: ", e, idAddress) + st, err := cst.Put(ctx, &account.State{Address: e}) + if err != nil { + return err + } + err = state.SetActor(idAddress, &types.Actor{ + Code: builtin.AccountActorCodeID, + Balance: types.NewInt(0), + Head: st, + }) + if err != nil { + return xerrors.Errorf("setting account from actmap: %w", err) + } + signers = append(signers, idAddress) + } + + st, err := cst.Put(ctx, &multisig.State{ + Signers: signers, + NumApprovalsThreshold: uint64(ainfo.Threshold), + StartEpoch: abi.ChainEpoch(ainfo.VestingStart), + UnlockDuration: abi.ChainEpoch(ainfo.VestingDuration), + PendingTxns: pending, + InitialBalance: info.Balance, + }) + if err != nil { + return err + } + err = state.SetActor(ida, &types.Actor{ + Code: builtin.MultisigActorCodeID, + Balance: info.Balance, + Head: st, + }) + if err != nil { + return xerrors.Errorf("setting account from actmap: %w", err) + } + return nil } func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot cid.Cid, template genesis.Template, keyIDs map[address.Address]address.Address) (cid.Cid, error) { @@ -399,11 +419,21 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err) } - for _, m := range template.Miners { + for mi, m := range template.Miners { + + /* + // Add the miner to the market actor's balance table + _, err = doExec(ctx, vm, builtin.StorageMarketActorAddr, m.Owner, builtin.MethodsMarket.AddBalance, mustEnc(&m.ID)) + if err != nil { + return cid.Undef, xerrors.Errorf("failed to add balance to miner: %w", err) + } + */ + + for si, s := range m.Sectors { + if s.Deal.Provider != m.ID { + return cid.Undef, xerrors.Errorf("Sector %d in miner %d in template had mismatch in provider and miner ID: %s != %s", si, mi, s.Deal.Provider, m.ID) + } - // Add the miner to the market actor's balance table - _, err = doExec(ctx, vm, builtin.StorageMarketActorAddr, m.Owner, builtin.MethodsMarket.AddBalance, mustEnc(adt.Empty)) - for _, s := range m.Sectors { amt := s.Deal.PieceSize verifNeeds[keyIDs[s.Deal.Client]] += amt sum += amt diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index cc649c84c..04c121d41 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -137,7 +137,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid params := mustEnc(&minerInfos[i].maddr) _, err := doExecValue(ctx, vm, builtin.StorageMarketActorAddr, m.Worker, m.MarketBalance, builtin.MethodsMarket.AddBalance, params) if err != nil { - return cid.Undef, xerrors.Errorf("failed to create genesis miner: %w", err) + return cid.Undef, xerrors.Errorf("failed to create genesis miner (add balance): %w", err) } } @@ -149,7 +149,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid ret, err := doExecValue(ctx, vm, builtin.StorageMarketActorAddr, m.Worker, big.Zero(), builtin.MethodsMarket.PublishStorageDeals, mustEnc(params)) if err != nil { - return xerrors.Errorf("failed to create genesis miner: %w", err) + return xerrors.Errorf("failed to create genesis miner (publish deals): %w", err) } var ids market.PublishStorageDealsReturn if err := ids.UnmarshalCBOR(bytes.NewReader(ret)); err != nil { diff --git a/chain/gen/genesis/t01_init.go b/chain/gen/genesis/t01_init.go index 095f275fd..68e3c366c 100644 --- a/chain/gen/genesis/t01_init.go +++ b/chain/gen/genesis/t01_init.go @@ -20,9 +20,9 @@ import ( bstore "github.com/filecoin-project/lotus/lib/blockstore" ) -func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesis.Actor, rootVerifier genesis.Actor) (*types.Actor, map[address.Address]address.Address, error) { +func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesis.Actor, rootVerifier genesis.Actor) (int64, *types.Actor, map[address.Address]address.Address, error) { if len(initialActors) > MaxAccounts { - return nil, nil, xerrors.New("too many initial actors") + return 0, nil, nil, xerrors.New("too many initial actors") } var ias init_.State @@ -39,7 +39,7 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi if a.Type == genesis.TMultisig { var ainfo genesis.MultisigMeta if err := json.Unmarshal(a.Meta, &ainfo); err != nil { - return nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err) + return 0, nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err) } for _, e := range ainfo.Signers { @@ -51,13 +51,13 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi value := cbg.CborInt(counter) if err := amap.Put(adt.AddrKey(e), &value); err != nil { - return nil, nil, err + return 0, nil, nil, err } counter = counter + 1 var err error keyToId[e], err = address.NewIDAddress(uint64(value)) if err != nil { - return nil, nil, err + return 0, nil, nil, err } } @@ -66,42 +66,42 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi } if a.Type != genesis.TAccount { - return nil, nil, xerrors.Errorf("unsupported account type: %s", a.Type) // TODO: Support msig (skip here) + return 0, nil, nil, xerrors.Errorf("unsupported account type: %s", a.Type) // TODO: Support msig (skip here) } var ainfo genesis.AccountMeta if err := json.Unmarshal(a.Meta, &ainfo); err != nil { - return nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err) + return 0, nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err) } fmt.Printf("init set %s t0%d\n", ainfo.Owner, counter) value := cbg.CborInt(counter) if err := amap.Put(adt.AddrKey(ainfo.Owner), &value); err != nil { - return nil, nil, err + return 0, nil, nil, err } counter = counter + 1 var err error keyToId[ainfo.Owner], err = address.NewIDAddress(uint64(value)) if err != nil { - return nil, nil, err + return 0, nil, nil, err } } if rootVerifier.Type == genesis.TAccount { var ainfo genesis.AccountMeta if err := json.Unmarshal(rootVerifier.Meta, &ainfo); err != nil { - return nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err) + return 0, nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err) } value := cbg.CborInt(80) if err := amap.Put(adt.AddrKey(ainfo.Owner), &value); err != nil { - return nil, nil, err + return 0, nil, nil, err } } else if rootVerifier.Type == genesis.TMultisig { var ainfo genesis.MultisigMeta if err := json.Unmarshal(rootVerifier.Meta, &ainfo); err != nil { - return nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err) + return 0, nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err) } for _, e := range ainfo.Signers { if _, ok := keyToId[e]; ok { @@ -111,13 +111,13 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi value := cbg.CborInt(counter) if err := amap.Put(adt.AddrKey(e), &value); err != nil { - return nil, nil, err + return 0, nil, nil, err } counter = counter + 1 var err error keyToId[e], err = address.NewIDAddress(uint64(value)) if err != nil { - return nil, nil, err + return 0, nil, nil, err } } @@ -125,13 +125,13 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi amapaddr, err := amap.Root() if err != nil { - return nil, nil, err + return 0, nil, nil, err } ias.AddressMap = amapaddr statecid, err := store.Put(store.Context(), &ias) if err != nil { - return nil, nil, err + return 0, nil, nil, err } act := &types.Actor{ @@ -139,5 +139,5 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi Head: statecid, } - return act, keyToId, nil + return counter, act, keyToId, nil } diff --git a/chain/gen/genesis/util.go b/chain/gen/genesis/util.go index 15ada30cb..e78f6a0d2 100644 --- a/chain/gen/genesis/util.go +++ b/chain/gen/genesis/util.go @@ -28,7 +28,7 @@ func doExec(ctx context.Context, vm *vm.VM, to, from address.Address, method abi func doExecValue(ctx context.Context, vm *vm.VM, to, from address.Address, value types.BigInt, method abi.MethodNum, params []byte) ([]byte, error) { act, err := vm.StateTree().GetActor(from) if err != nil { - return nil, xerrors.Errorf("doExec failed to get from actor: %w", err) + return nil, xerrors.Errorf("doExec failed to get from actor (%s): %w", from, err) } ret, err := vm.ApplyImplicitMessage(ctx, &types.Message{ diff --git a/cmd/lotus-seed/seed/seed.go b/cmd/lotus-seed/seed/seed.go index 5b4a1fbac..f892709f6 100644 --- a/cmd/lotus-seed/seed/seed.go +++ b/cmd/lotus-seed/seed/seed.go @@ -114,6 +114,7 @@ func PreSeal(maddr address.Address, spt abi.RegisteredSealProof, offset abi.Sect } miner := &genesis.Miner{ + ID: maddr, Owner: minerAddr.Address, Worker: minerAddr.Address, MarketBalance: big.Zero(), diff --git a/genesis/types.go b/genesis/types.go index 468a09067..13349def2 100644 --- a/genesis/types.go +++ b/genesis/types.go @@ -26,6 +26,7 @@ type PreSeal struct { } type Miner struct { + ID address.Address Owner address.Address Worker address.Address PeerId peer.ID //nolint:golint diff --git a/node/impl/full/multisig.go b/node/impl/full/multisig.go index 88ff4cdc9..9c5812b8e 100644 --- a/node/impl/full/multisig.go +++ b/node/impl/full/multisig.go @@ -2,6 +2,8 @@ package full import ( "context" + "encoding/json" + "fmt" "github.com/filecoin-project/specs-actors/actors/abi/big" @@ -122,6 +124,12 @@ func (a *MsigAPI) MsigPropose(ctx context.Context, msig address.Address, to addr Params: enc, } + b, err := json.Marshal(msg) + if err != nil { + panic(err) + } + fmt.Println("prpopose message: ", string(b)) + smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, msg, nil) if err != nil { return cid.Undef, xerrors.Errorf("failed to push message: %w", err) From 4f25c1c60e41804351aef354e67bd8b5c8135b8c Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Wed, 19 Aug 2020 13:10:07 -0700 Subject: [PATCH 51/53] minor improvements to multisig cli commands --- cli/multisig.go | 14 ++++++++++++-- cli/state.go | 22 +++++++++++++++++++++- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/cli/multisig.go b/cli/multisig.go index e2ff4e5a7..57f6c2c03 100644 --- a/cli/multisig.go +++ b/cli/multisig.go @@ -12,6 +12,7 @@ import ( "text/tabwriter" "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/go-address" @@ -231,10 +232,10 @@ var msigInspectCmd = &cli.Command{ }) w := tabwriter.NewWriter(os.Stdout, 8, 4, 0, ' ', 0) - fmt.Fprintf(w, "ID\tState\tTo\tValue\tMethod\tParams\n") + fmt.Fprintf(w, "ID\tState\tApprovals\tTo\tValue\tMethod\tParams\n") for _, txid := range txids { tx := pending[txid] - fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%d\t%x\n", txid, state(tx), tx.To, types.FIL(tx.Value), tx.Method, tx.Params) + fmt.Fprintf(w, "%d\t%s\t%d\t%s\t%s\t%d\t%x\n", txid, state(tx), len(tx.Approved), tx.To, types.FIL(tx.Value), tx.Method, tx.Params) } if err := w.Flush(); err != nil { return xerrors.Errorf("flushing output: %+v", err) @@ -355,6 +356,15 @@ var msigProposeCmd = &cli.Command{ from = defaddr } + act, err := api.StateGetActor(ctx, msig, types.EmptyTSK) + if err != nil { + return fmt.Errorf("failed to look up multisig %s: %w", msig, err) + } + + if act.Code != builtin.MultisigActorCodeID { + return fmt.Errorf("actor %s is not a multisig actor", msig) + } + msgCid, err := api.MsigPropose(ctx, msig, dest, types.BigInt(value), from, method, params) if err != nil { return err diff --git a/cli/state.go b/cli/state.go index 5e9952685..c8daade15 100644 --- a/cli/state.go +++ b/cli/state.go @@ -562,10 +562,30 @@ var stateGetActorCmd = &cli.Command{ return err } + var strtype string + switch a.Code { + case builtin.AccountActorCodeID: + strtype = "account" + case builtin.MultisigActorCodeID: + strtype = "multisig" + case builtin.CronActorCodeID: + strtype = "cron" + case builtin.InitActorCodeID: + strtype = "init" + case builtin.StorageMinerActorCodeID: + strtype = "miner" + case builtin.StorageMarketActorCodeID: + strtype = "market" + case builtin.StoragePowerActorCodeID: + strtype = "power" + default: + strtype = "unknown" + } + fmt.Printf("Address:\t%s\n", addr) fmt.Printf("Balance:\t%s\n", types.FIL(a.Balance)) fmt.Printf("Nonce:\t\t%d\n", a.Nonce) - fmt.Printf("Code:\t\t%s\n", a.Code) + fmt.Printf("Code:\t\t%s (%s)\n", a.Code, strtype) fmt.Printf("Head:\t\t%s\n", a.Head) return nil From 621d6759387ad7d4854e6f073192178c0c160f82 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Wed, 19 Aug 2020 13:32:53 -0700 Subject: [PATCH 52/53] fixup tests --- chain/gen/gen.go | 11 +++++------ chain/gen/genesis/genesis.go | 21 +++------------------ chain/gen/genesis/t01_init.go | 2 +- node/impl/full/multisig.go | 8 -------- 4 files changed, 9 insertions(+), 33 deletions(-) diff --git a/chain/gen/gen.go b/chain/gen/gen.go index f9bf90bfd..e34bb586b 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -92,10 +92,8 @@ func (m mybs) Get(c cid.Cid) (block.Block, error) { return b, nil } -var rootkey, _ = address.NewIDAddress(80) - var rootkeyMultisig = genesis.MultisigMeta{ - Signers: []address.Address{rootkey}, + Signers: []address.Address{remAccTestKey}, Threshold: 1, VestingDuration: 0, VestingStart: 0, @@ -108,12 +106,13 @@ var DefaultVerifregRootkeyActor = genesis.Actor{ } var remAccTestKey, _ = address.NewFromString("t1ceb34gnsc6qk5dt6n7xg6ycwzasjhbxm3iylkiy") -var remAccMeta = genesis.AccountMeta{ - Owner: remAccTestKey, +var remAccMeta = genesis.MultisigMeta{ + Signers: []address.Address{remAccTestKey}, + Threshold: 1, } var DefaultRemainderAccountActor = genesis.Actor{ - Type: genesis.TAccount, + Type: genesis.TMultisig, Balance: big.NewInt(0), Meta: remAccMeta.ActorMeta(), } diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index c915c77e0..a6a320b97 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -231,7 +231,6 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge if err != nil { return nil, nil, err } - _ = vregroot if err = createMultisigAccount(ctx, bs, cst, state, vregroot, template.VerifregRootKey, keyIDs); err != nil { return nil, nil, xerrors.Errorf("failed to set up verified registry signer: %w", err) @@ -275,8 +274,6 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge totalFilAllocated := big.Zero() - fmt.Println("finished basic setup, time for remainder") - // flush as ForEach works on the HAMT if _, err := state.Flush(ctx); err != nil { return nil, nil, err @@ -312,7 +309,6 @@ func createAccountActor(ctx context.Context, cst cbor.IpldStore, state *state.St if err := json.Unmarshal(info.Meta, &ainfo); err != nil { return xerrors.Errorf("unmarshaling account meta: %w", err) } - fmt.Println("Creating account: ", ainfo.Owner, keyIDs[ainfo.Owner]) st, err := cst.Put(ctx, &account.State{Address: ainfo.Owner}) if err != nil { return err @@ -349,21 +345,19 @@ func createMultisigAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.I var signers []address.Address - fmt.Println("setting up multisig signers") for _, e := range ainfo.Signers { - fmt.Println("Signer: ", e) idAddress, ok := keyIDs[e] - fmt.Println("keyIDs map: ", idAddress, ok) + if !ok { + return fmt.Errorf("no registered key ID for signer: %s", e) + } // Check if actor already exists _, err := state.GetActor(e) if err == nil { - fmt.Println("continue signer: ", idAddress) signers = append(signers, idAddress) continue } - fmt.Println("Creating account actor for: ", e, idAddress) st, err := cst.Put(ctx, &account.State{Address: e}) if err != nil { return err @@ -420,15 +414,6 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci } for mi, m := range template.Miners { - - /* - // Add the miner to the market actor's balance table - _, err = doExec(ctx, vm, builtin.StorageMarketActorAddr, m.Owner, builtin.MethodsMarket.AddBalance, mustEnc(&m.ID)) - if err != nil { - return cid.Undef, xerrors.Errorf("failed to add balance to miner: %w", err) - } - */ - for si, s := range m.Sectors { if s.Deal.Provider != m.ID { return cid.Undef, xerrors.Errorf("Sector %d in miner %d in template had mismatch in provider and miner ID: %s != %s", si, mi, s.Deal.Provider, m.ID) diff --git a/chain/gen/genesis/t01_init.go b/chain/gen/genesis/t01_init.go index 68e3c366c..1686102fe 100644 --- a/chain/gen/genesis/t01_init.go +++ b/chain/gen/genesis/t01_init.go @@ -66,7 +66,7 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi } if a.Type != genesis.TAccount { - return 0, nil, nil, xerrors.Errorf("unsupported account type: %s", a.Type) // TODO: Support msig (skip here) + return 0, nil, nil, xerrors.Errorf("unsupported account type: %s", a.Type) } var ainfo genesis.AccountMeta diff --git a/node/impl/full/multisig.go b/node/impl/full/multisig.go index 9c5812b8e..88ff4cdc9 100644 --- a/node/impl/full/multisig.go +++ b/node/impl/full/multisig.go @@ -2,8 +2,6 @@ package full import ( "context" - "encoding/json" - "fmt" "github.com/filecoin-project/specs-actors/actors/abi/big" @@ -124,12 +122,6 @@ func (a *MsigAPI) MsigPropose(ctx context.Context, msig address.Address, to addr Params: enc, } - b, err := json.Marshal(msg) - if err != nil { - panic(err) - } - fmt.Println("prpopose message: ", string(b)) - smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, msg, nil) if err != nil { return cid.Undef, xerrors.Errorf("failed to push message: %w", err) From f5dcd4a25fcbd2c8fba51e3422ff14804aa6a146 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Wed, 19 Aug 2020 13:42:34 -0700 Subject: [PATCH 53/53] set missing miner ID field --- storage/mockstorage/preseal.go | 1 + 1 file changed, 1 insertion(+) diff --git a/storage/mockstorage/preseal.go b/storage/mockstorage/preseal.go index 50810a4b2..fd4d0d69b 100644 --- a/storage/mockstorage/preseal.go +++ b/storage/mockstorage/preseal.go @@ -25,6 +25,7 @@ func PreSeal(ssize abi.SectorSize, maddr address.Address, sectors int) (*genesis } genm := &genesis.Miner{ + ID: maddr, Owner: k.Address, Worker: k.Address, MarketBalance: big.NewInt(0),