From 7246ef273feee95339a00e287e46243270710395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Wed, 2 Dec 2020 19:58:00 +0100 Subject: [PATCH] miner: Control address config for (pre)commits --- node/builder.go | 2 + node/config/def.go | 6 +++ node/modules/storageminer.go | 33 ++++++++++++++++- storage/addresses.go | 71 +++++++++++++++++++++++++++++++----- storage/miner.go | 1 + storage/wdpost_run.go | 2 +- storage/wdpost_sched.go | 4 +- 7 files changed, 106 insertions(+), 13 deletions(-) diff --git a/node/builder.go b/node/builder.go index 04400e1e1..5efd4aa3c 100644 --- a/node/builder.go +++ b/node/builder.go @@ -357,6 +357,7 @@ func Online() Option { Override(new(*sectorblocks.SectorBlocks), sectorblocks.NewSectorBlocks), Override(new(*storage.Miner), modules.StorageMiner(config.DefaultStorageMiner().Fees)), + Override(new(*storage.AddressSelector), modules.AddressSelector(nil)), Override(new(dtypes.NetworkName), modules.StorageNetworkName), Override(new(dtypes.StagingMultiDstore), modules.StagingMultiDatastore), @@ -511,6 +512,7 @@ func ConfigStorageMiner(c interface{}) Option { Override(new(storagemarket.StorageProviderNode), storageadapter.NewProviderNodeAdapter(&cfg.Fees)), Override(new(sectorstorage.SealerConfig), cfg.Storage), + Override(new(*storage.AddressSelector), modules.AddressSelector(&cfg.Addresses)), Override(new(*storage.Miner), modules.StorageMiner(cfg.Fees)), ) } diff --git a/node/config/def.go b/node/config/def.go index 7e45b88a3..ce4daec16 100644 --- a/node/config/def.go +++ b/node/config/def.go @@ -36,6 +36,7 @@ type StorageMiner struct { Sealing SealingConfig Storage sectorstorage.SealerConfig Fees MinerFeeConfig + Addresses MinerAddressConfig } type DealmakingConfig struct { @@ -71,6 +72,11 @@ type MinerFeeConfig struct { MaxMarketBalanceAddFee types.FIL } +type MinerAddressConfig struct { + PreCommitControl []string + CommitControl []string +} + // API contains configs for API endpoint type API struct { ListenAddress string diff --git a/node/modules/storageminer.go b/node/modules/storageminer.go index c5d8e7e54..e6901d2b5 100644 --- a/node/modules/storageminer.go +++ b/node/modules/storageminer.go @@ -145,6 +145,35 @@ func SectorIDCounter(ds dtypes.MetadataDS) sealing.SectorIDCounter { return &sidsc{sc} } +func AddressSelector(addrConf *config.MinerAddressConfig) func() (*storage.AddressSelector, error) { + return func() (*storage.AddressSelector, error) { + as := &storage.AddressSelector{} + if addrConf == nil { + return as, nil + } + + for _, s := range addrConf.PreCommitControl { + addr, err := address.NewFromString(s) + if err != nil { + return nil, xerrors.Errorf("parsing precommit control address: %w", err) + } + + as.PreCommitControl = append(as.PreCommitControl, addr) + } + + for _, s := range addrConf.CommitControl { + addr, err := address.NewFromString(s) + if err != nil { + return nil, xerrors.Errorf("parsing commit control address: %w", err) + } + + as.CommitControl = append(as.CommitControl, addr) + } + + return as, nil + } +} + type StorageMinerParams struct { fx.In @@ -158,6 +187,7 @@ type StorageMinerParams struct { Verifier ffiwrapper.Verifier GetSealingConfigFn dtypes.GetSealingConfigFunc Journal journal.Journal + AddrSel *storage.AddressSelector } func StorageMiner(fc config.MinerFeeConfig) func(params StorageMinerParams) (*storage.Miner, error) { @@ -173,6 +203,7 @@ func StorageMiner(fc config.MinerFeeConfig) func(params StorageMinerParams) (*st verif = params.Verifier gsd = params.GetSealingConfigFn j = params.Journal + as = params.AddrSel ) maddr, err := minerAddrFromDS(ds) @@ -182,7 +213,7 @@ func StorageMiner(fc config.MinerFeeConfig) func(params StorageMinerParams) (*st ctx := helpers.LifecycleCtx(mctx, lc) - fps, err := storage.NewWindowedPoStScheduler(api, fc, sealer, sealer, j, maddr) + fps, err := storage.NewWindowedPoStScheduler(api, fc, as, sealer, sealer, j, maddr) if err != nil { return nil, err } diff --git a/storage/addresses.go b/storage/addresses.go index f34625a56..ee7e896ec 100644 --- a/storage/addresses.go +++ b/storage/addresses.go @@ -5,8 +5,6 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" ) @@ -24,19 +22,72 @@ type addrSelectApi interface { WalletHas(context.Context, address.Address) (bool, error) StateAccountKey(context.Context, address.Address, types.TipSetKey) (address.Address, error) + StateLookupID(context.Context, address.Address, types.TipSetKey) (address.Address, error) } -func AddressFor(ctx context.Context, a addrSelectApi, mi miner.MinerInfo, use AddrUse, goodFunds, minFunds abi.TokenAmount) (address.Address, abi.TokenAmount, error) { - switch use { - case PreCommitAddr, CommitAddr: - // always use worker, at least for now - return mi.Worker, big.Zero(), nil - } +type AddressSelector struct { + PreCommitControl []address.Address + CommitControl []address.Address +} +func (as *AddressSelector) AddressFor(ctx context.Context, a addrSelectApi, mi miner.MinerInfo, use AddrUse, goodFunds, minFunds abi.TokenAmount) (address.Address, abi.TokenAmount, error) { + var addrs []address.Address + switch use { + case PreCommitAddr: + addrs = append(addrs, as.PreCommitControl...) + case CommitAddr: + addrs = append(addrs, as.CommitControl...) + default: + defaultCtl := map[address.Address]struct{}{} + for _, a := range mi.ControlAddresses { + defaultCtl[a] = struct{}{} + } + delete(defaultCtl, mi.Owner) + delete(defaultCtl, mi.Worker) + + for _, addr := range append(append([]address.Address{}, as.PreCommitControl...), as.CommitControl...) { + if addr.Protocol() != address.ID { + var err error + addr, err = a.StateLookupID(ctx, addr, types.EmptyTSK) + if err != nil { + log.Warnw("looking up control address", "address", addr, "error", err) + continue + } + } + + delete(defaultCtl, addr) + } + + for a := range defaultCtl { + addrs = append(addrs, a) + } + } + addrs = append(addrs, mi.Owner, mi.Worker) + + return pickAddress(ctx, a, mi, goodFunds, minFunds, addrs) +} + +func pickAddress(ctx context.Context, a addrSelectApi, mi miner.MinerInfo, goodFunds, minFunds abi.TokenAmount, addrs []address.Address) (address.Address, abi.TokenAmount, error) { leastBad := mi.Worker bestAvail := minFunds - for _, addr := range append(mi.ControlAddresses, mi.Owner, mi.Worker) { + ctl := map[address.Address]struct{}{} + for _, a := range append(mi.ControlAddresses, mi.Owner, mi.Worker) { + ctl[a] = struct{}{} + } + + for _, addr := range addrs { + addr, err := a.StateLookupID(ctx, addr, types.EmptyTSK) + if err != nil { + log.Warnw("looking up control address", "address", addr, "error", err) + continue + } + + if _, ok := ctl[addr]; !ok { + log.Warnw("non-control address configured for sending messages", "address", addr) + continue + } + if maybeUseAddress(ctx, a, addr, goodFunds, &leastBad, &bestAvail) { return leastBad, bestAvail, nil } @@ -68,7 +119,7 @@ func maybeUseAddress(ctx context.Context, a addrSelectApi, addr address.Address, } if !have { - log.Errorw("don't have key", "key", k) + log.Errorw("don't have key", "key", k, "address", addr) return false } diff --git a/storage/miner.go b/storage/miner.go index dcec234fd..f8bab2797 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -91,6 +91,7 @@ type storageMinerApi interface { StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error) StateAccountKey(context.Context, address.Address, types.TipSetKey) (address.Address, error) StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error) + StateLookupID(context.Context, address.Address, types.TipSetKey) (address.Address, error) MpoolPushMessage(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error) diff --git a/storage/wdpost_run.go b/storage/wdpost_run.go index 4d3d4b726..3ef21214d 100644 --- a/storage/wdpost_run.go +++ b/storage/wdpost_run.go @@ -799,7 +799,7 @@ func (s *WindowPoStScheduler) setSender(ctx context.Context, msg *types.Message, goodFunds := big.Add(msg.RequiredFunds(), msg.Value) minFunds := big.Min(big.Add(minGasFeeMsg.RequiredFunds(), minGasFeeMsg.Value), goodFunds) - pa, avail, err := AddressFor(ctx, s.api, mi, PoStAddr, goodFunds, minFunds) + pa, avail, err := s.addrSel.AddressFor(ctx, s.api, mi, PoStAddr, goodFunds, minFunds) if err != nil { log.Errorw("error selecting address for window post", "error", err) return nil diff --git a/storage/wdpost_sched.go b/storage/wdpost_sched.go index 1a1422e19..f81a60a1e 100644 --- a/storage/wdpost_sched.go +++ b/storage/wdpost_sched.go @@ -25,6 +25,7 @@ import ( type WindowPoStScheduler struct { api storageMinerApi feeCfg config.MinerFeeConfig + addrSel *AddressSelector prover storage.Prover faultTracker sectorstorage.FaultTracker proofType abi.RegisteredPoStProof @@ -40,7 +41,7 @@ type WindowPoStScheduler struct { // failLk sync.Mutex } -func NewWindowedPoStScheduler(api storageMinerApi, fc config.MinerFeeConfig, sb storage.Prover, ft sectorstorage.FaultTracker, j journal.Journal, actor address.Address) (*WindowPoStScheduler, error) { +func NewWindowedPoStScheduler(api storageMinerApi, fc config.MinerFeeConfig, as *AddressSelector, sb storage.Prover, ft sectorstorage.FaultTracker, j journal.Journal, actor address.Address) (*WindowPoStScheduler, error) { mi, err := api.StateMinerInfo(context.TODO(), actor, types.EmptyTSK) if err != nil { return nil, xerrors.Errorf("getting sector size: %w", err) @@ -54,6 +55,7 @@ func NewWindowedPoStScheduler(api storageMinerApi, fc config.MinerFeeConfig, sb return &WindowPoStScheduler{ api: api, feeCfg: fc, + addrSel: as, prover: sb, faultTracker: ft, proofType: rt,