From 1449644c343340a60d80688931cd709d85220686 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Thu, 4 Nov 2021 15:59:29 +0000 Subject: [PATCH 01/24] Integrate v7 actors --- build/openrpc/full.json.gz | Bin 25453 -> 25453 bytes build/params_2k.go | 2 + build/params_butterfly.go | 1 + build/params_calibnet.go | 2 + build/params_interop.go | 1 + build/params_mainnet.go | 10 +- build/params_shared_vals.go | 2 +- build/params_testground.go | 1 + chain/actors/builtin/account/account.go | 15 + chain/actors/builtin/account/v7.go | 40 ++ chain/actors/builtin/builtin.go | 60 +- chain/actors/builtin/cron/cron.go | 12 +- chain/actors/builtin/cron/v7.go | 35 ++ chain/actors/builtin/init/init.go | 19 +- chain/actors/builtin/init/v7.go | 114 ++++ chain/actors/builtin/market/market.go | 22 +- chain/actors/builtin/market/v7.go | 252 ++++++++ chain/actors/builtin/miner/miner.go | 17 +- chain/actors/builtin/miner/v7.go | 570 ++++++++++++++++++ chain/actors/builtin/multisig/message7.go | 71 +++ chain/actors/builtin/multisig/multisig.go | 32 +- chain/actors/builtin/multisig/v7.go | 119 ++++ chain/actors/builtin/paych/message7.go | 74 +++ chain/actors/builtin/paych/paych.go | 20 +- chain/actors/builtin/paych/v7.go | 114 ++++ chain/actors/builtin/power/power.go | 19 +- chain/actors/builtin/power/v7.go | 187 ++++++ chain/actors/builtin/reward/reward.go | 19 +- chain/actors/builtin/reward/v7.go | 98 +++ chain/actors/builtin/system/system.go | 10 +- chain/actors/builtin/system/v7.go | 35 ++ chain/actors/builtin/verifreg/v7.go | 75 +++ chain/actors/builtin/verifreg/verifreg.go | 19 +- chain/actors/policy/policy.go | 84 ++- chain/actors/version.go | 7 +- chain/consensus/filcns/compute_state.go | 2 + chain/consensus/filcns/upgrades.go | 108 +++- chain/gen/gen.go | 6 + chain/gen/genesis/miners.go | 7 +- chain/state/statetree.go | 2 +- chain/vm/gas.go | 31 +- chain/vm/gas_v0.go | 15 +- chain/vm/invoker.go | 2 +- chain/vm/mkactor.go | 3 + chain/vm/runtime.go | 8 +- chain/vm/syscalls.go | 40 +- cmd/lotus-bench/caching_verifier.go | 9 +- cmd/lotus-sim/simulation/mock/mock.go | 8 + documentation/en/api-v0-methods.md | 2 +- documentation/en/api-v1-unstable-methods.md | 2 +- extern/sector-storage/ffiwrapper/types.go | 3 + .../sector-storage/ffiwrapper/verifier_cgo.go | 7 + extern/sector-storage/mock/mock.go | 7 + gen/inlinegen-data.json | 8 +- go.mod | 1 + go.sum | 5 + itests/kit/ensemble_opts_nv.go | 6 +- lotuspond/front/src/chain/methods.json | 107 ++++ storage/wdpost_run_test.go | 18 +- testplans/lotus-soup/go.mod | 20 +- testplans/lotus-soup/go.sum | 131 ++++ 61 files changed, 2595 insertions(+), 121 deletions(-) create mode 100644 chain/actors/builtin/account/v7.go create mode 100644 chain/actors/builtin/cron/v7.go create mode 100644 chain/actors/builtin/init/v7.go create mode 100644 chain/actors/builtin/market/v7.go create mode 100644 chain/actors/builtin/miner/v7.go create mode 100644 chain/actors/builtin/multisig/message7.go create mode 100644 chain/actors/builtin/multisig/v7.go create mode 100644 chain/actors/builtin/paych/message7.go create mode 100644 chain/actors/builtin/paych/v7.go create mode 100644 chain/actors/builtin/power/v7.go create mode 100644 chain/actors/builtin/reward/v7.go create mode 100644 chain/actors/builtin/system/v7.go create mode 100644 chain/actors/builtin/verifreg/v7.go diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index 1578d746536613ea03a22c6165e5561d65e3df7a..8f71ee8a973b9f29d91d16893c3cbe8bf3db8356 100644 GIT binary patch delta 5087 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 B;#2?t delta 5127 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 diff --git a/build/params_2k.go b/build/params_2k.go index b9db0a46703..84023c38c6d 100644 --- a/build/params_2k.go +++ b/build/params_2k.go @@ -47,6 +47,8 @@ var UpgradeHyperdriveHeight = abi.ChainEpoch(-16) var UpgradeChocolateHeight = abi.ChainEpoch(-17) +var UpgradeSnapDealsHeight = abi.ChainEpoch(-18) + var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, } diff --git a/build/params_butterfly.go b/build/params_butterfly.go index 9a0018e73a2..e26fd78fa8f 100644 --- a/build/params_butterfly.go +++ b/build/params_butterfly.go @@ -41,6 +41,7 @@ const UpgradeNorwegianHeight = -14 const UpgradeTurboHeight = -15 const UpgradeHyperdriveHeight = -16 const UpgradeChocolateHeight = 6360 +const UpgradeSnapDealsHeight = 99999999 func init() { policy.SetConsensusMinerMinPower(abi.NewStoragePower(2 << 30)) diff --git a/build/params_calibnet.go b/build/params_calibnet.go index 8cd99d642cc..16d77c7e6fa 100644 --- a/build/params_calibnet.go +++ b/build/params_calibnet.go @@ -54,6 +54,8 @@ const UpgradeHyperdriveHeight = 420 const UpgradeChocolateHeight = 312746 +const UpgradeSnapDealsHeight = 99999999 + func init() { policy.SetConsensusMinerMinPower(abi.NewStoragePower(32 << 30)) policy.SetSupportedProofTypes( diff --git a/build/params_interop.go b/build/params_interop.go index de5ee9a12c8..66033937cc3 100644 --- a/build/params_interop.go +++ b/build/params_interop.go @@ -47,6 +47,7 @@ var UpgradeTurboHeight = abi.ChainEpoch(-15) var UpgradeHyperdriveHeight = abi.ChainEpoch(-16) var UpgradeChocolateHeight = abi.ChainEpoch(-17) +var UpgradeSnapDealsHeight = abi.ChainEpoch(-18) var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, diff --git a/build/params_mainnet.go b/build/params_mainnet.go index 0c8c53ba8cf..a4781f1ff1d 100644 --- a/build/params_mainnet.go +++ b/build/params_mainnet.go @@ -62,18 +62,20 @@ const UpgradeNorwegianHeight = 665280 const UpgradeTurboHeight = 712320 // 2021-06-30T22:00:00Z -var UpgradeHyperdriveHeight = abi.ChainEpoch(892800) +const UpgradeHyperdriveHeight = 892800 // 2021-10-26T13:30:00Z -var UpgradeChocolateHeight = abi.ChainEpoch(1231620) +const UpgradeChocolateHeight = 1231620 + +var UpgradeSnapDealsHeight = abi.ChainEpoch(999999999999) func init() { if os.Getenv("LOTUS_USE_TEST_ADDRESSES") != "1" { SetAddressNetwork(address.Mainnet) } - if os.Getenv("LOTUS_DISABLE_CHOCOLATE") == "1" { - UpgradeChocolateHeight = math.MaxInt64 + if os.Getenv("LOTUS_DISABLE_SNAPDEALS") == "1" { + UpgradeSnapDealsHeight = math.MaxInt64 } Devnet = false diff --git a/build/params_shared_vals.go b/build/params_shared_vals.go index 0a242f6f211..704c84639e2 100644 --- a/build/params_shared_vals.go +++ b/build/params_shared_vals.go @@ -34,7 +34,7 @@ const NewestNetworkVersion = network.Version{{.latestNetworkVersion}} /* inline-gen start */ -const NewestNetworkVersion = network.Version14 +const NewestNetworkVersion = network.Version15 /* inline-gen end */ diff --git a/build/params_testground.go b/build/params_testground.go index 48b76f82ca6..539e06b4541 100644 --- a/build/params_testground.go +++ b/build/params_testground.go @@ -99,6 +99,7 @@ var ( UpgradeTurboHeight abi.ChainEpoch = -14 UpgradeHyperdriveHeight abi.ChainEpoch = -15 UpgradeChocolateHeight abi.ChainEpoch = -16 + UpgradeSnapDealsHeight abi.ChainEpoch = -17 DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, diff --git a/chain/actors/builtin/account/account.go b/chain/actors/builtin/account/account.go index 249ce133fd2..57ea510bb3d 100644 --- a/chain/actors/builtin/account/account.go +++ b/chain/actors/builtin/account/account.go @@ -23,6 +23,8 @@ import ( builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" ) func init() { @@ -50,6 +52,10 @@ func init() { builtin.RegisterActorState(builtin6.AccountActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load6(store, root) }) + + builtin.RegisterActorState(builtin7.AccountActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load7(store, root) + }) } var Methods = builtin4.MethodsAccount @@ -75,6 +81,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin6.AccountActorCodeID: return load6(store, act.Head) + case builtin7.AccountActorCodeID: + return load7(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -100,6 +109,9 @@ func MakeState(store adt.Store, av actors.Version, addr address.Address) (State, case actors.Version6: return make6(store, addr) + case actors.Version7: + return make7(store, addr) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -125,6 +137,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version6: return builtin6.AccountActorCodeID, nil + case actors.Version7: + return builtin7.AccountActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) diff --git a/chain/actors/builtin/account/v7.go b/chain/actors/builtin/account/v7.go new file mode 100644 index 00000000000..883776cf8f0 --- /dev/null +++ b/chain/actors/builtin/account/v7.go @@ -0,0 +1,40 @@ +package account + +import ( + "github.com/filecoin-project/go-address" + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/actors/adt" + + account7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/account" +) + +var _ State = (*state7)(nil) + +func load7(store adt.Store, root cid.Cid) (State, error) { + out := state7{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make7(store adt.Store, addr address.Address) (State, error) { + out := state7{store: store} + out.State = account7.State{Address: addr} + return &out, nil +} + +type state7 struct { + account7.State + store adt.Store +} + +func (s *state7) PubkeyAddress() (address.Address, error) { + return s.Address, nil +} + +func (s *state7) GetState() interface{} { + return &s.State +} diff --git a/chain/actors/builtin/builtin.go b/chain/actors/builtin/builtin.go index ebfe2df2e12..d9373299939 100644 --- a/chain/actors/builtin/builtin.go +++ b/chain/actors/builtin/builtin.go @@ -23,46 +23,49 @@ import ( builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" smoothing6 "github.com/filecoin-project/specs-actors/v6/actors/util/smoothing" + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" + smoothing7 "github.com/filecoin-project/specs-actors/v7/actors/util/smoothing" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/types" - miner6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/miner" - proof6 "github.com/filecoin-project/specs-actors/v6/actors/runtime/proof" + miner7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/miner" + proof7 "github.com/filecoin-project/specs-actors/v7/actors/runtime/proof" ) -var SystemActorAddr = builtin6.SystemActorAddr -var BurntFundsActorAddr = builtin6.BurntFundsActorAddr -var CronActorAddr = builtin6.CronActorAddr +var SystemActorAddr = builtin7.SystemActorAddr +var BurntFundsActorAddr = builtin7.BurntFundsActorAddr +var CronActorAddr = builtin7.CronActorAddr var SaftAddress = makeAddress("t0122") var ReserveAddress = makeAddress("t090") var RootVerifierAddress = makeAddress("t080") var ( - ExpectedLeadersPerEpoch = builtin6.ExpectedLeadersPerEpoch + ExpectedLeadersPerEpoch = builtin7.ExpectedLeadersPerEpoch ) const ( - EpochDurationSeconds = builtin6.EpochDurationSeconds - EpochsInDay = builtin6.EpochsInDay - SecondsInDay = builtin6.SecondsInDay + EpochDurationSeconds = builtin7.EpochDurationSeconds + EpochsInDay = builtin7.EpochsInDay + SecondsInDay = builtin7.SecondsInDay ) const ( - MethodSend = builtin6.MethodSend - MethodConstructor = builtin6.MethodConstructor + MethodSend = builtin7.MethodSend + MethodConstructor = builtin7.MethodConstructor ) // These are all just type aliases across actor versions. In the future, that might change // and we might need to do something fancier. -type SectorInfo = proof6.SectorInfo -type PoStProof = proof6.PoStProof +type SectorInfo = proof7.SectorInfo +type PoStProof = proof7.PoStProof type FilterEstimate = smoothing0.FilterEstimate func QAPowerForWeight(size abi.SectorSize, duration abi.ChainEpoch, dealWeight, verifiedWeight abi.DealWeight) abi.StoragePower { - return miner6.QAPowerForWeight(size, duration, dealWeight, verifiedWeight) + return miner7.QAPowerForWeight(size, duration, dealWeight, verifiedWeight) } func FromV0FilterEstimate(v0 smoothing0.FilterEstimate) FilterEstimate { @@ -101,6 +104,12 @@ func FromV6FilterEstimate(v6 smoothing6.FilterEstimate) FilterEstimate { } +func FromV7FilterEstimate(v7 smoothing7.FilterEstimate) FilterEstimate { + + return (FilterEstimate)(v7) + +} + type ActorStateLoader func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) var ActorStateLoaders = make(map[cid.Cid]ActorStateLoader) @@ -138,6 +147,9 @@ func ActorNameByCode(c cid.Cid) string { case builtin6.IsBuiltinActor(c): return builtin6.ActorNameByCode(c) + case builtin7.IsBuiltinActor(c): + return builtin7.ActorNameByCode(c) + default: return "" } @@ -169,6 +181,10 @@ func IsBuiltinActor(c cid.Cid) bool { return true } + if builtin7.IsBuiltinActor(c) { + return true + } + return false } @@ -198,6 +214,10 @@ func IsAccountActor(c cid.Cid) bool { return true } + if c == builtin7.AccountActorCodeID { + return true + } + return false } @@ -227,6 +247,10 @@ func IsStorageMinerActor(c cid.Cid) bool { return true } + if c == builtin7.StorageMinerActorCodeID { + return true + } + return false } @@ -256,6 +280,10 @@ func IsMultisigActor(c cid.Cid) bool { return true } + if c == builtin7.MultisigActorCodeID { + return true + } + return false } @@ -285,6 +313,10 @@ func IsPaymentChannelActor(c cid.Cid) bool { return true } + if c == builtin7.PaymentChannelActorCodeID { + return true + } + return false } diff --git a/chain/actors/builtin/cron/cron.go b/chain/actors/builtin/cron/cron.go index 9178a44abc4..f27a14ac791 100644 --- a/chain/actors/builtin/cron/cron.go +++ b/chain/actors/builtin/cron/cron.go @@ -17,6 +17,8 @@ import ( builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" ) func MakeState(store adt.Store, av actors.Version) (State, error) { @@ -40,6 +42,9 @@ func MakeState(store adt.Store, av actors.Version) (State, error) { case actors.Version6: return make6(store) + case actors.Version7: + return make7(store) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -65,14 +70,17 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version6: return builtin6.CronActorCodeID, nil + case actors.Version7: + return builtin7.CronActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) } var ( - Address = builtin6.CronActorAddr - Methods = builtin6.MethodsCron + Address = builtin7.CronActorAddr + Methods = builtin7.MethodsCron ) type State interface { diff --git a/chain/actors/builtin/cron/v7.go b/chain/actors/builtin/cron/v7.go new file mode 100644 index 00000000000..e5538c89ff6 --- /dev/null +++ b/chain/actors/builtin/cron/v7.go @@ -0,0 +1,35 @@ +package cron + +import ( + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/actors/adt" + + cron7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/cron" +) + +var _ State = (*state7)(nil) + +func load7(store adt.Store, root cid.Cid) (State, error) { + out := state7{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make7(store adt.Store) (State, error) { + out := state7{store: store} + out.State = *cron7.ConstructState(cron7.BuiltInEntries()) + return &out, nil +} + +type state7 struct { + cron7.State + store adt.Store +} + +func (s *state7) GetState() interface{} { + return &s.State +} diff --git a/chain/actors/builtin/init/init.go b/chain/actors/builtin/init/init.go index ee06eeab792..737241ffea0 100644 --- a/chain/actors/builtin/init/init.go +++ b/chain/actors/builtin/init/init.go @@ -25,6 +25,8 @@ import ( builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" ) func init() { @@ -52,11 +54,15 @@ func init() { builtin.RegisterActorState(builtin6.InitActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load6(store, root) }) + + builtin.RegisterActorState(builtin7.InitActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load7(store, root) + }) } var ( - Address = builtin6.InitActorAddr - Methods = builtin6.MethodsInit + Address = builtin7.InitActorAddr + Methods = builtin7.MethodsInit ) func Load(store adt.Store, act *types.Actor) (State, error) { @@ -80,6 +86,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin6.InitActorCodeID: return load6(store, act.Head) + case builtin7.InitActorCodeID: + return load7(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -105,6 +114,9 @@ func MakeState(store adt.Store, av actors.Version, networkName string) (State, e case actors.Version6: return make6(store, networkName) + case actors.Version7: + return make7(store, networkName) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -130,6 +142,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version6: return builtin6.InitActorCodeID, nil + case actors.Version7: + return builtin7.InitActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) diff --git a/chain/actors/builtin/init/v7.go b/chain/actors/builtin/init/v7.go new file mode 100644 index 00000000000..341aa52cdb0 --- /dev/null +++ b/chain/actors/builtin/init/v7.go @@ -0,0 +1,114 @@ +package init + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/node/modules/dtypes" + + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" + + init7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/init" + adt7 "github.com/filecoin-project/specs-actors/v7/actors/util/adt" +) + +var _ State = (*state7)(nil) + +func load7(store adt.Store, root cid.Cid) (State, error) { + out := state7{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make7(store adt.Store, networkName string) (State, error) { + out := state7{store: store} + + s, err := init7.ConstructState(store, networkName) + if err != nil { + return nil, err + } + + out.State = *s + + return &out, nil +} + +type state7 struct { + init7.State + store adt.Store +} + +func (s *state7) ResolveAddress(address address.Address) (address.Address, bool, error) { + return s.State.ResolveAddress(s.store, address) +} + +func (s *state7) MapAddressToNewID(address address.Address) (address.Address, error) { + return s.State.MapAddressToNewID(s.store, address) +} + +func (s *state7) ForEachActor(cb func(id abi.ActorID, address address.Address) error) error { + addrs, err := adt7.AsMap(s.store, s.State.AddressMap, builtin7.DefaultHamtBitwidth) + if err != nil { + return err + } + var actorID cbg.CborInt + return addrs.ForEach(&actorID, func(key string) error { + addr, err := address.NewFromBytes([]byte(key)) + if err != nil { + return err + } + return cb(abi.ActorID(actorID), addr) + }) +} + +func (s *state7) NetworkName() (dtypes.NetworkName, error) { + return dtypes.NetworkName(s.State.NetworkName), nil +} + +func (s *state7) SetNetworkName(name string) error { + s.State.NetworkName = name + return nil +} + +func (s *state7) SetNextID(id abi.ActorID) error { + s.State.NextID = id + return nil +} + +func (s *state7) Remove(addrs ...address.Address) (err error) { + m, err := adt7.AsMap(s.store, s.State.AddressMap, builtin7.DefaultHamtBitwidth) + if err != nil { + return err + } + for _, addr := range addrs { + if err = m.Delete(abi.AddrKey(addr)); err != nil { + return xerrors.Errorf("failed to delete entry for address: %s; err: %w", addr, err) + } + } + amr, err := m.Root() + if err != nil { + return xerrors.Errorf("failed to get address map root: %w", err) + } + s.State.AddressMap = amr + return nil +} + +func (s *state7) SetAddressMap(mcid cid.Cid) error { + s.State.AddressMap = mcid + return nil +} + +func (s *state7) AddressMap() (adt.Map, error) { + return adt7.AsMap(s.store, s.State.AddressMap, builtin7.DefaultHamtBitwidth) +} + +func (s *state7) GetState() interface{} { + return &s.State +} diff --git a/chain/actors/builtin/market/market.go b/chain/actors/builtin/market/market.go index 7e35f39191a..6781b55e360 100644 --- a/chain/actors/builtin/market/market.go +++ b/chain/actors/builtin/market/market.go @@ -25,6 +25,8 @@ import ( builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" @@ -56,11 +58,15 @@ func init() { builtin.RegisterActorState(builtin6.StorageMarketActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load6(store, root) }) + + builtin.RegisterActorState(builtin7.StorageMarketActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load7(store, root) + }) } var ( - Address = builtin6.StorageMarketActorAddr - Methods = builtin6.MethodsMarket + Address = builtin7.StorageMarketActorAddr + Methods = builtin7.MethodsMarket ) func Load(store adt.Store, act *types.Actor) (State, error) { @@ -84,6 +90,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin6.StorageMarketActorCodeID: return load6(store, act.Head) + case builtin7.StorageMarketActorCodeID: + return load7(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -109,6 +118,9 @@ func MakeState(store adt.Store, av actors.Version) (State, error) { case actors.Version6: return make6(store) + case actors.Version7: + return make7(store) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -134,6 +146,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version6: return builtin6.StorageMarketActorCodeID, nil + case actors.Version7: + return builtin7.StorageMarketActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) @@ -211,6 +226,9 @@ func DecodePublishStorageDealsReturn(b []byte, nv network.Version) (PublishStora case actors.Version6: return decodePublishStorageDealsReturn6(b) + case actors.Version7: + return decodePublishStorageDealsReturn7(b) + } return nil, xerrors.Errorf("unknown actor version %d", av) } diff --git a/chain/actors/builtin/market/v7.go b/chain/actors/builtin/market/v7.go new file mode 100644 index 00000000000..55391314622 --- /dev/null +++ b/chain/actors/builtin/market/v7.go @@ -0,0 +1,252 @@ +package market + +import ( + "bytes" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/types" + + market7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/market" + adt7 "github.com/filecoin-project/specs-actors/v7/actors/util/adt" +) + +var _ State = (*state7)(nil) + +func load7(store adt.Store, root cid.Cid) (State, error) { + out := state7{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make7(store adt.Store) (State, error) { + out := state7{store: store} + + s, err := market7.ConstructState(store) + if err != nil { + return nil, err + } + + out.State = *s + + return &out, nil +} + +type state7 struct { + market7.State + store adt.Store +} + +func (s *state7) TotalLocked() (abi.TokenAmount, error) { + fml := types.BigAdd(s.TotalClientLockedCollateral, s.TotalProviderLockedCollateral) + fml = types.BigAdd(fml, s.TotalClientStorageFee) + return fml, nil +} + +func (s *state7) BalancesChanged(otherState State) (bool, error) { + otherState7, ok := otherState.(*state7) + if !ok { + // there's no way to compare different versions of the state, so let's + // just say that means the state of balances has changed + return true, nil + } + return !s.State.EscrowTable.Equals(otherState7.State.EscrowTable) || !s.State.LockedTable.Equals(otherState7.State.LockedTable), nil +} + +func (s *state7) StatesChanged(otherState State) (bool, error) { + otherState7, ok := otherState.(*state7) + if !ok { + // there's no way to compare different versions of the state, so let's + // just say that means the state of balances has changed + return true, nil + } + return !s.State.States.Equals(otherState7.State.States), nil +} + +func (s *state7) States() (DealStates, error) { + stateArray, err := adt7.AsArray(s.store, s.State.States, market7.StatesAmtBitwidth) + if err != nil { + return nil, err + } + return &dealStates7{stateArray}, nil +} + +func (s *state7) ProposalsChanged(otherState State) (bool, error) { + otherState7, ok := otherState.(*state7) + if !ok { + // there's no way to compare different versions of the state, so let's + // just say that means the state of balances has changed + return true, nil + } + return !s.State.Proposals.Equals(otherState7.State.Proposals), nil +} + +func (s *state7) Proposals() (DealProposals, error) { + proposalArray, err := adt7.AsArray(s.store, s.State.Proposals, market7.ProposalsAmtBitwidth) + if err != nil { + return nil, err + } + return &dealProposals7{proposalArray}, nil +} + +func (s *state7) EscrowTable() (BalanceTable, error) { + bt, err := adt7.AsBalanceTable(s.store, s.State.EscrowTable) + if err != nil { + return nil, err + } + return &balanceTable7{bt}, nil +} + +func (s *state7) LockedTable() (BalanceTable, error) { + bt, err := adt7.AsBalanceTable(s.store, s.State.LockedTable) + if err != nil { + return nil, err + } + return &balanceTable7{bt}, nil +} + +func (s *state7) VerifyDealsForActivation( + minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch, +) (weight, verifiedWeight abi.DealWeight, err error) { + w, vw, _, err := market7.ValidateDealsForActivation(&s.State, s.store, deals, minerAddr, sectorExpiry, currEpoch) + return w, vw, err +} + +func (s *state7) NextID() (abi.DealID, error) { + return s.State.NextID, nil +} + +type balanceTable7 struct { + *adt7.BalanceTable +} + +func (bt *balanceTable7) ForEach(cb func(address.Address, abi.TokenAmount) error) error { + asMap := (*adt7.Map)(bt.BalanceTable) + var ta abi.TokenAmount + return asMap.ForEach(&ta, func(key string) error { + a, err := address.NewFromBytes([]byte(key)) + if err != nil { + return err + } + return cb(a, ta) + }) +} + +type dealStates7 struct { + adt.Array +} + +func (s *dealStates7) Get(dealID abi.DealID) (*DealState, bool, error) { + var deal7 market7.DealState + found, err := s.Array.Get(uint64(dealID), &deal7) + if err != nil { + return nil, false, err + } + if !found { + return nil, false, nil + } + deal := fromV7DealState(deal7) + return &deal, true, nil +} + +func (s *dealStates7) ForEach(cb func(dealID abi.DealID, ds DealState) error) error { + var ds7 market7.DealState + return s.Array.ForEach(&ds7, func(idx int64) error { + return cb(abi.DealID(idx), fromV7DealState(ds7)) + }) +} + +func (s *dealStates7) decode(val *cbg.Deferred) (*DealState, error) { + var ds7 market7.DealState + if err := ds7.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return nil, err + } + ds := fromV7DealState(ds7) + return &ds, nil +} + +func (s *dealStates7) array() adt.Array { + return s.Array +} + +func fromV7DealState(v7 market7.DealState) DealState { + return (DealState)(v7) +} + +type dealProposals7 struct { + adt.Array +} + +func (s *dealProposals7) Get(dealID abi.DealID) (*DealProposal, bool, error) { + var proposal7 market7.DealProposal + found, err := s.Array.Get(uint64(dealID), &proposal7) + if err != nil { + return nil, false, err + } + if !found { + return nil, false, nil + } + proposal := fromV7DealProposal(proposal7) + return &proposal, true, nil +} + +func (s *dealProposals7) ForEach(cb func(dealID abi.DealID, dp DealProposal) error) error { + var dp7 market7.DealProposal + return s.Array.ForEach(&dp7, func(idx int64) error { + return cb(abi.DealID(idx), fromV7DealProposal(dp7)) + }) +} + +func (s *dealProposals7) decode(val *cbg.Deferred) (*DealProposal, error) { + var dp7 market7.DealProposal + if err := dp7.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return nil, err + } + dp := fromV7DealProposal(dp7) + return &dp, nil +} + +func (s *dealProposals7) array() adt.Array { + return s.Array +} + +func fromV7DealProposal(v7 market7.DealProposal) DealProposal { + return (DealProposal)(v7) +} + +func (s *state7) GetState() interface{} { + return &s.State +} + +var _ PublishStorageDealsReturn = (*publishStorageDealsReturn7)(nil) + +func decodePublishStorageDealsReturn7(b []byte) (PublishStorageDealsReturn, error) { + var retval market7.PublishStorageDealsReturn + if err := retval.UnmarshalCBOR(bytes.NewReader(b)); err != nil { + return nil, xerrors.Errorf("failed to unmarshal PublishStorageDealsReturn: %w", err) + } + + return &publishStorageDealsReturn7{retval}, nil +} + +type publishStorageDealsReturn7 struct { + market7.PublishStorageDealsReturn +} + +func (r *publishStorageDealsReturn7) IsDealValid(index uint64) (bool, error) { + + return r.ValidDeals.IsSet(index) + +} + +func (r *publishStorageDealsReturn7) DealIDs() ([]abi.DealID, error) { + return r.IDs, nil +} diff --git a/chain/actors/builtin/miner/miner.go b/chain/actors/builtin/miner/miner.go index 1c7f47e1151..f6d63388014 100644 --- a/chain/actors/builtin/miner/miner.go +++ b/chain/actors/builtin/miner/miner.go @@ -35,6 +35,8 @@ import ( builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" ) func init() { @@ -63,9 +65,13 @@ func init() { return load6(store, root) }) + builtin.RegisterActorState(builtin7.StorageMinerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load7(store, root) + }) + } -var Methods = builtin6.MethodsMiner +var Methods = builtin7.MethodsMiner // Unchanged between v0, v2, v3, v4, and v5 actors var WPoStProvingPeriod = miner0.WPoStProvingPeriod @@ -102,6 +108,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin6.StorageMinerActorCodeID: return load6(store, act.Head) + case builtin7.StorageMinerActorCodeID: + return load7(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -127,6 +136,9 @@ func MakeState(store adt.Store, av actors.Version) (State, error) { case actors.Version6: return make6(store) + case actors.Version7: + return make7(store) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -152,6 +164,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version6: return builtin6.StorageMinerActorCodeID, nil + case actors.Version7: + return builtin7.StorageMinerActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) diff --git a/chain/actors/builtin/miner/v7.go b/chain/actors/builtin/miner/v7.go new file mode 100644 index 00000000000..c7096a78149 --- /dev/null +++ b/chain/actors/builtin/miner/v7.go @@ -0,0 +1,570 @@ +package miner + +import ( + "bytes" + "errors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-bitfield" + rle "github.com/filecoin-project/go-bitfield/rle" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/dline" + "github.com/ipfs/go-cid" + "github.com/libp2p/go-libp2p-core/peer" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/actors/adt" + + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" + + miner7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/miner" + adt7 "github.com/filecoin-project/specs-actors/v7/actors/util/adt" +) + +var _ State = (*state7)(nil) + +func load7(store adt.Store, root cid.Cid) (State, error) { + out := state7{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make7(store adt.Store) (State, error) { + out := state7{store: store} + out.State = miner7.State{} + return &out, nil +} + +type state7 struct { + miner7.State + store adt.Store +} + +type deadline7 struct { + miner7.Deadline + store adt.Store +} + +type partition7 struct { + miner7.Partition + store adt.Store +} + +func (s *state7) AvailableBalance(bal abi.TokenAmount) (available abi.TokenAmount, err error) { + defer func() { + if r := recover(); r != nil { + err = xerrors.Errorf("failed to get available balance: %w", r) + available = abi.NewTokenAmount(0) + } + }() + // this panics if the miner doesnt have enough funds to cover their locked pledge + available, err = s.GetAvailableBalance(bal) + return available, err +} + +func (s *state7) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) { + return s.CheckVestedFunds(s.store, epoch) +} + +func (s *state7) LockedFunds() (LockedFunds, error) { + return LockedFunds{ + VestingFunds: s.State.LockedFunds, + InitialPledgeRequirement: s.State.InitialPledge, + PreCommitDeposits: s.State.PreCommitDeposits, + }, nil +} + +func (s *state7) FeeDebt() (abi.TokenAmount, error) { + return s.State.FeeDebt, nil +} + +func (s *state7) InitialPledge() (abi.TokenAmount, error) { + return s.State.InitialPledge, nil +} + +func (s *state7) PreCommitDeposits() (abi.TokenAmount, error) { + return s.State.PreCommitDeposits, nil +} + +func (s *state7) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) { + info, ok, err := s.State.GetSector(s.store, num) + if !ok || err != nil { + return nil, err + } + + ret := fromV7SectorOnChainInfo(*info) + return &ret, nil +} + +func (s *state7) FindSector(num abi.SectorNumber) (*SectorLocation, error) { + dlIdx, partIdx, err := s.State.FindSector(s.store, num) + if err != nil { + return nil, err + } + return &SectorLocation{ + Deadline: dlIdx, + Partition: partIdx, + }, nil +} + +func (s *state7) NumLiveSectors() (uint64, error) { + dls, err := s.State.LoadDeadlines(s.store) + if err != nil { + return 0, err + } + var total uint64 + if err := dls.ForEach(s.store, func(dlIdx uint64, dl *miner7.Deadline) error { + total += dl.LiveSectors + return nil + }); err != nil { + return 0, err + } + return total, nil +} + +// GetSectorExpiration returns the effective expiration of the given sector. +// +// If the sector does not expire early, the Early expiration field is 0. +func (s *state7) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, error) { + dls, err := s.State.LoadDeadlines(s.store) + if err != nil { + return nil, err + } + // NOTE: this can be optimized significantly. + // 1. If the sector is non-faulty, it will either expire on-time (can be + // learned from the sector info), or in the next quantized expiration + // epoch (i.e., the first element in the partition's expiration queue. + // 2. If it's faulty, it will expire early within the first 14 entries + // of the expiration queue. + stopErr := errors.New("stop") + out := SectorExpiration{} + err = dls.ForEach(s.store, func(dlIdx uint64, dl *miner7.Deadline) error { + partitions, err := dl.PartitionsArray(s.store) + if err != nil { + return err + } + quant := s.State.QuantSpecForDeadline(dlIdx) + var part miner7.Partition + return partitions.ForEach(&part, func(partIdx int64) error { + if found, err := part.Sectors.IsSet(uint64(num)); err != nil { + return err + } else if !found { + return nil + } + if found, err := part.Terminated.IsSet(uint64(num)); err != nil { + return err + } else if found { + // already terminated + return stopErr + } + + q, err := miner7.LoadExpirationQueue(s.store, part.ExpirationsEpochs, quant, miner7.PartitionExpirationAmtBitwidth) + if err != nil { + return err + } + var exp miner7.ExpirationSet + return q.ForEach(&exp, func(epoch int64) error { + if early, err := exp.EarlySectors.IsSet(uint64(num)); err != nil { + return err + } else if early { + out.Early = abi.ChainEpoch(epoch) + return nil + } + if onTime, err := exp.OnTimeSectors.IsSet(uint64(num)); err != nil { + return err + } else if onTime { + out.OnTime = abi.ChainEpoch(epoch) + return stopErr + } + return nil + }) + }) + }) + if err == stopErr { + err = nil + } + if err != nil { + return nil, err + } + if out.Early == 0 && out.OnTime == 0 { + return nil, xerrors.Errorf("failed to find sector %d", num) + } + return &out, nil +} + +func (s *state7) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) { + info, ok, err := s.State.GetPrecommittedSector(s.store, num) + if !ok || err != nil { + return nil, err + } + + ret := fromV7SectorPreCommitOnChainInfo(*info) + + return &ret, nil +} + +func (s *state7) ForEachPrecommittedSector(cb func(SectorPreCommitOnChainInfo) error) error { + precommitted, err := adt7.AsMap(s.store, s.State.PreCommittedSectors, builtin7.DefaultHamtBitwidth) + if err != nil { + return err + } + + var info miner7.SectorPreCommitOnChainInfo + if err := precommitted.ForEach(&info, func(_ string) error { + return cb(fromV7SectorPreCommitOnChainInfo(info)) + }); err != nil { + return err + } + + return nil +} + +func (s *state7) LoadSectors(snos *bitfield.BitField) ([]*SectorOnChainInfo, error) { + sectors, err := miner7.LoadSectors(s.store, s.State.Sectors) + if err != nil { + return nil, err + } + + // If no sector numbers are specified, load all. + if snos == nil { + infos := make([]*SectorOnChainInfo, 0, sectors.Length()) + var info7 miner7.SectorOnChainInfo + if err := sectors.ForEach(&info7, func(_ int64) error { + info := fromV7SectorOnChainInfo(info7) + infos = append(infos, &info) + return nil + }); err != nil { + return nil, err + } + return infos, nil + } + + // Otherwise, load selected. + infos7, err := sectors.Load(*snos) + if err != nil { + return nil, err + } + infos := make([]*SectorOnChainInfo, len(infos7)) + for i, info7 := range infos7 { + info := fromV7SectorOnChainInfo(*info7) + infos[i] = &info + } + return infos, nil +} + +func (s *state7) loadAllocatedSectorNumbers() (bitfield.BitField, error) { + var allocatedSectors bitfield.BitField + err := s.store.Get(s.store.Context(), s.State.AllocatedSectors, &allocatedSectors) + return allocatedSectors, err +} + +func (s *state7) IsAllocated(num abi.SectorNumber) (bool, error) { + allocatedSectors, err := s.loadAllocatedSectorNumbers() + if err != nil { + return false, err + } + + return allocatedSectors.IsSet(uint64(num)) +} + +func (s *state7) GetProvingPeriodStart() (abi.ChainEpoch, error) { + return s.State.ProvingPeriodStart, nil +} + +func (s *state7) UnallocatedSectorNumbers(count int) ([]abi.SectorNumber, error) { + allocatedSectors, err := s.loadAllocatedSectorNumbers() + if err != nil { + return nil, err + } + + allocatedRuns, err := allocatedSectors.RunIterator() + if err != nil { + return nil, err + } + + unallocatedRuns, err := rle.Subtract( + &rle.RunSliceIterator{Runs: []rle.Run{{Val: true, Len: abi.MaxSectorNumber}}}, + allocatedRuns, + ) + if err != nil { + return nil, err + } + + iter, err := rle.BitsFromRuns(unallocatedRuns) + if err != nil { + return nil, err + } + + sectors := make([]abi.SectorNumber, 0, count) + for iter.HasNext() && len(sectors) < count { + nextNo, err := iter.Next() + if err != nil { + return nil, err + } + sectors = append(sectors, abi.SectorNumber(nextNo)) + } + + return sectors, nil +} + +func (s *state7) GetAllocatedSectors() (*bitfield.BitField, error) { + var allocatedSectors bitfield.BitField + if err := s.store.Get(s.store.Context(), s.State.AllocatedSectors, &allocatedSectors); err != nil { + return nil, err + } + + return &allocatedSectors, nil +} + +func (s *state7) LoadDeadline(idx uint64) (Deadline, error) { + dls, err := s.State.LoadDeadlines(s.store) + if err != nil { + return nil, err + } + dl, err := dls.LoadDeadline(s.store, idx) + if err != nil { + return nil, err + } + return &deadline7{*dl, s.store}, nil +} + +func (s *state7) ForEachDeadline(cb func(uint64, Deadline) error) error { + dls, err := s.State.LoadDeadlines(s.store) + if err != nil { + return err + } + return dls.ForEach(s.store, func(i uint64, dl *miner7.Deadline) error { + return cb(i, &deadline7{*dl, s.store}) + }) +} + +func (s *state7) NumDeadlines() (uint64, error) { + return miner7.WPoStPeriodDeadlines, nil +} + +func (s *state7) DeadlinesChanged(other State) (bool, error) { + other7, ok := other.(*state7) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + + return !s.State.Deadlines.Equals(other7.Deadlines), nil +} + +func (s *state7) MinerInfoChanged(other State) (bool, error) { + other0, ok := other.(*state7) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + return !s.State.Info.Equals(other0.State.Info), nil +} + +func (s *state7) Info() (MinerInfo, error) { + info, err := s.State.GetInfo(s.store) + if err != nil { + return MinerInfo{}, err + } + + var pid *peer.ID + if peerID, err := peer.IDFromBytes(info.PeerId); err == nil { + pid = &peerID + } + + mi := MinerInfo{ + Owner: info.Owner, + Worker: info.Worker, + ControlAddresses: info.ControlAddresses, + + NewWorker: address.Undef, + WorkerChangeEpoch: -1, + + PeerId: pid, + Multiaddrs: info.Multiaddrs, + WindowPoStProofType: info.WindowPoStProofType, + SectorSize: info.SectorSize, + WindowPoStPartitionSectors: info.WindowPoStPartitionSectors, + ConsensusFaultElapsed: info.ConsensusFaultElapsed, + } + + if info.PendingWorkerKey != nil { + mi.NewWorker = info.PendingWorkerKey.NewWorker + mi.WorkerChangeEpoch = info.PendingWorkerKey.EffectiveAt + } + + return mi, nil +} + +func (s *state7) DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error) { + return s.State.RecordedDeadlineInfo(epoch), nil +} + +func (s *state7) DeadlineCronActive() (bool, error) { + return s.State.DeadlineCronActive, nil +} + +func (s *state7) sectors() (adt.Array, error) { + return adt7.AsArray(s.store, s.Sectors, miner7.SectorsAmtBitwidth) +} + +func (s *state7) decodeSectorOnChainInfo(val *cbg.Deferred) (SectorOnChainInfo, error) { + var si miner7.SectorOnChainInfo + err := si.UnmarshalCBOR(bytes.NewReader(val.Raw)) + if err != nil { + return SectorOnChainInfo{}, err + } + + return fromV7SectorOnChainInfo(si), nil +} + +func (s *state7) precommits() (adt.Map, error) { + return adt7.AsMap(s.store, s.PreCommittedSectors, builtin7.DefaultHamtBitwidth) +} + +func (s *state7) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) { + var sp miner7.SectorPreCommitOnChainInfo + err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) + if err != nil { + return SectorPreCommitOnChainInfo{}, err + } + + return fromV7SectorPreCommitOnChainInfo(sp), nil +} + +func (s *state7) EraseAllUnproven() error { + + dls, err := s.State.LoadDeadlines(s.store) + if err != nil { + return err + } + + err = dls.ForEach(s.store, func(dindx uint64, dl *miner7.Deadline) error { + ps, err := dl.PartitionsArray(s.store) + if err != nil { + return err + } + + var part miner7.Partition + err = ps.ForEach(&part, func(pindx int64) error { + _ = part.ActivateUnproven() + err = ps.Set(uint64(pindx), &part) + return nil + }) + + if err != nil { + return err + } + + dl.Partitions, err = ps.Root() + if err != nil { + return err + } + + return dls.UpdateDeadline(s.store, dindx, dl) + }) + if err != nil { + return err + } + + return s.State.SaveDeadlines(s.store, dls) + +} + +func (d *deadline7) LoadPartition(idx uint64) (Partition, error) { + p, err := d.Deadline.LoadPartition(d.store, idx) + if err != nil { + return nil, err + } + return &partition7{*p, d.store}, nil +} + +func (d *deadline7) ForEachPartition(cb func(uint64, Partition) error) error { + ps, err := d.Deadline.PartitionsArray(d.store) + if err != nil { + return err + } + var part miner7.Partition + return ps.ForEach(&part, func(i int64) error { + return cb(uint64(i), &partition7{part, d.store}) + }) +} + +func (d *deadline7) PartitionsChanged(other Deadline) (bool, error) { + other7, ok := other.(*deadline7) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + + return !d.Deadline.Partitions.Equals(other7.Deadline.Partitions), nil +} + +func (d *deadline7) PartitionsPoSted() (bitfield.BitField, error) { + return d.Deadline.PartitionsPoSted, nil +} + +func (d *deadline7) DisputableProofCount() (uint64, error) { + + ops, err := d.OptimisticProofsSnapshotArray(d.store) + if err != nil { + return 0, err + } + + return ops.Length(), nil + +} + +func (p *partition7) AllSectors() (bitfield.BitField, error) { + return p.Partition.Sectors, nil +} + +func (p *partition7) FaultySectors() (bitfield.BitField, error) { + return p.Partition.Faults, nil +} + +func (p *partition7) RecoveringSectors() (bitfield.BitField, error) { + return p.Partition.Recoveries, nil +} + +func (p *partition7) UnprovenSectors() (bitfield.BitField, error) { + return p.Partition.Unproven, nil +} + +func fromV7SectorOnChainInfo(v7 miner7.SectorOnChainInfo) SectorOnChainInfo { + + return SectorOnChainInfo{ + SectorNumber: v7.SectorNumber, + SealProof: v7.SealProof, + SealedCID: v7.SealedCID, + DealIDs: v7.DealIDs, + Activation: v7.Activation, + Expiration: v7.Expiration, + DealWeight: v7.DealWeight, + VerifiedDealWeight: v7.VerifiedDealWeight, + InitialPledge: v7.InitialPledge, + ExpectedDayReward: v7.ExpectedDayReward, + ExpectedStoragePledge: v7.ExpectedStoragePledge, + } + +} + +func fromV7SectorPreCommitOnChainInfo(v7 miner7.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { + + return SectorPreCommitOnChainInfo{ + Info: (SectorPreCommitInfo)(v7.Info), + PreCommitDeposit: v7.PreCommitDeposit, + PreCommitEpoch: v7.PreCommitEpoch, + DealWeight: v7.DealWeight, + VerifiedDealWeight: v7.VerifiedDealWeight, + } + +} + +func (s *state7) GetState() interface{} { + return &s.State +} diff --git a/chain/actors/builtin/multisig/message7.go b/chain/actors/builtin/multisig/message7.go new file mode 100644 index 00000000000..e7fb83e9bd0 --- /dev/null +++ b/chain/actors/builtin/multisig/message7.go @@ -0,0 +1,71 @@ +package multisig + +import ( + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" + init7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/init" + multisig7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/multisig" + + "github.com/filecoin-project/lotus/chain/actors" + init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" + "github.com/filecoin-project/lotus/chain/types" +) + +type message7 struct{ message0 } + +func (m message7) Create( + signers []address.Address, threshold uint64, + unlockStart, unlockDuration abi.ChainEpoch, + initialAmount abi.TokenAmount, +) (*types.Message, error) { + + lenAddrs := uint64(len(signers)) + + if lenAddrs < threshold { + return nil, xerrors.Errorf("cannot require signing of more addresses than provided for multisig") + } + + if threshold == 0 { + threshold = lenAddrs + } + + if m.from == address.Undef { + return nil, xerrors.Errorf("must provide source address") + } + + // Set up constructor parameters for multisig + msigParams := &multisig7.ConstructorParams{ + Signers: signers, + NumApprovalsThreshold: threshold, + UnlockDuration: unlockDuration, + StartEpoch: unlockStart, + } + + enc, actErr := actors.SerializeParams(msigParams) + if actErr != nil { + return nil, actErr + } + + // new actors are created by invoking 'exec' on the init actor with the constructor params + execParams := &init7.ExecParams{ + CodeCID: builtin7.MultisigActorCodeID, + ConstructorParams: enc, + } + + enc, actErr = actors.SerializeParams(execParams) + if actErr != nil { + return nil, actErr + } + + return &types.Message{ + To: init_.Address, + From: m.from, + Method: builtin7.MethodsInit.Exec, + Params: enc, + Value: initialAmount, + }, nil +} diff --git a/chain/actors/builtin/multisig/multisig.go b/chain/actors/builtin/multisig/multisig.go index ee725f7e58e..f1b50475af4 100644 --- a/chain/actors/builtin/multisig/multisig.go +++ b/chain/actors/builtin/multisig/multisig.go @@ -13,7 +13,7 @@ import ( "github.com/ipfs/go-cid" msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" - msig6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/multisig" + msig7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/multisig" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" @@ -27,6 +27,8 @@ import ( builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" @@ -58,6 +60,10 @@ func init() { builtin.RegisterActorState(builtin6.MultisigActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load6(store, root) }) + + builtin.RegisterActorState(builtin7.MultisigActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load7(store, root) + }) } func Load(store adt.Store, act *types.Actor) (State, error) { @@ -81,6 +87,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin6.MultisigActorCodeID: return load6(store, act.Head) + case builtin7.MultisigActorCodeID: + return load7(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -106,6 +115,9 @@ func MakeState(store adt.Store, av actors.Version, signers []address.Address, th case actors.Version6: return make6(store, signers, threshold, startEpoch, unlockDuration, initialBalance) + case actors.Version7: + return make7(store, signers, threshold, startEpoch, unlockDuration, initialBalance) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -131,6 +143,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version6: return builtin6.MultisigActorCodeID, nil + case actors.Version7: + return builtin7.MultisigActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) @@ -156,7 +171,7 @@ type State interface { type Transaction = msig0.Transaction -var Methods = builtin6.MethodsMultisig +var Methods = builtin7.MethodsMultisig func Message(version actors.Version, from address.Address) MessageBuilder { switch version { @@ -178,6 +193,9 @@ func Message(version actors.Version, from address.Address) MessageBuilder { case actors.Version6: return message6{message0{from}} + + case actors.Version7: + return message7{message0{from}} default: panic(fmt.Sprintf("unsupported actors version: %d", version)) } @@ -201,13 +219,13 @@ type MessageBuilder interface { } // this type is the same between v0 and v2 -type ProposalHashData = msig6.ProposalHashData -type ProposeReturn = msig6.ProposeReturn -type ProposeParams = msig6.ProposeParams -type ApproveReturn = msig6.ApproveReturn +type ProposalHashData = msig7.ProposalHashData +type ProposeReturn = msig7.ProposeReturn +type ProposeParams = msig7.ProposeParams +type ApproveReturn = msig7.ApproveReturn func txnParams(id uint64, data *ProposalHashData) ([]byte, error) { - params := msig6.TxnIDParams{ID: msig6.TxnID(id)} + params := msig7.TxnIDParams{ID: msig7.TxnID(id)} if data != nil { if data.Requester.Protocol() != address.ID { return nil, xerrors.Errorf("proposer address must be an ID address, was %s", data.Requester) diff --git a/chain/actors/builtin/multisig/v7.go b/chain/actors/builtin/multisig/v7.go new file mode 100644 index 00000000000..bbe41f3dbb0 --- /dev/null +++ b/chain/actors/builtin/multisig/v7.go @@ -0,0 +1,119 @@ +package multisig + +import ( + "bytes" + "encoding/binary" + + adt7 "github.com/filecoin-project/specs-actors/v7/actors/util/adt" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/actors/adt" + + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" + + msig7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/multisig" +) + +var _ State = (*state7)(nil) + +func load7(store adt.Store, root cid.Cid) (State, error) { + out := state7{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make7(store adt.Store, signers []address.Address, threshold uint64, startEpoch abi.ChainEpoch, unlockDuration abi.ChainEpoch, initialBalance abi.TokenAmount) (State, error) { + out := state7{store: store} + out.State = msig7.State{} + out.State.Signers = signers + out.State.NumApprovalsThreshold = threshold + out.State.StartEpoch = startEpoch + out.State.UnlockDuration = unlockDuration + out.State.InitialBalance = initialBalance + + em, err := adt7.StoreEmptyMap(store, builtin7.DefaultHamtBitwidth) + if err != nil { + return nil, err + } + + out.State.PendingTxns = em + + return &out, nil +} + +type state7 struct { + msig7.State + store adt.Store +} + +func (s *state7) LockedBalance(currEpoch abi.ChainEpoch) (abi.TokenAmount, error) { + return s.State.AmountLocked(currEpoch - s.State.StartEpoch), nil +} + +func (s *state7) StartEpoch() (abi.ChainEpoch, error) { + return s.State.StartEpoch, nil +} + +func (s *state7) UnlockDuration() (abi.ChainEpoch, error) { + return s.State.UnlockDuration, nil +} + +func (s *state7) InitialBalance() (abi.TokenAmount, error) { + return s.State.InitialBalance, nil +} + +func (s *state7) Threshold() (uint64, error) { + return s.State.NumApprovalsThreshold, nil +} + +func (s *state7) Signers() ([]address.Address, error) { + return s.State.Signers, nil +} + +func (s *state7) ForEachPendingTxn(cb func(id int64, txn Transaction) error) error { + arr, err := adt7.AsMap(s.store, s.State.PendingTxns, builtin7.DefaultHamtBitwidth) + if err != nil { + return err + } + var out msig7.Transaction + return arr.ForEach(&out, func(key string) error { + txid, n := binary.Varint([]byte(key)) + if n <= 0 { + return xerrors.Errorf("invalid pending transaction key: %v", key) + } + return cb(txid, (Transaction)(out)) //nolint:unconvert + }) +} + +func (s *state7) PendingTxnChanged(other State) (bool, error) { + other7, ok := other.(*state7) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + return !s.State.PendingTxns.Equals(other7.PendingTxns), nil +} + +func (s *state7) transactions() (adt.Map, error) { + return adt7.AsMap(s.store, s.PendingTxns, builtin7.DefaultHamtBitwidth) +} + +func (s *state7) decodeTransaction(val *cbg.Deferred) (Transaction, error) { + var tx msig7.Transaction + if err := tx.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return Transaction{}, err + } + return tx, nil +} + +func (s *state7) GetState() interface{} { + return &s.State +} diff --git a/chain/actors/builtin/paych/message7.go b/chain/actors/builtin/paych/message7.go new file mode 100644 index 00000000000..41dfa1bdd18 --- /dev/null +++ b/chain/actors/builtin/paych/message7.go @@ -0,0 +1,74 @@ +package paych + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" + init7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/init" + paych7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/paych" + + "github.com/filecoin-project/lotus/chain/actors" + init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" + "github.com/filecoin-project/lotus/chain/types" +) + +type message7 struct{ from address.Address } + +func (m message7) Create(to address.Address, initialAmount abi.TokenAmount) (*types.Message, error) { + params, aerr := actors.SerializeParams(&paych7.ConstructorParams{From: m.from, To: to}) + if aerr != nil { + return nil, aerr + } + enc, aerr := actors.SerializeParams(&init7.ExecParams{ + CodeCID: builtin7.PaymentChannelActorCodeID, + ConstructorParams: params, + }) + if aerr != nil { + return nil, aerr + } + + return &types.Message{ + To: init_.Address, + From: m.from, + Value: initialAmount, + Method: builtin7.MethodsInit.Exec, + Params: enc, + }, nil +} + +func (m message7) Update(paych address.Address, sv *SignedVoucher, secret []byte) (*types.Message, error) { + params, aerr := actors.SerializeParams(&paych7.UpdateChannelStateParams{ + Sv: *sv, + Secret: secret, + }) + if aerr != nil { + return nil, aerr + } + + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin7.MethodsPaych.UpdateChannelState, + Params: params, + }, nil +} + +func (m message7) Settle(paych address.Address) (*types.Message, error) { + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin7.MethodsPaych.Settle, + }, nil +} + +func (m message7) Collect(paych address.Address) (*types.Message, error) { + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin7.MethodsPaych.Collect, + }, nil +} diff --git a/chain/actors/builtin/paych/paych.go b/chain/actors/builtin/paych/paych.go index eea3659f8b5..f807b33edce 100644 --- a/chain/actors/builtin/paych/paych.go +++ b/chain/actors/builtin/paych/paych.go @@ -27,6 +27,8 @@ import ( builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" @@ -58,6 +60,10 @@ func init() { builtin.RegisterActorState(builtin6.PaymentChannelActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load6(store, root) }) + + builtin.RegisterActorState(builtin7.PaymentChannelActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load7(store, root) + }) } // Load returns an abstract copy of payment channel state, irregardless of actor version @@ -82,6 +88,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin6.PaymentChannelActorCodeID: return load6(store, act.Head) + case builtin7.PaymentChannelActorCodeID: + return load7(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -107,6 +116,9 @@ func MakeState(store adt.Store, av actors.Version) (State, error) { case actors.Version6: return make6(store) + case actors.Version7: + return make7(store) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -132,6 +144,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version6: return builtin6.PaymentChannelActorCodeID, nil + case actors.Version7: + return builtin7.PaymentChannelActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) @@ -185,7 +200,7 @@ func DecodeSignedVoucher(s string) (*SignedVoucher, error) { return &sv, nil } -var Methods = builtin6.MethodsPaych +var Methods = builtin7.MethodsPaych func Message(version actors.Version, from address.Address) MessageBuilder { switch version { @@ -208,6 +223,9 @@ func Message(version actors.Version, from address.Address) MessageBuilder { case actors.Version6: return message6{from} + case actors.Version7: + return message7{from} + default: panic(fmt.Sprintf("unsupported actors version: %d", version)) } diff --git a/chain/actors/builtin/paych/v7.go b/chain/actors/builtin/paych/v7.go new file mode 100644 index 00000000000..ce09ea2e4be --- /dev/null +++ b/chain/actors/builtin/paych/v7.go @@ -0,0 +1,114 @@ +package paych + +import ( + "github.com/ipfs/go-cid" + + "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/adt" + + paych7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/paych" + adt7 "github.com/filecoin-project/specs-actors/v7/actors/util/adt" +) + +var _ State = (*state7)(nil) + +func load7(store adt.Store, root cid.Cid) (State, error) { + out := state7{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make7(store adt.Store) (State, error) { + out := state7{store: store} + out.State = paych7.State{} + return &out, nil +} + +type state7 struct { + paych7.State + store adt.Store + lsAmt *adt7.Array +} + +// Channel owner, who has funded the actor +func (s *state7) From() (address.Address, error) { + return s.State.From, nil +} + +// Recipient of payouts from channel +func (s *state7) To() (address.Address, error) { + return s.State.To, nil +} + +// Height at which the channel can be `Collected` +func (s *state7) SettlingAt() (abi.ChainEpoch, error) { + return s.State.SettlingAt, nil +} + +// Amount successfully redeemed through the payment channel, paid out on `Collect()` +func (s *state7) ToSend() (abi.TokenAmount, error) { + return s.State.ToSend, nil +} + +func (s *state7) getOrLoadLsAmt() (*adt7.Array, error) { + if s.lsAmt != nil { + return s.lsAmt, nil + } + + // Get the lane state from the chain + lsamt, err := adt7.AsArray(s.store, s.State.LaneStates, paych7.LaneStatesAmtBitwidth) + if err != nil { + return nil, err + } + + s.lsAmt = lsamt + return lsamt, nil +} + +// Get total number of lanes +func (s *state7) LaneCount() (uint64, error) { + lsamt, err := s.getOrLoadLsAmt() + if err != nil { + return 0, err + } + return lsamt.Length(), nil +} + +func (s *state7) GetState() interface{} { + return &s.State +} + +// Iterate lane states +func (s *state7) ForEachLaneState(cb func(idx uint64, dl LaneState) error) error { + // Get the lane state from the chain + lsamt, err := s.getOrLoadLsAmt() + if err != nil { + return err + } + + // Note: we use a map instead of an array to store laneStates because the + // client sets the lane ID (the index) and potentially they could use a + // very large index. + var ls paych7.LaneState + return lsamt.ForEach(&ls, func(i int64) error { + return cb(uint64(i), &laneState7{ls}) + }) +} + +type laneState7 struct { + paych7.LaneState +} + +func (ls *laneState7) Redeemed() (big.Int, error) { + return ls.LaneState.Redeemed, nil +} + +func (ls *laneState7) Nonce() (uint64, error) { + return ls.LaneState.Nonce, nil +} diff --git a/chain/actors/builtin/power/power.go b/chain/actors/builtin/power/power.go index 84bd6948a86..9b73cdd603e 100644 --- a/chain/actors/builtin/power/power.go +++ b/chain/actors/builtin/power/power.go @@ -26,6 +26,8 @@ import ( builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" ) func init() { @@ -53,11 +55,15 @@ func init() { builtin.RegisterActorState(builtin6.StoragePowerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load6(store, root) }) + + builtin.RegisterActorState(builtin7.StoragePowerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load7(store, root) + }) } var ( - Address = builtin6.StoragePowerActorAddr - Methods = builtin6.MethodsPower + Address = builtin7.StoragePowerActorAddr + Methods = builtin7.MethodsPower ) func Load(store adt.Store, act *types.Actor) (State, error) { @@ -81,6 +87,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin6.StoragePowerActorCodeID: return load6(store, act.Head) + case builtin7.StoragePowerActorCodeID: + return load7(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -106,6 +115,9 @@ func MakeState(store adt.Store, av actors.Version) (State, error) { case actors.Version6: return make6(store) + case actors.Version7: + return make7(store) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -131,6 +143,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version6: return builtin6.StoragePowerActorCodeID, nil + case actors.Version7: + return builtin7.StoragePowerActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) diff --git a/chain/actors/builtin/power/v7.go b/chain/actors/builtin/power/v7.go new file mode 100644 index 00000000000..af1761cb2b8 --- /dev/null +++ b/chain/actors/builtin/power/v7.go @@ -0,0 +1,187 @@ +package power + +import ( + "bytes" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" + + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" + + power7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/power" + adt7 "github.com/filecoin-project/specs-actors/v7/actors/util/adt" +) + +var _ State = (*state7)(nil) + +func load7(store adt.Store, root cid.Cid) (State, error) { + out := state7{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make7(store adt.Store) (State, error) { + out := state7{store: store} + + s, err := power7.ConstructState(store) + if err != nil { + return nil, err + } + + out.State = *s + + return &out, nil +} + +type state7 struct { + power7.State + store adt.Store +} + +func (s *state7) TotalLocked() (abi.TokenAmount, error) { + return s.TotalPledgeCollateral, nil +} + +func (s *state7) TotalPower() (Claim, error) { + return Claim{ + RawBytePower: s.TotalRawBytePower, + QualityAdjPower: s.TotalQualityAdjPower, + }, nil +} + +// Committed power to the network. Includes miners below the minimum threshold. +func (s *state7) TotalCommitted() (Claim, error) { + return Claim{ + RawBytePower: s.TotalBytesCommitted, + QualityAdjPower: s.TotalQABytesCommitted, + }, nil +} + +func (s *state7) MinerPower(addr address.Address) (Claim, bool, error) { + claims, err := s.claims() + if err != nil { + return Claim{}, false, err + } + var claim power7.Claim + ok, err := claims.Get(abi.AddrKey(addr), &claim) + if err != nil { + return Claim{}, false, err + } + return Claim{ + RawBytePower: claim.RawBytePower, + QualityAdjPower: claim.QualityAdjPower, + }, ok, nil +} + +func (s *state7) MinerNominalPowerMeetsConsensusMinimum(a address.Address) (bool, error) { + return s.State.MinerNominalPowerMeetsConsensusMinimum(s.store, a) +} + +func (s *state7) TotalPowerSmoothed() (builtin.FilterEstimate, error) { + return builtin.FromV7FilterEstimate(s.State.ThisEpochQAPowerSmoothed), nil +} + +func (s *state7) MinerCounts() (uint64, uint64, error) { + return uint64(s.State.MinerAboveMinPowerCount), uint64(s.State.MinerCount), nil +} + +func (s *state7) ListAllMiners() ([]address.Address, error) { + claims, err := s.claims() + if err != nil { + return nil, err + } + + var miners []address.Address + err = claims.ForEach(nil, func(k string) error { + a, err := address.NewFromBytes([]byte(k)) + if err != nil { + return err + } + miners = append(miners, a) + return nil + }) + if err != nil { + return nil, err + } + + return miners, nil +} + +func (s *state7) ForEachClaim(cb func(miner address.Address, claim Claim) error) error { + claims, err := s.claims() + if err != nil { + return err + } + + var claim power7.Claim + return claims.ForEach(&claim, func(k string) error { + a, err := address.NewFromBytes([]byte(k)) + if err != nil { + return err + } + return cb(a, Claim{ + RawBytePower: claim.RawBytePower, + QualityAdjPower: claim.QualityAdjPower, + }) + }) +} + +func (s *state7) ClaimsChanged(other State) (bool, error) { + other7, ok := other.(*state7) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + return !s.State.Claims.Equals(other7.State.Claims), nil +} + +func (s *state7) SetTotalQualityAdjPower(p abi.StoragePower) error { + s.State.TotalQualityAdjPower = p + return nil +} + +func (s *state7) SetTotalRawBytePower(p abi.StoragePower) error { + s.State.TotalRawBytePower = p + return nil +} + +func (s *state7) SetThisEpochQualityAdjPower(p abi.StoragePower) error { + s.State.ThisEpochQualityAdjPower = p + return nil +} + +func (s *state7) SetThisEpochRawBytePower(p abi.StoragePower) error { + s.State.ThisEpochRawBytePower = p + return nil +} + +func (s *state7) GetState() interface{} { + return &s.State +} + +func (s *state7) claims() (adt.Map, error) { + return adt7.AsMap(s.store, s.Claims, builtin7.DefaultHamtBitwidth) +} + +func (s *state7) decodeClaim(val *cbg.Deferred) (Claim, error) { + var ci power7.Claim + if err := ci.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return Claim{}, err + } + return fromV7Claim(ci), nil +} + +func fromV7Claim(v7 power7.Claim) Claim { + return Claim{ + RawBytePower: v7.RawBytePower, + QualityAdjPower: v7.QualityAdjPower, + } +} diff --git a/chain/actors/builtin/reward/reward.go b/chain/actors/builtin/reward/reward.go index 38d5b5b875e..b6ee2f14668 100644 --- a/chain/actors/builtin/reward/reward.go +++ b/chain/actors/builtin/reward/reward.go @@ -21,6 +21,8 @@ import ( builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" @@ -51,11 +53,15 @@ func init() { builtin.RegisterActorState(builtin6.RewardActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load6(store, root) }) + + builtin.RegisterActorState(builtin7.RewardActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load7(store, root) + }) } var ( - Address = builtin6.RewardActorAddr - Methods = builtin6.MethodsReward + Address = builtin7.RewardActorAddr + Methods = builtin7.MethodsReward ) func Load(store adt.Store, act *types.Actor) (State, error) { @@ -79,6 +85,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin6.RewardActorCodeID: return load6(store, act.Head) + case builtin7.RewardActorCodeID: + return load7(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -104,6 +113,9 @@ func MakeState(store adt.Store, av actors.Version, currRealizedPower abi.Storage case actors.Version6: return make6(store, currRealizedPower) + case actors.Version7: + return make7(store, currRealizedPower) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -129,6 +141,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version6: return builtin6.RewardActorCodeID, nil + case actors.Version7: + return builtin7.RewardActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) diff --git a/chain/actors/builtin/reward/v7.go b/chain/actors/builtin/reward/v7.go new file mode 100644 index 00000000000..368bb3abd12 --- /dev/null +++ b/chain/actors/builtin/reward/v7.go @@ -0,0 +1,98 @@ +package reward + +import ( + "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" + + miner7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/miner" + reward7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/reward" + smoothing7 "github.com/filecoin-project/specs-actors/v7/actors/util/smoothing" +) + +var _ State = (*state7)(nil) + +func load7(store adt.Store, root cid.Cid) (State, error) { + out := state7{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make7(store adt.Store, currRealizedPower abi.StoragePower) (State, error) { + out := state7{store: store} + out.State = *reward7.ConstructState(currRealizedPower) + return &out, nil +} + +type state7 struct { + reward7.State + store adt.Store +} + +func (s *state7) ThisEpochReward() (abi.TokenAmount, error) { + return s.State.ThisEpochReward, nil +} + +func (s *state7) ThisEpochRewardSmoothed() (builtin.FilterEstimate, error) { + + return builtin.FilterEstimate{ + PositionEstimate: s.State.ThisEpochRewardSmoothed.PositionEstimate, + VelocityEstimate: s.State.ThisEpochRewardSmoothed.VelocityEstimate, + }, nil + +} + +func (s *state7) ThisEpochBaselinePower() (abi.StoragePower, error) { + return s.State.ThisEpochBaselinePower, nil +} + +func (s *state7) TotalStoragePowerReward() (abi.TokenAmount, error) { + return s.State.TotalStoragePowerReward, nil +} + +func (s *state7) EffectiveBaselinePower() (abi.StoragePower, error) { + return s.State.EffectiveBaselinePower, nil +} + +func (s *state7) EffectiveNetworkTime() (abi.ChainEpoch, error) { + return s.State.EffectiveNetworkTime, nil +} + +func (s *state7) CumsumBaseline() (reward7.Spacetime, error) { + return s.State.CumsumBaseline, nil +} + +func (s *state7) CumsumRealized() (reward7.Spacetime, error) { + return s.State.CumsumRealized, nil +} + +func (s *state7) InitialPledgeForPower(qaPower abi.StoragePower, networkTotalPledge abi.TokenAmount, networkQAPower *builtin.FilterEstimate, circSupply abi.TokenAmount) (abi.TokenAmount, error) { + return miner7.InitialPledgeForPower( + qaPower, + s.State.ThisEpochBaselinePower, + s.State.ThisEpochRewardSmoothed, + smoothing7.FilterEstimate{ + PositionEstimate: networkQAPower.PositionEstimate, + VelocityEstimate: networkQAPower.VelocityEstimate, + }, + circSupply, + ), nil +} + +func (s *state7) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, sectorWeight abi.StoragePower) (abi.TokenAmount, error) { + return miner7.PreCommitDepositForPower(s.State.ThisEpochRewardSmoothed, + smoothing7.FilterEstimate{ + PositionEstimate: networkQAPower.PositionEstimate, + VelocityEstimate: networkQAPower.VelocityEstimate, + }, + sectorWeight), nil +} + +func (s *state7) GetState() interface{} { + return &s.State +} diff --git a/chain/actors/builtin/system/system.go b/chain/actors/builtin/system/system.go index 3d6105c3801..fb7515f3547 100644 --- a/chain/actors/builtin/system/system.go +++ b/chain/actors/builtin/system/system.go @@ -17,10 +17,12 @@ import ( builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" ) var ( - Address = builtin6.SystemActorAddr + Address = builtin7.SystemActorAddr ) func MakeState(store adt.Store, av actors.Version) (State, error) { @@ -44,6 +46,9 @@ func MakeState(store adt.Store, av actors.Version) (State, error) { case actors.Version6: return make6(store) + case actors.Version7: + return make7(store) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -69,6 +74,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version6: return builtin6.SystemActorCodeID, nil + case actors.Version7: + return builtin7.SystemActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) diff --git a/chain/actors/builtin/system/v7.go b/chain/actors/builtin/system/v7.go new file mode 100644 index 00000000000..813add5fb14 --- /dev/null +++ b/chain/actors/builtin/system/v7.go @@ -0,0 +1,35 @@ +package system + +import ( + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/actors/adt" + + system7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/system" +) + +var _ State = (*state7)(nil) + +func load7(store adt.Store, root cid.Cid) (State, error) { + out := state7{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make7(store adt.Store) (State, error) { + out := state7{store: store} + out.State = system7.State{} + return &out, nil +} + +type state7 struct { + system7.State + store adt.Store +} + +func (s *state7) GetState() interface{} { + return &s.State +} diff --git a/chain/actors/builtin/verifreg/v7.go b/chain/actors/builtin/verifreg/v7.go new file mode 100644 index 00000000000..9b2ca928ab5 --- /dev/null +++ b/chain/actors/builtin/verifreg/v7.go @@ -0,0 +1,75 @@ +package verifreg + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" + verifreg7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/verifreg" + adt7 "github.com/filecoin-project/specs-actors/v7/actors/util/adt" +) + +var _ State = (*state7)(nil) + +func load7(store adt.Store, root cid.Cid) (State, error) { + out := state7{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make7(store adt.Store, rootKeyAddress address.Address) (State, error) { + out := state7{store: store} + + s, err := verifreg7.ConstructState(store, rootKeyAddress) + if err != nil { + return nil, err + } + + out.State = *s + + return &out, nil +} + +type state7 struct { + verifreg7.State + store adt.Store +} + +func (s *state7) RootKey() (address.Address, error) { + return s.State.RootKey, nil +} + +func (s *state7) VerifiedClientDataCap(addr address.Address) (bool, abi.StoragePower, error) { + return getDataCap(s.store, actors.Version7, s.verifiedClients, addr) +} + +func (s *state7) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, error) { + return getDataCap(s.store, actors.Version7, s.verifiers, addr) +} + +func (s *state7) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { + return forEachCap(s.store, actors.Version7, s.verifiers, cb) +} + +func (s *state7) ForEachClient(cb func(addr address.Address, dcap abi.StoragePower) error) error { + return forEachCap(s.store, actors.Version7, s.verifiedClients, cb) +} + +func (s *state7) verifiedClients() (adt.Map, error) { + return adt7.AsMap(s.store, s.VerifiedClients, builtin7.DefaultHamtBitwidth) +} + +func (s *state7) verifiers() (adt.Map, error) { + return adt7.AsMap(s.store, s.Verifiers, builtin7.DefaultHamtBitwidth) +} + +func (s *state7) GetState() interface{} { + return &s.State +} diff --git a/chain/actors/builtin/verifreg/verifreg.go b/chain/actors/builtin/verifreg/verifreg.go index 31e8e5a083e..f6281334dda 100644 --- a/chain/actors/builtin/verifreg/verifreg.go +++ b/chain/actors/builtin/verifreg/verifreg.go @@ -21,6 +21,8 @@ import ( builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" @@ -53,11 +55,15 @@ func init() { return load6(store, root) }) + builtin.RegisterActorState(builtin7.VerifiedRegistryActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load7(store, root) + }) + } var ( - Address = builtin6.VerifiedRegistryActorAddr - Methods = builtin6.MethodsVerifiedRegistry + Address = builtin7.VerifiedRegistryActorAddr + Methods = builtin7.MethodsVerifiedRegistry ) func Load(store adt.Store, act *types.Actor) (State, error) { @@ -81,6 +87,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin6.VerifiedRegistryActorCodeID: return load6(store, act.Head) + case builtin7.VerifiedRegistryActorCodeID: + return load7(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -106,6 +115,9 @@ func MakeState(store adt.Store, av actors.Version, rootKeyAddress address.Addres case actors.Version6: return make6(store, rootKeyAddress) + case actors.Version7: + return make7(store, rootKeyAddress) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -131,6 +143,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version6: return builtin6.VerifiedRegistryActorCodeID, nil + case actors.Version7: + return builtin7.VerifiedRegistryActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) diff --git a/chain/actors/policy/policy.go b/chain/actors/policy/policy.go index e00a6ae10cb..f51da7aa7d5 100644 --- a/chain/actors/policy/policy.go +++ b/chain/actors/policy/policy.go @@ -40,14 +40,19 @@ import ( miner6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/miner" verifreg6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/verifreg" - paych6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/paych" + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" + market7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/market" + miner7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/miner" + verifreg7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/verifreg" + + paych7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/paych" ) const ( - ChainFinality = miner6.ChainFinality + ChainFinality = miner7.ChainFinality SealRandomnessLookback = ChainFinality - PaychSettleDelay = paych6.SettleDelay - MaxPreCommitRandomnessLookback = builtin6.EpochsInDay + SealRandomnessLookback + PaychSettleDelay = paych7.SettleDelay + MaxPreCommitRandomnessLookback = builtin7.EpochsInDay + SealRandomnessLookback ) // SetSupportedProofTypes sets supported proof types, across all actor versions. @@ -72,6 +77,8 @@ func SetSupportedProofTypes(types ...abi.RegisteredSealProof) { miner6.PreCommitSealProofTypesV8 = make(map[abi.RegisteredSealProof]struct{}, len(types)) + miner7.PreCommitSealProofTypesV8 = make(map[abi.RegisteredSealProof]struct{}, len(types)) + AddSupportedProofTypes(types...) } @@ -119,6 +126,15 @@ func AddSupportedProofTypes(types ...abi.RegisteredSealProof) { miner6.WindowPoStProofTypes[wpp] = struct{}{} + miner7.PreCommitSealProofTypesV8[t+abi.RegisteredSealProof_StackedDrg2KiBV1_1] = struct{}{} + wpp, err = t.RegisteredWindowPoStProof() + if err != nil { + // Fine to panic, this is a test-only method + panic(err) + } + + miner7.WindowPoStProofTypes[wpp] = struct{}{} + } } @@ -139,11 +155,13 @@ func SetPreCommitChallengeDelay(delay abi.ChainEpoch) { miner6.PreCommitChallengeDelay = delay + miner7.PreCommitChallengeDelay = delay + } // TODO: this function shouldn't really exist. Instead, the API should expose the precommit delay. func GetPreCommitChallengeDelay() abi.ChainEpoch { - return miner6.PreCommitChallengeDelay + return miner7.PreCommitChallengeDelay } // SetConsensusMinerMinPower sets the minimum power of an individual miner must @@ -173,6 +191,10 @@ func SetConsensusMinerMinPower(p abi.StoragePower) { policy.ConsensusMinerMinPower = p } + for _, policy := range builtin7.PoStProofPolicies { + policy.ConsensusMinerMinPower = p + } + } // SetMinVerifiedDealSize sets the minimum size of a verified deal. This should @@ -191,6 +213,8 @@ func SetMinVerifiedDealSize(size abi.StoragePower) { verifreg6.MinVerifiedDealSize = size + verifreg7.MinVerifiedDealSize = size + } func GetMaxProveCommitDuration(ver actors.Version, t abi.RegisteredSealProof) (abi.ChainEpoch, error) { @@ -220,6 +244,10 @@ func GetMaxProveCommitDuration(ver actors.Version, t abi.RegisteredSealProof) (a return miner6.MaxProveCommitDuration[t], nil + case actors.Version7: + + return miner7.MaxProveCommitDuration[t], nil + default: return 0, xerrors.Errorf("unsupported actors version") } @@ -255,6 +283,11 @@ func SetProviderCollateralSupplyTarget(num, denom big.Int) { Denominator: denom, } + market7.ProviderCollateralSupplyTarget = builtin7.BigFrac{ + Numerator: num, + Denominator: denom, + } + } func DealProviderCollateralBounds( @@ -298,13 +331,18 @@ func DealProviderCollateralBounds( min, max := market6.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil) return min, max, nil + case actors.Version7: + + min, max := market7.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil) + return min, max, nil + default: return big.Zero(), big.Zero(), xerrors.Errorf("unsupported actors version") } } func DealDurationBounds(pieceSize abi.PaddedPieceSize) (min, max abi.ChainEpoch) { - return market6.DealDurationBounds(pieceSize) + return market7.DealDurationBounds(pieceSize) } // Sets the challenge window and scales the proving period to match (such that @@ -345,6 +383,13 @@ func SetWPoStChallengeWindow(period abi.ChainEpoch) { // scale it if we're scaling the challenge period. miner6.WPoStDisputeWindow = period * 30 + miner7.WPoStChallengeWindow = period + miner7.WPoStProvingPeriod = period * abi.ChainEpoch(miner7.WPoStPeriodDeadlines) + + // by default, this is 2x finality which is 30 periods. + // scale it if we're scaling the challenge period. + miner7.WPoStDisputeWindow = period * 30 + } func GetWinningPoStSectorSetLookback(nwVer network.Version) abi.ChainEpoch { @@ -357,15 +402,15 @@ func GetWinningPoStSectorSetLookback(nwVer network.Version) abi.ChainEpoch { } func GetMaxSectorExpirationExtension() abi.ChainEpoch { - return miner6.MaxSectorExpirationExtension + return miner7.MaxSectorExpirationExtension } func GetMinSectorExpiration() abi.ChainEpoch { - return miner6.MinSectorExpiration + return miner7.MinSectorExpiration } func GetMaxPoStPartitions(nv network.Version, p abi.RegisteredPoStProof) (int, error) { - sectorsPerPart, err := builtin6.PoStProofWindowPoStPartitionSectors(p) + sectorsPerPart, err := builtin7.PoStProofWindowPoStPartitionSectors(p) if err != nil { return 0, err } @@ -378,8 +423,8 @@ func GetMaxPoStPartitions(nv network.Version, p abi.RegisteredPoStProof) (int, e func GetDefaultSectorSize() abi.SectorSize { // supported sector sizes are the same across versions. - szs := make([]abi.SectorSize, 0, len(miner6.PreCommitSealProofTypesV8)) - for spt := range miner6.PreCommitSealProofTypesV8 { + szs := make([]abi.SectorSize, 0, len(miner7.PreCommitSealProofTypesV8)) + for spt := range miner7.PreCommitSealProofTypesV8 { ss, err := spt.SectorSize() if err != nil { panic(err) @@ -404,7 +449,7 @@ func GetSectorMaxLifetime(proof abi.RegisteredSealProof, nwVer network.Version) return builtin4.SealProofPoliciesV0[proof].SectorMaxLifetime } - return builtin6.SealProofPoliciesV11[proof].SectorMaxLifetime + return builtin7.SealProofPoliciesV11[proof].SectorMaxLifetime } func GetAddressedSectorsMax(nwVer network.Version) (int, error) { @@ -432,6 +477,9 @@ func GetAddressedSectorsMax(nwVer network.Version) (int, error) { case actors.Version6: return miner6.AddressedSectorsMax, nil + case actors.Version7: + return miner7.AddressedSectorsMax, nil + default: return 0, xerrors.Errorf("unsupported network version") } @@ -469,6 +517,10 @@ func GetDeclarationsMax(nwVer network.Version) (int, error) { return miner6.DeclarationsMax, nil + case actors.Version7: + + return miner7.DeclarationsMax, nil + default: return 0, xerrors.Errorf("unsupported network version") } @@ -505,6 +557,10 @@ func AggregateProveCommitNetworkFee(nwVer network.Version, aggregateSize int, ba return miner6.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil + case actors.Version7: + + return miner7.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil + default: return big.Zero(), xerrors.Errorf("unsupported network version") } @@ -541,6 +597,10 @@ func AggregatePreCommitNetworkFee(nwVer network.Version, aggregateSize int, base return miner6.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil + case actors.Version7: + + return miner7.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil + default: return big.Zero(), xerrors.Errorf("unsupported network version") } diff --git a/chain/actors/version.go b/chain/actors/version.go index 7b7a6393a44..af51161c9a1 100644 --- a/chain/actors/version.go +++ b/chain/actors/version.go @@ -20,9 +20,9 @@ const ({{range .actorVersions}} /* inline-gen start */ -var LatestVersion = 6 +var LatestVersion = 7 -var Versions = []int{0, 2, 3, 4, 5, 6} +var Versions = []int{0, 2, 3, 4, 5, 6, 7} const ( Version0 Version = 0 @@ -31,6 +31,7 @@ const ( Version4 Version = 4 Version5 Version = 5 Version6 Version = 6 + Version7 Version = 7 ) /* inline-gen end */ @@ -50,6 +51,8 @@ func VersionForNetwork(version network.Version) (Version, error) { return Version5, nil case network.Version14: return Version6, nil + case network.Version15: + return Version7, nil default: return -1, fmt.Errorf("unsupported network version %d", version) } diff --git a/chain/consensus/filcns/compute_state.go b/chain/consensus/filcns/compute_state.go index 3c333298ef9..847d41d4786 100644 --- a/chain/consensus/filcns/compute_state.go +++ b/chain/consensus/filcns/compute_state.go @@ -28,6 +28,7 @@ import ( exported4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/exported" exported5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/exported" exported6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/exported" + exported7 "github.com/filecoin-project/specs-actors/v7/actors/builtin/exported" /* inline-gen end */ @@ -59,6 +60,7 @@ func NewActorRegistry() *vm.ActorRegistry { inv.Register(vm.ActorsVersionPredicate(actors.Version4), exported4.BuiltinActors()...) inv.Register(vm.ActorsVersionPredicate(actors.Version5), exported5.BuiltinActors()...) inv.Register(vm.ActorsVersionPredicate(actors.Version6), exported6.BuiltinActors()...) + inv.Register(vm.ActorsVersionPredicate(actors.Version7), exported7.BuiltinActors()...) /* inline-gen end */ diff --git a/chain/consensus/filcns/upgrades.go b/chain/consensus/filcns/upgrades.go index cf4c62bf340..43f50311f72 100644 --- a/chain/consensus/filcns/upgrades.go +++ b/chain/consensus/filcns/upgrades.go @@ -156,6 +156,22 @@ func DefaultUpgradeSchedule() stmgr.UpgradeSchedule { StopWithin: 5, }}, Expensive: true, + }, { + Height: build.UpgradeSnapDealsHeight, + Network: network.Version15, + Migration: UpgradeActorsV7, + PreMigrations: []stmgr.PreMigration{{ + PreMigration: PreUpgradeActorsV7, + StartWithin: 120, + DontStartWithin: 60, + StopWithin: 35, + }, { + PreMigration: PreUpgradeActorsV7, + StartWithin: 30, + DontStartWithin: 15, + StopWithin: 5, + }}, + Expensive: true, }, } @@ -1170,7 +1186,97 @@ func upgradeActorsV6Common( // Perform the migration newHamtRoot, err := nv14.MigrateStateTree(ctx, store, stateRoot.Actors, epoch, config, migrationLogger{}, cache) if err != nil { - return cid.Undef, xerrors.Errorf("upgrading to actors v5: %w", err) + return cid.Undef, xerrors.Errorf("upgrading to actors v6: %w", err) + } + + // Persist the result. + newRoot, err := store.Put(ctx, &types.StateRoot{ + Version: types.StateTreeVersion4, + Actors: newHamtRoot, + Info: stateRoot.Info, + }) + if err != nil { + return cid.Undef, xerrors.Errorf("failed to persist new state root: %w", err) + } + + // Persist the new tree. + + { + from := buf + to := buf.Read() + + if err := vm.Copy(ctx, from, to, newRoot); err != nil { + return cid.Undef, xerrors.Errorf("copying migrated tree: %w", err) + } + } + + return newRoot, nil +} + +func UpgradeActorsV7(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, cb stmgr.ExecMonitor, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) { + // Use all the CPUs except 3. + workerCount := runtime.NumCPU() - 3 + if workerCount <= 0 { + workerCount = 1 + } + + config := nv14.Config{ + MaxWorkers: uint(workerCount), + JobQueueSize: 1000, + ResultQueueSize: 100, + ProgressLogPeriod: 10 * time.Second, + } + + newRoot, err := upgradeActorsV7Common(ctx, sm, cache, root, epoch, ts, config) + if err != nil { + return cid.Undef, xerrors.Errorf("migrating actors v6 state: %w", err) + } + + return newRoot, nil +} + +func PreUpgradeActorsV7(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error { + // Use half the CPUs for pre-migration, but leave at least 3. + workerCount := runtime.NumCPU() + if workerCount <= 4 { + workerCount = 1 + } else { + workerCount /= 2 + } + + //TODO: nv15 + config := nv14.Config{MaxWorkers: uint(workerCount)} + _, err := upgradeActorsV7Common(ctx, sm, cache, root, epoch, ts, config) + return err +} + +func upgradeActorsV7Common( + ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, + root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet, + //TODO: nv15 + config nv14.Config, +) (cid.Cid, error) { + buf := blockstore.NewTieredBstore(sm.ChainStore().StateBlockstore(), blockstore.NewMemorySync()) + store := store.ActorStore(ctx, buf) + + // Load the state root. + var stateRoot types.StateRoot + if err := store.Get(ctx, root, &stateRoot); err != nil { + return cid.Undef, xerrors.Errorf("failed to decode state root: %w", err) + } + + if stateRoot.Version != types.StateTreeVersion4 { + return cid.Undef, xerrors.Errorf( + "expected state root version 4 for actors v7 upgrade, got %d", + stateRoot.Version, + ) + } + + // Perform the migration + //TODO: nv15 + newHamtRoot, err := nv14.MigrateStateTree(ctx, store, stateRoot.Actors, epoch, config, migrationLogger{}, cache) + if err != nil { + return cid.Undef, xerrors.Errorf("upgrading to actors v7: %w", err) } // Persist the result. diff --git a/chain/gen/gen.go b/chain/gen/gen.go index 69ab32d58e8..60dd142e9fa 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -9,6 +9,8 @@ import ( "sync/atomic" "time" + proof7 "github.com/filecoin-project/specs-actors/v7/actors/runtime/proof" + "github.com/filecoin-project/lotus/chain/rand" "github.com/filecoin-project/go-state-types/network" @@ -686,6 +688,10 @@ func (m genFakeVerifier) VerifyAggregateSeals(aggregate proof5.AggregateSealVeri panic("not supported") } +func (m genFakeVerifier) VerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) (bool, error) { + panic("not supported") +} + func (m genFakeVerifier) VerifyWinningPoSt(ctx context.Context, info proof5.WinningPoStVerifyInfo) (bool, error) { panic("not supported") } diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index edacfe304c4..66691205802 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -6,6 +6,8 @@ import ( "fmt" "math/rand" + runtime7 "github.com/filecoin-project/specs-actors/v7/actors/runtime" + builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" "github.com/ipfs/go-cid" @@ -29,7 +31,6 @@ import ( market4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/market" power4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/power" reward4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/reward" - runtime5 "github.com/filecoin-project/specs-actors/v5/actors/runtime" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" @@ -57,7 +58,7 @@ func MinerAddress(genesisIndex uint64) address.Address { } type fakedSigSyscalls struct { - runtime5.Syscalls + runtime7.Syscalls } func (fss *fakedSigSyscalls) VerifySignature(signature crypto.Signature, signer address.Address, plaintext []byte) error { @@ -65,7 +66,7 @@ func (fss *fakedSigSyscalls) VerifySignature(signature crypto.Signature, signer } func mkFakedSigSyscalls(base vm.SyscallBuilder) vm.SyscallBuilder { - return func(ctx context.Context, rt *vm.Runtime) runtime5.Syscalls { + return func(ctx context.Context, rt *vm.Runtime) runtime7.Syscalls { return &fakedSigSyscalls{ base(ctx, rt), } diff --git a/chain/state/statetree.go b/chain/state/statetree.go index f230f7faa54..9a518a6227a 100644 --- a/chain/state/statetree.go +++ b/chain/state/statetree.go @@ -159,7 +159,7 @@ func VersionForNetwork(ver network.Version) (types.StateTreeVersion, error) { /* inline-gen start */ - case network.Version13, network.Version14: + case network.Version13, network.Version14, network.Version15: /* inline-gen end */ return types.StateTreeVersion4, nil diff --git a/chain/vm/gas.go b/chain/vm/gas.go index 206a55d3643..27d9c8d94ae 100644 --- a/chain/vm/gas.go +++ b/chain/vm/gas.go @@ -3,13 +3,14 @@ package vm import ( "fmt" + vmr "github.com/filecoin-project/specs-actors/v7/actors/runtime" + proof7 "github.com/filecoin-project/specs-actors/v7/actors/runtime/proof" + "github.com/filecoin-project/go-address" addr "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/build" - vmr5 "github.com/filecoin-project/specs-actors/v5/actors/runtime" - proof5 "github.com/filecoin-project/specs-actors/v5/actors/runtime/proof" "github.com/ipfs/go-cid" ) @@ -73,9 +74,10 @@ type Pricelist interface { OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error) OnHashing(dataSize int) GasCharge OnComputeUnsealedSectorCid(proofType abi.RegisteredSealProof, pieces []abi.PieceInfo) GasCharge - OnVerifySeal(info proof5.SealVerifyInfo) GasCharge - OnVerifyAggregateSeals(aggregate proof5.AggregateSealVerifyProofAndInfos) GasCharge - OnVerifyPost(info proof5.WindowPoStVerifyInfo) GasCharge + OnVerifySeal(info proof7.SealVerifyInfo) GasCharge + OnVerifyAggregateSeals(aggregate proof7.AggregateSealVerifyProofAndInfos) GasCharge + OnVerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) GasCharge + OnVerifyPost(info proof7.WindowPoStVerifyInfo) GasCharge OnVerifyConsensusFault() GasCharge } @@ -227,7 +229,7 @@ func PricelistByEpoch(epoch abi.ChainEpoch) Pricelist { } type pricedSyscalls struct { - under vmr5.Syscalls + under vmr.Syscalls pl Pricelist chargeGas func(GasCharge) } @@ -261,7 +263,7 @@ func (ps pricedSyscalls) ComputeUnsealedSectorCID(reg abi.RegisteredSealProof, p } // Verifies a sector seal proof. -func (ps pricedSyscalls) VerifySeal(vi proof5.SealVerifyInfo) error { +func (ps pricedSyscalls) VerifySeal(vi proof7.SealVerifyInfo) error { ps.chargeGas(ps.pl.OnVerifySeal(vi)) defer ps.chargeGas(gasOnActorExec) @@ -269,7 +271,7 @@ func (ps pricedSyscalls) VerifySeal(vi proof5.SealVerifyInfo) error { } // Verifies a proof of spacetime. -func (ps pricedSyscalls) VerifyPoSt(vi proof5.WindowPoStVerifyInfo) error { +func (ps pricedSyscalls) VerifyPoSt(vi proof7.WindowPoStVerifyInfo) error { ps.chargeGas(ps.pl.OnVerifyPost(vi)) defer ps.chargeGas(gasOnActorExec) @@ -286,14 +288,14 @@ func (ps pricedSyscalls) VerifyPoSt(vi proof5.WindowPoStVerifyInfo) error { // the "parent grinding fault", in which case it must be the sibling of h1 (same parent tipset) and one of the // blocks in the parent of h2 (i.e. h2's grandparent). // Returns nil and an error if the headers don't prove a fault. -func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte) (*vmr5.ConsensusFault, error) { +func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte) (*vmr.ConsensusFault, error) { ps.chargeGas(ps.pl.OnVerifyConsensusFault()) defer ps.chargeGas(gasOnActorExec) return ps.under.VerifyConsensusFault(h1, h2, extra) } -func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]proof5.SealVerifyInfo) (map[address.Address][]bool, error) { +func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]proof7.SealVerifyInfo) (map[address.Address][]bool, error) { count := int64(0) for _, svis := range inp { count += int64(len(svis)) @@ -307,9 +309,16 @@ func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]proof5.SealV return ps.under.BatchVerifySeals(inp) } -func (ps pricedSyscalls) VerifyAggregateSeals(aggregate proof5.AggregateSealVerifyProofAndInfos) error { +func (ps pricedSyscalls) VerifyAggregateSeals(aggregate proof7.AggregateSealVerifyProofAndInfos) error { ps.chargeGas(ps.pl.OnVerifyAggregateSeals(aggregate)) defer ps.chargeGas(gasOnActorExec) return ps.under.VerifyAggregateSeals(aggregate) } + +func (ps pricedSyscalls) VerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) error { + ps.chargeGas(ps.pl.OnVerifyReplicaUpdate(update)) + defer ps.chargeGas(gasOnActorExec) + + return ps.under.VerifyReplicaUpdate(update) +} diff --git a/chain/vm/gas_v0.go b/chain/vm/gas_v0.go index 13c5fdd86ad..548227a3356 100644 --- a/chain/vm/gas_v0.go +++ b/chain/vm/gas_v0.go @@ -3,8 +3,7 @@ package vm import ( "fmt" - proof2 "github.com/filecoin-project/specs-actors/v2/actors/runtime/proof" - proof5 "github.com/filecoin-project/specs-actors/v5/actors/runtime/proof" + proof7 "github.com/filecoin-project/specs-actors/v7/actors/runtime/proof" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" @@ -206,14 +205,14 @@ func (pl *pricelistV0) OnComputeUnsealedSectorCid(proofType abi.RegisteredSealPr } // OnVerifySeal -func (pl *pricelistV0) OnVerifySeal(info proof2.SealVerifyInfo) GasCharge { +func (pl *pricelistV0) OnVerifySeal(info proof7.SealVerifyInfo) GasCharge { // TODO: this needs more cost tunning, check with @lotus // this is not used return newGasCharge("OnVerifySeal", pl.verifySealBase, 0) } // OnVerifyAggregateSeals -func (pl *pricelistV0) OnVerifyAggregateSeals(aggregate proof5.AggregateSealVerifyProofAndInfos) GasCharge { +func (pl *pricelistV0) OnVerifyAggregateSeals(aggregate proof7.AggregateSealVerifyProofAndInfos) GasCharge { proofType := aggregate.SealProof perProof, ok := pl.verifyAggregateSealPer[proofType] if !ok { @@ -228,8 +227,14 @@ func (pl *pricelistV0) OnVerifyAggregateSeals(aggregate proof5.AggregateSealVeri return newGasCharge("OnVerifyAggregateSeals", perProof*num+step.Lookup(num), 0) } +// OnVerifyReplicaUpdate +func (pl *pricelistV0) OnVerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) GasCharge { + // TODO: do the thing + return GasCharge{} +} + // OnVerifyPost -func (pl *pricelistV0) OnVerifyPost(info proof2.WindowPoStVerifyInfo) GasCharge { +func (pl *pricelistV0) OnVerifyPost(info proof7.WindowPoStVerifyInfo) GasCharge { sectorSize := "unknown" var proofType abi.RegisteredPoStProof diff --git a/chain/vm/invoker.go b/chain/vm/invoker.go index 85357e51bda..8a7a4c8c9d0 100644 --- a/chain/vm/invoker.go +++ b/chain/vm/invoker.go @@ -16,7 +16,7 @@ import ( cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" - vmr "github.com/filecoin-project/specs-actors/v5/actors/runtime" + vmr "github.com/filecoin-project/specs-actors/v7/actors/runtime" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/exitcode" diff --git a/chain/vm/mkactor.go b/chain/vm/mkactor.go index ea49abff30a..5716b50067b 100644 --- a/chain/vm/mkactor.go +++ b/chain/vm/mkactor.go @@ -26,6 +26,7 @@ import ( builtin4 "github.com/filecoin-project/specs-actors/v4/actors/builtin" builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + builtin7 "github.com/filecoin-project/specs-actors/v7/actors/builtin" /* inline-gen end */ @@ -130,6 +131,8 @@ func newAccountActor(ver actors.Version) *types.Actor { code = builtin5.AccountActorCodeID case actors.Version6: code = builtin6.AccountActorCodeID + case actors.Version7: + code = builtin7.AccountActorCodeID /* inline-gen end */ default: panic("unsupported actors version") diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 6e94030bd2a..583c99593b9 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -17,7 +17,7 @@ import ( rtt "github.com/filecoin-project/go-state-types/rt" rt0 "github.com/filecoin-project/specs-actors/actors/runtime" rt5 "github.com/filecoin-project/specs-actors/v5/actors/runtime" - rt6 "github.com/filecoin-project/specs-actors/v6/actors/runtime" + rt7 "github.com/filecoin-project/specs-actors/v7/actors/runtime" "github.com/ipfs/go-cid" ipldcbor "github.com/ipfs/go-ipld-cbor" "go.opencensus.io/trace" @@ -55,8 +55,8 @@ func (m *Message) ValueReceived() abi.TokenAmount { var EnableGasTracing = false type Runtime struct { - rt5.Message - rt5.Syscalls + rt7.Message + rt7.Syscalls ctx context.Context @@ -142,7 +142,7 @@ func (rt *Runtime) StorePut(x cbor.Marshaler) cid.Cid { var _ rt0.Runtime = (*Runtime)(nil) var _ rt5.Runtime = (*Runtime)(nil) -var _ rt6.Runtime = (*Runtime)(nil) +var _ rt7.Runtime = (*Runtime)(nil) func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.ActorError) { defer func() { diff --git a/chain/vm/syscalls.go b/chain/vm/syscalls.go index 0cbefd1fd7f..b8c027bd7b4 100644 --- a/chain/vm/syscalls.go +++ b/chain/vm/syscalls.go @@ -7,6 +7,8 @@ import ( goruntime "runtime" "sync" + proof5 "github.com/filecoin-project/specs-actors/v5/actors/runtime/proof" + "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" "github.com/minio/blake2b-simd" @@ -26,8 +28,8 @@ import ( "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" "github.com/filecoin-project/lotus/lib/sigs" - runtime5 "github.com/filecoin-project/specs-actors/v5/actors/runtime" - proof5 "github.com/filecoin-project/specs-actors/v5/actors/runtime/proof" + runtime7 "github.com/filecoin-project/specs-actors/v7/actors/runtime" + proof7 "github.com/filecoin-project/specs-actors/v7/actors/runtime/proof" ) func init() { @@ -36,10 +38,10 @@ func init() { // Actual type is defined in chain/types/vmcontext.go because the VMContext interface is there -type SyscallBuilder func(ctx context.Context, rt *Runtime) runtime5.Syscalls +type SyscallBuilder func(ctx context.Context, rt *Runtime) runtime7.Syscalls func Syscalls(verifier ffiwrapper.Verifier) SyscallBuilder { - return func(ctx context.Context, rt *Runtime) runtime5.Syscalls { + return func(ctx context.Context, rt *Runtime) runtime7.Syscalls { return &syscallShim{ ctx: ctx, @@ -90,7 +92,7 @@ func (ss *syscallShim) HashBlake2b(data []byte) [32]byte { // Checks validity of the submitted consensus fault with the two block headers needed to prove the fault // and an optional extra one to check common ancestry (as needed). // Note that the blocks are ordered: the method requires a.Epoch() <= b.Epoch(). -func (ss *syscallShim) VerifyConsensusFault(a, b, extra []byte) (*runtime5.ConsensusFault, error) { +func (ss *syscallShim) VerifyConsensusFault(a, b, extra []byte) (*runtime7.ConsensusFault, error) { // Note that block syntax is not validated. Any validly signed block will be accepted pursuant to the below conditions. // Whether or not it could ever have been accepted in a chain is not checked/does not matter here. // for that reason when checking block parent relationships, rather than instantiating a Tipset to do so @@ -133,14 +135,14 @@ func (ss *syscallShim) VerifyConsensusFault(a, b, extra []byte) (*runtime5.Conse } // (2) check for the consensus faults themselves - var consensusFault *runtime5.ConsensusFault + var consensusFault *runtime7.ConsensusFault // (a) double-fork mining fault if blockA.Height == blockB.Height { - consensusFault = &runtime5.ConsensusFault{ + consensusFault = &runtime7.ConsensusFault{ Target: blockA.Miner, Epoch: blockB.Height, - Type: runtime5.ConsensusFaultDoubleForkMining, + Type: runtime7.ConsensusFaultDoubleForkMining, } } @@ -148,10 +150,10 @@ func (ss *syscallShim) VerifyConsensusFault(a, b, extra []byte) (*runtime5.Conse // strictly speaking no need to compare heights based on double fork mining check above, // but at same height this would be a different fault. if types.CidArrsEqual(blockA.Parents, blockB.Parents) && blockA.Height != blockB.Height { - consensusFault = &runtime5.ConsensusFault{ + consensusFault = &runtime7.ConsensusFault{ Target: blockA.Miner, Epoch: blockB.Height, - Type: runtime5.ConsensusFaultTimeOffsetMining, + Type: runtime7.ConsensusFaultTimeOffsetMining, } } @@ -171,10 +173,10 @@ func (ss *syscallShim) VerifyConsensusFault(a, b, extra []byte) (*runtime5.Conse if types.CidArrsEqual(blockA.Parents, blockC.Parents) && blockA.Height == blockC.Height && types.CidArrsContains(blockB.Parents, blockC.Cid()) && !types.CidArrsContains(blockB.Parents, blockA.Cid()) { - consensusFault = &runtime5.ConsensusFault{ + consensusFault = &runtime7.ConsensusFault{ Target: blockA.Miner, Epoch: blockB.Height, - Type: runtime5.ConsensusFaultParentGrinding, + Type: runtime7.ConsensusFaultParentGrinding, } } } @@ -286,6 +288,7 @@ func (ss *syscallShim) VerifyAggregateSeals(aggregate proof5.AggregateSealVerify if err != nil { return xerrors.Errorf("failed to verify aggregated PoRep: %w", err) } + if !ok { return fmt.Errorf("invalid aggregate proof") } @@ -293,6 +296,19 @@ func (ss *syscallShim) VerifyAggregateSeals(aggregate proof5.AggregateSealVerify return nil } +func (ss *syscallShim) VerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) error { + ok, err := ss.verifier.VerifyReplicaUpdate(update) + if err != nil { + return xerrors.Errorf("failed to verify replica update: %w", err) + } + + if !ok { + return fmt.Errorf("invalid replica update") + } + + return nil +} + func (ss *syscallShim) VerifySignature(sig crypto.Signature, addr address.Address, input []byte) error { // TODO: in genesis setup, we are currently faking signatures diff --git a/cmd/lotus-bench/caching_verifier.go b/cmd/lotus-bench/caching_verifier.go index f4cc0f83741..7d5e993a08d 100644 --- a/cmd/lotus-bench/caching_verifier.go +++ b/cmd/lotus-bench/caching_verifier.go @@ -5,10 +5,11 @@ import ( "context" "errors" + proof7 "github.com/filecoin-project/specs-actors/v7/actors/runtime/proof" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" proof2 "github.com/filecoin-project/specs-actors/v2/actors/runtime/proof" - proof5 "github.com/filecoin-project/specs-actors/v5/actors/runtime/proof" "github.com/ipfs/go-datastore" "github.com/minio/blake2b-simd" cbg "github.com/whyrusleeping/cbor-gen" @@ -97,8 +98,12 @@ func (cv *cachingVerifier) GenerateWinningPoStSectorChallenge(ctx context.Contex return cv.backend.GenerateWinningPoStSectorChallenge(ctx, proofType, a, rnd, u) } -func (cv cachingVerifier) VerifyAggregateSeals(aggregate proof5.AggregateSealVerifyProofAndInfos) (bool, error) { +func (cv cachingVerifier) VerifyAggregateSeals(aggregate proof7.AggregateSealVerifyProofAndInfos) (bool, error) { return cv.backend.VerifyAggregateSeals(aggregate) } +func (cv cachingVerifier) VerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) (bool, error) { + return cv.backend.VerifyReplicaUpdate(update) +} + var _ ffiwrapper.Verifier = (*cachingVerifier)(nil) diff --git a/cmd/lotus-sim/simulation/mock/mock.go b/cmd/lotus-sim/simulation/mock/mock.go index 38648f758dc..7656aaa28a6 100644 --- a/cmd/lotus-sim/simulation/mock/mock.go +++ b/cmd/lotus-sim/simulation/mock/mock.go @@ -6,6 +6,8 @@ import ( "encoding/binary" "fmt" + proof7 "github.com/filecoin-project/specs-actors/v7/actors/runtime/proof" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" @@ -70,6 +72,12 @@ func (mockVerifier) VerifyAggregateSeals(aggregate proof5.AggregateSealVerifyPro ) return false, nil } + +// TODO: do the thing +func (mockVerifier) VerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) (bool, error) { + return false, nil +} + func (mockVerifier) VerifyWinningPoSt(ctx context.Context, info proof5.WinningPoStVerifyInfo) (bool, error) { panic("should not be called") } diff --git a/documentation/en/api-v0-methods.md b/documentation/en/api-v0-methods.md index 4d953082116..42bb945d0f1 100644 --- a/documentation/en/api-v0-methods.md +++ b/documentation/en/api-v0-methods.md @@ -4698,7 +4698,7 @@ Inputs: ] ``` -Response: `14` +Response: `15` ### StateReadState StateReadState returns the indicated actor's state. diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index b03f75e9d05..3578a449218 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -4948,7 +4948,7 @@ Inputs: ] ``` -Response: `14` +Response: `15` ### StateReadState StateReadState returns the indicated actor's state. diff --git a/extern/sector-storage/ffiwrapper/types.go b/extern/sector-storage/ffiwrapper/types.go index a5b2fdf1fa0..1da7ea832b8 100644 --- a/extern/sector-storage/ffiwrapper/types.go +++ b/extern/sector-storage/ffiwrapper/types.go @@ -4,6 +4,8 @@ import ( "context" "io" + proof7 "github.com/filecoin-project/specs-actors/v7/actors/runtime/proof" + proof5 "github.com/filecoin-project/specs-actors/v5/actors/runtime/proof" "github.com/ipfs/go-cid" @@ -36,6 +38,7 @@ type Storage interface { type Verifier interface { VerifySeal(proof5.SealVerifyInfo) (bool, error) VerifyAggregateSeals(aggregate proof5.AggregateSealVerifyProofAndInfos) (bool, error) + VerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) (bool, error) VerifyWinningPoSt(ctx context.Context, info proof5.WinningPoStVerifyInfo) (bool, error) VerifyWindowPoSt(ctx context.Context, info proof5.WindowPoStVerifyInfo) (bool, error) diff --git a/extern/sector-storage/ffiwrapper/verifier_cgo.go b/extern/sector-storage/ffiwrapper/verifier_cgo.go index ff35ddc1f12..37256b26fd0 100644 --- a/extern/sector-storage/ffiwrapper/verifier_cgo.go +++ b/extern/sector-storage/ffiwrapper/verifier_cgo.go @@ -6,6 +6,8 @@ package ffiwrapper import ( "context" + proof7 "github.com/filecoin-project/specs-actors/v7/actors/runtime/proof" + "go.opencensus.io/trace" "golang.org/x/xerrors" @@ -120,6 +122,11 @@ func (proofVerifier) VerifyAggregateSeals(aggregate proof5.AggregateSealVerifyPr return ffi.VerifyAggregateSeals(aggregate) } +func (proofVerifier) VerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) (bool, error) { + //TODO: do the thing + return false, nil +} + func (proofVerifier) VerifyWinningPoSt(ctx context.Context, info proof5.WinningPoStVerifyInfo) (bool, error) { info.Randomness[31] &= 0x3f _, span := trace.StartSpan(ctx, "VerifyWinningPoSt") diff --git a/extern/sector-storage/mock/mock.go b/extern/sector-storage/mock/mock.go index 273f0928e41..8fb356d0bdd 100644 --- a/extern/sector-storage/mock/mock.go +++ b/extern/sector-storage/mock/mock.go @@ -10,6 +10,8 @@ import ( "math/rand" "sync" + proof7 "github.com/filecoin-project/specs-actors/v7/actors/runtime/proof" + proof5 "github.com/filecoin-project/specs-actors/v5/actors/runtime/proof" ffiwrapper2 "github.com/filecoin-project/go-commp-utils/ffiwrapper" @@ -547,6 +549,11 @@ func (m mockVerifProver) VerifyAggregateSeals(aggregate proof5.AggregateSealVeri return ok, nil } +// TODO: do the thing +func (m mockVerifProver) VerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) (bool, error) { + return false, nil +} + func (m mockVerifProver) AggregateSealProofs(aggregateInfo proof5.AggregateSealVerifyProofAndInfos, proofs [][]byte) ([]byte, error) { out := make([]byte, m.aggLen(len(aggregateInfo.Infos))) // todo: figure out more real length for pi, proof := range proofs { diff --git a/gen/inlinegen-data.json b/gen/inlinegen-data.json index e26b1b28f7d..ef97db6518f 100644 --- a/gen/inlinegen-data.json +++ b/gen/inlinegen-data.json @@ -1,7 +1,7 @@ { - "actorVersions": [0, 2, 3, 4, 5, 6], - "latestActorsVersion": 6, + "actorVersions": [0, 2, 3, 4, 5, 6, 7], + "latestActorsVersion": 7, - "networkVersions": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], - "latestNetworkVersion": 14 + "networkVersions": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + "latestNetworkVersion": 15 } diff --git a/go.mod b/go.mod index 37e6bb9165c..fd898ab5f96 100644 --- a/go.mod +++ b/go.mod @@ -50,6 +50,7 @@ require ( github.com/filecoin-project/specs-actors/v4 v4.0.1 github.com/filecoin-project/specs-actors/v5 v5.0.4 github.com/filecoin-project/specs-actors/v6 v6.0.1 + github.com/filecoin-project/specs-actors/v7 v7.0.0-20211110223913-e2abd33b42d4 github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 github.com/filecoin-project/test-vectors/schema v0.0.5 github.com/gbrlsnchs/jwt/v3 v3.0.1 diff --git a/go.sum b/go.sum index 6019140fce8..c9f2d33cbf5 100644 --- a/go.sum +++ b/go.sum @@ -391,8 +391,13 @@ github.com/filecoin-project/specs-actors/v4 v4.0.1/go.mod h1:TkHXf/l7Wyw4ZejyXIP github.com/filecoin-project/specs-actors/v5 v5.0.0-20210512015452-4fe3889fff57/go.mod h1:283yBMMUSDB2abcjP/hhrwTkhb9h3sfM6KGrep/ZlBI= github.com/filecoin-project/specs-actors/v5 v5.0.4 h1:OY7BdxJWlUfUFXWV/kpNBYGXNPasDIedf42T3sGx08s= github.com/filecoin-project/specs-actors/v5 v5.0.4/go.mod h1:5BAKRAMsOOlD8+qCw4UvT/lTLInCJ3JwOWZbX8Ipwq4= +github.com/filecoin-project/specs-actors/v6 v6.0.0/go.mod h1:V1AYfi5GkHXipx1mnVivoICZh3wtwPxDVuds+fbfQtk= github.com/filecoin-project/specs-actors/v6 v6.0.1 h1:laxvHNsvrq83Y9n+W7znVCePi3oLyRf0Rkl4jFO8Wew= github.com/filecoin-project/specs-actors/v6 v6.0.1/go.mod h1:V1AYfi5GkHXipx1mnVivoICZh3wtwPxDVuds+fbfQtk= +github.com/filecoin-project/specs-actors/v7 v7.0.0-20211109185520-8807da1012c5 h1:8SCNu2TkLCfsS8BpRfeOVt5e4pw2Ej3GInDlFEWqKHo= +github.com/filecoin-project/specs-actors/v7 v7.0.0-20211109185520-8807da1012c5/go.mod h1:F3/N4dIRgwEcSk7xp3RizaVyBE/Jlzhv9Le1/ZH50ZA= +github.com/filecoin-project/specs-actors/v7 v7.0.0-20211110223913-e2abd33b42d4 h1:5sswsw6rhw/JFG5+xU4En5na4K5QPf3jZ33zvAzGrY8= +github.com/filecoin-project/specs-actors/v7 v7.0.0-20211110223913-e2abd33b42d4/go.mod h1:F3/N4dIRgwEcSk7xp3RizaVyBE/Jlzhv9Le1/ZH50ZA= github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 h1:Ur/l2+6qN+lQiqjozWWc5p9UDaAMDZKTlDS98oRnlIw= github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/test-vectors/schema v0.0.5 h1:w3zHQhzM4pYxJDl21avXjOKBLF8egrvwUwjpT8TquDg= diff --git a/itests/kit/ensemble_opts_nv.go b/itests/kit/ensemble_opts_nv.go index 0d7d87e6aa5..45ed514439d 100644 --- a/itests/kit/ensemble_opts_nv.go +++ b/itests/kit/ensemble_opts_nv.go @@ -49,12 +49,12 @@ func LatestActorsAt(upgradeHeight abi.ChainEpoch) EnsembleOpt { }) /* inline-gen start */ return UpgradeSchedule(stmgr.Upgrade{ - Network: network.Version13, + Network: network.Version14, Height: -1, }, stmgr.Upgrade{ - Network: network.Version14, + Network: network.Version15, Height: upgradeHeight, - Migration: filcns.UpgradeActorsV6, + Migration: filcns.UpgradeActorsV7, }) /* inline-gen end */ } diff --git a/lotuspond/front/src/chain/methods.json b/lotuspond/front/src/chain/methods.json index c0f69d58ca9..1f6191a9425 100644 --- a/lotuspond/front/src/chain/methods.json +++ b/lotuspond/front/src/chain/methods.json @@ -622,5 +622,112 @@ "AddVerifiedClient", "UseBytes", "RestoreBytes" + ], + "fil/7/account": [ + "Send", + "Constructor", + "PubkeyAddress" + ], + "fil/7/cron": [ + "Send", + "Constructor", + "EpochTick" + ], + "fil/7/init": [ + "Send", + "Constructor", + "Exec" + ], + "fil/7/multisig": [ + "Send", + "Constructor", + "Propose", + "Approve", + "Cancel", + "AddSigner", + "RemoveSigner", + "SwapSigner", + "ChangeNumApprovalsThreshold", + "LockBalance" + ], + "fil/7/paymentchannel": [ + "Send", + "Constructor", + "UpdateChannelState", + "Settle", + "Collect" + ], + "fil/7/reward": [ + "Send", + "Constructor", + "AwardBlockReward", + "ThisEpochReward", + "UpdateNetworkKPI" + ], + "fil/7/storagemarket": [ + "Send", + "Constructor", + "AddBalance", + "WithdrawBalance", + "PublishStorageDeals", + "VerifyDealsForActivation", + "ActivateDeals", + "OnMinerSectorsTerminate", + "ComputeDataCommitment", + "CronTick" + ], + "fil/7/storageminer": [ + "Send", + "Constructor", + "ControlAddresses", + "ChangeWorkerAddress", + "ChangePeerID", + "SubmitWindowedPoSt", + "PreCommitSector", + "ProveCommitSector", + "ExtendSectorExpiration", + "TerminateSectors", + "DeclareFaults", + "DeclareFaultsRecovered", + "OnDeferredCronEvent", + "CheckSectorProven", + "ApplyRewards", + "ReportConsensusFault", + "WithdrawBalance", + "ConfirmSectorProofsValid", + "ChangeMultiaddrs", + "CompactPartitions", + "CompactSectorNumbers", + "ConfirmUpdateWorkerKey", + "RepayDebt", + "ChangeOwnerAddress", + "DisputeWindowedPoSt", + "PreCommitSectorBatch", + "ProveCommitAggregate", + "ProveReplicaUpdates" + ], + "fil/7/storagepower": [ + "Send", + "Constructor", + "CreateMiner", + "UpdateClaimedPower", + "EnrollCronEvent", + "OnEpochTickEnd", + "UpdatePledgeTotal", + "SubmitPoRepForBulkVerify", + "CurrentTotalPower" + ], + "fil/7/system": [ + "Send", + "Constructor" + ], + "fil/7/verifiedregistry": [ + "Send", + "Constructor", + "AddVerifier", + "RemoveVerifier", + "AddVerifiedClient", + "UseBytes", + "RestoreBytes" ] } \ No newline at end of file diff --git a/storage/wdpost_run_test.go b/storage/wdpost_run_test.go index 78d9431d40a..9ece295caa9 100644 --- a/storage/wdpost_run_test.go +++ b/storage/wdpost_run_test.go @@ -5,6 +5,8 @@ import ( "context" "testing" + proof7 "github.com/filecoin-project/specs-actors/v7/actors/runtime/proof" + builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" miner5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/miner" @@ -22,12 +24,6 @@ import ( "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/dline" "github.com/filecoin-project/go-state-types/network" - builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" - miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" - proof2 "github.com/filecoin-project/specs-actors/v2/actors/runtime/proof" - tutils "github.com/filecoin-project/specs-actors/v2/support/testing" - proof5 "github.com/filecoin-project/specs-actors/v5/actors/runtime/proof" - "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" @@ -35,6 +31,10 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/extern/sector-storage/storiface" "github.com/filecoin-project/lotus/journal" + builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" + miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" + proof2 "github.com/filecoin-project/specs-actors/v2/actors/runtime/proof" + tutils "github.com/filecoin-project/specs-actors/v2/support/testing" ) type mockStorageMinerAPI struct { @@ -149,7 +149,11 @@ func (m mockVerif) VerifyWindowPoSt(ctx context.Context, info proof2.WindowPoStV return true, nil } -func (m mockVerif) VerifyAggregateSeals(aggregate proof5.AggregateSealVerifyProofAndInfos) (bool, error) { +func (m mockVerif) VerifyAggregateSeals(aggregate proof7.AggregateSealVerifyProofAndInfos) (bool, error) { + panic("implement me") +} + +func (m mockVerif) VerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) (bool, error) { panic("implement me") } diff --git a/testplans/lotus-soup/go.mod b/testplans/lotus-soup/go.mod index 7f4a5363052..fdf53cfc227 100644 --- a/testplans/lotus-soup/go.mod +++ b/testplans/lotus-soup/go.mod @@ -3,15 +3,15 @@ module github.com/filecoin-project/lotus/testplans/lotus-soup go 1.16 require ( - contrib.go.opencensus.io/exporter/prometheus v0.1.0 + contrib.go.opencensus.io/exporter/prometheus v0.4.0 github.com/codeskyblue/go-sh v0.0.0-20200712050446-30169cf553fe github.com/davecgh/go-spew v1.1.1 github.com/drand/drand v1.2.1 - github.com/filecoin-project/go-address v0.0.5 - github.com/filecoin-project/go-data-transfer v1.10.1 - github.com/filecoin-project/go-fil-markets v1.12.0 - github.com/filecoin-project/go-jsonrpc v0.1.4-0.20210217175800-45ea43ac2bec - github.com/filecoin-project/go-state-types v0.1.1-0.20210915140513-d354ccf10379 + github.com/filecoin-project/go-address v0.0.6 + github.com/filecoin-project/go-data-transfer v1.11.4 + github.com/filecoin-project/go-fil-markets v1.13.3 + github.com/filecoin-project/go-jsonrpc v0.1.5 + github.com/filecoin-project/go-state-types v0.1.1 github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b github.com/filecoin-project/lotus v0.0.0-00010101000000-000000000000 github.com/filecoin-project/specs-actors v0.9.14 @@ -21,17 +21,17 @@ require ( github.com/influxdata/influxdb v1.9.4 // indirect github.com/ipfs/go-cid v0.1.0 github.com/ipfs/go-datastore v0.4.6 - github.com/ipfs/go-ipfs-files v0.0.8 + github.com/ipfs/go-ipfs-files v0.0.9 github.com/ipfs/go-ipld-format v0.2.0 github.com/ipfs/go-log/v2 v2.3.0 - github.com/ipfs/go-merkledag v0.3.2 + github.com/ipfs/go-merkledag v0.4.1 github.com/ipfs/go-unixfs v0.2.6 - github.com/ipld/go-car v0.3.1-null-padded-files + github.com/ipld/go-car v0.3.2-0.20211001225732-32d0d9933823 github.com/kpacha/opencensus-influxdb v0.0.0-20181102202715-663e2683a27c github.com/libp2p/go-libp2p v0.15.0 github.com/libp2p/go-libp2p-core v0.9.0 github.com/libp2p/go-libp2p-pubsub-tracer v0.0.0-20200626141350-e730b32bf1e6 - github.com/multiformats/go-multiaddr v0.4.0 + github.com/multiformats/go-multiaddr v0.4.1 github.com/testground/sdk-go v0.2.6 go.opencensus.io v0.23.0 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c diff --git a/testplans/lotus-soup/go.sum b/testplans/lotus-soup/go.sum index b6246d6349c..b31a9375347 100644 --- a/testplans/lotus-soup/go.sum +++ b/testplans/lotus-soup/go.sum @@ -38,8 +38,10 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= contrib.go.opencensus.io/exporter/jaeger v0.1.0/go.mod h1:VYianECmuFPwU37O699Vc1GOcy+y8kOsfaxHRImmjbA= +contrib.go.opencensus.io/exporter/jaeger v0.2.1/go.mod h1:Y8IsLgdxqh1QxYxPC5IgXVmBaeLUeQFfBeBi9PbeZd0= contrib.go.opencensus.io/exporter/prometheus v0.1.0 h1:SByaIoWwNgMdPSgl5sMqM2KDE5H/ukPWBRo314xiDvg= contrib.go.opencensus.io/exporter/prometheus v0.1.0/go.mod h1:cGFniUXGZlKRjzOyuZJ6mgB+PgBcCIa79kEKR8YCW+A= +contrib.go.opencensus.io/exporter/prometheus v0.4.0/go.mod h1:o7cosnyfuPVK0tB8q0QmaQNhGnptITnPQB+z1+qeFB0= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= @@ -80,6 +82,7 @@ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbt github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= @@ -90,10 +93,12 @@ github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/ github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= +github.com/GeertJohan/go.rice v1.0.2/go.mod h1:af5vUNlDNkCjOZeSGFgIJxDje9qdjsO6hshx0gTmZt4= github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee h1:8doiS7ib3zi6/K172oDhSKU0dJ/miJramo9NITOMyZQ= github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee/go.mod h1:W0GbEAA4uFNYOGG2cJpmFJ04E6SD1NLELPYZB57/7AY= github.com/HdrHistogram/hdrhistogram-go v1.1.0 h1:6dpdDPTRoo78HxAJ6T1HfMiKSnqhgRRqzCuPshRkQ7I= github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/Kubuxu/imtui v0.0.0-20210401140320-41663d68d0fa h1:1PPxEyGdIGVkX/kqMvLJ95a1dGS1Sz7tpNEgehEYYt0= @@ -115,6 +120,7 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo= github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= @@ -146,7 +152,9 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.3.3/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= @@ -159,12 +167,15 @@ github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/aws/aws-sdk-go v1.29.16/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg= github.com/aws/aws-sdk-go v1.30.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.32.11/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aws/aws-sdk-go-v2 v1.3.2/go.mod h1:7OaACgj2SX3XGWnrIjGlJM22h6yD6MEWKvm7levnnM8= +github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= github.com/aws/aws-sdk-go-v2/config v1.1.5/go.mod h1:P3F1hku7qzC81txjwXnwOM6Ex6ezkU6+/557Teyb64E= github.com/aws/aws-sdk-go-v2/credentials v1.1.5/go.mod h1:Ir1R6tPiR1/2y1hes8yOijFMz54hzSmgcmCDo6F45Qc= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.6/go.mod h1:0+fWMitrmIpENiY8/1DyhdYPUCAPvd9UNz9mtCsEoLQ= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.1.2/go.mod h1:Azf567f5wBUfUbwpyJJnLM/geFFIzEulGR30L+nQZOE= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.0.4/go.mod h1:BCfU3Uo2fhKcMZFp9zU5QQGQxqWCOYmZ/27Dju3S/do= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.6/go.mod h1:L0KWr0ASo83PRZu9NaZaDsw3koS6PspKv137DMDZjHo= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.2.2/go.mod h1:nnutjMLuna0s3GVY/MAkpLX03thyNER06gXvnMAPj5g= @@ -172,6 +183,7 @@ github.com/aws/aws-sdk-go-v2/service/s3 v1.5.0/go.mod h1:uwA7gs93Qcss43astPUb1eq github.com/aws/aws-sdk-go-v2/service/sso v1.1.5/go.mod h1:bpGz0tidC4y39sZkQSkpO/J0tzWCMXHbw6FZ0j1GkWM= github.com/aws/aws-sdk-go-v2/service/sts v1.2.2/go.mod h1:ssRzzJ2RZOVuKj2Vx1YE7ypfil/BIlgmQnCSW4DistU= github.com/aws/smithy-go v1.3.1/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= github.com/benbjohnson/clock v1.0.1/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.0.2/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= @@ -214,10 +226,12 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE 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/goterm v1.0.3/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQtB8tE= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/cactus/go-statsd-client/statsd v0.0.0-20191106001114-12b4e2b38748/go.mod h1:l/bIBLeOl9eX+wxJAzxS4TveKRtAqlyDpHjhkfO0MEI= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= github.com/cenkalti/backoff v0.0.0-20181003080854-62661b46c409/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= @@ -228,6 +242,7 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= @@ -239,6 +254,7 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -271,6 +287,7 @@ github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pq github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4PxnR5lg= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/corpix/uarand v0.1.1/go.mod h1:SFKZvkcRoLqVRFZ4u25xPmp6m9ktANfbpXZ7SJ0/FNU= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= @@ -346,10 +363,12 @@ github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7j github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elastic/go-sysinfo v1.3.0 h1:eb2XFGTMlSwG/yyU9Y8jVAYLIzU2sFzWXwo2gmetyrE= github.com/elastic/go-sysinfo v1.3.0/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= +github.com/elastic/go-sysinfo v1.7.0/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY= github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/elastic/gosigar v0.12.0 h1:AsdhYCJlTudhfOYQyFNgx+fIVTfrDO0V1ST0vHgiapU= github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= +github.com/elastic/gosigar v0.14.1/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/ema/qdisc v0.0.0-20190904071900-b82c76788043/go.mod h1:ix4kG2zvdUd8kEKSW0ZTr1XLks0epFpI4j745DXxlNE= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= @@ -358,6 +377,7 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etclabscore/go-jsonschema-walk v0.0.6/go.mod h1:VdfDY72AFAiUhy0ZXEaWSpveGjMT5JcDIm903NGqFwQ= @@ -369,12 +389,15 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/filecoin-project/dagstore v0.4.2/go.mod h1:WY5OoLfnwISCk6eASSF927KKPqLPIlTwmG1qHpA08KY= github.com/filecoin-project/dagstore v0.4.3 h1:yeFl6+2BRY1gOVp/hrZuFa24s7LY0Qqkqx/Gh8lidZs= github.com/filecoin-project/dagstore v0.4.3/go.mod h1:dm/91AO5UaDd3bABFjg/5fmRH99vvpS7g1mykqvz6KQ= github.com/filecoin-project/go-address v0.0.3/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8= github.com/filecoin-project/go-address v0.0.5 h1:SSaFT/5aLfPXycUlFyemoHYhRgdyXClXCyDdNJKPlDM= github.com/filecoin-project/go-address v0.0.5/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8= +github.com/filecoin-project/go-address v0.0.6/go.mod h1:7B0/5DA13n6nHkB8bbGx1gWzG/dbTsZ0fgOJVGsM3TE= github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 h1:t6qDiuGYYngDqaLc2ZUvdtAg4UNxPeOYaXhBWSNsVaM= github.com/filecoin-project/go-amt-ipld/v2 v2.1.0/go.mod h1:nfFPoGyX0CU9SkXX8EoCcSuHN1XcbN0c6KBh7yvP5fs= github.com/filecoin-project/go-amt-ipld/v3 v3.0.0/go.mod h1:Qa95YNAbtoVCTSVtX38aAC1ptBnJfPma1R/zZsKmx4o= @@ -386,14 +409,18 @@ github.com/filecoin-project/go-bitfield v0.2.4 h1:uZ7MeE+XfM5lqrHJZ93OnhQKc/rveW github.com/filecoin-project/go-bitfield v0.2.4/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 h1:av5fw6wmm58FYMgJeoB/lK9XXrgdugYiTqkdxjTy9k8= github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2/go.mod h1:pqTiPHobNkOVM5thSRsHYjyQfq7O5QSCMhvuu9JoDlg= +github.com/filecoin-project/go-cbor-util v0.0.1/go.mod h1:pqTiPHobNkOVM5thSRsHYjyQfq7O5QSCMhvuu9JoDlg= github.com/filecoin-project/go-commp-utils v0.1.1-0.20210427191551-70bf140d31c7 h1:U9Z+76pHCKBmtdxFV7JFZJj7OVm12I6dEKwtMVbq5p0= github.com/filecoin-project/go-commp-utils v0.1.1-0.20210427191551-70bf140d31c7/go.mod h1:6s95K91mCyHY51RPWECZieD3SGWTqIFLf1mPOes9l5U= +github.com/filecoin-project/go-commp-utils v0.1.2/go.mod h1:6s95K91mCyHY51RPWECZieD3SGWTqIFLf1mPOes9l5U= github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 h1:2pMXdBnCiXjfCYx/hLqFxccPoqsSveQFxVLvNxy9bus= github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= +github.com/filecoin-project/go-crypto v0.0.1/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= github.com/filecoin-project/go-data-transfer v1.0.1/go.mod h1:UxvfUAY9v3ub0a21BSK9u3pB2aq30Y0KMsG+w9/ysyo= github.com/filecoin-project/go-data-transfer v1.10.0/go.mod h1:uQtqy6vUAY5v70ZHdkF5mJ8CjVtjj/JA3aOoaqzWTVw= github.com/filecoin-project/go-data-transfer v1.10.1 h1:YQNLwhizxkdfFxegAyrnn3l7WjgMjqDlqFzr18iWiYI= github.com/filecoin-project/go-data-transfer v1.10.1/go.mod h1:CSDMCrPK2lVGodNB1wPEogjFvM9nVGyiL1GNbBRTSdw= +github.com/filecoin-project/go-data-transfer v1.11.4/go.mod h1:2MitLI0ebCkLlPKM7NRggP/t9d+gCcREUKkCKqWRCwU= github.com/filecoin-project/go-ds-versioning v0.1.0 h1:y/X6UksYTsK8TLCI7rttCKEvl8btmWxyFMEeeWGUxIQ= github.com/filecoin-project/go-ds-versioning v0.1.0/go.mod h1:mp16rb4i2QPmxBnmanUx8i/XANp+PFCCJWiAb+VW4/s= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= @@ -405,6 +432,7 @@ github.com/filecoin-project/go-fil-commp-hashhash v0.1.0/go.mod h1:73S8WSEWh9vr0 github.com/filecoin-project/go-fil-markets v1.0.5-0.20201113164554-c5eba40d5335/go.mod h1:AJySOJC00JRWEZzRG2KsfUnqEf5ITXxeX09BE9N4f9c= github.com/filecoin-project/go-fil-markets v1.12.0 h1:RpU5bLaMADVrU4CgLxKMGHC2ZUocNV35uINxogQCf00= github.com/filecoin-project/go-fil-markets v1.12.0/go.mod h1:XuuZFaFujI47nrgfQJiq7jWB+6rRya6nm7Sj6uXQ80U= +github.com/filecoin-project/go-fil-markets v1.13.3/go.mod h1:38zuj8AgDvOfdakFLpC/syYIYgXTzkq7xqBJ6T1AuG4= github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM= github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24= github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 h1:b3UDemBYN2HNfk3KOXNuxgTTxlWi3xVvbQP0IT38fvM= @@ -414,10 +442,12 @@ github.com/filecoin-project/go-hamt-ipld/v3 v3.1.0 h1:rVVNq0x6RGQIzCo1iiJlGFm9AG github.com/filecoin-project/go-hamt-ipld/v3 v3.1.0/go.mod h1:bxmzgT8tmeVQA1/gvBwFmYdT8SOFUwB3ovSUfG1Ux0g= github.com/filecoin-project/go-jsonrpc v0.1.4-0.20210217175800-45ea43ac2bec h1:rGI5I7fdU4viManxmDdbk5deZO7afe6L1Wc04dAmlOM= github.com/filecoin-project/go-jsonrpc v0.1.4-0.20210217175800-45ea43ac2bec/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= +github.com/filecoin-project/go-jsonrpc v0.1.5/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-multistore v0.0.3/go.mod h1:kaNqCC4IhU4B1uyr7YWFHd23TL4KM32aChS0jNkyUvQ= github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20/go.mod h1:mPn+LRRd5gEKNAtc+r3ScpW2JRU/pj4NBKdADYWHiak= github.com/filecoin-project/go-padreader v0.0.0-20210723183308-812a16dc01b1 h1:0BogtftbcgyBx4lP2JWM00ZK7/pXmgnrDqKp9aLTgVs= github.com/filecoin-project/go-padreader v0.0.0-20210723183308-812a16dc01b1/go.mod h1:VYVPJqwpsfmtoHnAmPx6MUwmrK6HIcDqZJiuZhtmfLQ= +github.com/filecoin-project/go-padreader v0.0.1/go.mod h1:VYVPJqwpsfmtoHnAmPx6MUwmrK6HIcDqZJiuZhtmfLQ= github.com/filecoin-project/go-paramfetch v0.0.2 h1:a6W3Ij6CKhwHYYlx+5mqvBIyw4CabZH2ojdEaoAZ6/g= github.com/filecoin-project/go-paramfetch v0.0.2/go.mod h1:1FH85P8U+DUEmWk1Jkw3Bw7FrwTVUNHk/95PSPG+dts= github.com/filecoin-project/go-state-types v0.0.0-20200903145444-247639ffa6ad/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= @@ -428,6 +458,8 @@ github.com/filecoin-project/go-state-types v0.1.0/go.mod h1:ezYnPf0bNkTsDibL/psS github.com/filecoin-project/go-state-types v0.1.1-0.20210506134452-99b279731c48/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-state-types v0.1.1-0.20210810190654-139e0e79e69e h1:XAgb6HmgXaGRklNjhZoNMSIYriKLqjWXIqYMotg6iSs= github.com/filecoin-project/go-state-types v0.1.1-0.20210810190654-139e0e79e69e/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= +github.com/filecoin-project/go-state-types v0.1.1-0.20210915140513-d354ccf10379/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= +github.com/filecoin-project/go-state-types v0.1.1/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v1.0.1 h1:LQ60+JDVjMdLxXmVFM2jjontzOYnfVE7u02CXV3WKSw= github.com/filecoin-project/go-statemachine v1.0.1/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54= @@ -454,6 +486,9 @@ github.com/filecoin-project/specs-actors/v4 v4.0.1/go.mod h1:TkHXf/l7Wyw4ZejyXIP github.com/filecoin-project/specs-actors/v5 v5.0.0-20210512015452-4fe3889fff57/go.mod h1:283yBMMUSDB2abcjP/hhrwTkhb9h3sfM6KGrep/ZlBI= github.com/filecoin-project/specs-actors/v5 v5.0.4 h1:OY7BdxJWlUfUFXWV/kpNBYGXNPasDIedf42T3sGx08s= github.com/filecoin-project/specs-actors/v5 v5.0.4/go.mod h1:5BAKRAMsOOlD8+qCw4UvT/lTLInCJ3JwOWZbX8Ipwq4= +github.com/filecoin-project/specs-actors/v6 v6.0.0/go.mod h1:V1AYfi5GkHXipx1mnVivoICZh3wtwPxDVuds+fbfQtk= +github.com/filecoin-project/specs-actors/v6 v6.0.1/go.mod h1:V1AYfi5GkHXipx1mnVivoICZh3wtwPxDVuds+fbfQtk= +github.com/filecoin-project/specs-actors/v7 v7.0.0-20211104150953-8bd473fc487a/go.mod h1:F3/N4dIRgwEcSk7xp3RizaVyBE/Jlzhv9Le1/ZH50ZA= github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 h1:Ur/l2+6qN+lQiqjozWWc5p9UDaAMDZKTlDS98oRnlIw= github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/test-vectors/schema v0.0.5/go.mod h1:iQ9QXLpYWL3m7warwvK1JC/pTri8mnfEmKygNDqqY6E= @@ -467,6 +502,7 @@ github.com/foxcpp/go-mockdns v0.0.0-20201212160233-ede2f9158d15/go.mod h1:tPg4cp github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= @@ -475,6 +511,7 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 h1:EzDjxMg43q1tA2c0MV3tNbaontnHLplHyFF6M5KiVP0= github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1/go.mod h1:0eHX/BVySxPc6SE2mZRoppGq7qcEagxdmQnA3dzork8= +github.com/gbrlsnchs/jwt/v3 v3.0.1/go.mod h1:AncDcjXz18xetI3A6STfXq2w+LuTx8pQ8bGEwRN8zVM= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell/v2 v2.2.0 h1:vSyEgKwraXPSOkvCk7IwOSyX+Pv3V2cV9CikJMXg4U4= @@ -500,15 +537,19 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= @@ -581,6 +622,7 @@ github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= @@ -609,6 +651,7 @@ github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968 h1:s+PDl6lozQ+dEUtUtQn github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -627,6 +670,7 @@ github.com/gogo/status v1.0.3/go.mod h1:SavQ51ycCLnc7dGyJxp8YAmudx8xqiVrRf+6IXRs github.com/gogo/status v1.1.0 h1:+eIkrewn5q6b30y+g/BJINVVdi2xH7je5MPJ3ZPK3JA= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= @@ -637,6 +681,7 @@ github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -670,6 +715,7 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8l github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf h1:gFVkHXmVAhEbxZVDln5V9GKrLaluNoFHDbrZwAWZgws= github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -687,6 +733,7 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -759,16 +806,21 @@ github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e h1:3YKHER4n github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e/go.mod h1:I8h3MITA53gN9OnWGCgaMa0JWVRdXthWw4M3CPM54OY= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/api v1.4.0/go.mod h1:xc8u05kyMa3Wjr9eEAsIAo3dg8+LywT5E/Cl7cNS5nU= +github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.4.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v0.12.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.2.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= @@ -796,12 +848,15 @@ github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.2.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.9.0/go.mod h1:YL0HO+FifKOW2u1ke99DGVu1zhcpZzNwrLIqBC7vbYU= +github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hodgesds/perf-utils v0.0.8/go.mod h1:F6TfvsbtrF88i++hou29dTXlI2sfsJv+gRZDtmTJkAs= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= github.com/huin/goupnp v1.0.2 h1:RfGLP+h3mvisuWEyybxNq5Eft3NWhHLPeUN72kpKZoI= github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM= @@ -810,6 +865,8 @@ github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0 github.com/iancoleman/orderedmap v0.1.0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428/go.mod h1:uhpZMVGznybq1itEKXj6RYw9I71qK4kH+OGMjRC4KEo= +github.com/icza/backscanner v0.0.0-20210726202459-ac2ffc679f94/go.mod h1:GYeBD1CF7AqnKZK+UCytLcY3G+UKo0ByXX/3xfdNyqQ= +github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA= github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -823,6 +880,7 @@ github.com/influxdata/influxdb-client-go/v2 v2.3.1-0.20210518120617-5d1fff431040 github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/influxdb1-client v0.0.0-20200515024757-02f0bf5dbca3 h1:k3/6a1Shi7GGCp9QpyYuXsMM6ncTOjCzOE9Fd6CDA+Q= github.com/influxdata/influxdb1-client v0.0.0-20200515024757-02f0bf5dbca3/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/influxql v1.1.0/go.mod h1:KpVI7okXjK6PRi3Z5B+mtKZli+R1DnZgb3N+tzevNgo= github.com/influxdata/influxql v1.1.1-0.20210223160523-b6ab99450c93/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk= github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= @@ -852,6 +910,7 @@ github.com/ipfs/go-blockservice v0.1.3/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYI github.com/ipfs/go-blockservice v0.1.4-0.20200624145336-a978cec6e834/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= github.com/ipfs/go-blockservice v0.1.5 h1:euqZu96CCbToPyYVwVshu8ENURi8BhFd7FUFfTLi+fQ= github.com/ipfs/go-blockservice v0.1.5/go.mod h1:yLk8lBJCBRWRqerqCSVi3cE/Dncdt3vGC/PJMVKhLTY= +github.com/ipfs/go-blockservice v0.1.7/go.mod h1:GmS+BAt4hrwBKkzE11AFDQUrnvqjwFatGS2MY7wOjEM= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= @@ -910,10 +969,13 @@ github.com/ipfs/go-graphsync v0.4.3/go.mod h1:mPOwDYv128gf8gxPFgXnz4fNrSYPsWyqis github.com/ipfs/go-graphsync v0.9.0/go.mod h1:J62ahWT9JbPsFL2UWsUM5rOu0lZJ0LOIH1chHdxGGcw= github.com/ipfs/go-graphsync v0.9.1 h1:jo7ZaAZ3lal89RhKxKoRkPzIO8lmOY6KUWA1mDRZ2+U= github.com/ipfs/go-graphsync v0.9.1/go.mod h1:J62ahWT9JbPsFL2UWsUM5rOu0lZJ0LOIH1chHdxGGcw= +github.com/ipfs/go-graphsync v0.10.0/go.mod h1:cKIshzTaa5rCZjryH5xmSKZVGX9uk1wvwGvz2WEha5Y= +github.com/ipfs/go-graphsync v0.10.4/go.mod h1:oei4tnWAKnZ6LPnapZGPYVVbyiKV1UP3f8BeLU7Z4JQ= github.com/ipfs/go-hamt-ipld v0.1.1/go.mod h1:1EZCr2v0jlCnhpa+aZ0JZYp8Tt2w16+JJOAVz17YcDk= github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= +github.com/ipfs/go-ipfs-blockstore v0.1.6/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= github.com/ipfs/go-ipfs-blockstore v1.0.0/go.mod h1:knLVdhVU9L7CC4T+T4nvGdeUIPAXlnd9zmXfp+9MIjU= github.com/ipfs/go-ipfs-blockstore v1.0.1/go.mod h1:MGNZlHNEnR4KGgPHM3/k8lBySIOK2Ve+0KjZubKlaOE= github.com/ipfs/go-ipfs-blockstore v1.0.3/go.mod h1:MGNZlHNEnR4KGgPHM3/k8lBySIOK2Ve+0KjZubKlaOE= @@ -943,6 +1005,7 @@ github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjN github.com/ipfs/go-ipfs-files v0.0.4/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= github.com/ipfs/go-ipfs-files v0.0.8 h1:8o0oFJkJ8UkO/ABl8T6ac6tKF3+NIpj67aAB6ZpusRg= github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= +github.com/ipfs/go-ipfs-files v0.0.9/go.mod h1:aFv2uQ/qxWpL/6lidWvnSQmaVqCrf0TBGoUr+C1Fo84= github.com/ipfs/go-ipfs-http-client v0.0.6 h1:k2QllZyP7Fz5hMgsX5hvHfn1WPG9Ngdy5WknQ7JNhBM= github.com/ipfs/go-ipfs-http-client v0.0.6/go.mod h1:8e2dQbntMZKxLfny+tyXJ7bJHZFERp/2vyzZdvkeLMc= github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs= @@ -966,6 +1029,7 @@ github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dC github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= github.com/ipfs/go-ipld-format v0.2.0 h1:xGlJKkArkmBvowr+GMCX0FEZtkro71K1AwiKnL37mwA= github.com/ipfs/go-ipld-format v0.2.0/go.mod h1:3l3C1uKoadTPbeNfrDi+xMInYKlx2Cvg1BuydPSdzQs= +github.com/ipfs/go-ipld-legacy v0.1.0/go.mod h1:86f5P/srAmh9GcIcWQR9lfFLZPrIyyXQeVlOWeeWEuI= github.com/ipfs/go-ipns v0.1.2 h1:O/s/0ht+4Jl9+VoxoUo0zaHjnZUS+aBQIKTuzdZ/ucI= github.com/ipfs/go-ipns v0.1.2/go.mod h1:ioQ0j02o6jdIVW+bmi18f4k2gRf0AV3kZ9KeHYHICnQ= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= @@ -993,6 +1057,7 @@ github.com/ipfs/go-merkledag v0.2.4/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB github.com/ipfs/go-merkledag v0.3.1/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= github.com/ipfs/go-merkledag v0.3.2 h1:MRqj40QkrWkvPswXs4EfSslhZ4RVPRbxwX11js0t1xY= github.com/ipfs/go-merkledag v0.3.2/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= +github.com/ipfs/go-merkledag v0.4.1/go.mod h1:56biPaS6e+IS0eXkEt6A8tG+BUQaEIFqDqJuFfQDBoE= github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= github.com/ipfs/go-metrics-prometheus v0.0.2/go.mod h1:ELLU99AQQNi+zX6GCGm2lAgnzdSH3u5UVlCdqSXnEks= @@ -1003,6 +1068,7 @@ github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3 github.com/ipfs/go-peertaskqueue v0.1.1/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= github.com/ipfs/go-peertaskqueue v0.2.0 h1:2cSr7exUGKYyDeUyQ7P/nHPs9P7Ht/B+ROrpN1EJOjc= github.com/ipfs/go-peertaskqueue v0.2.0/go.mod h1:5/eNrBEbtSKWCG+kQK8K8fGNixoYUnr+P7jivavs9lY= +github.com/ipfs/go-peertaskqueue v0.6.0/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU= github.com/ipfs/go-todocounter v0.0.1/go.mod h1:l5aErvQc8qKE2r7NDMjmq5UNAvuZy0rC8BHOplkWvZ4= github.com/ipfs/go-unixfs v0.2.2-0.20190827150610-868af2e9e5cb/go.mod h1:IwAAgul1UQIcNZzKPYZWOCijryFBeCV79cNubPzol+k= github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw= @@ -1022,6 +1088,7 @@ github.com/ipld/go-car v0.1.1-0.20201119040415-11b6074b6d4d/go.mod h1:2Gys8L8MJ6 github.com/ipld/go-car v0.3.1-0.20210601190600-f512dac51e8e/go.mod h1:wUxBdwOLA9/0HZBi3fnTBzla0MuwlqgJLyrhOg1XaKI= github.com/ipld/go-car v0.3.1-null-padded-files h1:FMD0Ce4tAM9P5aq7yklw2jnVK3ZuoJ4xK6vkL9VLmxs= github.com/ipld/go-car v0.3.1-null-padded-files/go.mod h1:wUxBdwOLA9/0HZBi3fnTBzla0MuwlqgJLyrhOg1XaKI= +github.com/ipld/go-car v0.3.2-0.20211001225732-32d0d9933823/go.mod h1:jSlTph+i/q1jLFoiKKeN69KGG0fXpwrcD0izu5C1Tpo= github.com/ipld/go-car/v2 v2.0.0-beta1.0.20210721090610-5a9d1b217d25/go.mod h1:I2ACeeg6XNBe5pdh5TaR7Ambhfa7If9KXxmXgZsYENU= github.com/ipld/go-car/v2 v2.0.2/go.mod h1:I2ACeeg6XNBe5pdh5TaR7Ambhfa7If9KXxmXgZsYENU= github.com/ipld/go-car/v2 v2.0.3-0.20210811121346-c514a30114d7 h1:6Z0beJSZNsRY+7udoqUl4gQ/tqtrPuRvDySrlsvbqZA= @@ -1034,13 +1101,18 @@ github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e/go.mod h1:uVI github.com/ipld/go-ipld-prime v0.5.1-0.20200828233916-988837377a7f/go.mod h1:0xEgdD6MKbZ1vF0GC+YcR/C4SQCAlRuOjIJ2i0HxqzM= github.com/ipld/go-ipld-prime v0.5.1-0.20201021195245-109253e8a018/go.mod h1:0xEgdD6MKbZ1vF0GC+YcR/C4SQCAlRuOjIJ2i0HxqzM= github.com/ipld/go-ipld-prime v0.9.0/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= +github.com/ipld/go-ipld-prime v0.9.1-0.20210324083106-dc342a9917db/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= +github.com/ipld/go-ipld-prime v0.10.0/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHtEaLglS3ZeV8= github.com/ipld/go-ipld-prime v0.12.0 h1:JapyKWTsJgmhrPI7hfx4V798c/RClr85sXfBZnH1VIw= github.com/ipld/go-ipld-prime v0.12.0/go.mod h1:hy8b93WleDMRKumOJnTIrr0MbbFbx9GD6Kzxa53Xppc= +github.com/ipld/go-ipld-prime v0.12.3-0.20210930132912-0b3aef3ca569/go.mod h1:PaeLYq8k6dJLmDUSLrzkEpoGV4PEfe/1OtFN/eALOc8= +github.com/ipld/go-ipld-prime v0.12.3/go.mod h1:PaeLYq8k6dJLmDUSLrzkEpoGV4PEfe/1OtFN/eALOc8= github.com/ipld/go-ipld-prime-proto v0.0.0-20191113031812-e32bd156a1e5/go.mod h1:gcvzoEDBjwycpXt3LBE061wT9f46szXGHAmj9uoP6fU= github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1/go.mod h1:OAV6xBmuTLsPZ+epzKkPB1e25FHk/vCtyatkdHcArLs= github.com/ipld/go-ipld-prime-proto v0.0.0-20200922192210-9a2bfd4440a6/go.mod h1:3pHYooM9Ea65jewRwrb2u5uHZCNkNTe9ABsVB+SrkH0= github.com/ipld/go-ipld-prime-proto v0.1.0/go.mod h1:11zp8f3sHVgIqtb/c9Kr5ZGqpnCLF1IVTNOez9TopzE= +github.com/ipld/go-ipld-selector-text-lite v0.0.0/go.mod h1:U2CQmFb+uWzfIEF3I1arrDa5rwtj00PrpiwwCO+k1RM= github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 h1:QG4CGBqCeuBo6aZlGAamSkxWdgWfZGeE49eUOWJPA4c= github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52/go.mod h1:fdg+/X9Gg4AsAIzWpEHwnqd+QY3b7lajxyjE1m4hkq4= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= @@ -1086,6 +1158,7 @@ github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= @@ -1117,6 +1190,8 @@ github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0 github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5 h1:2U0HzY8BJ8hVwDKIzp7y4voR9CX/nvcfymLmg2UiOio= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -1324,6 +1399,7 @@ github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuD github.com/libp2p/go-libp2p-peerstore v0.2.8/go.mod h1:gGiPlXdz7mIHd2vfAsHzBNAMqSDkt2UBFwgcITgw1lA= github.com/libp2p/go-libp2p-peerstore v0.2.9 h1:tVa7siDymmzOl3b3+SxPYpQUCnicmK13y6Re1PqWK+g= github.com/libp2p/go-libp2p-peerstore v0.2.9/go.mod h1:zhBaLzxiWpNGQ3+uI17G/OIjmOD8GxKyFuHbrZbgs0w= +github.com/libp2p/go-libp2p-peerstore v0.3.0/go.mod h1:fNX9WlOENMvdx/YD7YO/5Hkrn8+lQIk5A39BHa1HIrM= github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= @@ -1333,6 +1409,7 @@ github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h github.com/libp2p/go-libp2p-pubsub v0.3.2/go.mod h1:Uss7/Cfz872KggNb+doCVPHeCDmXB7z500m/R8DaAUk= github.com/libp2p/go-libp2p-pubsub v0.5.4 h1:rHl9/Xok4zX3zgi0pg0XnUj9Xj2OeXO8oTu85q2+YA8= github.com/libp2p/go-libp2p-pubsub v0.5.4/go.mod h1:gVOzwebXVdSMDQBTfH8ACO5EJ4SQrvsHqCmYsCZpD0E= +github.com/libp2p/go-libp2p-pubsub v0.5.6/go.mod h1:gVOzwebXVdSMDQBTfH8ACO5EJ4SQrvsHqCmYsCZpD0E= github.com/libp2p/go-libp2p-pubsub-tracer v0.0.0-20200626141350-e730b32bf1e6 h1:2lH7rMlvDPSvXeOR+g7FE6aqiEwxtpxWKQL8uigk5fQ= github.com/libp2p/go-libp2p-pubsub-tracer v0.0.0-20200626141350-e730b32bf1e6/go.mod h1:8ZodgKS4qRLayfw9FDKDd9DX4C16/GMofDxSldG8QPI= github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU= @@ -1507,6 +1584,7 @@ github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i github.com/lufia/iostat v1.1.0/go.mod h1:rEPNA0xXgjHQjuI5Cy05sLlS2oRcSlWHRLrvh/AQ+Pg= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magefile/mage v1.9.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -1542,6 +1620,7 @@ github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= @@ -1553,6 +1632,7 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -1590,6 +1670,8 @@ github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4S github.com/mileusna/useragent v0.0.0-20190129205925-3e331f0949a5/go.mod h1:JWhYAp2EXqUtsxTKdeGlY8Wp44M7VxThC9FEoNGi2IE= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= @@ -1598,6 +1680,7 @@ github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -1608,10 +1691,12 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= @@ -1622,6 +1707,7 @@ github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjW github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM= github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= @@ -1637,6 +1723,7 @@ github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWz github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= github.com/multiformats/go-multiaddr v0.4.0 h1:hL/K4ZJhJ5PTw3nwylq9lGU5yArzcAroZmex1ghSEkQ= github.com/multiformats/go-multiaddr v0.4.0/go.mod h1:YcpyLH8ZPudLxQlemYBPhSm0/oCXAT8Z4mzFpyoPyRc= +github.com/multiformats/go-multiaddr v0.4.1/go.mod h1:3afI9HfVW8csiF8UZqtpYRiDyew8pRX7qLIGHu9FLuM= github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.3/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= @@ -1673,6 +1760,7 @@ github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUj github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multihash v0.0.15 h1:hWOPdrNqDjwHDx82vsYGSDZNyktOJJ2dzZJzFkOV1jM= github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= +github.com/multiformats/go-multihash v0.0.16/go.mod h1:zhfEIgVnB/rPMfxgFw15ZmGoNaKyNUIE4IWHG/kC+Ag= github.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/multiformats/go-multistream v0.0.4/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= @@ -1692,10 +1780,16 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q= +github.com/nats-io/jwt/v2 v2.0.3/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY= github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats-server/v2 v2.5.0/go.mod h1:Kj86UtrXAL6LwYRA6H4RqzkHhK0Vcv2ZnKD5WbQ1t3g= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nats.go v1.12.1/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= +github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= @@ -1705,6 +1799,7 @@ github.com/nikkolasg/hexjson v0.0.0-20181101101858-78e39397e00c h1:5bFTChQxSKNwy github.com/nikkolasg/hexjson v0.0.0-20181101101858-78e39397e00c/go.mod h1:7qN3Y0BvzRUf4LofcoJplQL10lsFDb4PYlePTVwrP28= github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg= github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= +github.com/nkovacs/streamquote v1.0.0/go.mod h1:BN+NaZ2CmdKqUuTUXUEm9j95B2TRbpOWpxbJYzzgUsc= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -1758,6 +1853,7 @@ github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTm github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -1766,6 +1862,7 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+Tv1WTxkukpXeMlviSxvL7SRgk= github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= @@ -1789,6 +1886,7 @@ github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXx github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e h1:ZOcivgkkFRnjfoTcGsDq3UQYiBmekwLA+qg0OjyB/ls= github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/alertmanager v0.20.0/go.mod h1:9g2i48FAyZW6BtbsnvHtMHQXl2aVtrORKwKVCQ+nbrg= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -1825,6 +1923,7 @@ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB8 github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.30.0 h1:JEkYlQnpzrzQFxi6gnukFPdQ+ac82oRhzMcIduJu/Ug= github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/node_exporter v1.0.0-rc.0.0.20200428091818-01054558c289/go.mod h1:FGbBv5OPKjch+jNUJmEQpMZytIdyW0NdBtWFcfSKusc= @@ -1845,6 +1944,7 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/prometheus v0.0.0-20200609090129-a6600f564e3c/go.mod h1:S5n0C6tSgdnwWshBUceRx5G1OsjLv/EeZ9t3wIfEtsY= +github.com/prometheus/statsd_exporter v0.21.0/go.mod h1:rbT83sZq2V+p73lHhPZfMc3MLCHmSHelCh9hSGYNLTQ= github.com/raulk/clock v1.1.0 h1:dpb29+UKMbLqiU/jqIJptgLR1nn23HLgMY0sTCDza5Y= github.com/raulk/clock v1.1.0/go.mod h1:3MpVxdZ/ODBQDxbN+kzshf5OSZwPjtMDx6BBXBmOeY0= github.com/raulk/go-watchdog v1.0.1 h1:qgm3DIJAeb+2byneLrQJ7kvmDLGxN2vy3apXyGaDKN4= @@ -1957,7 +2057,9 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -1993,6 +2095,7 @@ github.com/uber/athenadriver v1.1.4/go.mod h1:tQjho4NzXw55LGfSZEcETuYydpY1vtmixU github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-client-go v2.23.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-client-go v2.23.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-client-go v2.28.0+incompatible h1:G4QSBfvPKvg5ZM2j9MrJFdfI5iSljY/WnJqOGFao6HI= github.com/uber/jaeger-client-go v2.28.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v1.5.1-0.20181102163054-1fc5c315e03c/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= @@ -2045,6 +2148,7 @@ github.com/whyrusleeping/cbor-gen v0.0.0-20200812213548-958ddffe352c/go.mod h1:f github.com/whyrusleeping/cbor-gen v0.0.0-20200826160007-0b9f6c5fb163/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20210118024343-169e9d70c0c2/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20210303213153-67a261a1d291/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20210713220151-be142a5ae1a8 h1:TEv7MId88TyIqIUL4hbf9otOookIolMxlEbN0ro671Y= github.com/whyrusleeping/cbor-gen v0.0.0-20210713220151-be142a5ae1a8/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E= @@ -2103,6 +2207,10 @@ go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= @@ -2140,6 +2248,7 @@ go.uber.org/fx v1.9.0/go.mod h1:mFdUyAUuJ3w4jAckiKSKbldsxy1ojpAMJ+dVZg5Y0Aw= go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= @@ -2155,9 +2264,11 @@ go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU= go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= @@ -2187,6 +2298,7 @@ golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -2195,6 +2307,7 @@ golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200422194213-44a606286825/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -2206,12 +2319,15 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e h1:VvfwVmMH40bpMeizC9/K7ipM5Qjucuu16RWfneFPyhQ= golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2247,6 +2363,7 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= @@ -2329,8 +2446,10 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -2367,6 +2486,7 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -2399,6 +2519,7 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2454,6 +2575,8 @@ golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210317225723-c4fcb01b228e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2465,6 +2588,7 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= @@ -2486,6 +2610,7 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2518,6 +2643,7 @@ golang.org/x/tools v0.0.0-20190813034749-528a2984e271/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -2566,6 +2692,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1-0.20210225150353-54dc8c5edb56/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2651,6 +2778,8 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 h1:PDIOdWxZ8eRizhKa1AAvY53xsvLB1cWorMjslvY3VA8= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= @@ -2678,6 +2807,7 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -2774,6 +2904,7 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/structured-merge-diff/v2 v2.0.1/go.mod h1:Wb7vfKAodbKgf6tn1Kl0VvGj7mRH6DGaRcixXEJXTsE= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= From 07f1be0ff6634d9329f1736e5a8162fd18e51a4b Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Tue, 16 Nov 2021 19:09:10 -0500 Subject: [PATCH 02/24] Plug in the FFI call --- extern/filecoin-ffi | 2 +- extern/sector-storage/ffiwrapper/verifier_cgo.go | 4 ++-- go.mod | 2 +- go.sum | 7 +++---- itests/ccupgrade_test.go | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index 7912389334e..e8857b32c34 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit 7912389334e347bbb2eac0520c836830875c39de +Subproject commit e8857b32c348d92258d1452f1e8738ff03d72c6d diff --git a/extern/sector-storage/ffiwrapper/verifier_cgo.go b/extern/sector-storage/ffiwrapper/verifier_cgo.go index 37256b26fd0..5d537870d00 100644 --- a/extern/sector-storage/ffiwrapper/verifier_cgo.go +++ b/extern/sector-storage/ffiwrapper/verifier_cgo.go @@ -123,8 +123,8 @@ func (proofVerifier) VerifyAggregateSeals(aggregate proof5.AggregateSealVerifyPr } func (proofVerifier) VerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) (bool, error) { - //TODO: do the thing - return false, nil + v := ffi.FunctionsSectorUpdate{} + return v.VerifyUpdateProof(update.UpdateProof, update.Proof, update.OldSealedSectorCID, update.NewSealedSectorCID, update.NewUnsealedSectorCID) } func (proofVerifier) VerifyWinningPoSt(ctx context.Context, info proof5.WinningPoStVerifyInfo) (bool, error) { diff --git a/go.mod b/go.mod index fd898ab5f96..1202fd20067 100644 --- a/go.mod +++ b/go.mod @@ -50,7 +50,7 @@ require ( github.com/filecoin-project/specs-actors/v4 v4.0.1 github.com/filecoin-project/specs-actors/v5 v5.0.4 github.com/filecoin-project/specs-actors/v6 v6.0.1 - github.com/filecoin-project/specs-actors/v7 v7.0.0-20211110223913-e2abd33b42d4 + github.com/filecoin-project/specs-actors/v7 v7.0.0-20211116235548-301b685341ad github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 github.com/filecoin-project/test-vectors/schema v0.0.5 github.com/gbrlsnchs/jwt/v3 v3.0.1 diff --git a/go.sum b/go.sum index c9f2d33cbf5..7747074b931 100644 --- a/go.sum +++ b/go.sum @@ -363,6 +363,7 @@ github.com/filecoin-project/go-state-types v0.0.0-20201102161440-c8033295a1fc/go github.com/filecoin-project/go-state-types v0.1.0/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-state-types v0.1.1-0.20210506134452-99b279731c48/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-state-types v0.1.1-0.20210810190654-139e0e79e69e/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= +github.com/filecoin-project/go-state-types v0.1.1-0.20211102152656-6027e22b77fd/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-state-types v0.1.1 h1:LR260vya4p++atgf256W6yV3Lxl5mKrBFcEZePWQrdg= github.com/filecoin-project/go-state-types v0.1.1/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= @@ -394,10 +395,8 @@ github.com/filecoin-project/specs-actors/v5 v5.0.4/go.mod h1:5BAKRAMsOOlD8+qCw4U github.com/filecoin-project/specs-actors/v6 v6.0.0/go.mod h1:V1AYfi5GkHXipx1mnVivoICZh3wtwPxDVuds+fbfQtk= github.com/filecoin-project/specs-actors/v6 v6.0.1 h1:laxvHNsvrq83Y9n+W7znVCePi3oLyRf0Rkl4jFO8Wew= github.com/filecoin-project/specs-actors/v6 v6.0.1/go.mod h1:V1AYfi5GkHXipx1mnVivoICZh3wtwPxDVuds+fbfQtk= -github.com/filecoin-project/specs-actors/v7 v7.0.0-20211109185520-8807da1012c5 h1:8SCNu2TkLCfsS8BpRfeOVt5e4pw2Ej3GInDlFEWqKHo= -github.com/filecoin-project/specs-actors/v7 v7.0.0-20211109185520-8807da1012c5/go.mod h1:F3/N4dIRgwEcSk7xp3RizaVyBE/Jlzhv9Le1/ZH50ZA= -github.com/filecoin-project/specs-actors/v7 v7.0.0-20211110223913-e2abd33b42d4 h1:5sswsw6rhw/JFG5+xU4En5na4K5QPf3jZ33zvAzGrY8= -github.com/filecoin-project/specs-actors/v7 v7.0.0-20211110223913-e2abd33b42d4/go.mod h1:F3/N4dIRgwEcSk7xp3RizaVyBE/Jlzhv9Le1/ZH50ZA= +github.com/filecoin-project/specs-actors/v7 v7.0.0-20211116235548-301b685341ad h1:uUl9I4MCOAkbrY/JI3y6Php3t5c3tu1nux5VkCBwO4E= +github.com/filecoin-project/specs-actors/v7 v7.0.0-20211116235548-301b685341ad/go.mod h1:p6LIOFezA1rgRLMewbvdi3Pp6SAu+q9FtJ9CAleSjrE= github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 h1:Ur/l2+6qN+lQiqjozWWc5p9UDaAMDZKTlDS98oRnlIw= github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/test-vectors/schema v0.0.5 h1:w3zHQhzM4pYxJDl21avXjOKBLF8egrvwUwjpT8TquDg= diff --git a/itests/ccupgrade_test.go b/itests/ccupgrade_test.go index c5b38083512..12bc1fc869a 100644 --- a/itests/ccupgrade_test.go +++ b/itests/ccupgrade_test.go @@ -32,7 +32,7 @@ func runTestCCUpgrade(t *testing.T, upgradeHeight abi.ChainEpoch) { ctx := context.Background() blockTime := 5 * time.Millisecond - client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.LatestActorsAt(upgradeHeight)) + client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.TurboUpgradeAt(upgradeHeight)) ens.InterconnectAll().BeginMining(blockTime) maddr, err := miner.ActorAddress(ctx) From 8665e32221cd1e73435d8a62f9718a655590ea4c Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 17 Nov 2021 12:41:42 -0500 Subject: [PATCH 03/24] Update deps --- chain/consensus/filcns/upgrades.go | 12 +++++------- extern/filecoin-ffi | 2 +- extern/sector-storage/ffiwrapper/verifier_cgo.go | 3 +-- extern/sector-storage/mock/mock.go | 3 +-- go.mod | 2 +- go.sum | 6 ++---- itests/ccupgrade_test.go | 1 + itests/wdpost_test.go | 2 +- 8 files changed, 13 insertions(+), 18 deletions(-) diff --git a/chain/consensus/filcns/upgrades.go b/chain/consensus/filcns/upgrades.go index 43f50311f72..a8e85d78fc1 100644 --- a/chain/consensus/filcns/upgrades.go +++ b/chain/consensus/filcns/upgrades.go @@ -6,6 +6,7 @@ import ( "time" "github.com/filecoin-project/specs-actors/v6/actors/migration/nv14" + "github.com/filecoin-project/specs-actors/v7/actors/migration/nv15" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" @@ -1220,7 +1221,7 @@ func UpgradeActorsV7(ctx context.Context, sm *stmgr.StateManager, cache stmgr.Mi workerCount = 1 } - config := nv14.Config{ + config := nv15.Config{ MaxWorkers: uint(workerCount), JobQueueSize: 1000, ResultQueueSize: 100, @@ -1244,8 +1245,7 @@ func PreUpgradeActorsV7(ctx context.Context, sm *stmgr.StateManager, cache stmgr workerCount /= 2 } - //TODO: nv15 - config := nv14.Config{MaxWorkers: uint(workerCount)} + config := nv15.Config{MaxWorkers: uint(workerCount)} _, err := upgradeActorsV7Common(ctx, sm, cache, root, epoch, ts, config) return err } @@ -1253,8 +1253,7 @@ func PreUpgradeActorsV7(ctx context.Context, sm *stmgr.StateManager, cache stmgr func upgradeActorsV7Common( ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet, - //TODO: nv15 - config nv14.Config, + config nv15.Config, ) (cid.Cid, error) { buf := blockstore.NewTieredBstore(sm.ChainStore().StateBlockstore(), blockstore.NewMemorySync()) store := store.ActorStore(ctx, buf) @@ -1273,8 +1272,7 @@ func upgradeActorsV7Common( } // Perform the migration - //TODO: nv15 - newHamtRoot, err := nv14.MigrateStateTree(ctx, store, stateRoot.Actors, epoch, config, migrationLogger{}, cache) + newHamtRoot, err := nv15.MigrateStateTree(ctx, store, stateRoot.Actors, epoch, config, migrationLogger{}, cache) if err != nil { return cid.Undef, xerrors.Errorf("upgrading to actors v7: %w", err) } diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index e8857b32c34..fe2a3175719 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit e8857b32c348d92258d1452f1e8738ff03d72c6d +Subproject commit fe2a317571931b31fb1ca6dd2adf1414e375b902 diff --git a/extern/sector-storage/ffiwrapper/verifier_cgo.go b/extern/sector-storage/ffiwrapper/verifier_cgo.go index 5d537870d00..94e04f26a25 100644 --- a/extern/sector-storage/ffiwrapper/verifier_cgo.go +++ b/extern/sector-storage/ffiwrapper/verifier_cgo.go @@ -123,8 +123,7 @@ func (proofVerifier) VerifyAggregateSeals(aggregate proof5.AggregateSealVerifyPr } func (proofVerifier) VerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) (bool, error) { - v := ffi.FunctionsSectorUpdate{} - return v.VerifyUpdateProof(update.UpdateProof, update.Proof, update.OldSealedSectorCID, update.NewSealedSectorCID, update.NewUnsealedSectorCID) + return ffi.SectorUpdate.VerifyUpdateProof(update) } func (proofVerifier) VerifyWinningPoSt(ctx context.Context, info proof5.WinningPoStVerifyInfo) (bool, error) { diff --git a/extern/sector-storage/mock/mock.go b/extern/sector-storage/mock/mock.go index 8fb356d0bdd..64568dc2d55 100644 --- a/extern/sector-storage/mock/mock.go +++ b/extern/sector-storage/mock/mock.go @@ -549,9 +549,8 @@ func (m mockVerifProver) VerifyAggregateSeals(aggregate proof5.AggregateSealVeri return ok, nil } -// TODO: do the thing func (m mockVerifProver) VerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) (bool, error) { - return false, nil + return true, nil } func (m mockVerifProver) AggregateSealProofs(aggregateInfo proof5.AggregateSealVerifyProofAndInfos, proofs [][]byte) ([]byte, error) { diff --git a/go.mod b/go.mod index 1202fd20067..e0dc4058319 100644 --- a/go.mod +++ b/go.mod @@ -50,7 +50,7 @@ require ( github.com/filecoin-project/specs-actors/v4 v4.0.1 github.com/filecoin-project/specs-actors/v5 v5.0.4 github.com/filecoin-project/specs-actors/v6 v6.0.1 - github.com/filecoin-project/specs-actors/v7 v7.0.0-20211116235548-301b685341ad + github.com/filecoin-project/specs-actors/v7 v7.0.0-20211117170924-fd07a4c7dff9 github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 github.com/filecoin-project/test-vectors/schema v0.0.5 github.com/gbrlsnchs/jwt/v3 v3.0.1 diff --git a/go.sum b/go.sum index 7747074b931..b91544f8d6f 100644 --- a/go.sum +++ b/go.sum @@ -363,7 +363,6 @@ github.com/filecoin-project/go-state-types v0.0.0-20201102161440-c8033295a1fc/go github.com/filecoin-project/go-state-types v0.1.0/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-state-types v0.1.1-0.20210506134452-99b279731c48/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-state-types v0.1.1-0.20210810190654-139e0e79e69e/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= -github.com/filecoin-project/go-state-types v0.1.1-0.20211102152656-6027e22b77fd/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-state-types v0.1.1 h1:LR260vya4p++atgf256W6yV3Lxl5mKrBFcEZePWQrdg= github.com/filecoin-project/go-state-types v0.1.1/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= @@ -389,14 +388,13 @@ github.com/filecoin-project/specs-actors/v3 v3.1.1/go.mod h1:mpynccOLlIRy0QnR008 github.com/filecoin-project/specs-actors/v4 v4.0.0/go.mod h1:TkHXf/l7Wyw4ZejyXIPS2rK8bBO0rdwhTZyQQgaglng= github.com/filecoin-project/specs-actors/v4 v4.0.1 h1:AiWrtvJZ63MHGe6rn7tPu4nSUY8bA1KDNszqJaD5+Fg= github.com/filecoin-project/specs-actors/v4 v4.0.1/go.mod h1:TkHXf/l7Wyw4ZejyXIPS2rK8bBO0rdwhTZyQQgaglng= -github.com/filecoin-project/specs-actors/v5 v5.0.0-20210512015452-4fe3889fff57/go.mod h1:283yBMMUSDB2abcjP/hhrwTkhb9h3sfM6KGrep/ZlBI= github.com/filecoin-project/specs-actors/v5 v5.0.4 h1:OY7BdxJWlUfUFXWV/kpNBYGXNPasDIedf42T3sGx08s= github.com/filecoin-project/specs-actors/v5 v5.0.4/go.mod h1:5BAKRAMsOOlD8+qCw4UvT/lTLInCJ3JwOWZbX8Ipwq4= github.com/filecoin-project/specs-actors/v6 v6.0.0/go.mod h1:V1AYfi5GkHXipx1mnVivoICZh3wtwPxDVuds+fbfQtk= github.com/filecoin-project/specs-actors/v6 v6.0.1 h1:laxvHNsvrq83Y9n+W7znVCePi3oLyRf0Rkl4jFO8Wew= github.com/filecoin-project/specs-actors/v6 v6.0.1/go.mod h1:V1AYfi5GkHXipx1mnVivoICZh3wtwPxDVuds+fbfQtk= -github.com/filecoin-project/specs-actors/v7 v7.0.0-20211116235548-301b685341ad h1:uUl9I4MCOAkbrY/JI3y6Php3t5c3tu1nux5VkCBwO4E= -github.com/filecoin-project/specs-actors/v7 v7.0.0-20211116235548-301b685341ad/go.mod h1:p6LIOFezA1rgRLMewbvdi3Pp6SAu+q9FtJ9CAleSjrE= +github.com/filecoin-project/specs-actors/v7 v7.0.0-20211117170924-fd07a4c7dff9 h1:H10WnEAJQH3JwHyaHwMEgaaj00z+/QMCb9Sjd/SUW1w= +github.com/filecoin-project/specs-actors/v7 v7.0.0-20211117170924-fd07a4c7dff9/go.mod h1:p6LIOFezA1rgRLMewbvdi3Pp6SAu+q9FtJ9CAleSjrE= github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 h1:Ur/l2+6qN+lQiqjozWWc5p9UDaAMDZKTlDS98oRnlIw= github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/test-vectors/schema v0.0.5 h1:w3zHQhzM4pYxJDl21avXjOKBLF8egrvwUwjpT8TquDg= diff --git a/itests/ccupgrade_test.go b/itests/ccupgrade_test.go index 12bc1fc869a..b5ca414161c 100644 --- a/itests/ccupgrade_test.go +++ b/itests/ccupgrade_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/require" ) +// TODO: This needs to be repurposed into a SnapDeals test suite func TestCCUpgrade(t *testing.T) { kit.QuietMiningLogs() diff --git a/itests/wdpost_test.go b/itests/wdpost_test.go index d87059bb48d..b1420e6a361 100644 --- a/itests/wdpost_test.go +++ b/itests/wdpost_test.go @@ -23,7 +23,7 @@ import ( ) func TestWindowedPost(t *testing.T) { - kit.Expensive(t) + //kit.Expensive(t) kit.QuietMiningLogs() From 91fb1114624e56f5d4fd86e29998ae509c0a1ff1 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 17 Nov 2021 17:50:36 -0500 Subject: [PATCH 04/24] Update FFI --- extern/filecoin-ffi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index fe2a3175719..58c014a42b7 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit fe2a317571931b31fb1ca6dd2adf1414e375b902 +Subproject commit 58c014a42b7a21e73560879841a71e679126a852 From a5847fd06f34325d240fda97f4c758a94957873e Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 17 Nov 2021 20:33:18 -0500 Subject: [PATCH 05/24] Update actors --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index e0dc4058319..ce52b7975c4 100644 --- a/go.mod +++ b/go.mod @@ -50,7 +50,7 @@ require ( github.com/filecoin-project/specs-actors/v4 v4.0.1 github.com/filecoin-project/specs-actors/v5 v5.0.4 github.com/filecoin-project/specs-actors/v6 v6.0.1 - github.com/filecoin-project/specs-actors/v7 v7.0.0-20211117170924-fd07a4c7dff9 + github.com/filecoin-project/specs-actors/v7 v7.0.0-20211118013026-3dce48197cec github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 github.com/filecoin-project/test-vectors/schema v0.0.5 github.com/gbrlsnchs/jwt/v3 v3.0.1 diff --git a/go.sum b/go.sum index b91544f8d6f..06341ce01eb 100644 --- a/go.sum +++ b/go.sum @@ -393,8 +393,9 @@ github.com/filecoin-project/specs-actors/v5 v5.0.4/go.mod h1:5BAKRAMsOOlD8+qCw4U github.com/filecoin-project/specs-actors/v6 v6.0.0/go.mod h1:V1AYfi5GkHXipx1mnVivoICZh3wtwPxDVuds+fbfQtk= github.com/filecoin-project/specs-actors/v6 v6.0.1 h1:laxvHNsvrq83Y9n+W7znVCePi3oLyRf0Rkl4jFO8Wew= github.com/filecoin-project/specs-actors/v6 v6.0.1/go.mod h1:V1AYfi5GkHXipx1mnVivoICZh3wtwPxDVuds+fbfQtk= -github.com/filecoin-project/specs-actors/v7 v7.0.0-20211117170924-fd07a4c7dff9 h1:H10WnEAJQH3JwHyaHwMEgaaj00z+/QMCb9Sjd/SUW1w= github.com/filecoin-project/specs-actors/v7 v7.0.0-20211117170924-fd07a4c7dff9/go.mod h1:p6LIOFezA1rgRLMewbvdi3Pp6SAu+q9FtJ9CAleSjrE= +github.com/filecoin-project/specs-actors/v7 v7.0.0-20211118013026-3dce48197cec h1:KV9vE+Sl2Y3qKsrpba4HcE7wHwK7v6O5U/S0xHbje6A= +github.com/filecoin-project/specs-actors/v7 v7.0.0-20211118013026-3dce48197cec/go.mod h1:p6LIOFezA1rgRLMewbvdi3Pp6SAu+q9FtJ9CAleSjrE= github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 h1:Ur/l2+6qN+lQiqjozWWc5p9UDaAMDZKTlDS98oRnlIw= github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/test-vectors/schema v0.0.5 h1:w3zHQhzM4pYxJDl21avXjOKBLF8egrvwUwjpT8TquDg= From 5f1783c9a5965f1820e568a66da6200e9cbadc17 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Thu, 18 Nov 2021 18:35:06 -0500 Subject: [PATCH 06/24] Address review --- build/openrpc/full.json.gz | Bin 25453 -> 25465 bytes chain/actors/builtin/miner/actor.go.template | 1 + chain/actors/builtin/miner/miner.go | 1 + chain/actors/builtin/miner/state.go.template | 23 ++++++++++++++----- chain/actors/builtin/miner/v0.go | 18 ++++++++++++--- chain/actors/builtin/miner/v2.go | 6 ++--- chain/actors/builtin/miner/v3.go | 6 ++--- chain/actors/builtin/miner/v4.go | 6 ++--- chain/actors/builtin/miner/v5.go | 6 ++--- chain/actors/builtin/miner/v6.go | 8 +++---- chain/actors/builtin/miner/v7.go | 15 ++++++------ chain/vm/runtime.go | 9 ++++++++ documentation/en/api-v0-methods.md | 3 ++- documentation/en/api-v1-unstable-methods.md | 3 ++- itests/wdpost_test.go | 2 +- 15 files changed, 72 insertions(+), 35 deletions(-) diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index 8f71ee8a973b9f29d91d16893c3cbe8bf3db8356..8719b71713e8587d8e7ec8ea03f23b0d6486fd6c 100644 GIT binary patch delta 24728 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 D;PdR} delta 24759 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 Nw@J1LHh4gQ`9C{nHm3jp diff --git a/chain/actors/builtin/miner/actor.go.template b/chain/actors/builtin/miner/actor.go.template index 2669a05a6c5..2b6b78ebcea 100644 --- a/chain/actors/builtin/miner/actor.go.template +++ b/chain/actors/builtin/miner/actor.go.template @@ -177,6 +177,7 @@ type SectorOnChainInfo struct { InitialPledge abi.TokenAmount ExpectedDayReward abi.TokenAmount ExpectedStoragePledge abi.TokenAmount + SectorKeyCID *cid.Cid } type SectorPreCommitInfo = miner0.SectorPreCommitInfo diff --git a/chain/actors/builtin/miner/miner.go b/chain/actors/builtin/miner/miner.go index f6d63388014..e60ff8da8b4 100644 --- a/chain/actors/builtin/miner/miner.go +++ b/chain/actors/builtin/miner/miner.go @@ -266,6 +266,7 @@ type SectorOnChainInfo struct { InitialPledge abi.TokenAmount ExpectedDayReward abi.TokenAmount ExpectedStoragePledge abi.TokenAmount + SectorKeyCID *cid.Cid } type SectorPreCommitInfo = miner0.SectorPreCommitInfo diff --git a/chain/actors/builtin/miner/state.go.template b/chain/actors/builtin/miner/state.go.template index 2ea6a905e11..77563196109 100644 --- a/chain/actors/builtin/miner/state.go.template +++ b/chain/actors/builtin/miner/state.go.template @@ -138,11 +138,22 @@ func (s *state{{.v}}) GetSectorExpiration(num abi.SectorNumber) (*SectorExpirati return nil, err } // NOTE: this can be optimized significantly. - // 1. If the sector is non-faulty, it will either expire on-time (can be +{{if (ge .v 7) -}} + // 1. If the sector is non-faulty, it will expire on-time (can be + // learned from the sector info). +{{- else -}} + // 1. If the sector is non-faulty, it will either expire on-time (can be // learned from the sector info), or in the next quantized expiration // epoch (i.e., the first element in the partition's expiration queue. +{{- end}} +{{if (ge .v 6) -}} + // 2. If it's faulty, it will expire early within the first 42 entries + // of the expiration queue. +{{- else -}} // 2. If it's faulty, it will expire early within the first 14 entries // of the expiration queue. +{{- end}} + stopErr := errors.New("stop") out := SectorExpiration{} err = dls.ForEach(s.store, func(dlIdx uint64, dl *miner{{.v}}.Deadline) error { @@ -554,8 +565,7 @@ func (p *partition{{.v}}) UnprovenSectors() (bitfield.BitField, error) { } func fromV{{.v}}SectorOnChainInfo(v{{.v}} miner{{.v}}.SectorOnChainInfo) SectorOnChainInfo { -{{if (ge .v 2)}} - return SectorOnChainInfo{ + info := SectorOnChainInfo{ SectorNumber: v{{.v}}.SectorNumber, SealProof: v{{.v}}.SealProof, SealedCID: v{{.v}}.SealedCID, @@ -567,10 +577,11 @@ func fromV{{.v}}SectorOnChainInfo(v{{.v}} miner{{.v}}.SectorOnChainInfo) SectorO InitialPledge: v{{.v}}.InitialPledge, ExpectedDayReward: v{{.v}}.ExpectedDayReward, ExpectedStoragePledge: v{{.v}}.ExpectedStoragePledge, + {{if (ge .v 7)}} + SectorKeyCID: v{{.v}}.SectorKeyCID, + {{end}} } -{{else}} - return (SectorOnChainInfo)(v0) -{{end}} + return info } func fromV{{.v}}SectorPreCommitOnChainInfo(v{{.v}} miner{{.v}}.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { diff --git a/chain/actors/builtin/miner/v0.go b/chain/actors/builtin/miner/v0.go index 564bcbbc27b..8bde8bf73e2 100644 --- a/chain/actors/builtin/miner/v0.go +++ b/chain/actors/builtin/miner/v0.go @@ -140,6 +140,7 @@ func (s *state0) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e // epoch (i.e., the first element in the partition's expiration queue. // 2. If it's faulty, it will expire early within the first 14 entries // of the expiration queue. + stopErr := errors.New("stop") out := SectorExpiration{} err = dls.ForEach(s.store, func(dlIdx uint64, dl *miner0.Deadline) error { @@ -505,9 +506,20 @@ func (p *partition0) UnprovenSectors() (bitfield.BitField, error) { } func fromV0SectorOnChainInfo(v0 miner0.SectorOnChainInfo) SectorOnChainInfo { - - return (SectorOnChainInfo)(v0) - + info := SectorOnChainInfo{ + SectorNumber: v0.SectorNumber, + SealProof: v0.SealProof, + SealedCID: v0.SealedCID, + DealIDs: v0.DealIDs, + Activation: v0.Activation, + Expiration: v0.Expiration, + DealWeight: v0.DealWeight, + VerifiedDealWeight: v0.VerifiedDealWeight, + InitialPledge: v0.InitialPledge, + ExpectedDayReward: v0.ExpectedDayReward, + ExpectedStoragePledge: v0.ExpectedStoragePledge, + } + return info } func fromV0SectorPreCommitOnChainInfo(v0 miner0.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { diff --git a/chain/actors/builtin/miner/v2.go b/chain/actors/builtin/miner/v2.go index fe0863111dd..bbfdd403e3c 100644 --- a/chain/actors/builtin/miner/v2.go +++ b/chain/actors/builtin/miner/v2.go @@ -138,6 +138,7 @@ func (s *state2) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e // epoch (i.e., the first element in the partition's expiration queue. // 2. If it's faulty, it will expire early within the first 14 entries // of the expiration queue. + stopErr := errors.New("stop") out := SectorExpiration{} err = dls.ForEach(s.store, func(dlIdx uint64, dl *miner2.Deadline) error { @@ -535,8 +536,7 @@ func (p *partition2) UnprovenSectors() (bitfield.BitField, error) { } func fromV2SectorOnChainInfo(v2 miner2.SectorOnChainInfo) SectorOnChainInfo { - - return SectorOnChainInfo{ + info := SectorOnChainInfo{ SectorNumber: v2.SectorNumber, SealProof: v2.SealProof, SealedCID: v2.SealedCID, @@ -549,7 +549,7 @@ func fromV2SectorOnChainInfo(v2 miner2.SectorOnChainInfo) SectorOnChainInfo { ExpectedDayReward: v2.ExpectedDayReward, ExpectedStoragePledge: v2.ExpectedStoragePledge, } - + return info } func fromV2SectorPreCommitOnChainInfo(v2 miner2.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { diff --git a/chain/actors/builtin/miner/v3.go b/chain/actors/builtin/miner/v3.go index b0d5429ea3c..68505918a79 100644 --- a/chain/actors/builtin/miner/v3.go +++ b/chain/actors/builtin/miner/v3.go @@ -140,6 +140,7 @@ func (s *state3) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e // epoch (i.e., the first element in the partition's expiration queue. // 2. If it's faulty, it will expire early within the first 14 entries // of the expiration queue. + stopErr := errors.New("stop") out := SectorExpiration{} err = dls.ForEach(s.store, func(dlIdx uint64, dl *miner3.Deadline) error { @@ -536,8 +537,7 @@ func (p *partition3) UnprovenSectors() (bitfield.BitField, error) { } func fromV3SectorOnChainInfo(v3 miner3.SectorOnChainInfo) SectorOnChainInfo { - - return SectorOnChainInfo{ + info := SectorOnChainInfo{ SectorNumber: v3.SectorNumber, SealProof: v3.SealProof, SealedCID: v3.SealedCID, @@ -550,7 +550,7 @@ func fromV3SectorOnChainInfo(v3 miner3.SectorOnChainInfo) SectorOnChainInfo { ExpectedDayReward: v3.ExpectedDayReward, ExpectedStoragePledge: v3.ExpectedStoragePledge, } - + return info } func fromV3SectorPreCommitOnChainInfo(v3 miner3.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { diff --git a/chain/actors/builtin/miner/v4.go b/chain/actors/builtin/miner/v4.go index 7e5a9761a61..5c40d418976 100644 --- a/chain/actors/builtin/miner/v4.go +++ b/chain/actors/builtin/miner/v4.go @@ -140,6 +140,7 @@ func (s *state4) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e // epoch (i.e., the first element in the partition's expiration queue. // 2. If it's faulty, it will expire early within the first 14 entries // of the expiration queue. + stopErr := errors.New("stop") out := SectorExpiration{} err = dls.ForEach(s.store, func(dlIdx uint64, dl *miner4.Deadline) error { @@ -536,8 +537,7 @@ func (p *partition4) UnprovenSectors() (bitfield.BitField, error) { } func fromV4SectorOnChainInfo(v4 miner4.SectorOnChainInfo) SectorOnChainInfo { - - return SectorOnChainInfo{ + info := SectorOnChainInfo{ SectorNumber: v4.SectorNumber, SealProof: v4.SealProof, SealedCID: v4.SealedCID, @@ -550,7 +550,7 @@ func fromV4SectorOnChainInfo(v4 miner4.SectorOnChainInfo) SectorOnChainInfo { ExpectedDayReward: v4.ExpectedDayReward, ExpectedStoragePledge: v4.ExpectedStoragePledge, } - + return info } func fromV4SectorPreCommitOnChainInfo(v4 miner4.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { diff --git a/chain/actors/builtin/miner/v5.go b/chain/actors/builtin/miner/v5.go index 7f4aaf168e5..f717934f436 100644 --- a/chain/actors/builtin/miner/v5.go +++ b/chain/actors/builtin/miner/v5.go @@ -140,6 +140,7 @@ func (s *state5) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e // epoch (i.e., the first element in the partition's expiration queue. // 2. If it's faulty, it will expire early within the first 14 entries // of the expiration queue. + stopErr := errors.New("stop") out := SectorExpiration{} err = dls.ForEach(s.store, func(dlIdx uint64, dl *miner5.Deadline) error { @@ -536,8 +537,7 @@ func (p *partition5) UnprovenSectors() (bitfield.BitField, error) { } func fromV5SectorOnChainInfo(v5 miner5.SectorOnChainInfo) SectorOnChainInfo { - - return SectorOnChainInfo{ + info := SectorOnChainInfo{ SectorNumber: v5.SectorNumber, SealProof: v5.SealProof, SealedCID: v5.SealedCID, @@ -550,7 +550,7 @@ func fromV5SectorOnChainInfo(v5 miner5.SectorOnChainInfo) SectorOnChainInfo { ExpectedDayReward: v5.ExpectedDayReward, ExpectedStoragePledge: v5.ExpectedStoragePledge, } - + return info } func fromV5SectorPreCommitOnChainInfo(v5 miner5.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { diff --git a/chain/actors/builtin/miner/v6.go b/chain/actors/builtin/miner/v6.go index de5a22a1091..7a9dfb0dfa3 100644 --- a/chain/actors/builtin/miner/v6.go +++ b/chain/actors/builtin/miner/v6.go @@ -138,8 +138,9 @@ func (s *state6) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e // 1. If the sector is non-faulty, it will either expire on-time (can be // learned from the sector info), or in the next quantized expiration // epoch (i.e., the first element in the partition's expiration queue. - // 2. If it's faulty, it will expire early within the first 14 entries + // 2. If it's faulty, it will expire early within the first 42 entries // of the expiration queue. + stopErr := errors.New("stop") out := SectorExpiration{} err = dls.ForEach(s.store, func(dlIdx uint64, dl *miner6.Deadline) error { @@ -536,8 +537,7 @@ func (p *partition6) UnprovenSectors() (bitfield.BitField, error) { } func fromV6SectorOnChainInfo(v6 miner6.SectorOnChainInfo) SectorOnChainInfo { - - return SectorOnChainInfo{ + info := SectorOnChainInfo{ SectorNumber: v6.SectorNumber, SealProof: v6.SealProof, SealedCID: v6.SealedCID, @@ -550,7 +550,7 @@ func fromV6SectorOnChainInfo(v6 miner6.SectorOnChainInfo) SectorOnChainInfo { ExpectedDayReward: v6.ExpectedDayReward, ExpectedStoragePledge: v6.ExpectedStoragePledge, } - + return info } func fromV6SectorPreCommitOnChainInfo(v6 miner6.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { diff --git a/chain/actors/builtin/miner/v7.go b/chain/actors/builtin/miner/v7.go index c7096a78149..e1b2520e4dc 100644 --- a/chain/actors/builtin/miner/v7.go +++ b/chain/actors/builtin/miner/v7.go @@ -135,11 +135,11 @@ func (s *state7) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e return nil, err } // NOTE: this can be optimized significantly. - // 1. If the sector is non-faulty, it will either expire on-time (can be - // learned from the sector info), or in the next quantized expiration - // epoch (i.e., the first element in the partition's expiration queue. - // 2. If it's faulty, it will expire early within the first 14 entries + // 1. If the sector is non-faulty, it will expire on-time (can be + // learned from the sector info). + // 2. If it's faulty, it will expire early within the first 42 entries // of the expiration queue. + stopErr := errors.New("stop") out := SectorExpiration{} err = dls.ForEach(s.store, func(dlIdx uint64, dl *miner7.Deadline) error { @@ -536,8 +536,7 @@ func (p *partition7) UnprovenSectors() (bitfield.BitField, error) { } func fromV7SectorOnChainInfo(v7 miner7.SectorOnChainInfo) SectorOnChainInfo { - - return SectorOnChainInfo{ + info := SectorOnChainInfo{ SectorNumber: v7.SectorNumber, SealProof: v7.SealProof, SealedCID: v7.SealedCID, @@ -549,8 +548,10 @@ func fromV7SectorOnChainInfo(v7 miner7.SectorOnChainInfo) SectorOnChainInfo { InitialPledge: v7.InitialPledge, ExpectedDayReward: v7.ExpectedDayReward, ExpectedStoragePledge: v7.ExpectedStoragePledge, - } + SectorKeyCID: v7.SectorKeyCID, + } + return info } func fromV7SectorPreCommitOnChainInfo(v7 miner7.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 583c99593b9..0dbe98224ee 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -16,7 +16,11 @@ import ( "github.com/filecoin-project/go-state-types/network" rtt "github.com/filecoin-project/go-state-types/rt" rt0 "github.com/filecoin-project/specs-actors/actors/runtime" + rt2 "github.com/filecoin-project/specs-actors/v2/actors/runtime" + rt3 "github.com/filecoin-project/specs-actors/v3/actors/runtime" + rt4 "github.com/filecoin-project/specs-actors/v4/actors/runtime" rt5 "github.com/filecoin-project/specs-actors/v5/actors/runtime" + rt6 "github.com/filecoin-project/specs-actors/v6/actors/runtime" rt7 "github.com/filecoin-project/specs-actors/v7/actors/runtime" "github.com/ipfs/go-cid" ipldcbor "github.com/ipfs/go-ipld-cbor" @@ -142,6 +146,11 @@ func (rt *Runtime) StorePut(x cbor.Marshaler) cid.Cid { var _ rt0.Runtime = (*Runtime)(nil) var _ rt5.Runtime = (*Runtime)(nil) +var _ rt2.Runtime = (*Runtime)(nil) +var _ rt3.Runtime = (*Runtime)(nil) +var _ rt4.Runtime = (*Runtime)(nil) +var _ rt5.Runtime = (*Runtime)(nil) +var _ rt6.Runtime = (*Runtime)(nil) var _ rt7.Runtime = (*Runtime)(nil) func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.ActorError) { diff --git a/documentation/en/api-v0-methods.md b/documentation/en/api-v0-methods.md index 42bb945d0f1..09c3d1c34ad 100644 --- a/documentation/en/api-v0-methods.md +++ b/documentation/en/api-v0-methods.md @@ -5016,7 +5016,8 @@ Response: "VerifiedDealWeight": "0", "InitialPledge": "0", "ExpectedDayReward": "0", - "ExpectedStoragePledge": "0" + "ExpectedStoragePledge": "0", + "SectorKeyCID": null } ``` diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index 3578a449218..91baffdc6ea 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -5223,7 +5223,8 @@ Response: "VerifiedDealWeight": "0", "InitialPledge": "0", "ExpectedDayReward": "0", - "ExpectedStoragePledge": "0" + "ExpectedStoragePledge": "0", + "SectorKeyCID": null } ``` diff --git a/itests/wdpost_test.go b/itests/wdpost_test.go index b1420e6a361..d87059bb48d 100644 --- a/itests/wdpost_test.go +++ b/itests/wdpost_test.go @@ -23,7 +23,7 @@ import ( ) func TestWindowedPost(t *testing.T) { - //kit.Expensive(t) + kit.Expensive(t) kit.QuietMiningLogs() From 7d2b3f05db38cee481c4b91e628b53bb460bdadc Mon Sep 17 00:00:00 2001 From: zenground0 Date: Wed, 10 Nov 2021 13:53:00 -0500 Subject: [PATCH 07/24] WIP sector storage and integration test --- api/api_storage.go | 25 +-- api/api_worker.go | 3 + api/proxy_gen.go | 78 +++++++++ build/openrpc/full.json.gz | Bin 25465 -> 25466 bytes build/openrpc/miner.json.gz | Bin 10467 -> 10672 bytes build/openrpc/worker.json.gz | Bin 2713 -> 2940 bytes documentation/en/api-v0-methods-miner.md | 85 +++++++++ documentation/en/api-v0-methods-worker.md | 118 +++++++++++++ extern/filecoin-ffi | 2 +- .../sector-storage/ffiwrapper/sealer_cgo.go | 83 +++++++++ .../sector-storage/ffiwrapper/verifier_cgo.go | 3 +- extern/sector-storage/manager.go | 161 ++++++++++++++++++ extern/sector-storage/manager_calltracker.go | 1 - extern/sector-storage/manager_test.go | 139 ++++++++++++++- extern/sector-storage/mock/mock.go | 32 ++++ extern/sector-storage/sched_test.go | 12 ++ extern/sector-storage/sealtasks/task.go | 27 ++- extern/sector-storage/storiface/filetype.go | 42 +++-- extern/sector-storage/storiface/worker.go | 6 + extern/sector-storage/teststorage_test.go | 16 ++ extern/sector-storage/testworker_test.go | 28 +++ extern/sector-storage/worker_local.go | 85 ++++++--- extern/sector-storage/worker_tracked.go | 19 ++- go.mod | 4 +- go.sum | 10 +- 25 files changed, 911 insertions(+), 68 deletions(-) diff --git a/api/api_storage.go b/api/api_storage.go index 8cca2aa5be5..bf7520d09e7 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -118,17 +118,20 @@ type StorageMiner interface { WorkerJobs(context.Context) (map[uuid.UUID][]storiface.WorkerJob, error) //perm:admin //storiface.WorkerReturn - ReturnAddPiece(ctx context.Context, callID storiface.CallID, pi abi.PieceInfo, err *storiface.CallError) error //perm:admin retry:true - ReturnSealPreCommit1(ctx context.Context, callID storiface.CallID, p1o storage.PreCommit1Out, err *storiface.CallError) error //perm:admin retry:true - ReturnSealPreCommit2(ctx context.Context, callID storiface.CallID, sealed storage.SectorCids, err *storiface.CallError) error //perm:admin retry:true - ReturnSealCommit1(ctx context.Context, callID storiface.CallID, out storage.Commit1Out, err *storiface.CallError) error //perm:admin retry:true - ReturnSealCommit2(ctx context.Context, callID storiface.CallID, proof storage.Proof, err *storiface.CallError) error //perm:admin retry:true - ReturnFinalizeSector(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error //perm:admin retry:true - ReturnReleaseUnsealed(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error //perm:admin retry:true - ReturnMoveStorage(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error //perm:admin retry:true - ReturnUnsealPiece(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error //perm:admin retry:true - ReturnReadPiece(ctx context.Context, callID storiface.CallID, ok bool, err *storiface.CallError) error //perm:admin retry:true - ReturnFetch(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error //perm:admin retry:true + ReturnAddPiece(ctx context.Context, callID storiface.CallID, pi abi.PieceInfo, err *storiface.CallError) error //perm:admin retry:true + ReturnSealPreCommit1(ctx context.Context, callID storiface.CallID, p1o storage.PreCommit1Out, err *storiface.CallError) error //perm:admin retry:true + ReturnSealPreCommit2(ctx context.Context, callID storiface.CallID, sealed storage.SectorCids, err *storiface.CallError) error //perm:admin retry:true + ReturnSealCommit1(ctx context.Context, callID storiface.CallID, out storage.Commit1Out, err *storiface.CallError) error //perm:admin retry:true + ReturnSealCommit2(ctx context.Context, callID storiface.CallID, proof storage.Proof, err *storiface.CallError) error //perm:admin retry:true + ReturnFinalizeSector(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error //perm:admin retry:true + ReturnReplicaUpdate(ctx context.Context, callID storiface.CallID, out storage.ReplicaUpdateOut, err *storiface.CallError) error //perm:admin retry:true + ReturnProveReplicaUpdate1(ctx context.Context, callID storiface.CallID, vanillaProofs storage.ReplicaVanillaProofs, err *storiface.CallError) error //perm:admin retry:true + ReturnProveReplicaUpdate2(ctx context.Context, callID storiface.CallID, proof storage.ReplicaUpdateProof, err *storiface.CallError) error //perm:admin retry:true + ReturnReleaseUnsealed(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error //perm:admin retry:true + ReturnMoveStorage(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error //perm:admin retry:true + ReturnUnsealPiece(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error //perm:admin retry:true + ReturnReadPiece(ctx context.Context, callID storiface.CallID, ok bool, err *storiface.CallError) error //perm:admin retry:true + ReturnFetch(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error //perm:admin retry:true // SealingSchedDiag dumps internal sealing scheduler state SealingSchedDiag(ctx context.Context, doSched bool) (interface{}, error) //perm:admin diff --git a/api/api_worker.go b/api/api_worker.go index 4553c30e095..5e0b4f8c6d4 100644 --- a/api/api_worker.go +++ b/api/api_worker.go @@ -39,6 +39,9 @@ type Worker interface { SealCommit1(ctx context.Context, sector storage.SectorRef, ticket abi.SealRandomness, seed abi.InteractiveSealRandomness, pieces []abi.PieceInfo, cids storage.SectorCids) (storiface.CallID, error) //perm:admin SealCommit2(ctx context.Context, sector storage.SectorRef, c1o storage.Commit1Out) (storiface.CallID, error) //perm:admin FinalizeSector(ctx context.Context, sector storage.SectorRef, keepUnsealed []storage.Range) (storiface.CallID, error) //perm:admin + ReplicaUpdate(ctx context.Context, sector storage.SectorRef, pieces []abi.PieceInfo) (storiface.CallID, error) //perm:admin + ProveReplicaUpdate1(ctx context.Context, sector storage.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid) (storiface.CallID, error) //perm:admin + ProveReplicaUpdate2(ctx context.Context, sector storage.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid, vanillaProofs storage.ReplicaVanillaProofs) (storiface.CallID, error) //perm:admin ReleaseUnsealed(ctx context.Context, sector storage.SectorRef, safeToFree []storage.Range) (storiface.CallID, error) //perm:admin MoveStorage(ctx context.Context, sector storage.SectorRef, types storiface.SectorFileType) (storiface.CallID, error) //perm:admin UnsealPiece(context.Context, storage.SectorRef, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize, abi.SealRandomness, cid.Cid) (storiface.CallID, error) //perm:admin diff --git a/api/proxy_gen.go b/api/proxy_gen.go index b36f19a7e1e..b78b40959b2 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -709,10 +709,16 @@ type StorageMinerStruct struct { ReturnMoveStorage func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` + ReturnProveReplicaUpdate1 func(p0 context.Context, p1 storiface.CallID, p2 storage.ReplicaVanillaProofs, p3 *storiface.CallError) error `perm:"admin"` + + ReturnProveReplicaUpdate2 func(p0 context.Context, p1 storiface.CallID, p2 storage.ReplicaUpdateProof, p3 *storiface.CallError) error `perm:"admin"` + ReturnReadPiece func(p0 context.Context, p1 storiface.CallID, p2 bool, p3 *storiface.CallError) error `perm:"admin"` ReturnReleaseUnsealed func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` + ReturnReplicaUpdate func(p0 context.Context, p1 storiface.CallID, p2 storage.ReplicaUpdateOut, p3 *storiface.CallError) error `perm:"admin"` + ReturnSealCommit1 func(p0 context.Context, p1 storiface.CallID, p2 storage.Commit1Out, p3 *storiface.CallError) error `perm:"admin"` ReturnSealCommit2 func(p0 context.Context, p1 storiface.CallID, p2 storage.Proof, p3 *storiface.CallError) error `perm:"admin"` @@ -852,10 +858,16 @@ type WorkerStruct struct { ProcessSession func(p0 context.Context) (uuid.UUID, error) `perm:"admin"` + ProveReplicaUpdate1 func(p0 context.Context, p1 storage.SectorRef, p2 cid.Cid, p3 cid.Cid, p4 cid.Cid) (storiface.CallID, error) `perm:"admin"` + + ProveReplicaUpdate2 func(p0 context.Context, p1 storage.SectorRef, p2 cid.Cid, p3 cid.Cid, p4 cid.Cid, p5 storage.ReplicaVanillaProofs) (storiface.CallID, error) `perm:"admin"` + ReleaseUnsealed func(p0 context.Context, p1 storage.SectorRef, p2 []storage.Range) (storiface.CallID, error) `perm:"admin"` Remove func(p0 context.Context, p1 abi.SectorID) error `perm:"admin"` + ReplicaUpdate func(p0 context.Context, p1 storage.SectorRef, p2 []abi.PieceInfo) (storiface.CallID, error) `perm:"admin"` + SealCommit1 func(p0 context.Context, p1 storage.SectorRef, p2 abi.SealRandomness, p3 abi.InteractiveSealRandomness, p4 []abi.PieceInfo, p5 storage.SectorCids) (storiface.CallID, error) `perm:"admin"` SealCommit2 func(p0 context.Context, p1 storage.SectorRef, p2 storage.Commit1Out) (storiface.CallID, error) `perm:"admin"` @@ -4165,6 +4177,28 @@ func (s *StorageMinerStub) ReturnMoveStorage(p0 context.Context, p1 storiface.Ca return ErrNotSupported } +func (s *StorageMinerStruct) ReturnProveReplicaUpdate1(p0 context.Context, p1 storiface.CallID, p2 storage.ReplicaVanillaProofs, p3 *storiface.CallError) error { + if s.Internal.ReturnProveReplicaUpdate1 == nil { + return ErrNotSupported + } + return s.Internal.ReturnProveReplicaUpdate1(p0, p1, p2, p3) +} + +func (s *StorageMinerStub) ReturnProveReplicaUpdate1(p0 context.Context, p1 storiface.CallID, p2 storage.ReplicaVanillaProofs, p3 *storiface.CallError) error { + return ErrNotSupported +} + +func (s *StorageMinerStruct) ReturnProveReplicaUpdate2(p0 context.Context, p1 storiface.CallID, p2 storage.ReplicaUpdateProof, p3 *storiface.CallError) error { + if s.Internal.ReturnProveReplicaUpdate2 == nil { + return ErrNotSupported + } + return s.Internal.ReturnProveReplicaUpdate2(p0, p1, p2, p3) +} + +func (s *StorageMinerStub) ReturnProveReplicaUpdate2(p0 context.Context, p1 storiface.CallID, p2 storage.ReplicaUpdateProof, p3 *storiface.CallError) error { + return ErrNotSupported +} + func (s *StorageMinerStruct) ReturnReadPiece(p0 context.Context, p1 storiface.CallID, p2 bool, p3 *storiface.CallError) error { if s.Internal.ReturnReadPiece == nil { return ErrNotSupported @@ -4187,6 +4221,17 @@ func (s *StorageMinerStub) ReturnReleaseUnsealed(p0 context.Context, p1 storifac return ErrNotSupported } +func (s *StorageMinerStruct) ReturnReplicaUpdate(p0 context.Context, p1 storiface.CallID, p2 storage.ReplicaUpdateOut, p3 *storiface.CallError) error { + if s.Internal.ReturnReplicaUpdate == nil { + return ErrNotSupported + } + return s.Internal.ReturnReplicaUpdate(p0, p1, p2, p3) +} + +func (s *StorageMinerStub) ReturnReplicaUpdate(p0 context.Context, p1 storiface.CallID, p2 storage.ReplicaUpdateOut, p3 *storiface.CallError) error { + return ErrNotSupported +} + func (s *StorageMinerStruct) ReturnSealCommit1(p0 context.Context, p1 storiface.CallID, p2 storage.Commit1Out, p3 *storiface.CallError) error { if s.Internal.ReturnSealCommit1 == nil { return ErrNotSupported @@ -4858,6 +4903,28 @@ func (s *WorkerStub) ProcessSession(p0 context.Context) (uuid.UUID, error) { return *new(uuid.UUID), ErrNotSupported } +func (s *WorkerStruct) ProveReplicaUpdate1(p0 context.Context, p1 storage.SectorRef, p2 cid.Cid, p3 cid.Cid, p4 cid.Cid) (storiface.CallID, error) { + if s.Internal.ProveReplicaUpdate1 == nil { + return *new(storiface.CallID), ErrNotSupported + } + return s.Internal.ProveReplicaUpdate1(p0, p1, p2, p3, p4) +} + +func (s *WorkerStub) ProveReplicaUpdate1(p0 context.Context, p1 storage.SectorRef, p2 cid.Cid, p3 cid.Cid, p4 cid.Cid) (storiface.CallID, error) { + return *new(storiface.CallID), ErrNotSupported +} + +func (s *WorkerStruct) ProveReplicaUpdate2(p0 context.Context, p1 storage.SectorRef, p2 cid.Cid, p3 cid.Cid, p4 cid.Cid, p5 storage.ReplicaVanillaProofs) (storiface.CallID, error) { + if s.Internal.ProveReplicaUpdate2 == nil { + return *new(storiface.CallID), ErrNotSupported + } + return s.Internal.ProveReplicaUpdate2(p0, p1, p2, p3, p4, p5) +} + +func (s *WorkerStub) ProveReplicaUpdate2(p0 context.Context, p1 storage.SectorRef, p2 cid.Cid, p3 cid.Cid, p4 cid.Cid, p5 storage.ReplicaVanillaProofs) (storiface.CallID, error) { + return *new(storiface.CallID), ErrNotSupported +} + func (s *WorkerStruct) ReleaseUnsealed(p0 context.Context, p1 storage.SectorRef, p2 []storage.Range) (storiface.CallID, error) { if s.Internal.ReleaseUnsealed == nil { return *new(storiface.CallID), ErrNotSupported @@ -4880,6 +4947,17 @@ func (s *WorkerStub) Remove(p0 context.Context, p1 abi.SectorID) error { return ErrNotSupported } +func (s *WorkerStruct) ReplicaUpdate(p0 context.Context, p1 storage.SectorRef, p2 []abi.PieceInfo) (storiface.CallID, error) { + if s.Internal.ReplicaUpdate == nil { + return *new(storiface.CallID), ErrNotSupported + } + return s.Internal.ReplicaUpdate(p0, p1, p2) +} + +func (s *WorkerStub) ReplicaUpdate(p0 context.Context, p1 storage.SectorRef, p2 []abi.PieceInfo) (storiface.CallID, error) { + return *new(storiface.CallID), ErrNotSupported +} + func (s *WorkerStruct) SealCommit1(p0 context.Context, p1 storage.SectorRef, p2 abi.SealRandomness, p3 abi.InteractiveSealRandomness, p4 []abi.PieceInfo, p5 storage.SectorCids) (storiface.CallID, error) { if s.Internal.SealCommit1 == nil { return *new(storiface.CallID), ErrNotSupported diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index 8719b71713e8587d8e7ec8ea03f23b0d6486fd6c..a5816ef4f3d57f10df36cc9e5a911257fb47e0e6 100644 GIT binary patch delta 25088 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 WJUo1P`2PU_0RR7TD+|HU^Z@`4(25@b delta 10388 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 literal 2713 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", t) } @@ -104,9 +116,11 @@ func (t SectorFileType) All() [FileTypes]bool { type SectorPaths struct { ID abi.SectorID - Unsealed string - Sealed string - Cache string + Unsealed string + Sealed string + Cache string + Update string + UpdateCache string } func ParseSectorID(baseName string) (abi.SectorID, error) { @@ -139,6 +153,10 @@ func PathByType(sps SectorPaths, fileType SectorFileType) string { return sps.Sealed case FTCache: return sps.Cache + case FTUpdate: + return sps.Update + case FTUpdateCache: + return sps.UpdateCache } panic("requested unknown path type") @@ -152,5 +170,9 @@ func SetPathByType(sps *SectorPaths, fileType SectorFileType, p string) { sps.Sealed = p case FTCache: sps.Cache = p + case FTUpdate: + sps.Update = p + case FTUpdateCache: + sps.UpdateCache = p } } diff --git a/extern/sector-storage/storiface/worker.go b/extern/sector-storage/storiface/worker.go index e3374d6cf86..970e0ec33a2 100644 --- a/extern/sector-storage/storiface/worker.go +++ b/extern/sector-storage/storiface/worker.go @@ -92,6 +92,9 @@ type WorkerCalls interface { SealCommit2(ctx context.Context, sector storage.SectorRef, c1o storage.Commit1Out) (CallID, error) FinalizeSector(ctx context.Context, sector storage.SectorRef, keepUnsealed []storage.Range) (CallID, error) ReleaseUnsealed(ctx context.Context, sector storage.SectorRef, safeToFree []storage.Range) (CallID, error) + ReplicaUpdate(ctx context.Context, sector storage.SectorRef, pieces []abi.PieceInfo) (CallID, error) + ProveReplicaUpdate1(ctx context.Context, sector storage.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid) (CallID, error) + ProveReplicaUpdate2(ctx context.Context, sector storage.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid, vanillaProofs storage.ReplicaVanillaProofs) (CallID, error) MoveStorage(ctx context.Context, sector storage.SectorRef, types SectorFileType) (CallID, error) UnsealPiece(context.Context, storage.SectorRef, UnpaddedByteIndex, abi.UnpaddedPieceSize, abi.SealRandomness, cid.Cid) (CallID, error) Fetch(context.Context, storage.SectorRef, SectorFileType, PathType, AcquireMode) (CallID, error) @@ -145,6 +148,9 @@ type WorkerReturn interface { ReturnSealCommit2(ctx context.Context, callID CallID, proof storage.Proof, err *CallError) error ReturnFinalizeSector(ctx context.Context, callID CallID, err *CallError) error ReturnReleaseUnsealed(ctx context.Context, callID CallID, err *CallError) error + ReturnReplicaUpdate(ctx context.Context, callID CallID, out storage.ReplicaUpdateOut, err *CallError) error + ReturnProveReplicaUpdate1(ctx context.Context, callID CallID, proofs storage.ReplicaVanillaProofs, err *CallError) error + ReturnProveReplicaUpdate2(ctx context.Context, callID CallID, proof storage.ReplicaUpdateProof, err *CallError) error ReturnMoveStorage(ctx context.Context, callID CallID, err *CallError) error ReturnUnsealPiece(ctx context.Context, callID CallID, err *CallError) error ReturnReadPiece(ctx context.Context, callID CallID, ok bool, err *CallError) error diff --git a/extern/sector-storage/teststorage_test.go b/extern/sector-storage/teststorage_test.go index 72b27b154dc..4061b48d99c 100644 --- a/extern/sector-storage/teststorage_test.go +++ b/extern/sector-storage/teststorage_test.go @@ -55,10 +55,26 @@ func (t *testExec) ReleaseUnsealed(ctx context.Context, sector storage.SectorRef panic("implement me") } +func (t *testExec) ReleaseSealed(ctx context.Context, sector storage.SectorRef) error { + panic("implement me") +} + func (t *testExec) Remove(ctx context.Context, sector storage.SectorRef) error { panic("implement me") } +func (t *testExec) ReplicaUpdate(ctx context.Context, sector storage.SectorRef, pieces []abi.PieceInfo) (storage.ReplicaUpdateOut, error) { + panic("implement me") +} + +func (t *testExec) ProveReplicaUpdate1(ctx context.Context, sector storage.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid) (storage.ReplicaVanillaProofs, error) { + panic("implement me") +} + +func (t *testExec) ProveReplicaUpdate2(ctx context.Context, sector storage.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid, vanillaProofs storage.ReplicaVanillaProofs) (storage.ReplicaUpdateProof, error) { + panic("implement me") +} + func (t *testExec) NewSector(ctx context.Context, sector storage.SectorRef) error { panic("implement me") } diff --git a/extern/sector-storage/testworker_test.go b/extern/sector-storage/testworker_test.go index 2fe99f3d4cc..a5c678415d4 100644 --- a/extern/sector-storage/testworker_test.go +++ b/extern/sector-storage/testworker_test.go @@ -7,6 +7,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" "github.com/google/uuid" + cid "github.com/ipfs/go-cid" "github.com/filecoin-project/lotus/extern/sector-storage/mock" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" @@ -67,6 +68,33 @@ func (t *testWorker) AddPiece(ctx context.Context, sector storage.SectorRef, pie }) } +func (t *testWorker) ReplicaUpdate(ctx context.Context, sector storage.SectorRef, pieces []abi.PieceInfo) (storiface.CallID, error) { + return t.asyncCall(sector, func(ci storiface.CallID) { + out, err := t.mockSeal.ReplicaUpdate(ctx, sector, pieces) + if err := t.ret.ReturnReplicaUpdate(ctx, ci, out, toCallError(err)); err != nil { + log.Error(err) + } + }) +} + +func (t *testWorker) ProveReplicaUpdate1(ctx context.Context, sector storage.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid) (storiface.CallID, error) { + return t.asyncCall(sector, func(ci storiface.CallID) { + vanillaProofs, err := t.mockSeal.ProveReplicaUpdate1(ctx, sector, sectorKey, newSealed, newUnsealed) + if err := t.ret.ReturnProveReplicaUpdate1(ctx, ci, vanillaProofs, toCallError(err)); err != nil { + log.Error(err) + } + }) +} + +func (t *testWorker) ProveReplicaUpdate2(ctx context.Context, sector storage.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid, vanillaProofs storage.ReplicaVanillaProofs) (storiface.CallID, error) { + return t.asyncCall(sector, func(ci storiface.CallID) { + proof, err := t.mockSeal.ProveReplicaUpdate2(ctx, sector, sectorKey, newSealed, newUnsealed, vanillaProofs) + if err := t.ret.ReturnProveReplicaUpdate2(ctx, ci, proof, toCallError(err)); err != nil { + log.Error(err) + } + }) +} + func (t *testWorker) SealPreCommit1(ctx context.Context, sector storage.SectorRef, ticket abi.SealRandomness, pieces []abi.PieceInfo) (storiface.CallID, error) { return t.asyncCall(sector, func(ci storiface.CallID) { t.pc1s++ diff --git a/extern/sector-storage/worker_local.go b/extern/sector-storage/worker_local.go index d45d140f818..cc41e916e20 100644 --- a/extern/sector-storage/worker_local.go +++ b/extern/sector-storage/worker_local.go @@ -28,7 +28,7 @@ import ( "github.com/filecoin-project/lotus/extern/sector-storage/storiface" ) -var pathTypes = []storiface.SectorFileType{storiface.FTUnsealed, storiface.FTSealed, storiface.FTCache} +var pathTypes = []storiface.SectorFileType{storiface.FTUnsealed, storiface.FTSealed, storiface.FTCache, storiface.FTUpdate, storiface.FTUpdateCache} type WorkerConfig struct { TaskTypes []sealtasks.TaskType @@ -145,7 +145,6 @@ func (l *localWorkerPathProvider) AcquireSector(ctx context.Context, sector stor } sid := storiface.PathByType(storageIDs, fileType) - if err := l.w.sindex.StorageDeclareSector(ctx, stores.ID(sid), sector.ID, fileType, l.op == storiface.AcquireMove); err != nil { log.Errorf("declare sector error: %+v", err) } @@ -160,16 +159,19 @@ func (l *LocalWorker) ffiExec() (ffiwrapper.Storage, error) { type ReturnType string const ( - AddPiece ReturnType = "AddPiece" - SealPreCommit1 ReturnType = "SealPreCommit1" - SealPreCommit2 ReturnType = "SealPreCommit2" - SealCommit1 ReturnType = "SealCommit1" - SealCommit2 ReturnType = "SealCommit2" - FinalizeSector ReturnType = "FinalizeSector" - ReleaseUnsealed ReturnType = "ReleaseUnsealed" - MoveStorage ReturnType = "MoveStorage" - UnsealPiece ReturnType = "UnsealPiece" - Fetch ReturnType = "Fetch" + AddPiece ReturnType = "AddPiece" + SealPreCommit1 ReturnType = "SealPreCommit1" + SealPreCommit2 ReturnType = "SealPreCommit2" + SealCommit1 ReturnType = "SealCommit1" + SealCommit2 ReturnType = "SealCommit2" + FinalizeSector ReturnType = "FinalizeSector" + ReplicaUpdate ReturnType = "ReplicaUpdate" + ProveReplicaUpdate1 ReturnType = "ProveReplicaUpdate1" + ProveReplicaUpdate2 ReturnType = "ProveReplicaUpdate2" + ReleaseUnsealed ReturnType = "ReleaseUnsealed" + MoveStorage ReturnType = "MoveStorage" + UnsealPiece ReturnType = "UnsealPiece" + Fetch ReturnType = "Fetch" ) // in: func(WorkerReturn, context.Context, CallID, err string) @@ -207,16 +209,19 @@ func rfunc(in interface{}) func(context.Context, storiface.CallID, storiface.Wor } var returnFunc = map[ReturnType]func(context.Context, storiface.CallID, storiface.WorkerReturn, interface{}, *storiface.CallError) error{ - AddPiece: rfunc(storiface.WorkerReturn.ReturnAddPiece), - SealPreCommit1: rfunc(storiface.WorkerReturn.ReturnSealPreCommit1), - SealPreCommit2: rfunc(storiface.WorkerReturn.ReturnSealPreCommit2), - SealCommit1: rfunc(storiface.WorkerReturn.ReturnSealCommit1), - SealCommit2: rfunc(storiface.WorkerReturn.ReturnSealCommit2), - FinalizeSector: rfunc(storiface.WorkerReturn.ReturnFinalizeSector), - ReleaseUnsealed: rfunc(storiface.WorkerReturn.ReturnReleaseUnsealed), - MoveStorage: rfunc(storiface.WorkerReturn.ReturnMoveStorage), - UnsealPiece: rfunc(storiface.WorkerReturn.ReturnUnsealPiece), - Fetch: rfunc(storiface.WorkerReturn.ReturnFetch), + AddPiece: rfunc(storiface.WorkerReturn.ReturnAddPiece), + SealPreCommit1: rfunc(storiface.WorkerReturn.ReturnSealPreCommit1), + SealPreCommit2: rfunc(storiface.WorkerReturn.ReturnSealPreCommit2), + SealCommit1: rfunc(storiface.WorkerReturn.ReturnSealCommit1), + SealCommit2: rfunc(storiface.WorkerReturn.ReturnSealCommit2), + FinalizeSector: rfunc(storiface.WorkerReturn.ReturnFinalizeSector), + ReleaseUnsealed: rfunc(storiface.WorkerReturn.ReturnReleaseUnsealed), + ReplicaUpdate: rfunc(storiface.WorkerReturn.ReturnReplicaUpdate), + ProveReplicaUpdate1: rfunc(storiface.WorkerReturn.ReturnProveReplicaUpdate1), + ProveReplicaUpdate2: rfunc(storiface.WorkerReturn.ReturnProveReplicaUpdate2), + MoveStorage: rfunc(storiface.WorkerReturn.ReturnMoveStorage), + UnsealPiece: rfunc(storiface.WorkerReturn.ReturnUnsealPiece), + Fetch: rfunc(storiface.WorkerReturn.ReturnFetch), } func (l *LocalWorker) asyncCall(ctx context.Context, sector storage.SectorRef, rt ReturnType, work func(ctx context.Context, ci storiface.CallID) (interface{}, error)) (storiface.CallID, error) { @@ -240,7 +245,6 @@ func (l *LocalWorker) asyncCall(ctx context.Context, sector storage.SectorRef, r } res, err := work(ctx, ci) - if err != nil { rb, err := json.Marshal(res) if err != nil { @@ -258,7 +262,6 @@ func (l *LocalWorker) asyncCall(ctx context.Context, sector storage.SectorRef, r } } }() - return ci, nil } @@ -382,6 +385,40 @@ func (l *LocalWorker) SealCommit2(ctx context.Context, sector storage.SectorRef, }) } +func (l *LocalWorker) ReplicaUpdate(ctx context.Context, sector storage.SectorRef, pieces []abi.PieceInfo) (storiface.CallID, error) { + sb, err := l.executor() + if err != nil { + return storiface.UndefCall, err + } + + return l.asyncCall(ctx, sector, ReplicaUpdate, func(ctx context.Context, ci storiface.CallID) (interface{}, error) { + sealerOut, err := sb.ReplicaUpdate(ctx, sector, pieces) + return sealerOut, err + }) +} + +func (l *LocalWorker) ProveReplicaUpdate1(ctx context.Context, sector storage.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid) (storiface.CallID, error) { + sb, err := l.executor() + if err != nil { + return storiface.UndefCall, err + } + + return l.asyncCall(ctx, sector, ProveReplicaUpdate1, func(ctx context.Context, ci storiface.CallID) (interface{}, error) { + return sb.ProveReplicaUpdate1(ctx, sector, sectorKey, newSealed, newUnsealed) + }) +} + +func (l *LocalWorker) ProveReplicaUpdate2(ctx context.Context, sector storage.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid, vanillaProofs storage.ReplicaVanillaProofs) (storiface.CallID, error) { + sb, err := l.executor() + if err != nil { + return storiface.UndefCall, err + } + + return l.asyncCall(ctx, sector, ProveReplicaUpdate2, func(ctx context.Context, ci storiface.CallID) (interface{}, error) { + return sb.ProveReplicaUpdate2(ctx, sector, sectorKey, newSealed, newUnsealed, vanillaProofs) + }) +} + func (l *LocalWorker) FinalizeSector(ctx context.Context, sector storage.SectorRef, keepUnsealed []storage.Range) (storiface.CallID, error) { sb, err := l.executor() if err != nil { diff --git a/extern/sector-storage/worker_tracked.go b/extern/sector-storage/worker_tracked.go index 5702426c31a..b87abed061f 100644 --- a/extern/sector-storage/worker_tracked.go +++ b/extern/sector-storage/worker_tracked.go @@ -98,7 +98,6 @@ func (wt *workTracker) track(ctx context.Context, ready chan struct{}, wid Worke wt.lk.Lock() delete(wt.prepared, prepID) } - callID, err := cb() if err != nil { return callID, err @@ -198,4 +197,22 @@ func (t *trackedWorker) UnsealPiece(ctx context.Context, id storage.SectorRef, i return t.tracker.track(ctx, t.execute, t.wid, t.workerInfo, id, sealtasks.TTUnseal, func() (storiface.CallID, error) { return t.Worker.UnsealPiece(ctx, id, index, size, randomness, cid) }) } +func (t *trackedWorker) ReplicaUpdate(ctx context.Context, sector storage.SectorRef, pieces []abi.PieceInfo) (storiface.CallID, error) { + return t.tracker.track(ctx, t.execute, t.wid, t.workerInfo, sector, sealtasks.TTReplicaUpdate, func() (storiface.CallID, error) { + return t.Worker.ReplicaUpdate(ctx, sector, pieces) + }) +} + +func (t *trackedWorker) ProveReplicaUpdate1(ctx context.Context, sector storage.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid) (storiface.CallID, error) { + return t.tracker.track(ctx, t.execute, t.wid, t.workerInfo, sector, sealtasks.TTProveReplicaUpdate1, func() (storiface.CallID, error) { + return t.Worker.ProveReplicaUpdate1(ctx, sector, sectorKey, newSealed, newUnsealed) + }) +} + +func (t *trackedWorker) ProveReplicaUpdate2(ctx context.Context, sector storage.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid, vanillaProofs storage.ReplicaVanillaProofs) (storiface.CallID, error) { + return t.tracker.track(ctx, t.execute, t.wid, t.workerInfo, sector, sealtasks.TTProveReplicaUpdate2, func() (storiface.CallID, error) { + return t.Worker.ProveReplicaUpdate2(ctx, sector, sectorKey, newSealed, newUnsealed, vanillaProofs) + }) +} + var _ Worker = &trackedWorker{} diff --git a/go.mod b/go.mod index ce52b7975c4..e0823094dfa 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/filecoin-project/specs-actors/v5 v5.0.4 github.com/filecoin-project/specs-actors/v6 v6.0.1 github.com/filecoin-project/specs-actors/v7 v7.0.0-20211118013026-3dce48197cec - github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 + github.com/filecoin-project/specs-storage v0.1.1-0.20211123153428-712cb8da07a3 github.com/filecoin-project/test-vectors/schema v0.0.5 github.com/gbrlsnchs/jwt/v3 v3.0.1 github.com/gdamore/tcell/v2 v2.2.0 @@ -156,7 +156,7 @@ require ( golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac - golang.org/x/tools v0.1.5 + golang.org/x/tools v0.1.7 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 gopkg.in/cheggaaa/pb.v1 v1.0.28 gotest.tools v2.2.0+incompatible diff --git a/go.sum b/go.sum index 06341ce01eb..e404ca72e56 100644 --- a/go.sum +++ b/go.sum @@ -396,8 +396,8 @@ github.com/filecoin-project/specs-actors/v6 v6.0.1/go.mod h1:V1AYfi5GkHXipx1mnVi github.com/filecoin-project/specs-actors/v7 v7.0.0-20211117170924-fd07a4c7dff9/go.mod h1:p6LIOFezA1rgRLMewbvdi3Pp6SAu+q9FtJ9CAleSjrE= github.com/filecoin-project/specs-actors/v7 v7.0.0-20211118013026-3dce48197cec h1:KV9vE+Sl2Y3qKsrpba4HcE7wHwK7v6O5U/S0xHbje6A= github.com/filecoin-project/specs-actors/v7 v7.0.0-20211118013026-3dce48197cec/go.mod h1:p6LIOFezA1rgRLMewbvdi3Pp6SAu+q9FtJ9CAleSjrE= -github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 h1:Ur/l2+6qN+lQiqjozWWc5p9UDaAMDZKTlDS98oRnlIw= -github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= +github.com/filecoin-project/specs-storage v0.1.1-0.20211123153428-712cb8da07a3 h1:FLPxD2ksWwGc/sbnFLWep2p8ViP93VCAwFaVxrtVCyo= +github.com/filecoin-project/specs-storage v0.1.1-0.20211123153428-712cb8da07a3/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/test-vectors/schema v0.0.5 h1:w3zHQhzM4pYxJDl21avXjOKBLF8egrvwUwjpT8TquDg= github.com/filecoin-project/test-vectors/schema v0.0.5/go.mod h1:iQ9QXLpYWL3m7warwvK1JC/pTri8mnfEmKygNDqqY6E= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= @@ -1872,6 +1872,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= github.com/zondax/ledger-go v0.12.1 h1:hYRcyznPRJp+5mzF2sazTLP2nGvGjYDD2VzhHhFomLU= @@ -2104,6 +2105,7 @@ golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210917221730-978cfadd31cf h1:R150MpwJIv1MpS0N/pc+NhTM8ajzvlmxlY5OYsrevXQ= golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -2227,6 +2229,7 @@ golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 h1:J27LZFQBFoihqXoegpscI10HpjZ7B5WQLLKL2FZXQKw= golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2318,8 +2321,9 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1-0.20210225150353-54dc8c5edb56/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From e16e9ad34393c5c97f18d895749ffc3a1c70a8c8 Mon Sep 17 00:00:00 2001 From: c r Date: Mon, 29 Nov 2021 17:26:47 -0500 Subject: [PATCH 08/24] reorder `transfer` checks so as to ensure sending more money than you have to yourself fails with an error (fixing issue 7596) PR #7637, also adds tests to make sure behavior is correct across versions. --- .circleci/config.yml | 5 ++ chain/vm/runtime.go | 2 +- chain/vm/vm.go | 93 ++++++++++++++++++++++---------- itests/self_sent_txn_test.go | 102 +++++++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+), 28 deletions(-) create mode 100644 itests/self_sent_txn_test.go diff --git a/.circleci/config.yml b/.circleci/config.yml index 30f2d5c01fd..d747e2cab2f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -890,6 +890,11 @@ workflows: suite: itest-sector_terminate target: "./itests/sector_terminate_test.go" + - test: + name: test-itest-self_sent_txn + suite: itest-self_sent_txn + target: "./itests/self_sent_txn_test.go" + - test: name: test-itest-tape suite: itest-tape diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 0dbe98224ee..548b0902806 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -332,7 +332,7 @@ func (rt *Runtime) DeleteActor(beneficiary address.Address) { } // Transfer the executing actor's balance to the beneficiary - if err := rt.vm.transfer(rt.Receiver(), beneficiary, act.Balance); err != nil { + if err := rt.vm.transfer(rt.Receiver(), beneficiary, act.Balance, rt.NetworkVersion()); err != nil { panic(aerrors.Fatalf("failed to transfer balance to beneficiary actor: %s", err)) } } diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 36308fe03f6..16ad5e2a463 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -339,7 +339,7 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime, defer rt.chargeGasSafe(newGasCharge("OnMethodInvocationDone", 0, 0)) if types.BigCmp(msg.Value, types.NewInt(0)) != 0 { - if err := vm.transfer(msg.From, msg.To, msg.Value); err != nil { + if err := vm.transfer(msg.From, msg.To, msg.Value, vm.ntwkVersion(ctx, vm.blockHeight)); err != nil { return nil, aerrors.Wrap(err, "failed to transfer funds") } } @@ -869,32 +869,71 @@ func (vm *VM) incrementNonce(addr address.Address) error { }) } -func (vm *VM) transfer(from, to address.Address, amt types.BigInt) aerrors.ActorError { - if from == to { - return nil - } +func (vm *VM) transfer(from, to address.Address, amt types.BigInt, networkVersion network.Version) aerrors.ActorError { + var f *types.Actor + var fromID, toID address.Address + var err error + // switching the order around so that transactions for more than the balance sent to self fail + if networkVersion >= network.Version15 { + if amt.LessThan(types.NewInt(0)) { + return aerrors.Newf(exitcode.SysErrForbidden, "attempted to transfer negative value: %s", amt) + } - fromID, err := vm.cstate.LookupID(from) - if err != nil { - return aerrors.Fatalf("transfer failed when resolving sender address: %s", err) - } + fromID, err = vm.cstate.LookupID(from) + if err != nil { + return aerrors.Fatalf("transfer failed when resolving sender address: %s", err) + } - toID, err := vm.cstate.LookupID(to) - if err != nil { - return aerrors.Fatalf("transfer failed when resolving receiver address: %s", err) - } + f, err = vm.cstate.GetActor(fromID) + if err != nil { + return aerrors.Fatalf("transfer failed when retrieving sender actor: %s", err) + } - if fromID == toID { - return nil - } + if f.Balance.LessThan(amt) { + return aerrors.Newf(exitcode.SysErrInsufficientFunds, "transfer failed, insufficient balance in sender actor: %v", f.Balance) + } - if amt.LessThan(types.NewInt(0)) { - return aerrors.Newf(exitcode.SysErrForbidden, "attempted to transfer negative value: %s", amt) - } + if from == to { + log.Infow("sending to same address: noop", "from/to addr", from) + return nil + } - f, err := vm.cstate.GetActor(fromID) - if err != nil { - return aerrors.Fatalf("transfer failed when retrieving sender actor: %s", err) + toID, err = vm.cstate.LookupID(to) + if err != nil { + return aerrors.Fatalf("transfer failed when resolving receiver address: %s", err) + } + + if fromID == toID { + log.Infow("sending to same actor ID: noop", "from/to actor", fromID) + return nil + } + } else { + if from == to { + return nil + } + + fromID, err = vm.cstate.LookupID(from) + if err != nil { + return aerrors.Fatalf("transfer failed when resolving sender address: %s", err) + } + + toID, err = vm.cstate.LookupID(to) + if err != nil { + return aerrors.Fatalf("transfer failed when resolving receiver address: %s", err) + } + + if fromID == toID { + return nil + } + + if amt.LessThan(types.NewInt(0)) { + return aerrors.Newf(exitcode.SysErrForbidden, "attempted to transfer negative value: %s", amt) + } + + f, err = vm.cstate.GetActor(fromID) + if err != nil { + return aerrors.Fatalf("transfer failed when retrieving sender actor: %s", err) + } } t, err := vm.cstate.GetActor(toID) @@ -902,17 +941,17 @@ func (vm *VM) transfer(from, to address.Address, amt types.BigInt) aerrors.Actor return aerrors.Fatalf("transfer failed when retrieving receiver actor: %s", err) } - if err := deductFunds(f, amt); err != nil { + if err = deductFunds(f, amt); err != nil { return aerrors.Newf(exitcode.SysErrInsufficientFunds, "transfer failed when deducting funds (%s): %s", types.FIL(amt), err) } depositFunds(t, amt) - if err := vm.cstate.SetActor(fromID, f); err != nil { - return aerrors.Fatalf("transfer failed when setting receiver actor: %s", err) + if err = vm.cstate.SetActor(fromID, f); err != nil { + return aerrors.Fatalf("transfer failed when setting sender actor: %s", err) } - if err := vm.cstate.SetActor(toID, t); err != nil { - return aerrors.Fatalf("transfer failed when setting sender actor: %s", err) + if err = vm.cstate.SetActor(toID, t); err != nil { + return aerrors.Fatalf("transfer failed when setting receiver actor: %s", err) } return nil diff --git a/itests/self_sent_txn_test.go b/itests/self_sent_txn_test.go new file mode 100644 index 00000000000..846bcff05d8 --- /dev/null +++ b/itests/self_sent_txn_test.go @@ -0,0 +1,102 @@ +package itests + +import ( + "context" + "testing" + "time" + + "github.com/filecoin-project/go-state-types/network" + + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/exitcode" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/itests/kit" + "github.com/stretchr/testify/require" +) + + +// these tests check that the versioned code in vm.transfer is functioning correctly across versions! +// we reordered the checks to make sure that a transaction with too much money in it sent to yourself will fail instead of succeeding as a noop +// more info in this PR! https://github.com/filecoin-project/lotus/pull/7637 +func TestSelfSentTxnV15(t *testing.T) { + ctx := context.Background() + + kit.QuietMiningLogs() + + client15, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.GenesisNetworkVersion(network.Version15)) + ens.InterconnectAll().BeginMining(10 * time.Millisecond) + + bal, err := client15.WalletBalance(ctx, client15.DefaultKey.Address) + require.NoError(t, err) + + // send self half of account balance + msgHalfBal := &types.Message{ + From: client15.DefaultKey.Address, + To: client15.DefaultKey.Address, + Value: big.Div(bal, big.NewInt(2)), + } + smHalfBal, err := client15.MpoolPushMessage(ctx, msgHalfBal, nil) + require.NoError(t, err) + mLookup, err := client15.StateWaitMsg(ctx, smHalfBal.Cid(), 3, api.LookbackNoLimit, true) + require.NoError(t, err) + require.Equal(t, exitcode.Ok, mLookup.Receipt.ExitCode) + + msgOverBal := &types.Message{ + From: client15.DefaultKey.Address, + To: client15.DefaultKey.Address, + Value: big.Mul(big.NewInt(2), bal), + GasLimit: 10000000000, + GasPremium: big.NewInt(10000000000), + GasFeeCap: big.NewInt(100000000000), + Nonce: 1, + } + smOverBal, err := client15.WalletSignMessage(ctx, client15.DefaultKey.Address, msgOverBal) + require.NoError(t, err) + smcid, err := client15.MpoolPush(ctx, smOverBal) + require.NoError(t, err) + mLookup, err = client15.StateWaitMsg(ctx, smcid, 3, api.LookbackNoLimit, true) + require.NoError(t, err) + require.Equal(t, exitcode.SysErrInsufficientFunds, mLookup.Receipt.ExitCode) +} + +func TestSelfSentTxnV14(t *testing.T) { + ctx := context.Background() + + kit.QuietMiningLogs() + + client14, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.GenesisNetworkVersion(network.Version14)) + ens.InterconnectAll().BeginMining(10 * time.Millisecond) + + bal, err := client14.WalletBalance(ctx, client14.DefaultKey.Address) + require.NoError(t, err) + + // send self half of account balance + msgHalfBal := &types.Message{ + From: client14.DefaultKey.Address, + To: client14.DefaultKey.Address, + Value: big.Div(bal, big.NewInt(2)), + } + smHalfBal, err := client14.MpoolPushMessage(ctx, msgHalfBal, nil) + require.NoError(t, err) + mLookup, err := client14.StateWaitMsg(ctx, smHalfBal.Cid(), 3, api.LookbackNoLimit, true) + require.NoError(t, err) + require.Equal(t, exitcode.Ok, mLookup.Receipt.ExitCode) + + msgOverBal := &types.Message{ + From: client14.DefaultKey.Address, + To: client14.DefaultKey.Address, + Value: big.Mul(big.NewInt(2), bal), + GasLimit: 10000000000, + GasPremium: big.NewInt(10000000000), + GasFeeCap: big.NewInt(100000000000), + Nonce: 1, + } + smOverBal, err := client14.WalletSignMessage(ctx, client14.DefaultKey.Address, msgOverBal) + require.NoError(t, err) + smcid, err := client14.MpoolPush(ctx, smOverBal) + require.NoError(t, err) + mLookup, err = client14.StateWaitMsg(ctx, smcid, 3, api.LookbackNoLimit, true) + require.NoError(t, err) + require.Equal(t, exitcode.Ok, mLookup.Receipt.ExitCode) +} From f88fcdbcfc5c238f8bc6545a39c78c2e9a1df7d4 Mon Sep 17 00:00:00 2001 From: zenground0 Date: Tue, 30 Nov 2021 12:40:14 -0500 Subject: [PATCH 09/24] WIP --- extern/sector-storage/ffiwrapper/sealer_cgo.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extern/sector-storage/ffiwrapper/sealer_cgo.go b/extern/sector-storage/ffiwrapper/sealer_cgo.go index 81dbfb42694..b9fad3a0418 100644 --- a/extern/sector-storage/ffiwrapper/sealer_cgo.go +++ b/extern/sector-storage/ffiwrapper/sealer_cgo.go @@ -628,9 +628,9 @@ func (sb *Sealer) ReplicaUpdate(ctx context.Context, sector storage.SectorRef, p } // XXX: we want to keep the stuff at the end - if err := os.Truncate(paths.Unsealed, sealedSize); err != nil { - return empty, xerrors.Errorf("failed to truncate unsealed data file: %w", err) - } + // if err := os.Truncate(paths.Unsealed, sealedSize); err != nil { + // return empty, xerrors.Errorf("failed to truncate unsealed data file: %w", err) + // } sealed, unsealed, err := ffi.SectorUpdate.EncodeInto(updateProofType, paths.Update, paths.UpdateCache, paths.Sealed, paths.Cache, paths.Unsealed, pieces) if err != nil { From 40d16a8f880395c7ce2b8cc62a2e4605e95e2c5d Mon Sep 17 00:00:00 2001 From: zenground0 Date: Tue, 30 Nov 2021 13:53:37 -0500 Subject: [PATCH 10/24] Review Response --- extern/filecoin-ffi | 2 +- extern/sector-storage/ffiwrapper/sealer_cgo.go | 6 +++--- extern/sector-storage/manager_test.go | 15 ++++++++++----- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index b1a66cfd126..ce7083b3d18 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit b1a66cfd12686a8af6030fccace49916849b1954 +Subproject commit ce7083b3d187ec3bc41a68ab66567bd4f3be6dfc diff --git a/extern/sector-storage/ffiwrapper/sealer_cgo.go b/extern/sector-storage/ffiwrapper/sealer_cgo.go index b9fad3a0418..81dbfb42694 100644 --- a/extern/sector-storage/ffiwrapper/sealer_cgo.go +++ b/extern/sector-storage/ffiwrapper/sealer_cgo.go @@ -628,9 +628,9 @@ func (sb *Sealer) ReplicaUpdate(ctx context.Context, sector storage.SectorRef, p } // XXX: we want to keep the stuff at the end - // if err := os.Truncate(paths.Unsealed, sealedSize); err != nil { - // return empty, xerrors.Errorf("failed to truncate unsealed data file: %w", err) - // } + if err := os.Truncate(paths.Unsealed, sealedSize); err != nil { + return empty, xerrors.Errorf("failed to truncate unsealed data file: %w", err) + } sealed, unsealed, err := ffi.SectorUpdate.EncodeInto(updateProofType, paths.Update, paths.UpdateCache, paths.Sealed, paths.Cache, paths.Unsealed, pieces) if err != nil { diff --git a/extern/sector-storage/manager_test.go b/extern/sector-storage/manager_test.go index e4ca355600a..77e185b9398 100644 --- a/extern/sector-storage/manager_test.go +++ b/extern/sector-storage/manager_test.go @@ -68,11 +68,16 @@ func newTestStorage(t *testing.T) *testStorage { } func (t testStorage) cleanup() { - // for _, path := range t.StoragePaths { - // if err := os.RemoveAll(path.Path); err != nil { - // fmt.Println("Cleanup error:", err) - // } - // } + noCleanup := os.Getenv("LOTUS_TEST_NO_CLEANUP") != "" + for _, path := range t.StoragePaths { + if noCleanup { + fmt.Printf("Not cleaning up test storage at %s\n", path) + continue + } + if err := os.RemoveAll(path.Path); err != nil { + fmt.Println("Cleanup error:", err) + } + } } func (t testStorage) GetStorage() (stores.StorageConfig, error) { From c2437b7bf2a24d4244a00945d9ebfe304cf05cb6 Mon Sep 17 00:00:00 2001 From: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:37:22 -0500 Subject: [PATCH 11/24] Create pull_request_template.md This is the very first iteration of the lotus PR template. The goal of adding PR template is to standardize PR requests and encourage contributors to: - come up with good PR descriptions to give code reviewers a clear overview of what's in the PR - have a clear PR title as lotus generates a change log based on it - check that tests and documentation for the codes that changed are icnluded The PR type follows the https://www.conventionalcommits.org/en/v1.0.0-beta.2/. The [contribution guideline](https://github.com/filecoin-project/lotus#contribute) should be updated with how to create a pr after the template is accepted. --- .github/pull_request_template.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000000..6984f6ffd3d --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,20 @@ +## Related Issues + + +## Proposed Changes + + + +## Additional Info + + +## Checklist + +Before you mark the PR ready for review, please make sure that: +- [ ] The PR title is in the form of of `: <#issue number> : ` + - example: ` fix: #1234 mempool: Introduce a cache for valid signatures` + - `PR type`: _fix_, _feat_, _BREAKING CHANGE_, _build_, _chore_, _ci_, _docs_, _perf_, _refactor_, _revert_, _style_, _test_ + - `area`: _api_, _chain_, _state_, _vm_, _data transfer_, _market_, _mempool_, _message_, _block production_, _multisig_, _networking_, _paychan_, _proving_, _sealing_, _wallet_ +- [ ] This PR has tests for new functionality or change in behaviour +- [ ] If new user-facing features are introduced, clear usage guidelines and / or documentation updates should be included in https://lotus.filecoin.io or [Discussion Tutorials.](https://github.com/filecoin-project/lotus/discussions/categories/tutorials) +- [ ] CI is green From a5be80828a28908b665b9f5b5a647b084c2bc6ba Mon Sep 17 00:00:00 2001 From: zenground0 Date: Wed, 1 Dec 2021 14:01:55 -0500 Subject: [PATCH 12/24] RemoveData and Decode - Unsealing replica update with sector key works and tested - Sector key generation added and tested --- api/api_storage.go | 1 + api/api_worker.go | 1 + api/proxy_gen.go | 26 +++++++ build/openrpc/full.json.gz | Bin 25466 -> 25465 bytes build/openrpc/miner.json.gz | Bin 10672 -> 10724 bytes build/openrpc/worker.json.gz | Bin 2940 -> 3000 bytes documentation/en/api-v0-methods-miner.md | 25 ++++++ documentation/en/api-v0-methods-worker.md | 37 +++++++++ extern/filecoin-ffi | 2 +- .../sector-storage/ffiwrapper/sealer_cgo.go | 60 ++++++++++++-- extern/sector-storage/manager.go | 73 +++++++++++++++++- extern/sector-storage/manager_test.go | 36 ++++++--- extern/sector-storage/mock/mock.go | 8 ++ extern/sector-storage/sched_test.go | 4 + extern/sector-storage/sealtasks/task.go | 5 +- extern/sector-storage/storiface/worker.go | 2 + extern/sector-storage/teststorage_test.go | 4 + extern/sector-storage/worker_local.go | 13 ++++ go.mod | 2 +- go.sum | 4 +- itests/self_sent_txn_test.go | 3 +- 21 files changed, 281 insertions(+), 25 deletions(-) diff --git a/api/api_storage.go b/api/api_storage.go index bf7520d09e7..92117d2fb09 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -127,6 +127,7 @@ type StorageMiner interface { ReturnReplicaUpdate(ctx context.Context, callID storiface.CallID, out storage.ReplicaUpdateOut, err *storiface.CallError) error //perm:admin retry:true ReturnProveReplicaUpdate1(ctx context.Context, callID storiface.CallID, vanillaProofs storage.ReplicaVanillaProofs, err *storiface.CallError) error //perm:admin retry:true ReturnProveReplicaUpdate2(ctx context.Context, callID storiface.CallID, proof storage.ReplicaUpdateProof, err *storiface.CallError) error //perm:admin retry:true + ReturnGenerateSectorKeyFromData(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error //perm:admin retry:true ReturnReleaseUnsealed(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error //perm:admin retry:true ReturnMoveStorage(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error //perm:admin retry:true ReturnUnsealPiece(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error //perm:admin retry:true diff --git a/api/api_worker.go b/api/api_worker.go index 5e0b4f8c6d4..68d8e7baf5c 100644 --- a/api/api_worker.go +++ b/api/api_worker.go @@ -42,6 +42,7 @@ type Worker interface { ReplicaUpdate(ctx context.Context, sector storage.SectorRef, pieces []abi.PieceInfo) (storiface.CallID, error) //perm:admin ProveReplicaUpdate1(ctx context.Context, sector storage.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid) (storiface.CallID, error) //perm:admin ProveReplicaUpdate2(ctx context.Context, sector storage.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid, vanillaProofs storage.ReplicaVanillaProofs) (storiface.CallID, error) //perm:admin + GenerateSectorKeyFromData(ctx context.Context, sector storage.SectorRef, commD cid.Cid) (storiface.CallID, error) //perm:admin ReleaseUnsealed(ctx context.Context, sector storage.SectorRef, safeToFree []storage.Range) (storiface.CallID, error) //perm:admin MoveStorage(ctx context.Context, sector storage.SectorRef, types storiface.SectorFileType) (storiface.CallID, error) //perm:admin UnsealPiece(context.Context, storage.SectorRef, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize, abi.SealRandomness, cid.Cid) (storiface.CallID, error) //perm:admin diff --git a/api/proxy_gen.go b/api/proxy_gen.go index b78b40959b2..5733c3cc851 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -707,6 +707,8 @@ type StorageMinerStruct struct { ReturnFinalizeSector func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` + ReturnGenerateSectorKeyFromData func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` + ReturnMoveStorage func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` ReturnProveReplicaUpdate1 func(p0 context.Context, p1 storiface.CallID, p2 storage.ReplicaVanillaProofs, p3 *storiface.CallError) error `perm:"admin"` @@ -850,6 +852,8 @@ type WorkerStruct struct { FinalizeSector func(p0 context.Context, p1 storage.SectorRef, p2 []storage.Range) (storiface.CallID, error) `perm:"admin"` + GenerateSectorKeyFromData func(p0 context.Context, p1 storage.SectorRef, p2 cid.Cid) (storiface.CallID, error) `perm:"admin"` + Info func(p0 context.Context) (storiface.WorkerInfo, error) `perm:"admin"` MoveStorage func(p0 context.Context, p1 storage.SectorRef, p2 storiface.SectorFileType) (storiface.CallID, error) `perm:"admin"` @@ -4166,6 +4170,17 @@ func (s *StorageMinerStub) ReturnFinalizeSector(p0 context.Context, p1 storiface return ErrNotSupported } +func (s *StorageMinerStruct) ReturnGenerateSectorKeyFromData(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error { + if s.Internal.ReturnGenerateSectorKeyFromData == nil { + return ErrNotSupported + } + return s.Internal.ReturnGenerateSectorKeyFromData(p0, p1, p2) +} + +func (s *StorageMinerStub) ReturnGenerateSectorKeyFromData(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error { + return ErrNotSupported +} + func (s *StorageMinerStruct) ReturnMoveStorage(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error { if s.Internal.ReturnMoveStorage == nil { return ErrNotSupported @@ -4859,6 +4874,17 @@ func (s *WorkerStub) FinalizeSector(p0 context.Context, p1 storage.SectorRef, p2 return *new(storiface.CallID), ErrNotSupported } +func (s *WorkerStruct) GenerateSectorKeyFromData(p0 context.Context, p1 storage.SectorRef, p2 cid.Cid) (storiface.CallID, error) { + if s.Internal.GenerateSectorKeyFromData == nil { + return *new(storiface.CallID), ErrNotSupported + } + return s.Internal.GenerateSectorKeyFromData(p0, p1, p2) +} + +func (s *WorkerStub) GenerateSectorKeyFromData(p0 context.Context, p1 storage.SectorRef, p2 cid.Cid) (storiface.CallID, error) { + return *new(storiface.CallID), ErrNotSupported +} + func (s *WorkerStruct) Info(p0 context.Context) (storiface.WorkerInfo, error) { if s.Internal.Info == nil { return *new(storiface.WorkerInfo), ErrNotSupported diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index a5816ef4f3d57f10df36cc9e5a911257fb47e0e6..839e95e61f36b78820c1705ba99bb12de914ce52 100644 GIT binary patch delta 24891 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 diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index 0c176bbef0d3f369e719e67fffeed4443dd180b3..f0eaa49ec9bd976dc3f27084730e55661bfeaf14 100644 GIT binary patch delta 10012 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 delta 9959 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 literal 2940 zcmV-?3xo6@iwFP!00000|Lk3FZ`-!k|0)EZH_f2fj_stWfxYOHZo2{6E;m`W7fo^5$&wt=v3ebc7|_KO4|xuG{``1EQjeI2z(nZc0X}MVTPN7T zl#MtZJYq$a4|sq-aurE*d2xo`Uz}qH--D2pvzX$j*Xka6aF1sW4nR$~C-LCRBW5Jf zq`y)hTuxc*z2{v}Z~;5m1L+DHs-%gpU%!s|4I4$wMQPdgm z)(4`<0eYi<(h+f?bw+&u{DXr)2rdrL;|;q}bcAH~9Y%Qb~Mzeiz!)7<^>({T?!7>U0 zBBpqNm%Sz9sr!^S3_Ca^f&|I%MnX@~aC#VWN#p5AALphpJSxmtVbpVd>mTj}0-|*Y zzL6mGA!+gagD(0+83;T$>U25|{u~8E{p;P#!54z_(I3+g@ZfZI>tNz}Fh1bQ+;0WMLxBo=PwEN81*n5_zHs5NIS^8H%}Qw6C~6eP&^m5ddl5)rf_ zyDQ~O(s+7}}3Uz!y;xpFz0d35<^EUbKu;icle|RG=kt*|JE!BO}I|St0dD7s~ ziGu^mGQZNwiH^^ljO@GTsWx^!#WHOvN#Odx-I9_1jjBmBL;?b?0Qr>NVFyRT#{)c3 zDwKnEdmLA3xjbl(QV4Mv3a=R6zo_YeuotdM-FM}x^eZTLVyH+ljTxF`OUqBz;rH+#08lt5nA^{EJJq=t={BbWi+9`{wg8 z;{q;0@<_Pz^s|FA1&{a>1Q(O3q%QICpxv)9U(wYmOS73D2N96{xP8Yectx1r~ zjCE7})01wwoBG7>;VQu>hTbYext(mFAh^rrJmdc+dUZH?VKXRA&G4Ewh{{lLm)JmpoF-5YgwszXDurVfhx7#*$ z5~J?IsxH;&rx$Ut(J+P1Jz$ECXo-hAqaG5vdkIWwHz&a#9VT^#l#LSuWC{__6Cfpc zh%Q=dp>w63!$e>gKXxnq+%dzRdJ z*Ey++go^>(6bW~?ii8~$9xo``9xxh)akMxtfMeO;i;v$&jXg|NO&2 z5&_Etpl+l*?wQ25loj1|c}Sb@{cWS))da-Wu7=9WS<~7pY~0Ljo3#K#eJ}HspCi9` zuSQy!S-38CZ}|QTH?CgAtr@ulsj-b^Xg9eNF1{HmKCoj7Ofwxf2TSwPSx~wQw!dSb zG^fRlgVMOCvvdRKx};iR|EGnh7NS~+`s^rrTyeR?6%hZ72LV;4TNyKyW)U=jcErDo zcil3Oa&e(*9KwjJ=sgr_^jAY~?hS9!#ToTX-|J??Xeu7(N6Nm(wUK#EWG-6A9$v6o zY3DCm*5V6B3$vd40&wZqYkIB4%ZkBvUTBQ=vXCvRfMZR|x zx3X<^9ozHoVQcCFwx@1h`$+F#>X>b<&L%E zPN(9IwJT7YeOhrzSOpV@ocn9`%r6^w?!NgPD{J=7FFOo~xRXdtU~UyeB1oRK=ho3e zpSeP6Li9gWA_+=SHojp2nIc8*01-5T2PDDe%#%oQq}@9i69xK*BJvJtb@w8Fi#zpy z%r_nFR``#{oui7|Skgln?>#TROV!kH^3>IfEJ4|Lo&Dt7dA1Q1*s8Xqt*waSoKU^b z>Se!LvCS)^UY%BVD^4H(LFCoV9aXwtI+O##R0wf zoS1$DU_n>D1P(~}r8x1oGNyir`T3)j>exiA!1#?!CazmKcK!-O`r_%$JTzCKM zh42$n6lUb<`gIa+bGy=7IybGsW4z@xBuWp;MK0ge`sv98)n2ELjyoq6$8wVGyYV|s zL+i;g;cK#Qk>faFsWvG%1x>BXAOnxoMo}2s1_Ft}k%dUn#ckd*Mn4&&X6A*xi0K}5F mbP|b(vH0EIGd1?rC8OT;@N9NF`)>dM0RR8#PS8G&m;eBTe!1}g diff --git a/documentation/en/api-v0-methods-miner.md b/documentation/en/api-v0-methods-miner.md index c037a0af6ea..a498cddff68 100644 --- a/documentation/en/api-v0-methods-miner.md +++ b/documentation/en/api-v0-methods-miner.md @@ -94,6 +94,7 @@ * [ReturnAddPiece](#ReturnAddPiece) * [ReturnFetch](#ReturnFetch) * [ReturnFinalizeSector](#ReturnFinalizeSector) + * [ReturnGenerateSectorKeyFromData](#ReturnGenerateSectorKeyFromData) * [ReturnMoveStorage](#ReturnMoveStorage) * [ReturnProveReplicaUpdate1](#ReturnProveReplicaUpdate1) * [ReturnProveReplicaUpdate2](#ReturnProveReplicaUpdate2) @@ -1443,6 +1444,30 @@ Response: `{}` ### ReturnFinalizeSector +Perms: admin + +Inputs: +```json +[ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + }, + { + "Code": 0, + "Message": "string value" + } +] +``` + +Response: `{}` + +### ReturnGenerateSectorKeyFromData + + Perms: admin Inputs: diff --git a/documentation/en/api-v0-methods-worker.md b/documentation/en/api-v0-methods-worker.md index 7aee91d526e..5d4b33a52f1 100644 --- a/documentation/en/api-v0-methods-worker.md +++ b/documentation/en/api-v0-methods-worker.md @@ -11,6 +11,8 @@ * [AddPiece](#AddPiece) * [Finalize](#Finalize) * [FinalizeSector](#FinalizeSector) +* [Generate](#Generate) + * [GenerateSectorKeyFromData](#GenerateSectorKeyFromData) * [Move](#Move) * [MoveStorage](#MoveStorage) * [Process](#Process) @@ -220,6 +222,41 @@ Response: } ``` +## Generate + + +### GenerateSectorKeyFromData + + +Perms: admin + +Inputs: +```json +[ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + }, + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: +```json +{ + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" +} +``` + ## Move diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index ce7083b3d18..428503c87d9 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit ce7083b3d187ec3bc41a68ab66567bd4f3be6dfc +Subproject commit 428503c87d917cc5e3e637983b43b4c260863bf0 diff --git a/extern/sector-storage/ffiwrapper/sealer_cgo.go b/extern/sector-storage/ffiwrapper/sealer_cgo.go index 81dbfb42694..65c6762fa20 100644 --- a/extern/sector-storage/ffiwrapper/sealer_cgo.go +++ b/extern/sector-storage/ffiwrapper/sealer_cgo.go @@ -251,6 +251,23 @@ func (sb *Sealer) pieceCid(spt abi.RegisteredSealProof, in []byte) (cid.Cid, err return pieceCID, werr() } +func (sb *Sealer) tryDecodeUpdatedReplica(ctx context.Context, sector storage.SectorRef, commD cid.Cid, unsealedPath string) (bool, error) { + paths, done, err := sb.sectors.AcquireSector(ctx, sector, storiface.FTUpdate|storiface.FTSealed|storiface.FTCache, storiface.FTNone, storiface.PathStorage) + if xerrors.Is(err, storiface.ErrSectorNotFound) { + return false, nil + } else if err != nil { + return false, xerrors.Errorf("reading updated replica: %w", err) + } + defer done() + + // Sector data stored in replica update + updateProof, err := sector.ProofType.RegisteredUpdateProof() + if err != nil { + return false, err + } + return true, ffi.SectorUpdate.DecodeFrom(updateProof, unsealedPath, paths.Update, paths.Sealed, paths.Cache, commD) +} + func (sb *Sealer) UnsealPiece(ctx context.Context, sector storage.SectorRef, offset storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize, randomness abi.SealRandomness, commd cid.Cid) error { ssize, err := sector.ProofType.SectorSize() if err != nil { @@ -301,6 +318,16 @@ func (sb *Sealer) UnsealPiece(ctx context.Context, sector storage.SectorRef, off return nil } + // If piece data stored in updated replica decode whole sector + decoded, err := sb.tryDecodeUpdatedReplica(ctx, sector, commd, unsealedPath.Unsealed) + if err != nil { + return xerrors.Errorf("decoding sector from replica: %w", err) + } + if decoded { + return pf.MarkAllocated(0, maxPieceSize) + } + + // Piece data sealed in sector srcPaths, srcDone, err := sb.sectors.AcquireSector(ctx, sector, storiface.FTCache|storiface.FTSealed, storiface.FTNone, storiface.PathStorage) if err != nil { return xerrors.Errorf("acquire sealed sector paths: %w", err) @@ -626,12 +653,6 @@ func (sb *Sealer) ReplicaUpdate(ctx context.Context, sector storage.SectorRef, p return empty, err } } - - // XXX: we want to keep the stuff at the end - if err := os.Truncate(paths.Unsealed, sealedSize); err != nil { - return empty, xerrors.Errorf("failed to truncate unsealed data file: %w", err) - } - sealed, unsealed, err := ffi.SectorUpdate.EncodeInto(updateProofType, paths.Update, paths.UpdateCache, paths.Sealed, paths.Cache, paths.Unsealed, pieces) if err != nil { return empty, xerrors.Errorf("failed to update replica %d with new deal data: %w", sector.ID.Number, err) @@ -661,6 +682,33 @@ func (sb *Sealer) ProveReplicaUpdate2(ctx context.Context, sector storage.Sector return ffi.SectorUpdate.GenerateUpdateProofWithVanilla(updateProofType, sectorKey, newSealed, newUnsealed, vanillaProofs) } +func (sb *Sealer) GenerateSectorKeyFromData(ctx context.Context, sector storage.SectorRef, commD cid.Cid) error { + paths, done, err := sb.sectors.AcquireSector(ctx, sector, storiface.FTUnsealed|storiface.FTCache|storiface.FTUpdate|storiface.FTUpdateCache, storiface.FTSealed, storiface.PathSealing) + defer done() + if err != nil { + return xerrors.Errorf("failed to acquire sector paths: %w", err) + } + + s, err := os.Stat(paths.Update) + if err != nil { + return xerrors.Errorf("measuring update file size: %w", err) + } + sealedSize := s.Size() + e, err := os.OpenFile(paths.Sealed, os.O_RDWR|os.O_CREATE, 0644) // nolint:gosec + if err != nil { + return xerrors.Errorf("ensuring sector key file exists: %w", err) + } + if err := fallocate.Fallocate(e, 0, sealedSize); err != nil { + return xerrors.Errorf("allocating space for sector key file: %w", err) + } + if err := e.Close(); err != nil { + return err + } + + updateProofType := abi.SealProofInfos[sector.ProofType].UpdateProof + return ffi.SectorUpdate.RemoveData(updateProofType, paths.Sealed, paths.Cache, paths.Update, paths.UpdateCache, paths.Unsealed, commD) +} + func (sb *Sealer) ReleaseSealed(ctx context.Context, sector storage.SectorRef) error { return xerrors.Errorf("not supported at this layer") } diff --git a/extern/sector-storage/manager.go b/extern/sector-storage/manager.go index e0abf1773fd..3deff4d6bd4 100644 --- a/extern/sector-storage/manager.go +++ b/extern/sector-storage/manager.go @@ -578,15 +578,72 @@ func (m *Manager) ReleaseUnsealed(ctx context.Context, sector storage.SectorRef, return nil } -func (m *Manager) ReleaseSealed(ctx context.Context, sector storage.SectorRef) error { - return nil +func (m *Manager) ReleaseSectorKey(ctx context.Context, sector storage.SectorRef) error { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + if err := m.index.StorageLock(ctx, sector.ID, storiface.FTNone, storiface.FTSealed); err != nil { + return xerrors.Errorf("acquiring sector lock: %w", err) + } + + return m.storage.Remove(ctx, sector.ID, storiface.FTSealed, true, nil) +} + +func (m *Manager) GenerateSectorKeyFromData(ctx context.Context, sector storage.SectorRef, commD cid.Cid) error { + + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + wk, wait, cancel, err := m.getWork(ctx, sealtasks.TTRegenSectorKey, sector, commD) + if err != nil { + return xerrors.Errorf("getWork: %w", err) + } + defer cancel() + + var waitErr error + waitRes := func() { + _, werr := m.waitWork(ctx, wk) + if werr != nil { + waitErr = werr + return + } + } + + if wait { // already in progress + waitRes() + return waitErr + } + + if err := m.index.StorageLock(ctx, sector.ID, storiface.FTUnsealed|storiface.FTUpdate|storiface.FTUpdateCache, storiface.FTSealed|storiface.FTCache); err != nil { + return xerrors.Errorf("acquiring sector lock: %w", err) + } + + // NOTE: We set allowFetch to false in so that we always execute on a worker + // with direct access to the data. We want to do that because this step is + // generally very cheap / fast, and transferring data is not worth the effort + selector := newExistingSelector(m.index, sector.ID, storiface.FTUnsealed|storiface.FTUpdate|storiface.FTUpdateCache|storiface.FTCache, true) + + err = m.sched.Schedule(ctx, sector, sealtasks.TTRegenSectorKey, selector, m.schedFetch(sector, storiface.FTUpdate|storiface.FTUnsealed, storiface.PathSealing, storiface.AcquireMove), func(ctx context.Context, w Worker) error { + err := m.startWork(ctx, w, wk)(w.GenerateSectorKeyFromData(ctx, sector, commD)) + if err != nil { + return err + } + + waitRes() + return nil + }) + if err != nil { + return err + } + + return waitErr } func (m *Manager) Remove(ctx context.Context, sector storage.SectorRef) error { ctx, cancel := context.WithCancel(ctx) defer cancel() - if err := m.index.StorageLock(ctx, sector.ID, storiface.FTNone, storiface.FTSealed|storiface.FTUnsealed|storiface.FTCache); err != nil { + if err := m.index.StorageLock(ctx, sector.ID, storiface.FTNone, storiface.FTSealed|storiface.FTUnsealed|storiface.FTCache|storiface.FTUpdate|storiface.FTUpdateCache); err != nil { return xerrors.Errorf("acquiring sector lock: %w", err) } @@ -601,6 +658,12 @@ func (m *Manager) Remove(ctx context.Context, sector storage.SectorRef) error { if rerr := m.storage.Remove(ctx, sector.ID, storiface.FTUnsealed, true, nil); rerr != nil { err = multierror.Append(err, xerrors.Errorf("removing sector (unsealed): %w", rerr)) } + if rerr := m.storage.Remove(ctx, sector.ID, storiface.FTUpdate, true, nil); rerr != nil { + err = multierror.Append(err, xerrors.Errorf("removing sector (unsealed): %w", rerr)) + } + if rerr := m.storage.Remove(ctx, sector.ID, storiface.FTUpdateCache, true, nil); rerr != nil { + err = multierror.Append(err, xerrors.Errorf("removing sector (unsealed): %w", rerr)) + } return err } @@ -790,6 +853,10 @@ func (m *Manager) ReturnProveReplicaUpdate2(ctx context.Context, callID storifac return m.returnResult(ctx, callID, proof, err) } +func (m *Manager) ReturnGenerateSectorKeyFromData(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error { + return m.returnResult(ctx, callID, nil, err) +} + func (m *Manager) ReturnMoveStorage(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error { return m.returnResult(ctx, callID, nil, err) } diff --git a/extern/sector-storage/manager_test.go b/extern/sector-storage/manager_test.go index 77e185b9398..cf54ccbf25a 100644 --- a/extern/sector-storage/manager_test.go +++ b/extern/sector-storage/manager_test.go @@ -199,7 +199,8 @@ func TestSnapDeals(t *testing.T) { localTasks := []sealtasks.TaskType{ sealtasks.TTAddPiece, sealtasks.TTPreCommit1, sealtasks.TTPreCommit2, sealtasks.TTCommit1, sealtasks.TTCommit2, sealtasks.TTFinalize, - sealtasks.TTFetch, sealtasks.TTReplicaUpdate, sealtasks.TTProveReplicaUpdate1, sealtasks.TTProveReplicaUpdate2, + sealtasks.TTFetch, sealtasks.TTReplicaUpdate, sealtasks.TTProveReplicaUpdate1, sealtasks.TTProveReplicaUpdate2, sealtasks.TTUnseal, + sealtasks.TTRegenSectorKey, } wds := datastore.NewMapDatastore() @@ -245,14 +246,6 @@ func TestSnapDeals(t *testing.T) { require.NoError(t, err) fmt.Printf("PC2\n") pc2Out, err := m.SealPreCommit2(ctx, sid, pc1Out) - - require.NoError(t, err) - seed := abi.InteractiveSealRandomness{1, 1, 1, 1, 1, 1, 1} - fmt.Printf("C1\n") - c1Out, err := m.SealCommit1(ctx, sid, ticket, seed, nil, pc2Out) - require.NoError(t, err) - fmt.Printf("C2\n") - _, err = m.SealCommit2(ctx, sid, c1Out) require.NoError(t, err) // Now do a snap deals replica update @@ -270,19 +263,26 @@ func TestSnapDeals(t *testing.T) { pieces := []abi.PieceInfo{p1, p2} fmt.Printf("RU\n") + startRU := time.Now() out, err := m.ReplicaUpdate(ctx, sid, pieces) require.NoError(t, err) + fmt.Printf("RU duration (%s): %s\n", ss.ShortString(), time.Since(startRU)) + updateProofType, err := sid.ProofType.RegisteredUpdateProof() require.NoError(t, err) require.NotNil(t, out) fmt.Printf("PR1\n") + startPR1 := time.Now() vanillaProofs, err := m.ProveReplicaUpdate1(ctx, sid, sectorKey, out.NewSealed, out.NewUnsealed) require.NoError(t, err) require.NotNil(t, vanillaProofs) + fmt.Printf("PR1 duration (%s): %s\n", ss.ShortString(), time.Since(startPR1)) fmt.Printf("PR2\n") + startPR2 := time.Now() proof, err := m.ProveReplicaUpdate2(ctx, sid, sectorKey, out.NewSealed, out.NewUnsealed, vanillaProofs) require.NoError(t, err) require.NotNil(t, proof) + fmt.Printf("PR2 duration (%s): %s\n", ss.ShortString(), time.Since(startPR2)) vInfo := proof7.ReplicaUpdateInfo{ Proof: proof, @@ -294,6 +294,24 @@ func TestSnapDeals(t *testing.T) { pass, err := ffiwrapper.ProofVerifier.VerifyReplicaUpdate(vInfo) require.NoError(t, err) assert.True(t, pass) + + fmt.Printf("Decode\n") + // Remove unsealed data and decode for retrieval + require.NoError(t, m.FinalizeSector(ctx, sid, nil)) + startDecode := time.Now() + require.NoError(t, m.SectorsUnsealPiece(ctx, sid, 0, p1.Size.Unpadded(), ticket, &out.NewUnsealed)) + fmt.Printf("Decode duration (%s): %s\n", ss.ShortString(), time.Since(startDecode)) + + // Remove just the first piece and decode for retrieval + require.NoError(t, m.FinalizeSector(ctx, sid, []storage.Range{{Offset: p1.Size.Unpadded(), Size: p2.Size.Unpadded()}})) + require.NoError(t, m.SectorsUnsealPiece(ctx, sid, 0, p1.Size.Unpadded(), ticket, &out.NewUnsealed)) + + fmt.Printf("GSK\n") + require.NoError(t, m.ReleaseSectorKey(ctx, sid)) + startGSK := time.Now() + require.NoError(t, m.GenerateSectorKeyFromData(ctx, sid, out.NewUnsealed)) + fmt.Printf("GSK duration (%s): %s\n", ss.ShortString(), time.Since(startGSK)) + } func TestRedoPC1(t *testing.T) { diff --git a/extern/sector-storage/mock/mock.go b/extern/sector-storage/mock/mock.go index 023904984a3..95b11c004e0 100644 --- a/extern/sector-storage/mock/mock.go +++ b/extern/sector-storage/mock/mock.go @@ -277,6 +277,10 @@ func (mgr *SectorMgr) ProveReplicaUpdate2(ctx context.Context, sector storage.Se return make([]byte, 0), nil } +func (mgr *SectorMgr) GenerateSectorKeyFromData(ctx context.Context, sector storage.SectorRef, commD cid.Cid) error { + return nil +} + func (mgr *SectorMgr) ReleaseSealed(ctx context.Context, sid storage.SectorRef) error { return nil } @@ -534,6 +538,10 @@ func (mgr *SectorMgr) ReturnProveReplicaUpdate2(ctx context.Context, callID stor panic("not supported") } +func (mgr *SectorMgr) ReturnGenerateSectorKeyFromData(ctx context.Context, callID storiface.CallID, err *storiface.CallError) error { + panic("not supported") +} + func (m mockVerifProver) VerifySeal(svi proof5.SealVerifyInfo) (bool, error) { plen, err := svi.SealProof.ProofSize() if err != nil { diff --git a/extern/sector-storage/sched_test.go b/extern/sector-storage/sched_test.go index fd3c90295b9..a41e7c855a4 100644 --- a/extern/sector-storage/sched_test.go +++ b/extern/sector-storage/sched_test.go @@ -112,6 +112,10 @@ func (s *schedTestWorker) ProveReplicaUpdate2(ctx context.Context, sector storag panic("implement me") } +func (s *schedTestWorker) GenerateSectorKeyFromData(ctx context.Context, sector storage.SectorRef, commD cid.Cid) (storiface.CallID, error) { + panic("implement me") +} + func (s *schedTestWorker) MoveStorage(ctx context.Context, sector storage.SectorRef, types storiface.SectorFileType) (storiface.CallID, error) { panic("implement me") } diff --git a/extern/sector-storage/sealtasks/task.go b/extern/sector-storage/sealtasks/task.go index 3f2a9701fba..f6104878b21 100644 --- a/extern/sector-storage/sealtasks/task.go +++ b/extern/sector-storage/sealtasks/task.go @@ -17,10 +17,12 @@ const ( TTReplicaUpdate TaskType = "seal/v0/replicaupdate" TTProveReplicaUpdate1 TaskType = "seal/v0/provereplicaupdate/1" TTProveReplicaUpdate2 TaskType = "seal/v0/provereplicaupdate/2" + TTRegenSectorKey TaskType = "seal/v0/regensectorkey" ) var order = map[TaskType]int{ - TTAddPiece: 9, // least priority + TTRegenSectorKey: 10, // least priority + TTAddPiece: 9, TTReplicaUpdate: 8, TTProveReplicaUpdate2: 7, TTProveReplicaUpdate1: 6, @@ -49,6 +51,7 @@ var shortNames = map[TaskType]string{ TTReplicaUpdate: "RU", TTProveReplicaUpdate1: "PR1", TTProveReplicaUpdate2: "PR2", + TTRegenSectorKey: "GSK", } func (a TaskType) MuchLess(b TaskType) (bool, bool) { diff --git a/extern/sector-storage/storiface/worker.go b/extern/sector-storage/storiface/worker.go index 970e0ec33a2..ab8c484e660 100644 --- a/extern/sector-storage/storiface/worker.go +++ b/extern/sector-storage/storiface/worker.go @@ -95,6 +95,7 @@ type WorkerCalls interface { ReplicaUpdate(ctx context.Context, sector storage.SectorRef, pieces []abi.PieceInfo) (CallID, error) ProveReplicaUpdate1(ctx context.Context, sector storage.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid) (CallID, error) ProveReplicaUpdate2(ctx context.Context, sector storage.SectorRef, sectorKey, newSealed, newUnsealed cid.Cid, vanillaProofs storage.ReplicaVanillaProofs) (CallID, error) + GenerateSectorKeyFromData(ctx context.Context, sector storage.SectorRef, commD cid.Cid) (CallID, error) MoveStorage(ctx context.Context, sector storage.SectorRef, types SectorFileType) (CallID, error) UnsealPiece(context.Context, storage.SectorRef, UnpaddedByteIndex, abi.UnpaddedPieceSize, abi.SealRandomness, cid.Cid) (CallID, error) Fetch(context.Context, storage.SectorRef, SectorFileType, PathType, AcquireMode) (CallID, error) @@ -151,6 +152,7 @@ type WorkerReturn interface { ReturnReplicaUpdate(ctx context.Context, callID CallID, out storage.ReplicaUpdateOut, err *CallError) error ReturnProveReplicaUpdate1(ctx context.Context, callID CallID, proofs storage.ReplicaVanillaProofs, err *CallError) error ReturnProveReplicaUpdate2(ctx context.Context, callID CallID, proof storage.ReplicaUpdateProof, err *CallError) error + ReturnGenerateSectorKeyFromData(ctx context.Context, callID CallID, err *CallError) error ReturnMoveStorage(ctx context.Context, callID CallID, err *CallError) error ReturnUnsealPiece(ctx context.Context, callID CallID, err *CallError) error ReturnReadPiece(ctx context.Context, callID CallID, ok bool, err *CallError) error diff --git a/extern/sector-storage/teststorage_test.go b/extern/sector-storage/teststorage_test.go index 4061b48d99c..9fdb3a913dd 100644 --- a/extern/sector-storage/teststorage_test.go +++ b/extern/sector-storage/teststorage_test.go @@ -75,6 +75,10 @@ func (t *testExec) ProveReplicaUpdate2(ctx context.Context, sector storage.Secto panic("implement me") } +func (t *testExec) GenerateSectorKeyFromData(ctx context.Context, sector storage.SectorRef, commD cid.Cid) error { + panic("implement me") +} + func (t *testExec) NewSector(ctx context.Context, sector storage.SectorRef) error { panic("implement me") } diff --git a/extern/sector-storage/worker_local.go b/extern/sector-storage/worker_local.go index cc41e916e20..387a47f8fa3 100644 --- a/extern/sector-storage/worker_local.go +++ b/extern/sector-storage/worker_local.go @@ -168,6 +168,7 @@ const ( ReplicaUpdate ReturnType = "ReplicaUpdate" ProveReplicaUpdate1 ReturnType = "ProveReplicaUpdate1" ProveReplicaUpdate2 ReturnType = "ProveReplicaUpdate2" + GenerateSectorKey ReturnType = "GenerateSectorKey" ReleaseUnsealed ReturnType = "ReleaseUnsealed" MoveStorage ReturnType = "MoveStorage" UnsealPiece ReturnType = "UnsealPiece" @@ -219,6 +220,7 @@ var returnFunc = map[ReturnType]func(context.Context, storiface.CallID, storifac ReplicaUpdate: rfunc(storiface.WorkerReturn.ReturnReplicaUpdate), ProveReplicaUpdate1: rfunc(storiface.WorkerReturn.ReturnProveReplicaUpdate1), ProveReplicaUpdate2: rfunc(storiface.WorkerReturn.ReturnProveReplicaUpdate2), + GenerateSectorKey: rfunc(storiface.WorkerReturn.ReturnGenerateSectorKeyFromData), MoveStorage: rfunc(storiface.WorkerReturn.ReturnMoveStorage), UnsealPiece: rfunc(storiface.WorkerReturn.ReturnUnsealPiece), Fetch: rfunc(storiface.WorkerReturn.ReturnFetch), @@ -419,6 +421,17 @@ func (l *LocalWorker) ProveReplicaUpdate2(ctx context.Context, sector storage.Se }) } +func (l *LocalWorker) GenerateSectorKeyFromData(ctx context.Context, sector storage.SectorRef, commD cid.Cid) (storiface.CallID, error) { + sb, err := l.executor() + if err != nil { + return storiface.UndefCall, err + } + + return l.asyncCall(ctx, sector, GenerateSectorKey, func(ctx context.Context, ci storiface.CallID) (interface{}, error) { + return nil, sb.GenerateSectorKeyFromData(ctx, sector, commD) + }) +} + func (l *LocalWorker) FinalizeSector(ctx context.Context, sector storage.SectorRef, keepUnsealed []storage.Range) (storiface.CallID, error) { sb, err := l.executor() if err != nil { diff --git a/go.mod b/go.mod index e0823094dfa..95618417bc7 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/filecoin-project/specs-actors/v5 v5.0.4 github.com/filecoin-project/specs-actors/v6 v6.0.1 github.com/filecoin-project/specs-actors/v7 v7.0.0-20211118013026-3dce48197cec - github.com/filecoin-project/specs-storage v0.1.1-0.20211123153428-712cb8da07a3 + github.com/filecoin-project/specs-storage v0.1.1-0.20211202151826-2e51da61d454 github.com/filecoin-project/test-vectors/schema v0.0.5 github.com/gbrlsnchs/jwt/v3 v3.0.1 github.com/gdamore/tcell/v2 v2.2.0 diff --git a/go.sum b/go.sum index e404ca72e56..38f77202546 100644 --- a/go.sum +++ b/go.sum @@ -396,8 +396,8 @@ github.com/filecoin-project/specs-actors/v6 v6.0.1/go.mod h1:V1AYfi5GkHXipx1mnVi github.com/filecoin-project/specs-actors/v7 v7.0.0-20211117170924-fd07a4c7dff9/go.mod h1:p6LIOFezA1rgRLMewbvdi3Pp6SAu+q9FtJ9CAleSjrE= github.com/filecoin-project/specs-actors/v7 v7.0.0-20211118013026-3dce48197cec h1:KV9vE+Sl2Y3qKsrpba4HcE7wHwK7v6O5U/S0xHbje6A= github.com/filecoin-project/specs-actors/v7 v7.0.0-20211118013026-3dce48197cec/go.mod h1:p6LIOFezA1rgRLMewbvdi3Pp6SAu+q9FtJ9CAleSjrE= -github.com/filecoin-project/specs-storage v0.1.1-0.20211123153428-712cb8da07a3 h1:FLPxD2ksWwGc/sbnFLWep2p8ViP93VCAwFaVxrtVCyo= -github.com/filecoin-project/specs-storage v0.1.1-0.20211123153428-712cb8da07a3/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= +github.com/filecoin-project/specs-storage v0.1.1-0.20211202151826-2e51da61d454 h1:9II9Xf+jq5xAPQiS4rVoKIiALINa3loMC+ghyFYIrqQ= +github.com/filecoin-project/specs-storage v0.1.1-0.20211202151826-2e51da61d454/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/test-vectors/schema v0.0.5 h1:w3zHQhzM4pYxJDl21avXjOKBLF8egrvwUwjpT8TquDg= github.com/filecoin-project/test-vectors/schema v0.0.5/go.mod h1:iQ9QXLpYWL3m7warwvK1JC/pTri8mnfEmKygNDqqY6E= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= diff --git a/itests/self_sent_txn_test.go b/itests/self_sent_txn_test.go index 846bcff05d8..b5ec2c0dcaf 100644 --- a/itests/self_sent_txn_test.go +++ b/itests/self_sent_txn_test.go @@ -15,8 +15,7 @@ import ( "github.com/stretchr/testify/require" ) - -// these tests check that the versioned code in vm.transfer is functioning correctly across versions! +// these tests check that the versioned code in vm.transfer is functioning correctly across versions! // we reordered the checks to make sure that a transaction with too much money in it sent to yourself will fail instead of succeeding as a noop // more info in this PR! https://github.com/filecoin-project/lotus/pull/7637 func TestSelfSentTxnV15(t *testing.T) { From d7528557dfac0e4ae91cf24bc4e10ccb1a272979 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Sun, 12 Dec 2021 22:05:43 -0500 Subject: [PATCH 13/24] Shed: Add a util to list terminated deals --- cmd/lotus-shed/main.go | 1 + cmd/lotus-shed/terminations.go | 173 +++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 cmd/lotus-shed/terminations.go diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index d35fb56dd8b..d189313124f 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -65,6 +65,7 @@ func main() { fr32Cmd, chainCmd, balancerCmd, + terminationsCmd, } app := &cli.App{ diff --git a/cmd/lotus-shed/terminations.go b/cmd/lotus-shed/terminations.go new file mode 100644 index 00000000000..0cc0800e429 --- /dev/null +++ b/cmd/lotus-shed/terminations.go @@ -0,0 +1,173 @@ +package main + +import ( + "bytes" + "context" + "fmt" + "io" + + "github.com/filecoin-project/lotus/chain/types" + + "github.com/filecoin-project/lotus/chain/actors/builtin/market" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/consensus/filcns" + "github.com/filecoin-project/lotus/chain/state" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/node/repo" + miner2 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" + "github.com/urfave/cli/v2" +) + +var terminationsCmd = &cli.Command{ + Name: "terminations", + Description: "Lists terminated deals from the past 2 days", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + Value: "~/.lotus", + }, + }, + Action: func(cctx *cli.Context) error { + ctx := context.TODO() + + if !cctx.Args().Present() { + return fmt.Errorf("must pass block cid") + } + + blkCid, err := cid.Decode(cctx.Args().First()) + if err != nil { + return fmt.Errorf("failed to parse input: %w", err) + } + + fsrepo, err := repo.NewFS(cctx.String("repo")) + if err != nil { + return err + } + + lkrepo, err := fsrepo.Lock(repo.FullNode) + if err != nil { + return err + } + + defer lkrepo.Close() //nolint:errcheck + + bs, err := lkrepo.Blockstore(ctx, repo.UniversalBlockstore) + if err != nil { + return fmt.Errorf("failed to open blockstore: %w", err) + } + + defer func() { + if c, ok := bs.(io.Closer); ok { + if err := c.Close(); err != nil { + log.Warnf("failed to close blockstore: %s", err) + } + } + }() + + mds, err := lkrepo.Datastore(context.Background(), "/metadata") + if err != nil { + return err + } + + cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil) + defer cs.Close() //nolint:errcheck + + cst := cbor.NewCborStore(bs) + store := adt.WrapStore(ctx, cst) + + blk, err := cs.GetBlock(blkCid) + if err != nil { + return err + } + + minerCode, err := miner.GetActorCodeID(actors.Version6) + if err != nil { + return err + } + + for i := 0; i < 2880*2; i++ { + pts, err := cs.LoadTipSet(types.NewTipSetKey(blk.Parents...)) + if err != nil { + return err + } + + blk = pts.Blocks()[0] + + msgs, err := cs.MessagesForTipset(pts) + if err != nil { + return err + } + + for _, v := range msgs { + msg := v.VMMessage() + if msg.Method != miner.Methods.TerminateSectors { + continue + } + + tree, err := state.LoadStateTree(cst, blk.ParentStateRoot) + if err != nil { + return err + } + + minerAct, err := tree.GetActor(msg.To) + if err != nil { + return err + } + + if minerAct.Code != minerCode { + continue + } + + minerSt, err := miner.Load(store, minerAct) + if err != nil { + return err + } + + marketAct, err := tree.GetActor(market.Address) + if err != nil { + return err + } + + marketSt, err := market.Load(store, marketAct) + if err != nil { + return err + } + + proposals, err := marketSt.Proposals() + if err != nil { + return err + } + + var termParams miner2.TerminateSectorsParams + err = termParams.UnmarshalCBOR(bytes.NewBuffer(msg.Params)) + if err != nil { + return err + } + + for _, t := range termParams.Terminations { + sectors, err := minerSt.LoadSectors(&t.Sectors) + if err != nil { + return err + } + + for _, sector := range sectors { + for _, deal := range sector.DealIDs { + prop, find, err := proposals.Get(deal) + if err != nil || !find { + return err + } + fmt.Printf("%s, %d, %d, %s, %s\n", msg.To, sector.SectorNumber, deal, prop.PieceCID, prop.Label) + } + } + } + } + } + + return nil + }, +} From 8c4c2eeffc4b5a53d7de5a5a8020acb44e681125 Mon Sep 17 00:00:00 2001 From: Jennifer Wang Date: Mon, 13 Dec 2021 03:35:56 -0500 Subject: [PATCH 14/24] add client address --- cmd/lotus-shed/terminations.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/lotus-shed/terminations.go b/cmd/lotus-shed/terminations.go index 0cc0800e429..c28d595b4e1 100644 --- a/cmd/lotus-shed/terminations.go +++ b/cmd/lotus-shed/terminations.go @@ -161,7 +161,7 @@ var terminationsCmd = &cli.Command{ if err != nil || !find { return err } - fmt.Printf("%s, %d, %d, %s, %s\n", msg.To, sector.SectorNumber, deal, prop.PieceCID, prop.Label) + fmt.Printf("%s, %d, %d, %s, %s, %s\n", msg.To, sector.SectorNumber, deal, prop.Client, prop.PieceCID, prop.Label) } } } From 3e288f1066f290f59316696f506b2ae2b02a2cd3 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Mon, 13 Dec 2021 15:47:17 -0500 Subject: [PATCH 15/24] Update FFI --- extern/filecoin-ffi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index 428503c87d9..52d80081bfd 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit 428503c87d917cc5e3e637983b43b4c260863bf0 +Subproject commit 52d80081bfdd8a30bc44bcfe44cb0f299615b9f3 From ac3cdf75fa8e50ae61c3a7caf6473e2e38038f4d Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 8 Sep 2021 15:22:41 -0400 Subject: [PATCH 16/24] Mempool: Selection logic should respect block message limits --- chain/messagepool/selection.go | 77 +++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index acff7c4cff9..88b1b63af28 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -92,7 +92,7 @@ func (mp *MessagePool) selectMessagesOptimal(ctx context.Context, curTs, ts *typ result, gasLimit := mp.selectPriorityMessages(ctx, pending, baseFee, ts) // have we filled the block? - if gasLimit < minGas { + if gasLimit < minGas || len(result) >= build.BlockMessageLimit { return result, nil } @@ -117,19 +117,21 @@ func (mp *MessagePool) selectMessagesOptimal(ctx context.Context, curTs, ts *typ return result, nil } - // 3. Parition chains into blocks (without trimming) + // 3. Partition chains into blocks (without trimming) // we use the full blockGasLimit (as opposed to the residual gas limit from the - // priority message selection) as we have to account for what other miners are doing + // priority message selection) as we have to account for what other block providers are doing nextChain := 0 partitions := make([][]*msgChain, MaxBlocks) for i := 0; i < MaxBlocks && nextChain < len(chains); i++ { gasLimit := int64(build.BlockGasLimit) + msgLimit := build.BlockMessageLimit for nextChain < len(chains) { chain := chains[nextChain] nextChain++ partitions[i] = append(partitions[i], chain) gasLimit -= chain.gasLimit - if gasLimit < minGas { + msgLimit -= len(chain.msgs) + if gasLimit < minGas || msgLimit <= 0 { break } } @@ -158,7 +160,7 @@ func (mp *MessagePool) selectMessagesOptimal(ctx context.Context, curTs, ts *typ }) // 6. Merge the head chains to produce the list of messages selected for inclusion - // subject to the residual gas limit + // subject to the residual block limits // When a chain is merged in, all its previous dependent chains *must* also be // merged in or we'll have a broken block startMerge := time.Now() @@ -176,14 +178,16 @@ func (mp *MessagePool) selectMessagesOptimal(ctx context.Context, curTs, ts *typ // compute the dependencies that must be merged and the gas limit including deps chainGasLimit := chain.gasLimit + chainMsgLimit := len(chain.msgs) var chainDeps []*msgChain for curChain := chain.prev; curChain != nil && !curChain.merged; curChain = curChain.prev { chainDeps = append(chainDeps, curChain) chainGasLimit += curChain.gasLimit + chainMsgLimit += len(curChain.msgs) } // does it all fit in the block? - if chainGasLimit <= gasLimit { + if chainGasLimit <= gasLimit && chainMsgLimit+len(result) <= build.BlockMessageLimit { // include it together with all dependencies for i := len(chainDeps) - 1; i >= 0; i-- { curChain := chainDeps[i] @@ -192,7 +196,7 @@ func (mp *MessagePool) selectMessagesOptimal(ctx context.Context, curTs, ts *typ } chain.merged = true - // adjust the effective pefromance for all subsequent chains + // adjust the effective performance for all subsequent chains if next := chain.next; next != nil && next.effPerf > 0 { next.effPerf += next.parentOffset for next = next.next; next != nil && next.effPerf > 0; next = next.next { @@ -222,7 +226,7 @@ func (mp *MessagePool) selectMessagesOptimal(ctx context.Context, curTs, ts *typ // 7. We have reached the edge of what can fit wholesale; if we still hae available // gasLimit to pack some more chains, then trim the last chain and push it down. - // Trimming invalidaates subsequent dependent chains so that they can't be selected + // Trimming invalidates subsequent dependent chains so that they can't be selected // as their dependency cannot be (fully) included. // We do this in a loop because the blocker might have been inordinately large and // we might have to do it multiple times to satisfy tail packing @@ -231,7 +235,7 @@ tailLoop: for gasLimit >= minGas && last < len(chains) { // trim if necessary if chains[last].gasLimit > gasLimit { - chains[last].Trim(gasLimit, mp, baseFee) + chains[last].Trim(gasLimit, build.BlockMessageLimit-len(result), mp, baseFee) } // push down if it hasn't been invalidated @@ -263,16 +267,20 @@ tailLoop: // compute the dependencies that must be merged and the gas limit including deps chainGasLimit := chain.gasLimit + chainMsgLimit := len(chain.msgs) depGasLimit := int64(0) + depMsgLimit := 0 var chainDeps []*msgChain for curChain := chain.prev; curChain != nil && !curChain.merged; curChain = curChain.prev { chainDeps = append(chainDeps, curChain) chainGasLimit += curChain.gasLimit + chainMsgLimit += len(curChain.msgs) depGasLimit += curChain.gasLimit + depMsgLimit += len(curChain.msgs) } // does it all fit in the bock - if chainGasLimit <= gasLimit { + if chainGasLimit <= gasLimit && len(result)+chainMsgLimit <= build.BlockMessageLimit { // include it together with all dependencies for i := len(chainDeps) - 1; i >= 0; i-- { curChain := chainDeps[i] @@ -288,17 +296,17 @@ tailLoop: // it doesn't all fit; now we have to take into account the dependent chains before // making a decision about trimming or invalidating. - // if the dependencies exceed the gas limit, then we must invalidate the chain + // if the dependencies exceed the block limits, then we must invalidate the chain // as it can never be included. // Otherwise we can just trim and continue - if depGasLimit > gasLimit { + if depGasLimit > gasLimit || len(result)+depMsgLimit >= build.BlockMessageLimit { chain.Invalidate() last += i + 1 continue tailLoop } // dependencies fit, just trim it - chain.Trim(gasLimit-depGasLimit, mp, baseFee) + chain.Trim(gasLimit-depGasLimit, build.BlockMessageLimit-len(result)-depMsgLimit, mp, baseFee) last += i continue tailLoop } @@ -311,9 +319,9 @@ tailLoop: log.Infow("pack tail chains done", "took", dt) } - // if we have gasLimit to spare, pick some random (non-negative) chains to fill the block - // we pick randomly so that we minimize the probability of duplication among all miners - if gasLimit >= minGas { + // if we have room to spare, pick some random (non-negative) chains to fill the block + // we pick randomly so that we minimize the probability of duplication among all block producers + if gasLimit >= minGas && len(result) <= build.BlockMessageLimit { randomCount := 0 startRandom := time.Now() @@ -321,7 +329,7 @@ tailLoop: for _, chain := range chains { // have we filled the block - if gasLimit < minGas { + if gasLimit < minGas || len(result) >= build.BlockMessageLimit { break } @@ -337,23 +345,27 @@ tailLoop: // compute the dependencies that must be merged and the gas limit including deps chainGasLimit := chain.gasLimit + chainMsgLimit := len(chain.msgs) depGasLimit := int64(0) + depMsgLimit := 0 var chainDeps []*msgChain for curChain := chain.prev; curChain != nil && !curChain.merged; curChain = curChain.prev { chainDeps = append(chainDeps, curChain) chainGasLimit += curChain.gasLimit + chainMsgLimit += len(curChain.msgs) depGasLimit += curChain.gasLimit + depMsgLimit += len(curChain.msgs) } // do the deps fit? if the deps won't fit, invalidate the chain - if depGasLimit > gasLimit { + if depGasLimit > gasLimit || len(result)+depMsgLimit > build.BlockMessageLimit { chain.Invalidate() continue } // do they fit as is? if it doesn't, trim to make it fit if possible - if chainGasLimit > gasLimit { - chain.Trim(gasLimit-depGasLimit, mp, baseFee) + if chainGasLimit > gasLimit || len(result)+chainMsgLimit > build.BlockMessageLimit { + chain.Trim(gasLimit-depGasLimit, build.BlockMessageLimit-len(result)-depMsgLimit, mp, baseFee) if !chain.valid { continue @@ -416,7 +428,7 @@ func (mp *MessagePool) selectMessagesGreedy(ctx context.Context, curTs, ts *type result, gasLimit := mp.selectPriorityMessages(ctx, pending, baseFee, ts) // have we filled the block? - if gasLimit < minGas { + if gasLimit < minGas || len(result) > build.BlockMessageLimit { return result, nil } @@ -442,7 +454,7 @@ func (mp *MessagePool) selectMessagesGreedy(ctx context.Context, curTs, ts *type } // 3. Merge the head chains to produce the list of messages selected for inclusion, subject to - // the block gas limit. + // the block gas and message limits. startMerge := time.Now() last := len(chains) for i, chain := range chains { @@ -452,13 +464,13 @@ func (mp *MessagePool) selectMessagesGreedy(ctx context.Context, curTs, ts *type } // does it fit in the block? - if chain.gasLimit <= gasLimit { + if chain.gasLimit <= gasLimit && len(result)+len(chain.msgs) <= build.BlockMessageLimit { gasLimit -= chain.gasLimit result = append(result, chain.msgs...) continue } - // we can't fit this chain because of block gasLimit -- we are at the edge + // we can't fit this chain because of block limits -- we are at the edge last = i break } @@ -476,7 +488,7 @@ func (mp *MessagePool) selectMessagesGreedy(ctx context.Context, curTs, ts *type tailLoop: for gasLimit >= minGas && last < len(chains) { // trim - chains[last].Trim(gasLimit, mp, baseFee) + chains[last].Trim(gasLimit, build.BlockMessageLimit-len(result), mp, baseFee) // push down if it hasn't been invalidated if chains[last].valid { @@ -501,7 +513,7 @@ tailLoop: } // does it fit in the bock? - if chain.gasLimit <= gasLimit { + if chain.gasLimit <= gasLimit && len(result)+len(chain.msgs) <= build.BlockMessageLimit { gasLimit -= chain.gasLimit result = append(result, chain.msgs...) continue @@ -778,11 +790,16 @@ func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint6 return nil } + // if we have more messages from this sender than can fit in a block, drop the extra ones + if len(msgs) > build.BlockMessageLimit { + msgs = msgs[:build.BlockMessageLimit] + } + // ok, now we can construct the chains using the messages we have // invariant: each chain has a bigger gasPerf than the next -- otherwise they can be merged // and increase the gasPerf of the first chain // We do this in two passes: - // - in the first pass we create chains that aggreagate messages with non-decreasing gasPerf + // - in the first pass we create chains that aggregate messages with non-decreasing gasPerf // - in the second pass we merge chains to maintain the invariant. var chains []*msgChain var curChain *msgChain @@ -808,7 +825,7 @@ func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint6 gasLimit := curChain.gasLimit + m.Message.GasLimit gasPerf := mp.getGasPerf(gasReward, gasLimit) - // try to add the message to the current chain -- if it decreases the gasPerf, then make a + // try to add the message to the current chain -- if it decreases the gasPerf, or then make a // new chain if gasPerf < curChain.gasPerf { chains = append(chains, curChain) @@ -868,9 +885,9 @@ func (mc *msgChain) Before(other *msgChain) bool { (mc.gasPerf == other.gasPerf && mc.gasReward.Cmp(other.gasReward) > 0) } -func (mc *msgChain) Trim(gasLimit int64, mp *MessagePool, baseFee types.BigInt) { +func (mc *msgChain) Trim(gasLimit int64, msgLimit int, mp *MessagePool, baseFee types.BigInt) { i := len(mc.msgs) - 1 - for i >= 0 && (mc.gasLimit > gasLimit || mc.gasPerf < 0) { + for i >= 0 && (mc.gasLimit > gasLimit || mc.gasPerf < 0 || i >= msgLimit) { gasReward := mp.getGasReward(mc.msgs[i], baseFee) mc.gasReward = new(big.Int).Sub(mc.gasReward, gasReward) mc.gasLimit -= mc.msgs[i].Message.GasLimit From dd20cb73019d6f4e462a0cef23c9aa3e67cc36ea Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Fri, 10 Sep 2021 17:47:12 -0400 Subject: [PATCH 17/24] Consensus: Safety check against unknown sig types --- chain/consensus/filcns/mine.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chain/consensus/filcns/mine.go b/chain/consensus/filcns/mine.go index bbda35fcfd3..757363a76c2 100644 --- a/chain/consensus/filcns/mine.go +++ b/chain/consensus/filcns/mine.go @@ -65,7 +65,7 @@ func (filec *FilecoinEC) CreateBlock(ctx context.Context, w api.Wallet, bt *api. } blsMsgCids = append(blsMsgCids, c) - } else { + } else if msg.Signature.Type == crypto.SigTypeSecp256k1 { c, err := filec.sm.ChainStore().PutMessage(msg) if err != nil { return nil, err @@ -74,6 +74,8 @@ func (filec *FilecoinEC) CreateBlock(ctx context.Context, w api.Wallet, bt *api. secpkMsgCids = append(secpkMsgCids, c) secpkMessages = append(secpkMessages, msg) + } else { + return nil, xerrors.Errorf("unknown sig type: %d", msg.Signature.Type) } } From ec00e73c9d983140291bada2b866c1991518477e Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Fri, 10 Sep 2021 20:24:12 -0400 Subject: [PATCH 18/24] Mempool: Selection should respect CBOR limits --- chain/messagepool/repub.go | 6 +- chain/messagepool/selection.go | 340 ++++++++++++++++------------ chain/messagepool/selection_test.go | 8 +- 3 files changed, 203 insertions(+), 151 deletions(-) diff --git a/chain/messagepool/repub.go b/chain/messagepool/repub.go index 4323bdee197..d92b5bd5855 100644 --- a/chain/messagepool/repub.go +++ b/chain/messagepool/repub.go @@ -121,7 +121,7 @@ loop: // we can't fit the current chain but there is gas to spare // trim it and push it down - chain.Trim(gasLimit, mp, baseFee) + chain.Trim(gasLimit, repubMsgLimit, mp, baseFee) for j := i; j < len(chains)-1; j++ { if chains[j].Before(chains[j+1]) { break @@ -131,6 +131,10 @@ loop: } count := 0 + if len(msgs) > repubMsgLimit { + msgs = msgs[:repubMsgLimit] + } + log.Infof("republishing %d messages", len(msgs)) for _, m := range msgs { mb, err := m.Serialize() diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 88b1b63af28..7446ee4e4b4 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -7,6 +7,10 @@ import ( "sort" "time" + cbg "github.com/whyrusleeping/cbor-gen" + + "github.com/filecoin-project/go-state-types/crypto" + "golang.org/x/xerrors" "github.com/filecoin-project/go-address" @@ -34,9 +38,10 @@ type msgChain struct { merged bool next *msgChain prev *msgChain + sigType crypto.SigType } -func (mp *MessagePool) SelectMessages(ctx context.Context, ts *types.TipSet, tq float64) (msgs []*types.SignedMessage, err error) { +func (mp *MessagePool) SelectMessages(ctx context.Context, ts *types.TipSet, tq float64) ([]*types.SignedMessage, error) { mp.curTsLk.Lock() defer mp.curTsLk.Unlock() @@ -46,24 +51,151 @@ func (mp *MessagePool) SelectMessages(ctx context.Context, ts *types.TipSet, tq // if the ticket quality is high enough that the first block has higher probability // than any other block, then we don't bother with optimal selection because the // first block will always have higher effective performance + var sm *selectedMessages + var err error if tq > 0.84 { - msgs, err = mp.selectMessagesGreedy(ctx, mp.curTs, ts) + sm, err = mp.selectMessagesGreedy(ctx, mp.curTs, ts) } else { - msgs, err = mp.selectMessagesOptimal(ctx, mp.curTs, ts, tq) + sm, err = mp.selectMessagesOptimal(ctx, mp.curTs, ts, tq) } if err != nil { return nil, err } - if len(msgs) > build.BlockMessageLimit { - msgs = msgs[:build.BlockMessageLimit] + // one last sanity check + if len(sm.msgs) > build.BlockMessageLimit { + sm.msgs = sm.msgs[:build.BlockMessageLimit] + } + + return sm.msgs, nil +} + +type selectedMessages struct { + msgs []*types.SignedMessage + gasLimit int64 + secpLimit int + blsLimit int +} + +// returns false if chain can't be added due to block constraints +func (sm *selectedMessages) tryToAdd(mc *msgChain) bool { + l := len(mc.msgs) + + if build.BlockMessageLimit < l+len(sm.msgs) || sm.gasLimit < mc.gasLimit { + return false + } + + if mc.sigType == crypto.SigTypeBLS { + if sm.blsLimit < l { + return false + } + + sm.msgs = append(sm.msgs, mc.msgs...) + sm.blsLimit -= l + sm.gasLimit -= mc.gasLimit + } else if mc.sigType == crypto.SigTypeSecp256k1 { + if sm.secpLimit < l { + return false + } + + sm.msgs = append(sm.msgs, mc.msgs...) + sm.secpLimit -= l + sm.gasLimit -= mc.gasLimit + } + + // don't add the weird sigType msg, but otherwise proceed + return true +} + +// returns false if messages can't be added due to block constraints +// will trim / invalidate chain as appropriate +func (sm *selectedMessages) tryToAddWithDeps(mc *msgChain, mp *MessagePool, baseFee types.BigInt) bool { + // compute the dependencies that must be merged and the gas limit including deps + chainGasLimit := mc.gasLimit + chainMsgLimit := len(mc.msgs) + depGasLimit := int64(0) + depMsgLimit := 0 + smMsgLimit := 0 + + if mc.sigType == crypto.SigTypeBLS { + smMsgLimit = sm.blsLimit + } else if mc.sigType == crypto.SigTypeSecp256k1 { + smMsgLimit = sm.secpLimit + } else { + return false + } + + if smMsgLimit > build.BlockMessageLimit-len(sm.msgs) { + smMsgLimit = build.BlockMessageLimit - len(sm.msgs) + } + + var chainDeps []*msgChain + for curChain := mc.prev; curChain != nil && !curChain.merged; curChain = curChain.prev { + chainDeps = append(chainDeps, curChain) + chainGasLimit += curChain.gasLimit + chainMsgLimit += len(curChain.msgs) + depGasLimit += curChain.gasLimit + depMsgLimit += len(curChain.msgs) + } + + // the chain doesn't fit as-is, so trim / invalidate it and return false + if chainGasLimit > sm.gasLimit || chainMsgLimit > smMsgLimit { + + // it doesn't all fit; now we have to take into account the dependent chains before + // making a decision about trimming or invalidating. + // if the dependencies exceed the block limits, then we must invalidate the chain + // as it can never be included. + // Otherwise we can just trim and continue + if depGasLimit > sm.gasLimit || depMsgLimit >= smMsgLimit { + mc.Invalidate() + } else { + // dependencies fit, just trim it + mc.Trim(sm.gasLimit-depGasLimit, smMsgLimit-depMsgLimit, mp, baseFee) + } + + return false + } + + // the chain fits! include it together with all dependencies + for i := len(chainDeps) - 1; i >= 0; i-- { + curChain := chainDeps[i] + curChain.merged = true + sm.msgs = append(sm.msgs, curChain.msgs...) + } + + mc.merged = true + + sm.msgs = append(sm.msgs, mc.msgs...) + sm.gasLimit -= chainGasLimit + + if mc.sigType == crypto.SigTypeBLS { + sm.blsLimit -= chainMsgLimit + } else if mc.sigType == crypto.SigTypeSecp256k1 { + sm.secpLimit -= chainMsgLimit } - return msgs, nil + return true } -func (mp *MessagePool) selectMessagesOptimal(ctx context.Context, curTs, ts *types.TipSet, tq float64) ([]*types.SignedMessage, error) { +func (sm *selectedMessages) trimChain(mc *msgChain, mp *MessagePool, baseFee types.BigInt) { + msgLimit := build.BlockMessageLimit - len(sm.msgs) + if mc.sigType == crypto.SigTypeBLS { + if msgLimit > sm.blsLimit { + msgLimit = sm.blsLimit + } + } else if mc.sigType == crypto.SigTypeSecp256k1 { + if msgLimit > sm.secpLimit { + msgLimit = sm.secpLimit + } + } + + if mc.gasLimit > sm.gasLimit || len(mc.msgs) > msgLimit { + mc.Trim(sm.gasLimit, msgLimit, mp, baseFee) + } +} + +func (mp *MessagePool) selectMessagesOptimal(ctx context.Context, curTs, ts *types.TipSet, tq float64) (*selectedMessages, error) { start := time.Now() baseFee, err := mp.api.ChainComputeBaseFee(context.TODO(), ts) @@ -89,10 +221,10 @@ func (mp *MessagePool) selectMessagesOptimal(ctx context.Context, curTs, ts *typ // 0b. Select all priority messages that fit in the block minGas := int64(gasguess.MinGas) - result, gasLimit := mp.selectPriorityMessages(ctx, pending, baseFee, ts) + result := mp.selectPriorityMessages(ctx, pending, baseFee, ts) // have we filled the block? - if gasLimit < minGas || len(result) >= build.BlockMessageLimit { + if result.gasLimit < minGas || len(result.msgs) >= build.BlockMessageLimit { return result, nil } @@ -176,26 +308,7 @@ func (mp *MessagePool) selectMessagesOptimal(ctx context.Context, curTs, ts *typ continue } - // compute the dependencies that must be merged and the gas limit including deps - chainGasLimit := chain.gasLimit - chainMsgLimit := len(chain.msgs) - var chainDeps []*msgChain - for curChain := chain.prev; curChain != nil && !curChain.merged; curChain = curChain.prev { - chainDeps = append(chainDeps, curChain) - chainGasLimit += curChain.gasLimit - chainMsgLimit += len(curChain.msgs) - } - - // does it all fit in the block? - if chainGasLimit <= gasLimit && chainMsgLimit+len(result) <= build.BlockMessageLimit { - // include it together with all dependencies - for i := len(chainDeps) - 1; i >= 0; i-- { - curChain := chainDeps[i] - curChain.merged = true - result = append(result, curChain.msgs...) - } - - chain.merged = true + if result.tryToAddWithDeps(chain, mp, baseFee) { // adjust the effective performance for all subsequent chains if next := chain.next; next != nil && next.effPerf > 0 { next.effPerf += next.parentOffset @@ -203,10 +316,8 @@ func (mp *MessagePool) selectMessagesOptimal(ctx context.Context, curTs, ts *typ next.setEffPerf() } } - result = append(result, chain.msgs...) - gasLimit -= chainGasLimit - // resort to account for already merged chains and effective performance adjustments + // re-sort to account for already merged chains and effective performance adjustments // the sort *must* be stable or we end up getting negative gasPerfs pushed up. sort.SliceStable(chains[i+1:], func(i, j int) bool { return chains[i].BeforeEffective(chains[j]) @@ -215,7 +326,7 @@ func (mp *MessagePool) selectMessagesOptimal(ctx context.Context, curTs, ts *typ continue } - // we can't fit this chain and its dependencies because of block gasLimit -- we are + // we can't fit this chain and its dependencies because of block limits -- we are // at the edge last = i break @@ -232,12 +343,16 @@ func (mp *MessagePool) selectMessagesOptimal(ctx context.Context, curTs, ts *typ // we might have to do it multiple times to satisfy tail packing startTail := time.Now() tailLoop: - for gasLimit >= minGas && last < len(chains) { - // trim if necessary - if chains[last].gasLimit > gasLimit { - chains[last].Trim(gasLimit, build.BlockMessageLimit-len(result), mp, baseFee) + for result.gasLimit >= minGas && last < len(chains) { + + if !chains[last].valid { + last++ + continue tailLoop } + // trim if necessary + result.trimChain(chains[last], mp, baseFee) + // push down if it hasn't been invalidated if chains[last].valid { for i := last; i < len(chains)-1; i++ { @@ -249,7 +364,7 @@ tailLoop: } // select the next (valid and fitting) chain and its dependencies for inclusion - for i, chain := range chains[last:] { + for _, chain := range chains[last:] { // has the chain been invalidated? if !chain.valid { continue @@ -265,49 +380,10 @@ tailLoop: break tailLoop } - // compute the dependencies that must be merged and the gas limit including deps - chainGasLimit := chain.gasLimit - chainMsgLimit := len(chain.msgs) - depGasLimit := int64(0) - depMsgLimit := 0 - var chainDeps []*msgChain - for curChain := chain.prev; curChain != nil && !curChain.merged; curChain = curChain.prev { - chainDeps = append(chainDeps, curChain) - chainGasLimit += curChain.gasLimit - chainMsgLimit += len(curChain.msgs) - depGasLimit += curChain.gasLimit - depMsgLimit += len(curChain.msgs) - } - - // does it all fit in the bock - if chainGasLimit <= gasLimit && len(result)+chainMsgLimit <= build.BlockMessageLimit { - // include it together with all dependencies - for i := len(chainDeps) - 1; i >= 0; i-- { - curChain := chainDeps[i] - curChain.merged = true - result = append(result, curChain.msgs...) - } - - chain.merged = true - result = append(result, chain.msgs...) - gasLimit -= chainGasLimit + if result.tryToAddWithDeps(chain, mp, baseFee) { continue } - // it doesn't all fit; now we have to take into account the dependent chains before - // making a decision about trimming or invalidating. - // if the dependencies exceed the block limits, then we must invalidate the chain - // as it can never be included. - // Otherwise we can just trim and continue - if depGasLimit > gasLimit || len(result)+depMsgLimit >= build.BlockMessageLimit { - chain.Invalidate() - last += i + 1 - continue tailLoop - } - - // dependencies fit, just trim it - chain.Trim(gasLimit-depGasLimit, build.BlockMessageLimit-len(result)-depMsgLimit, mp, baseFee) - last += i continue tailLoop } @@ -321,15 +397,15 @@ tailLoop: // if we have room to spare, pick some random (non-negative) chains to fill the block // we pick randomly so that we minimize the probability of duplication among all block producers - if gasLimit >= minGas && len(result) <= build.BlockMessageLimit { - randomCount := 0 + if result.gasLimit >= minGas && len(result.msgs) <= build.BlockMessageLimit { + preRandomLength := len(result.msgs) startRandom := time.Now() shuffleChains(chains) for _, chain := range chains { // have we filled the block - if gasLimit < minGas || len(result) >= build.BlockMessageLimit { + if result.gasLimit < minGas || len(result.msgs) >= build.BlockMessageLimit { break } @@ -343,63 +419,31 @@ tailLoop: continue } - // compute the dependencies that must be merged and the gas limit including deps - chainGasLimit := chain.gasLimit - chainMsgLimit := len(chain.msgs) - depGasLimit := int64(0) - depMsgLimit := 0 - var chainDeps []*msgChain - for curChain := chain.prev; curChain != nil && !curChain.merged; curChain = curChain.prev { - chainDeps = append(chainDeps, curChain) - chainGasLimit += curChain.gasLimit - chainMsgLimit += len(curChain.msgs) - depGasLimit += curChain.gasLimit - depMsgLimit += len(curChain.msgs) - } - - // do the deps fit? if the deps won't fit, invalidate the chain - if depGasLimit > gasLimit || len(result)+depMsgLimit > build.BlockMessageLimit { - chain.Invalidate() + if result.tryToAddWithDeps(chain, mp, baseFee) { continue } - // do they fit as is? if it doesn't, trim to make it fit if possible - if chainGasLimit > gasLimit || len(result)+chainMsgLimit > build.BlockMessageLimit { - chain.Trim(gasLimit-depGasLimit, build.BlockMessageLimit-len(result)-depMsgLimit, mp, baseFee) - - if !chain.valid { - continue - } - } - - // include it together with all dependencies - for i := len(chainDeps) - 1; i >= 0; i-- { - curChain := chainDeps[i] - curChain.merged = true - result = append(result, curChain.msgs...) - randomCount += len(curChain.msgs) + if chain.valid { + // chain got trimmed on the previous call to tryToAddWithDeps, can now be included + result.tryToAddWithDeps(chain, mp, baseFee) + continue } - - chain.merged = true - result = append(result, chain.msgs...) - randomCount += len(chain.msgs) - gasLimit -= chainGasLimit } if dt := time.Since(startRandom); dt > time.Millisecond { log.Infow("pack random tail chains done", "took", dt) } - if randomCount > 0 { + if len(result.msgs) != preRandomLength { log.Warnf("optimal selection failed to pack a block; picked %d messages with random selection", - randomCount) + len(result.msgs)-preRandomLength) } } return result, nil } -func (mp *MessagePool) selectMessagesGreedy(ctx context.Context, curTs, ts *types.TipSet) ([]*types.SignedMessage, error) { +func (mp *MessagePool) selectMessagesGreedy(ctx context.Context, curTs, ts *types.TipSet) (*selectedMessages, error) { start := time.Now() baseFee, err := mp.api.ChainComputeBaseFee(context.TODO(), ts) @@ -425,10 +469,10 @@ func (mp *MessagePool) selectMessagesGreedy(ctx context.Context, curTs, ts *type // 0b. Select all priority messages that fit in the block minGas := int64(gasguess.MinGas) - result, gasLimit := mp.selectPriorityMessages(ctx, pending, baseFee, ts) + result := mp.selectPriorityMessages(ctx, pending, baseFee, ts) // have we filled the block? - if gasLimit < minGas || len(result) > build.BlockMessageLimit { + if result.gasLimit < minGas || len(result.msgs) > build.BlockMessageLimit { return result, nil } @@ -464,9 +508,8 @@ func (mp *MessagePool) selectMessagesGreedy(ctx context.Context, curTs, ts *type } // does it fit in the block? - if chain.gasLimit <= gasLimit && len(result)+len(chain.msgs) <= build.BlockMessageLimit { - gasLimit -= chain.gasLimit - result = append(result, chain.msgs...) + if result.tryToAdd(chain) { + // there was room, we added the chain, keep going continue } @@ -486,9 +529,9 @@ func (mp *MessagePool) selectMessagesGreedy(ctx context.Context, curTs, ts *type // have to do it multiple times to satisfy tail packing. startTail := time.Now() tailLoop: - for gasLimit >= minGas && last < len(chains) { + for result.gasLimit >= minGas && last < len(chains) { // trim - chains[last].Trim(gasLimit, build.BlockMessageLimit-len(result), mp, baseFee) + result.trimChain(chains[last], mp, baseFee) // push down if it hasn't been invalidated if chains[last].valid { @@ -513,9 +556,8 @@ tailLoop: } // does it fit in the bock? - if chain.gasLimit <= gasLimit && len(result)+len(chain.msgs) <= build.BlockMessageLimit { - gasLimit -= chain.gasLimit - result = append(result, chain.msgs...) + if result.tryToAdd(chain) { + // there was room, we added the chain, keep going continue } @@ -535,7 +577,7 @@ tailLoop: return result, nil } -func (mp *MessagePool) selectPriorityMessages(ctx context.Context, pending map[address.Address]map[uint64]*types.SignedMessage, baseFee types.BigInt, ts *types.TipSet) ([]*types.SignedMessage, int64) { +func (mp *MessagePool) selectPriorityMessages(ctx context.Context, pending map[address.Address]map[uint64]*types.SignedMessage, baseFee types.BigInt, ts *types.TipSet) *selectedMessages { start := time.Now() defer func() { if dt := time.Since(start); dt > time.Millisecond { @@ -543,8 +585,12 @@ func (mp *MessagePool) selectPriorityMessages(ctx context.Context, pending map[a } }() mpCfg := mp.getConfig() - result := make([]*types.SignedMessage, 0, mpCfg.SizeLimitLow) - gasLimit := int64(build.BlockGasLimit) + result := &selectedMessages{ + msgs: make([]*types.SignedMessage, 0, mpCfg.SizeLimitLow), + gasLimit: int64(build.BlockGasLimit), + blsLimit: cbg.MaxLength, + secpLimit: cbg.MaxLength, + } minGas := int64(gasguess.MinGas) // 1. Get priority actor chains @@ -554,7 +600,7 @@ func (mp *MessagePool) selectPriorityMessages(ctx context.Context, pending map[a pk, err := mp.resolveToKey(ctx, actor) if err != nil { log.Debugf("mpooladdlocal failed to resolve sender: %s", err) - return nil, gasLimit + return result } mset, ok := pending[pk] @@ -566,9 +612,8 @@ func (mp *MessagePool) selectPriorityMessages(ctx context.Context, pending map[a chains = append(chains, next...) } } - if len(chains) == 0 { - return nil, gasLimit + return result } // 2. Sort the chains @@ -578,7 +623,7 @@ func (mp *MessagePool) selectPriorityMessages(ctx context.Context, pending map[a if len(chains) != 0 && chains[0].gasPerf < 0 { log.Warnw("all priority messages in mpool have negative gas performance", "bestGasPerf", chains[0].gasPerf) - return nil, gasLimit + return result } // 3. Merge chains until the block limit, as long as they have non-negative gas performance @@ -588,9 +633,8 @@ func (mp *MessagePool) selectPriorityMessages(ctx context.Context, pending map[a break } - if chain.gasLimit <= gasLimit { - gasLimit -= chain.gasLimit - result = append(result, chain.msgs...) + if result.tryToAdd(chain) { + // there was room, we added the chain, keep going continue } @@ -600,9 +644,10 @@ func (mp *MessagePool) selectPriorityMessages(ctx context.Context, pending map[a } tailLoop: - for gasLimit >= minGas && last < len(chains) { + for result.gasLimit >= minGas && last < len(chains) { // trim, discarding negative performing messages - chains[last].Trim(gasLimit, mp, baseFee) + + result.trimChain(chains[last], mp, baseFee) // push down if it hasn't been invalidated if chains[last].valid { @@ -627,9 +672,8 @@ tailLoop: } // does it fit in the bock? - if chain.gasLimit <= gasLimit { - gasLimit -= chain.gasLimit - result = append(result, chain.msgs...) + if result.tryToAdd(chain) { + // there was room, we added the chain, keep going continue } @@ -643,7 +687,7 @@ tailLoop: break } - return result, gasLimit + return result } func (mp *MessagePool) getPendingMessages(curTs, ts *types.TipSet) (map[address.Address]map[uint64]*types.SignedMessage, error) { @@ -811,6 +855,7 @@ func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint6 chain.gasLimit = m.Message.GasLimit chain.gasPerf = mp.getGasPerf(chain.gasReward, chain.gasLimit) chain.valid = true + chain.sigType = m.Signature.Type return chain } @@ -910,6 +955,7 @@ func (mc *msgChain) Trim(gasLimit int64, msgLimit int, mp *MessagePool, baseFee mc.msgs = mc.msgs[:i+1] } + // TODO: if the trim above is a no-op, this (may) needlessly invalidates the next chain if mc.next != nil { mc.next.Invalidate() mc.next = nil diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 0f8fd8ee6f2..72739b6a14a 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -577,7 +577,7 @@ func TestMessageSelectionTrimming(t *testing.T) { expected := int(build.BlockGasLimit / gasLimit) if len(msgs) != expected { - t.Fatalf("expected %d messages, bug got %d", expected, len(msgs)) + t.Fatalf("expected %d messages, but got %d", expected, len(msgs)) } mGasLimit := int64(0) @@ -978,7 +978,7 @@ func TestOptimalMessageSelection2(t *testing.T) { func TestOptimalMessageSelection3(t *testing.T) { // this test uses 10 actors sending a block of messages to each other, with the the first // actors paying higher gas premium than the subsequent actors. - // We select with a low ticket quality; the chain depenent merging algorithm should pick + // We select with a low ticket quality; the chain dependent merging algorithm should pick // messages from the median actor from the start mp, tma := makeTestMpool() @@ -1109,11 +1109,13 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu logging.SetLogLevel("messagepool", "error") // 1. greedy selection - greedyMsgs, err := mp.selectMessagesGreedy(context.Background(), ts, ts) + gm, err := mp.selectMessagesGreedy(context.Background(), ts, ts) if err != nil { t.Fatal(err) } + greedyMsgs := gm.msgs + totalGreedyCapacity := 0.0 totalGreedyReward := 0.0 totalOptimalCapacity := 0.0 From a45803d8a033bb267b61bfb2bab53f5fe5dc5c50 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Sat, 11 Sep 2021 21:23:49 -0400 Subject: [PATCH 19/24] Mempool: add selection tests --- chain/messagepool/selection.go | 4 + chain/messagepool/selection_test.go | 199 +++++++++++++++++++++++++++- 2 files changed, 202 insertions(+), 1 deletion(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 7446ee4e4b4..d7f7750fc6d 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -63,6 +63,10 @@ func (mp *MessagePool) SelectMessages(ctx context.Context, ts *types.TipSet, tq return nil, err } + if sm == nil { + return nil, nil + } + // one last sanity check if len(sm.msgs) > build.BlockMessageLimit { sm.msgs = sm.msgs[:build.BlockMessageLimit] diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 72739b6a14a..f3389896f6d 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -13,6 +13,10 @@ import ( "sort" "testing" + "github.com/filecoin-project/go-state-types/crypto" + + cbg "github.com/whyrusleeping/cbor-gen" + "github.com/filecoin-project/go-address" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" @@ -527,7 +531,7 @@ func TestBasicMessageSelection(t *testing.T) { } } -func TestMessageSelectionTrimming(t *testing.T) { +func TestMessageSelectionTrimmingGas(t *testing.T) { mp, tma := makeTestMpool() // the actors @@ -590,6 +594,199 @@ func TestMessageSelectionTrimming(t *testing.T) { } +func TestMessageSelectionTrimmingMsgsBasic(t *testing.T) { + mp, tma := makeTestMpool() + + // the actors + w1, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1) + if err != nil { + t.Fatal(err) + } + + block := tma.nextBlock() + ts := mock.TipSet(block) + tma.applyBlock(t, block) + + tma.setBalance(a1, 1) // in FIL + + // create a larger than selectable chain + for i := 0; i < build.BlockMessageLimit; i++ { + m := makeTestMessage(w1, a1, a1, uint64(i), 300000, 100) + mustAdd(t, mp, m) + } + + msgs, err := mp.SelectMessages(context.Background(), ts, 1.0) + if err != nil { + t.Fatal(err) + } + + expected := cbg.MaxLength + if len(msgs) != expected { + t.Fatalf("expected %d messages, but got %d", expected, len(msgs)) + } + + mGasLimit := int64(0) + for _, m := range msgs { + mGasLimit += m.Message.GasLimit + } + if mGasLimit > build.BlockGasLimit { + t.Fatal("selected messages gas limit exceeds block gas limit!") + } + +} + +func TestMessageSelectionTrimmingMsgsTwoSendersBasic(t *testing.T) { + mp, tma := makeTestMpool() + + // the actors + w1, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1) + if err != nil { + t.Fatal(err) + } + + w2, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a2, err := w2.WalletNew(context.Background(), types.KTBLS) + if err != nil { + t.Fatal(err) + } + + block := tma.nextBlock() + ts := mock.TipSet(block) + tma.applyBlock(t, block) + + tma.setBalance(a1, 1) // in FIL + tma.setBalance(a2, 1) // in FIL + + // create 2 larger than selectable chains + for i := 0; i < build.BlockMessageLimit; i++ { + m := makeTestMessage(w1, a1, a2, uint64(i), 300000, 100) + mustAdd(t, mp, m) + // a2's messages are preferred + m = makeTestMessage(w2, a2, a1, uint64(i), 300000, 1000) + mustAdd(t, mp, m) + } + + msgs, err := mp.SelectMessages(context.Background(), ts, 1.0) + if err != nil { + t.Fatal(err) + } + + mGasLimit := int64(0) + counts := make(map[crypto.SigType]uint) + for _, m := range msgs { + mGasLimit += m.Message.GasLimit + counts[m.Signature.Type]++ + } + + if mGasLimit > build.BlockGasLimit { + t.Fatal("selected messages gas limit exceeds block gas limit!") + } + + expected := build.BlockMessageLimit + if len(msgs) != expected { + t.Fatalf("expected %d messages, but got %d", expected, len(msgs)) + } + + if counts[crypto.SigTypeBLS] != cbg.MaxLength { + t.Fatalf("expected %d bls messages, but got %d", cbg.MaxLength, len(msgs)) + } +} + +func TestMessageSelectionTrimmingMsgsTwoSendersAdvanced(t *testing.T) { + mp, tma := makeTestMpool() + + // the actors + w1, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1) + if err != nil { + t.Fatal(err) + } + + w2, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a2, err := w2.WalletNew(context.Background(), types.KTBLS) + if err != nil { + t.Fatal(err) + } + + block := tma.nextBlock() + ts := mock.TipSet(block) + tma.applyBlock(t, block) + + tma.setBalance(a1, 1) // in FIL + tma.setBalance(a2, 1) // in FIL + + // create 2 almost max-length chains of equal value + i := 0 + for i = 0; i < cbg.MaxLength-1; i++ { + m := makeTestMessage(w1, a1, a2, uint64(i), 300000, 100) + mustAdd(t, mp, m) + // a2's messages are preferred + m = makeTestMessage(w2, a2, a1, uint64(i), 300000, 100) + mustAdd(t, mp, m) + } + + // a1's 8192th message is worth more than a2's + m := makeTestMessage(w1, a1, a2, uint64(i), 300000, 1000) + mustAdd(t, mp, m) + + m = makeTestMessage(w2, a2, a1, uint64(i), 300000, 100) + mustAdd(t, mp, m) + + i++ + + // a2's (unselectable) 8193rd message is worth SO MUCH + m = makeTestMessage(w2, a2, a1, uint64(i), 300000, 1000000) + mustAdd(t, mp, m) + + msgs, err := mp.SelectMessages(context.Background(), ts, 1.0) + if err != nil { + t.Fatal(err) + } + + mGasLimit := int64(0) + counts := make(map[crypto.SigType]uint) + for _, m := range msgs { + mGasLimit += m.Message.GasLimit + counts[m.Signature.Type]++ + } + + if mGasLimit > build.BlockGasLimit { + t.Fatal("selected messages gas limit exceeds block gas limit!") + } + + expected := build.BlockMessageLimit + if len(msgs) != expected { + t.Fatalf("expected %d messages, but got %d", expected, len(msgs)) + } + + // we should have taken the secp chain + if counts[crypto.SigTypeSecp256k1] != cbg.MaxLength { + t.Fatalf("expected %d bls messages, but got %d", cbg.MaxLength, len(msgs)) + } +} + func TestPriorityMessageSelection(t *testing.T) { mp, tma := makeTestMpool() From b08bf32040d246078547de935ea0f0e88f844509 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Mon, 13 Dec 2021 18:31:31 -0500 Subject: [PATCH 20/24] Add a log for when message selection fails --- chain/messagepool/selection.go | 1 + 1 file changed, 1 insertion(+) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index d7f7750fc6d..3ccf2e40619 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -69,6 +69,7 @@ func (mp *MessagePool) SelectMessages(ctx context.Context, ts *types.TipSet, tq // one last sanity check if len(sm.msgs) > build.BlockMessageLimit { + log.Errorf("message selection chose too many messages %d > %d", len(sm.msgs), build.BlockMessageLimit) sm.msgs = sm.msgs[:build.BlockMessageLimit] } From fac769ff17f03731520476bd8a0db49a9a3a4081 Mon Sep 17 00:00:00 2001 From: Jennifer Wang Date: Mon, 13 Dec 2021 04:18:31 -0500 Subject: [PATCH 21/24] i forced pushed and brought a bug that was fixed back so im fixing it back --- cmd/lotus-shed/terminations.go | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/cmd/lotus-shed/terminations.go b/cmd/lotus-shed/terminations.go index c28d595b4e1..a209e459f1f 100644 --- a/cmd/lotus-shed/terminations.go +++ b/cmd/lotus-shed/terminations.go @@ -5,12 +5,15 @@ import ( "context" "fmt" "io" + "strconv" + "github.com/filecoin-project/lotus/chain/actors/builtin" + + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/actors/builtin/market" - "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/consensus/filcns" @@ -26,6 +29,7 @@ import ( var terminationsCmd = &cli.Command{ Name: "terminations", Description: "Lists terminated deals from the past 2 days", + ArgsUsage: "[block to look back from] [lookback period (epochs)]", Flags: []cli.Flag{ &cli.StringFlag{ Name: "repo", @@ -35,8 +39,8 @@ var terminationsCmd = &cli.Command{ Action: func(cctx *cli.Context) error { ctx := context.TODO() - if !cctx.Args().Present() { - return fmt.Errorf("must pass block cid") + if cctx.NArg() != 2 { + return fmt.Errorf("must pass block cid && lookback period") } blkCid, err := cid.Decode(cctx.Args().First()) @@ -85,12 +89,14 @@ var terminationsCmd = &cli.Command{ return err } - minerCode, err := miner.GetActorCodeID(actors.Version6) + lbp, err := strconv.Atoi(cctx.Args().Get(1)) if err != nil { - return err + return fmt.Errorf("failed to parse input: %w", err) } - for i := 0; i < 2880*2; i++ { + cutoff := blk.Height - abi.ChainEpoch(lbp) + + for blk.Height > cutoff { pts, err := cs.LoadTipSet(types.NewTipSetKey(blk.Parents...)) if err != nil { return err @@ -119,7 +125,7 @@ var terminationsCmd = &cli.Command{ return err } - if minerAct.Code != minerCode { + if !builtin.IsStorageMinerActor(minerAct.Code) { continue } @@ -158,10 +164,12 @@ var terminationsCmd = &cli.Command{ for _, sector := range sectors { for _, deal := range sector.DealIDs { prop, find, err := proposals.Get(deal) - if err != nil || !find { + if err != nil { return err } - fmt.Printf("%s, %d, %d, %s, %s, %s\n", msg.To, sector.SectorNumber, deal, prop.Client, prop.PieceCID, prop.Label) + if find { + fmt.Printf("%s, %d, %d, %s, %s, %s\n", msg.To, sector.SectorNumber, deal, prop.Client, prop.PieceCID, prop.Label) + } } } } From 0f0a70e2516ea983ca7c1e095e5c1977867fed75 Mon Sep 17 00:00:00 2001 From: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> Date: Thu, 16 Dec 2021 23:00:58 -0500 Subject: [PATCH 22/24] Update .github/pull_request_template.md --- .github/pull_request_template.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 6984f6ffd3d..d4989af72fa 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -11,6 +11,7 @@ ## Checklist Before you mark the PR ready for review, please make sure that: +- [ ] All commits have a clear commit message. - [ ] The PR title is in the form of of `: <#issue number> : ` - example: ` fix: #1234 mempool: Introduce a cache for valid signatures` - `PR type`: _fix_, _feat_, _BREAKING CHANGE_, _build_, _chore_, _ci_, _docs_, _perf_, _refactor_, _revert_, _style_, _test_ From 52fbee6749787741d8f61a45b18061a6aed209f4 Mon Sep 17 00:00:00 2001 From: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> Date: Thu, 16 Dec 2021 23:01:03 -0500 Subject: [PATCH 23/24] Update .github/pull_request_template.md --- .github/pull_request_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index d4989af72fa..76d38d2927c 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -14,7 +14,7 @@ Before you mark the PR ready for review, please make sure that: - [ ] All commits have a clear commit message. - [ ] The PR title is in the form of of `: <#issue number> : ` - example: ` fix: #1234 mempool: Introduce a cache for valid signatures` - - `PR type`: _fix_, _feat_, _BREAKING CHANGE_, _build_, _chore_, _ci_, _docs_, _perf_, _refactor_, _revert_, _style_, _test_ + - `PR type`: _fix_, _feat_, _INTERFACE BREAKING CHANGE_, _CONSENSUS BREAKING_, _build_, _chore_, _ci_, _docs_, _misc_,_perf_, _refactor_, _revert_, _style_, _test_ - `area`: _api_, _chain_, _state_, _vm_, _data transfer_, _market_, _mempool_, _message_, _block production_, _multisig_, _networking_, _paychan_, _proving_, _sealing_, _wallet_ - [ ] This PR has tests for new functionality or change in behaviour - [ ] If new user-facing features are introduced, clear usage guidelines and / or documentation updates should be included in https://lotus.filecoin.io or [Discussion Tutorials.](https://github.com/filecoin-project/lotus/discussions/categories/tutorials) From 1f04cc1f23b1a86d79ee1a9afa59180ac1699ab5 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Thu, 16 Dec 2021 23:59:26 -0500 Subject: [PATCH 24/24] VM: Circ supply should be constant per epoch --- chain/gen/genesis/genesis.go | 6 +++++- chain/vm/vm.go | 19 ++++++++++++++----- conformance/driver.go | 8 ++++++++ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 29f03e2af92..45387df50bc 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -479,6 +479,10 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, sys vm.Sysca verifNeeds := make(map[address.Address]abi.PaddedPieceSize) var sum abi.PaddedPieceSize + csc := func(context.Context, abi.ChainEpoch, *state.StateTree) (abi.TokenAmount, error) { + return big.Zero(), nil + } + vmopt := vm.VMOpts{ StateBase: stateroot, Epoch: 0, @@ -486,7 +490,7 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, sys vm.Sysca Bstore: cs.StateBlockstore(), Actors: filcns.NewActorRegistry(), Syscalls: mkFakedSigSyscalls(sys), - CircSupplyCalc: nil, + CircSupplyCalc: csc, NtwkVersion: func(_ context.Context, _ abi.ChainEpoch) network.Version { return nv }, diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 16ad5e2a463..d569dbbbf96 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -202,9 +202,7 @@ type ( ) type VM struct { - cstate *state.StateTree - // TODO: Is base actually used? Can we delete it? - base cid.Cid + cstate *state.StateTree cst *cbor.BasicIpldStore buf *blockstore.BufferedBlockstore blockHeight abi.ChainEpoch @@ -214,6 +212,7 @@ type VM struct { ntwkVersion NtwkVersionGetter baseFee abi.TokenAmount lbStateGet LookbackStateGetter + baseCircSupply abi.TokenAmount Syscalls SyscallBuilder } @@ -239,9 +238,13 @@ func NewVM(ctx context.Context, opts *VMOpts) (*VM, error) { return nil, err } + baseCirc, err := opts.CircSupplyCalc(ctx, opts.Epoch, state) + if err != nil { + return nil, err + } + return &VM{ cstate: state, - base: opts.StateBase, cst: cst, buf: buf, blockHeight: opts.Epoch, @@ -251,6 +254,7 @@ func NewVM(ctx context.Context, opts *VMOpts) (*VM, error) { ntwkVersion: opts.NtwkVersion, Syscalls: opts.Syscalls, baseFee: opts.BaseFee, + baseCircSupply: baseCirc, lbStateGet: opts.LookbackState, }, nil } @@ -859,7 +863,12 @@ func (vm *VM) GetNtwkVersion(ctx context.Context, ce abi.ChainEpoch) network.Ver } func (vm *VM) GetCircSupply(ctx context.Context) (abi.TokenAmount, error) { - return vm.circSupplyCalc(ctx, vm.blockHeight, vm.cstate) + // Before v15, this was recalculated on each invocation as the state tree was mutated + if vm.GetNtwkVersion(ctx, vm.blockHeight) <= network.Version14 { + return vm.circSupplyCalc(ctx, vm.blockHeight, vm.cstate) + } + + return vm.baseCircSupply, nil } func (vm *VM) incrementNonce(addr address.Address) error { diff --git a/conformance/driver.go b/conformance/driver.go index 8669089da08..c6a20e3599c 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -153,6 +153,14 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params results: []*vm.ApplyRet{}, } + sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) { + vmopt.CircSupplyCalc = func(context.Context, abi.ChainEpoch, *state.StateTree) (abi.TokenAmount, error) { + return big.Zero(), nil + } + + return vm.NewVM(ctx, vmopt) + }) + postcid, receiptsroot, err := tse.ApplyBlocks(context.Background(), sm, params.ParentEpoch,