diff --git a/build/bootstrap/butterflynet.pi b/build/bootstrap/butterflynet.pi index cc4ce4f1d..fbfa1e92c 100644 --- a/build/bootstrap/butterflynet.pi +++ b/build/bootstrap/butterflynet.pi @@ -1,2 +1,2 @@ -/dns4/bootstrap-0.butterfly.fildev.network/tcp/1347/p2p/12D3KooWBbZd7Su9XfLUQ12RynGQ3ZmGY1nGqFntmqop9pLNJE6g -/dns4/bootstrap-1.butterfly.fildev.network/tcp/1347/p2p/12D3KooWGKRzEY4tJFTmAmrYUpa1CVVohmV9YjJbC9v5XWY2gUji +/dns4/bootstrap-0.butterfly.fildev.network/tcp/1347/p2p/12D3KooWBzv5sf4eTyo8cjJGfGnpxo6QkEPkRShG9GqjE2A5QaW5 +/dns4/bootstrap-1.butterfly.fildev.network/tcp/1347/p2p/12D3KooWBo9TSD4XXRFtu6snv6QNYvXgRaSaVb116YiYEsDWgKtq diff --git a/build/genesis/butterflynet.car b/build/genesis/butterflynet.car index 7c2d19251..cb8401042 100644 Binary files a/build/genesis/butterflynet.car and b/build/genesis/butterflynet.car differ diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index 27f986f40..d830d2d4f 100644 Binary files a/build/openrpc/full.json.gz and b/build/openrpc/full.json.gz differ diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index d31b7e433..0460cf239 100644 Binary files a/build/openrpc/miner.json.gz and b/build/openrpc/miner.json.gz differ diff --git a/build/openrpc/worker.json.gz b/build/openrpc/worker.json.gz index 221ffc279..889e30c5e 100644 Binary files a/build/openrpc/worker.json.gz and b/build/openrpc/worker.json.gz differ diff --git a/build/params_2k.go b/build/params_2k.go index 479bd3b82..485f7bec0 100644 --- a/build/params_2k.go +++ b/build/params_2k.go @@ -10,12 +10,16 @@ import ( "github.com/ipfs/go-cid" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/chain/actors/policy" + miner6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/miner" ) const BootstrappersFile = "" const GenesisFile = "" +const GenesisNetworkVersion = network.Version14 + var UpgradeBreezeHeight = abi.ChainEpoch(-1) const BreezeGasTampingDuration = 0 @@ -42,6 +46,8 @@ var UpgradeTurboHeight = abi.ChainEpoch(-15) var UpgradeHyperdriveHeight = abi.ChainEpoch(-16) +var UpgradeChocolateHeight = abi.ChainEpoch(-17) + var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, } @@ -82,8 +88,12 @@ func init() { UpgradeNorwegianHeight = getUpgradeHeight("LOTUS_NORWEGIAN_HEIGHT", UpgradeNorwegianHeight) UpgradeTurboHeight = getUpgradeHeight("LOTUS_ACTORSV4_HEIGHT", UpgradeTurboHeight) UpgradeHyperdriveHeight = getUpgradeHeight("LOTUS_HYPERDRIVE_HEIGHT", UpgradeHyperdriveHeight) + UpgradeChocolateHeight = getUpgradeHeight("LOTUS_CHOCOLATE_HEIGHT", UpgradeChocolateHeight) BuildType |= Build2k + + // To test out what this proposal would like on devnets / testnets: https://github.com/filecoin-project/FIPs/pull/190 + miner6.FaultMaxAge = miner6.WPoStProvingPeriod * 42 } const BlockDelaySecs = uint64(4) diff --git a/build/params_butterfly.go b/build/params_butterfly.go index 1477c363a..70d1cff95 100644 --- a/build/params_butterfly.go +++ b/build/params_butterfly.go @@ -6,8 +6,10 @@ package build import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/chain/actors/policy" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" + miner6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/miner" "github.com/ipfs/go-cid" ) @@ -15,6 +17,8 @@ var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, } +const GenesisNetworkVersion = network.Version13 + const BootstrappersFile = "butterflynet.pi" const GenesisFile = "butterflynet.car" @@ -24,19 +28,20 @@ const UpgradeSmokeHeight = -2 const UpgradeIgnitionHeight = -3 const UpgradeRefuelHeight = -4 -var UpgradeAssemblyHeight = abi.ChainEpoch(30) +var UpgradeAssemblyHeight = abi.ChainEpoch(-5) -const UpgradeTapeHeight = 60 -const UpgradeLiftoffHeight = -5 -const UpgradeKumquatHeight = 90 -const UpgradeCalicoHeight = 120 -const UpgradePersianHeight = 150 -const UpgradeClausHeight = 180 -const UpgradeOrangeHeight = 210 -const UpgradeTrustHeight = 240 -const UpgradeNorwegianHeight = UpgradeTrustHeight + (builtin2.EpochsInHour * 12) -const UpgradeTurboHeight = 8922 -const UpgradeHyperdriveHeight = 9999999 +const UpgradeTapeHeight = -6 +const UpgradeLiftoffHeight = -7 +const UpgradeKumquatHeight = -8 +const UpgradeCalicoHeight = -9 +const UpgradePersianHeight = -10 +const UpgradeClausHeight = -11 +const UpgradeOrangeHeight = -12 +const UpgradeTrustHeight = -13 +const UpgradeNorwegianHeight = -14 +const UpgradeTurboHeight = -15 +const UpgradeHyperdriveHeight = -16 +const UpgradeChocolateHeight = 6360 func init() { policy.SetConsensusMinerMinPower(abi.NewStoragePower(2 << 30)) @@ -49,6 +54,9 @@ func init() { Devnet = true BuildType = BuildButterflynet + + // To test out what this proposal would like on devnets / testnets: https://github.com/filecoin-project/FIPs/pull/190 + miner6.FaultMaxAge = miner6.WPoStProvingPeriod * 42 } const BlockDelaySecs = uint64(builtin2.EpochDurationSeconds) diff --git a/build/params_calibnet.go b/build/params_calibnet.go index bafed3015..be16d08b9 100644 --- a/build/params_calibnet.go +++ b/build/params_calibnet.go @@ -6,8 +6,10 @@ package build import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/chain/actors/policy" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" + miner6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/miner" "github.com/ipfs/go-cid" ) @@ -15,6 +17,8 @@ var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, } +const GenesisNetworkVersion = network.Version0 + const BootstrappersFile = "calibnet.pi" const GenesisFile = "calibnet.car" @@ -49,6 +53,8 @@ const UpgradeTurboHeight = 390 const UpgradeHyperdriveHeight = 420 +const UpgradeChocolateHeight = 312746 + func init() { policy.SetConsensusMinerMinPower(abi.NewStoragePower(32 << 30)) policy.SetSupportedProofTypes( @@ -61,6 +67,9 @@ func init() { Devnet = true BuildType = BuildCalibnet + + // To test out what this proposal would like on devnets / testnets: https://github.com/filecoin-project/FIPs/pull/190 + miner6.FaultMaxAge = miner6.WPoStProvingPeriod * 42 } const BlockDelaySecs = uint64(builtin2.EpochDurationSeconds) diff --git a/build/params_interop.go b/build/params_interop.go index 0040bb9d0..e928da8a0 100644 --- a/build/params_interop.go +++ b/build/params_interop.go @@ -11,7 +11,9 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/network" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" + miner6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/actors/policy" ) @@ -19,6 +21,8 @@ import ( const BootstrappersFile = "interopnet.pi" const GenesisFile = "interopnet.car" +const GenesisNetworkVersion = network.Version13 + var UpgradeBreezeHeight = abi.ChainEpoch(-1) const BreezeGasTampingDuration = 0 @@ -44,6 +48,7 @@ var UpgradeNorwegianHeight = abi.ChainEpoch(-14) var UpgradeTurboHeight = abi.ChainEpoch(-15) var UpgradeHyperdriveHeight = abi.ChainEpoch(-16) +var UpgradeChocolateHeight = abi.ChainEpoch(-17) var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, @@ -93,6 +98,9 @@ func init() { BuildType |= BuildInteropnet SetAddressNetwork(address.Testnet) Devnet = true + + // To test out what this proposal would like on devnets / testnets: https://github.com/filecoin-project/FIPs/pull/190 + miner6.FaultMaxAge = miner6.WPoStProvingPeriod * 42 } const BlockDelaySecs = uint64(builtin2.EpochDurationSeconds) diff --git a/build/params_mainnet.go b/build/params_mainnet.go index 1e9996082..e6b730335 100644 --- a/build/params_mainnet.go +++ b/build/params_mainnet.go @@ -7,6 +7,8 @@ import ( "math" "os" + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" @@ -17,6 +19,8 @@ var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ UpgradeSmokeHeight: DrandMainnet, } +const GenesisNetworkVersion = network.Version0 + const BootstrappersFile = "mainnet.pi" const GenesisFile = "mainnet.car" @@ -60,13 +64,16 @@ const UpgradeTurboHeight = 712320 // 2021-06-30T22:00:00Z var UpgradeHyperdriveHeight = abi.ChainEpoch(892800) +// ??? +var UpgradeChocolateHeight = abi.ChainEpoch(999999999) + func init() { if os.Getenv("LOTUS_USE_TEST_ADDRESSES") != "1" { SetAddressNetwork(address.Mainnet) } - if os.Getenv("LOTUS_DISABLE_HYPERDRIVE") == "1" { - UpgradeHyperdriveHeight = math.MaxInt64 + if os.Getenv("LOTUS_DISABLE_CHOCOLATE") == "1" { + UpgradeChocolateHeight = math.MaxInt64 } Devnet = false diff --git a/build/params_shared_vals.go b/build/params_shared_vals.go index f3b6cb6a2..5b6197d9b 100644 --- a/build/params_shared_vals.go +++ b/build/params_shared_vals.go @@ -26,6 +26,8 @@ const UnixfsLinksPerLevel = 1024 // Consensus / Network const AllowableClockDriftSecs = uint64(1) + +// TODO: This is still terrible...What's the impact of updating this before mainnet actually upgrades const NewestNetworkVersion = network.Version13 // Epochs diff --git a/build/params_testground.go b/build/params_testground.go index 0bb984a27..48b76f82c 100644 --- a/build/params_testground.go +++ b/build/params_testground.go @@ -98,12 +98,15 @@ var ( UpgradeNorwegianHeight abi.ChainEpoch = -13 UpgradeTurboHeight abi.ChainEpoch = -14 UpgradeHyperdriveHeight abi.ChainEpoch = -15 + UpgradeChocolateHeight abi.ChainEpoch = -16 DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, } - NewestNetworkVersion = network.Version11 + GenesisNetworkVersion = network.Version0 + + NewestNetworkVersion = network.Version14 ActorUpgradeNetworkVersion = network.Version4 Devnet = true diff --git a/build/version.go b/build/version.go index 51233ed0c..c9f6f4a53 100644 --- a/build/version.go +++ b/build/version.go @@ -37,7 +37,7 @@ func BuildTypeString() string { } // BuildVersion is the local build version -const BuildVersion = "1.11.4-dev" +const BuildVersion = "1.13.0-dev" func UserVersion() string { if os.Getenv("LOTUS_VERSION_IGNORE_COMMIT") == "1" { diff --git a/chain/actors/builtin/account/account.go b/chain/actors/builtin/account/account.go index 04c82b340..249ce133f 100644 --- a/chain/actors/builtin/account/account.go +++ b/chain/actors/builtin/account/account.go @@ -21,6 +21,8 @@ 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" ) func init() { @@ -44,6 +46,10 @@ func init() { builtin.RegisterActorState(builtin5.AccountActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load5(store, root) }) + + builtin.RegisterActorState(builtin6.AccountActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load6(store, root) + }) } var Methods = builtin4.MethodsAccount @@ -66,6 +72,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin5.AccountActorCodeID: return load5(store, act.Head) + case builtin6.AccountActorCodeID: + return load6(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -88,6 +97,9 @@ func MakeState(store adt.Store, av actors.Version, addr address.Address) (State, case actors.Version5: return make5(store, addr) + case actors.Version6: + return make6(store, addr) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -110,6 +122,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version5: return builtin5.AccountActorCodeID, nil + case actors.Version6: + return builtin6.AccountActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) diff --git a/chain/actors/builtin/account/v6.go b/chain/actors/builtin/account/v6.go new file mode 100644 index 000000000..a0d157ae5 --- /dev/null +++ b/chain/actors/builtin/account/v6.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" + + account6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/account" +) + +var _ State = (*state6)(nil) + +func load6(store adt.Store, root cid.Cid) (State, error) { + out := state6{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make6(store adt.Store, addr address.Address) (State, error) { + out := state6{store: store} + out.State = account6.State{Address: addr} + return &out, nil +} + +type state6 struct { + account6.State + store adt.Store +} + +func (s *state6) PubkeyAddress() (address.Address, error) { + return s.Address, nil +} + +func (s *state6) GetState() interface{} { + return &s.State +} diff --git a/chain/actors/builtin/builtin.go b/chain/actors/builtin/builtin.go index 74d622819..ebfe2df2e 100644 --- a/chain/actors/builtin/builtin.go +++ b/chain/actors/builtin/builtin.go @@ -20,46 +20,49 @@ import ( builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" smoothing5 "github.com/filecoin-project/specs-actors/v5/actors/util/smoothing" + builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + smoothing6 "github.com/filecoin-project/specs-actors/v6/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" - miner5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/miner" - proof5 "github.com/filecoin-project/specs-actors/v5/actors/runtime/proof" + miner6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/miner" + proof6 "github.com/filecoin-project/specs-actors/v6/actors/runtime/proof" ) -var SystemActorAddr = builtin5.SystemActorAddr -var BurntFundsActorAddr = builtin5.BurntFundsActorAddr -var CronActorAddr = builtin5.CronActorAddr +var SystemActorAddr = builtin6.SystemActorAddr +var BurntFundsActorAddr = builtin6.BurntFundsActorAddr +var CronActorAddr = builtin6.CronActorAddr var SaftAddress = makeAddress("t0122") var ReserveAddress = makeAddress("t090") var RootVerifierAddress = makeAddress("t080") var ( - ExpectedLeadersPerEpoch = builtin5.ExpectedLeadersPerEpoch + ExpectedLeadersPerEpoch = builtin6.ExpectedLeadersPerEpoch ) const ( - EpochDurationSeconds = builtin5.EpochDurationSeconds - EpochsInDay = builtin5.EpochsInDay - SecondsInDay = builtin5.SecondsInDay + EpochDurationSeconds = builtin6.EpochDurationSeconds + EpochsInDay = builtin6.EpochsInDay + SecondsInDay = builtin6.SecondsInDay ) const ( - MethodSend = builtin5.MethodSend - MethodConstructor = builtin5.MethodConstructor + MethodSend = builtin6.MethodSend + MethodConstructor = builtin6.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 = proof5.SectorInfo -type PoStProof = proof5.PoStProof +type SectorInfo = proof6.SectorInfo +type PoStProof = proof6.PoStProof type FilterEstimate = smoothing0.FilterEstimate func QAPowerForWeight(size abi.SectorSize, duration abi.ChainEpoch, dealWeight, verifiedWeight abi.DealWeight) abi.StoragePower { - return miner5.QAPowerForWeight(size, duration, dealWeight, verifiedWeight) + return miner6.QAPowerForWeight(size, duration, dealWeight, verifiedWeight) } func FromV0FilterEstimate(v0 smoothing0.FilterEstimate) FilterEstimate { @@ -92,6 +95,12 @@ func FromV5FilterEstimate(v5 smoothing5.FilterEstimate) FilterEstimate { } +func FromV6FilterEstimate(v6 smoothing6.FilterEstimate) FilterEstimate { + + return (FilterEstimate)(v6) + +} + type ActorStateLoader func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) var ActorStateLoaders = make(map[cid.Cid]ActorStateLoader) @@ -126,6 +135,9 @@ func ActorNameByCode(c cid.Cid) string { case builtin5.IsBuiltinActor(c): return builtin5.ActorNameByCode(c) + case builtin6.IsBuiltinActor(c): + return builtin6.ActorNameByCode(c) + default: return "" } @@ -153,6 +165,10 @@ func IsBuiltinActor(c cid.Cid) bool { return true } + if builtin6.IsBuiltinActor(c) { + return true + } + return false } @@ -178,6 +194,10 @@ func IsAccountActor(c cid.Cid) bool { return true } + if c == builtin6.AccountActorCodeID { + return true + } + return false } @@ -203,6 +223,10 @@ func IsStorageMinerActor(c cid.Cid) bool { return true } + if c == builtin6.StorageMinerActorCodeID { + return true + } + return false } @@ -228,6 +252,10 @@ func IsMultisigActor(c cid.Cid) bool { return true } + if c == builtin6.MultisigActorCodeID { + return true + } + return false } @@ -253,6 +281,10 @@ func IsPaymentChannelActor(c cid.Cid) bool { return true } + if c == builtin6.PaymentChannelActorCodeID { + return true + } + return false } diff --git a/chain/actors/builtin/cron/cron.go b/chain/actors/builtin/cron/cron.go index 2275e747f..9178a44ab 100644 --- a/chain/actors/builtin/cron/cron.go +++ b/chain/actors/builtin/cron/cron.go @@ -15,6 +15,8 @@ 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" ) func MakeState(store adt.Store, av actors.Version) (State, error) { @@ -35,6 +37,9 @@ func MakeState(store adt.Store, av actors.Version) (State, error) { case actors.Version5: return make5(store) + case actors.Version6: + return make6(store) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -57,14 +62,17 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version5: return builtin5.CronActorCodeID, nil + case actors.Version6: + return builtin6.CronActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) } var ( - Address = builtin5.CronActorAddr - Methods = builtin5.MethodsCron + Address = builtin6.CronActorAddr + Methods = builtin6.MethodsCron ) type State interface { diff --git a/chain/actors/builtin/cron/v6.go b/chain/actors/builtin/cron/v6.go new file mode 100644 index 000000000..8bbadd79f --- /dev/null +++ b/chain/actors/builtin/cron/v6.go @@ -0,0 +1,35 @@ +package cron + +import ( + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/actors/adt" + + cron6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/cron" +) + +var _ State = (*state6)(nil) + +func load6(store adt.Store, root cid.Cid) (State, error) { + out := state6{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make6(store adt.Store) (State, error) { + out := state6{store: store} + out.State = *cron6.ConstructState(cron6.BuiltInEntries()) + return &out, nil +} + +type state6 struct { + cron6.State + store adt.Store +} + +func (s *state6) GetState() interface{} { + return &s.State +} diff --git a/chain/actors/builtin/init/init.go b/chain/actors/builtin/init/init.go index e1bd6f371..ee06eeab7 100644 --- a/chain/actors/builtin/init/init.go +++ b/chain/actors/builtin/init/init.go @@ -23,6 +23,8 @@ 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" ) func init() { @@ -46,11 +48,15 @@ func init() { builtin.RegisterActorState(builtin5.InitActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load5(store, root) }) + + builtin.RegisterActorState(builtin6.InitActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load6(store, root) + }) } var ( - Address = builtin5.InitActorAddr - Methods = builtin5.MethodsInit + Address = builtin6.InitActorAddr + Methods = builtin6.MethodsInit ) func Load(store adt.Store, act *types.Actor) (State, error) { @@ -71,6 +77,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin5.InitActorCodeID: return load5(store, act.Head) + case builtin6.InitActorCodeID: + return load6(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -93,6 +102,9 @@ func MakeState(store adt.Store, av actors.Version, networkName string) (State, e case actors.Version5: return make5(store, networkName) + case actors.Version6: + return make6(store, networkName) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -115,6 +127,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version5: return builtin5.InitActorCodeID, nil + case actors.Version6: + return builtin6.InitActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) diff --git a/chain/actors/builtin/init/v6.go b/chain/actors/builtin/init/v6.go new file mode 100644 index 000000000..a5bd9edfb --- /dev/null +++ b/chain/actors/builtin/init/v6.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" + + builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + + init6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/init" + adt6 "github.com/filecoin-project/specs-actors/v6/actors/util/adt" +) + +var _ State = (*state6)(nil) + +func load6(store adt.Store, root cid.Cid) (State, error) { + out := state6{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make6(store adt.Store, networkName string) (State, error) { + out := state6{store: store} + + s, err := init6.ConstructState(store, networkName) + if err != nil { + return nil, err + } + + out.State = *s + + return &out, nil +} + +type state6 struct { + init6.State + store adt.Store +} + +func (s *state6) ResolveAddress(address address.Address) (address.Address, bool, error) { + return s.State.ResolveAddress(s.store, address) +} + +func (s *state6) MapAddressToNewID(address address.Address) (address.Address, error) { + return s.State.MapAddressToNewID(s.store, address) +} + +func (s *state6) ForEachActor(cb func(id abi.ActorID, address address.Address) error) error { + addrs, err := adt6.AsMap(s.store, s.State.AddressMap, builtin6.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 *state6) NetworkName() (dtypes.NetworkName, error) { + return dtypes.NetworkName(s.State.NetworkName), nil +} + +func (s *state6) SetNetworkName(name string) error { + s.State.NetworkName = name + return nil +} + +func (s *state6) SetNextID(id abi.ActorID) error { + s.State.NextID = id + return nil +} + +func (s *state6) Remove(addrs ...address.Address) (err error) { + m, err := adt6.AsMap(s.store, s.State.AddressMap, builtin6.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 *state6) SetAddressMap(mcid cid.Cid) error { + s.State.AddressMap = mcid + return nil +} + +func (s *state6) AddressMap() (adt.Map, error) { + return adt6.AsMap(s.store, s.State.AddressMap, builtin6.DefaultHamtBitwidth) +} + +func (s *state6) GetState() interface{} { + return &s.State +} diff --git a/chain/actors/builtin/market/actor.go.template b/chain/actors/builtin/market/actor.go.template index f78c84b8f..72b0bd322 100644 --- a/chain/actors/builtin/market/actor.go.template +++ b/chain/actors/builtin/market/actor.go.template @@ -1,6 +1,7 @@ package market import ( + "github.com/filecoin-project/go-state-types/network" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" @@ -103,7 +104,28 @@ type DealProposals interface { } type PublishStorageDealsParams = market0.PublishStorageDealsParams -type PublishStorageDealsReturn = market0.PublishStorageDealsReturn + +type PublishStorageDealsReturn interface { + DealIDs() ([]abi.DealID, error) + // Note that this index is based on the batch of deals that were published, NOT the DealID + IsDealValid(index uint64) (bool, error) +} + +func DecodePublishStorageDealsReturn(b []byte, nv network.Version) (PublishStorageDealsReturn, error) { + av, err := actors.VersionForNetwork(nv) + if err != nil { + return nil, err + } + + switch av { +{{range .versions}} + case actors.Version{{.}}: + return decodePublishStorageDealsReturn{{.}}(b) +{{end}} +} + return nil, xerrors.Errorf("unknown actor version %d", av) +} + type VerifyDealsForActivationParams = market0.VerifyDealsForActivationParams type WithdrawBalanceParams = market0.WithdrawBalanceParams diff --git a/chain/actors/builtin/market/market.go b/chain/actors/builtin/market/market.go index 026e35d4e..7e35f3919 100644 --- a/chain/actors/builtin/market/market.go +++ b/chain/actors/builtin/market/market.go @@ -1,6 +1,7 @@ package market import ( + "github.com/filecoin-project/go-state-types/network" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" @@ -22,6 +23,8 @@ import ( builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" + builtin6 "github.com/filecoin-project/specs-actors/v6/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" @@ -49,11 +52,15 @@ func init() { builtin.RegisterActorState(builtin5.StorageMarketActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load5(store, root) }) + + builtin.RegisterActorState(builtin6.StorageMarketActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load6(store, root) + }) } var ( - Address = builtin5.StorageMarketActorAddr - Methods = builtin5.MethodsMarket + Address = builtin6.StorageMarketActorAddr + Methods = builtin6.MethodsMarket ) func Load(store adt.Store, act *types.Actor) (State, error) { @@ -74,6 +81,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin5.StorageMarketActorCodeID: return load5(store, act.Head) + case builtin6.StorageMarketActorCodeID: + return load6(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -96,6 +106,9 @@ func MakeState(store adt.Store, av actors.Version) (State, error) { case actors.Version5: return make5(store) + case actors.Version6: + return make6(store) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -118,6 +131,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version5: return builtin5.StorageMarketActorCodeID, nil + case actors.Version6: + return builtin6.StorageMarketActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) @@ -162,7 +178,43 @@ type DealProposals interface { } type PublishStorageDealsParams = market0.PublishStorageDealsParams -type PublishStorageDealsReturn = market0.PublishStorageDealsReturn + +type PublishStorageDealsReturn interface { + DealIDs() ([]abi.DealID, error) + // Note that this index is based on the batch of deals that were published, NOT the DealID + IsDealValid(index uint64) (bool, error) +} + +func DecodePublishStorageDealsReturn(b []byte, nv network.Version) (PublishStorageDealsReturn, error) { + av, err := actors.VersionForNetwork(nv) + if err != nil { + return nil, err + } + + switch av { + + case actors.Version0: + return decodePublishStorageDealsReturn0(b) + + case actors.Version2: + return decodePublishStorageDealsReturn2(b) + + case actors.Version3: + return decodePublishStorageDealsReturn3(b) + + case actors.Version4: + return decodePublishStorageDealsReturn4(b) + + case actors.Version5: + return decodePublishStorageDealsReturn5(b) + + case actors.Version6: + return decodePublishStorageDealsReturn6(b) + + } + return nil, xerrors.Errorf("unknown actor version %d", av) +} + type VerifyDealsForActivationParams = market0.VerifyDealsForActivationParams type WithdrawBalanceParams = market0.WithdrawBalanceParams diff --git a/chain/actors/builtin/market/state.go.template b/chain/actors/builtin/market/state.go.template index 70b731148..e8272276c 100644 --- a/chain/actors/builtin/market/state.go.template +++ b/chain/actors/builtin/market/state.go.template @@ -7,6 +7,7 @@ import ( "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" @@ -236,3 +237,31 @@ func fromV{{.v}}DealProposal(v{{.v}} market{{.v}}.DealProposal) DealProposal { func (s *state{{.v}}) GetState() interface{} { return &s.State } + +var _ PublishStorageDealsReturn = (*publishStorageDealsReturn{{.v}})(nil) + +func decodePublishStorageDealsReturn{{.v}}(b []byte) (PublishStorageDealsReturn, error) { + var retval market{{.v}}.PublishStorageDealsReturn + if err := retval.UnmarshalCBOR(bytes.NewReader(b)); err != nil { + return nil, xerrors.Errorf("failed to unmarshal PublishStorageDealsReturn: %w", err) + } + + return &publishStorageDealsReturn{{.v}}{retval}, nil +} + +type publishStorageDealsReturn{{.v}} struct { + market{{.v}}.PublishStorageDealsReturn +} + +func (r *publishStorageDealsReturn{{.v}}) IsDealValid(index uint64) (bool, error) { + {{if (ge .v 6)}} + return r.ValidDeals.IsSet(index) + {{else}} + // PublishStorageDeals only succeeded if all deals were valid in this version of actors + return true, nil + {{end}} +} + +func (r *publishStorageDealsReturn{{.v}}) DealIDs() ([]abi.DealID, error) { + return r.IDs, nil +} diff --git a/chain/actors/builtin/market/v0.go b/chain/actors/builtin/market/v0.go index b3093b54b..f5a60b229 100644 --- a/chain/actors/builtin/market/v0.go +++ b/chain/actors/builtin/market/v0.go @@ -7,6 +7,7 @@ import ( "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" @@ -229,3 +230,29 @@ func fromV0DealProposal(v0 market0.DealProposal) DealProposal { func (s *state0) GetState() interface{} { return &s.State } + +var _ PublishStorageDealsReturn = (*publishStorageDealsReturn0)(nil) + +func decodePublishStorageDealsReturn0(b []byte) (PublishStorageDealsReturn, error) { + var retval market0.PublishStorageDealsReturn + if err := retval.UnmarshalCBOR(bytes.NewReader(b)); err != nil { + return nil, xerrors.Errorf("failed to unmarshal PublishStorageDealsReturn: %w", err) + } + + return &publishStorageDealsReturn0{retval}, nil +} + +type publishStorageDealsReturn0 struct { + market0.PublishStorageDealsReturn +} + +func (r *publishStorageDealsReturn0) IsDealValid(index uint64) (bool, error) { + + // PublishStorageDeals only succeeded if all deals were valid in this version of actors + return true, nil + +} + +func (r *publishStorageDealsReturn0) DealIDs() ([]abi.DealID, error) { + return r.IDs, nil +} diff --git a/chain/actors/builtin/market/v2.go b/chain/actors/builtin/market/v2.go index fdedcce85..3c6914d0c 100644 --- a/chain/actors/builtin/market/v2.go +++ b/chain/actors/builtin/market/v2.go @@ -7,6 +7,7 @@ import ( "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" @@ -229,3 +230,29 @@ func fromV2DealProposal(v2 market2.DealProposal) DealProposal { func (s *state2) GetState() interface{} { return &s.State } + +var _ PublishStorageDealsReturn = (*publishStorageDealsReturn2)(nil) + +func decodePublishStorageDealsReturn2(b []byte) (PublishStorageDealsReturn, error) { + var retval market2.PublishStorageDealsReturn + if err := retval.UnmarshalCBOR(bytes.NewReader(b)); err != nil { + return nil, xerrors.Errorf("failed to unmarshal PublishStorageDealsReturn: %w", err) + } + + return &publishStorageDealsReturn2{retval}, nil +} + +type publishStorageDealsReturn2 struct { + market2.PublishStorageDealsReturn +} + +func (r *publishStorageDealsReturn2) IsDealValid(index uint64) (bool, error) { + + // PublishStorageDeals only succeeded if all deals were valid in this version of actors + return true, nil + +} + +func (r *publishStorageDealsReturn2) DealIDs() ([]abi.DealID, error) { + return r.IDs, nil +} diff --git a/chain/actors/builtin/market/v3.go b/chain/actors/builtin/market/v3.go index 53d266443..2409bb05b 100644 --- a/chain/actors/builtin/market/v3.go +++ b/chain/actors/builtin/market/v3.go @@ -7,6 +7,7 @@ import ( "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" @@ -224,3 +225,29 @@ func fromV3DealProposal(v3 market3.DealProposal) DealProposal { func (s *state3) GetState() interface{} { return &s.State } + +var _ PublishStorageDealsReturn = (*publishStorageDealsReturn3)(nil) + +func decodePublishStorageDealsReturn3(b []byte) (PublishStorageDealsReturn, error) { + var retval market3.PublishStorageDealsReturn + if err := retval.UnmarshalCBOR(bytes.NewReader(b)); err != nil { + return nil, xerrors.Errorf("failed to unmarshal PublishStorageDealsReturn: %w", err) + } + + return &publishStorageDealsReturn3{retval}, nil +} + +type publishStorageDealsReturn3 struct { + market3.PublishStorageDealsReturn +} + +func (r *publishStorageDealsReturn3) IsDealValid(index uint64) (bool, error) { + + // PublishStorageDeals only succeeded if all deals were valid in this version of actors + return true, nil + +} + +func (r *publishStorageDealsReturn3) DealIDs() ([]abi.DealID, error) { + return r.IDs, nil +} diff --git a/chain/actors/builtin/market/v4.go b/chain/actors/builtin/market/v4.go index 30aa26920..4e9011d10 100644 --- a/chain/actors/builtin/market/v4.go +++ b/chain/actors/builtin/market/v4.go @@ -7,6 +7,7 @@ import ( "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" @@ -224,3 +225,29 @@ func fromV4DealProposal(v4 market4.DealProposal) DealProposal { func (s *state4) GetState() interface{} { return &s.State } + +var _ PublishStorageDealsReturn = (*publishStorageDealsReturn4)(nil) + +func decodePublishStorageDealsReturn4(b []byte) (PublishStorageDealsReturn, error) { + var retval market4.PublishStorageDealsReturn + if err := retval.UnmarshalCBOR(bytes.NewReader(b)); err != nil { + return nil, xerrors.Errorf("failed to unmarshal PublishStorageDealsReturn: %w", err) + } + + return &publishStorageDealsReturn4{retval}, nil +} + +type publishStorageDealsReturn4 struct { + market4.PublishStorageDealsReturn +} + +func (r *publishStorageDealsReturn4) IsDealValid(index uint64) (bool, error) { + + // PublishStorageDeals only succeeded if all deals were valid in this version of actors + return true, nil + +} + +func (r *publishStorageDealsReturn4) DealIDs() ([]abi.DealID, error) { + return r.IDs, nil +} diff --git a/chain/actors/builtin/market/v5.go b/chain/actors/builtin/market/v5.go index 12378c76d..139a32247 100644 --- a/chain/actors/builtin/market/v5.go +++ b/chain/actors/builtin/market/v5.go @@ -7,6 +7,7 @@ import ( "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" @@ -224,3 +225,29 @@ func fromV5DealProposal(v5 market5.DealProposal) DealProposal { func (s *state5) GetState() interface{} { return &s.State } + +var _ PublishStorageDealsReturn = (*publishStorageDealsReturn5)(nil) + +func decodePublishStorageDealsReturn5(b []byte) (PublishStorageDealsReturn, error) { + var retval market5.PublishStorageDealsReturn + if err := retval.UnmarshalCBOR(bytes.NewReader(b)); err != nil { + return nil, xerrors.Errorf("failed to unmarshal PublishStorageDealsReturn: %w", err) + } + + return &publishStorageDealsReturn5{retval}, nil +} + +type publishStorageDealsReturn5 struct { + market5.PublishStorageDealsReturn +} + +func (r *publishStorageDealsReturn5) IsDealValid(index uint64) (bool, error) { + + // PublishStorageDeals only succeeded if all deals were valid in this version of actors + return true, nil + +} + +func (r *publishStorageDealsReturn5) DealIDs() ([]abi.DealID, error) { + return r.IDs, nil +} diff --git a/chain/actors/builtin/market/v6.go b/chain/actors/builtin/market/v6.go new file mode 100644 index 000000000..8230f3cf1 --- /dev/null +++ b/chain/actors/builtin/market/v6.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" + + market6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/market" + adt6 "github.com/filecoin-project/specs-actors/v6/actors/util/adt" +) + +var _ State = (*state6)(nil) + +func load6(store adt.Store, root cid.Cid) (State, error) { + out := state6{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make6(store adt.Store) (State, error) { + out := state6{store: store} + + s, err := market6.ConstructState(store) + if err != nil { + return nil, err + } + + out.State = *s + + return &out, nil +} + +type state6 struct { + market6.State + store adt.Store +} + +func (s *state6) TotalLocked() (abi.TokenAmount, error) { + fml := types.BigAdd(s.TotalClientLockedCollateral, s.TotalProviderLockedCollateral) + fml = types.BigAdd(fml, s.TotalClientStorageFee) + return fml, nil +} + +func (s *state6) BalancesChanged(otherState State) (bool, error) { + otherState6, ok := otherState.(*state6) + 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(otherState6.State.EscrowTable) || !s.State.LockedTable.Equals(otherState6.State.LockedTable), nil +} + +func (s *state6) StatesChanged(otherState State) (bool, error) { + otherState6, ok := otherState.(*state6) + 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(otherState6.State.States), nil +} + +func (s *state6) States() (DealStates, error) { + stateArray, err := adt6.AsArray(s.store, s.State.States, market6.StatesAmtBitwidth) + if err != nil { + return nil, err + } + return &dealStates6{stateArray}, nil +} + +func (s *state6) ProposalsChanged(otherState State) (bool, error) { + otherState6, ok := otherState.(*state6) + 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(otherState6.State.Proposals), nil +} + +func (s *state6) Proposals() (DealProposals, error) { + proposalArray, err := adt6.AsArray(s.store, s.State.Proposals, market6.ProposalsAmtBitwidth) + if err != nil { + return nil, err + } + return &dealProposals6{proposalArray}, nil +} + +func (s *state6) EscrowTable() (BalanceTable, error) { + bt, err := adt6.AsBalanceTable(s.store, s.State.EscrowTable) + if err != nil { + return nil, err + } + return &balanceTable6{bt}, nil +} + +func (s *state6) LockedTable() (BalanceTable, error) { + bt, err := adt6.AsBalanceTable(s.store, s.State.LockedTable) + if err != nil { + return nil, err + } + return &balanceTable6{bt}, nil +} + +func (s *state6) VerifyDealsForActivation( + minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch, +) (weight, verifiedWeight abi.DealWeight, err error) { + w, vw, _, err := market6.ValidateDealsForActivation(&s.State, s.store, deals, minerAddr, sectorExpiry, currEpoch) + return w, vw, err +} + +func (s *state6) NextID() (abi.DealID, error) { + return s.State.NextID, nil +} + +type balanceTable6 struct { + *adt6.BalanceTable +} + +func (bt *balanceTable6) ForEach(cb func(address.Address, abi.TokenAmount) error) error { + asMap := (*adt6.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 dealStates6 struct { + adt.Array +} + +func (s *dealStates6) Get(dealID abi.DealID) (*DealState, bool, error) { + var deal6 market6.DealState + found, err := s.Array.Get(uint64(dealID), &deal6) + if err != nil { + return nil, false, err + } + if !found { + return nil, false, nil + } + deal := fromV6DealState(deal6) + return &deal, true, nil +} + +func (s *dealStates6) ForEach(cb func(dealID abi.DealID, ds DealState) error) error { + var ds6 market6.DealState + return s.Array.ForEach(&ds6, func(idx int64) error { + return cb(abi.DealID(idx), fromV6DealState(ds6)) + }) +} + +func (s *dealStates6) decode(val *cbg.Deferred) (*DealState, error) { + var ds6 market6.DealState + if err := ds6.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return nil, err + } + ds := fromV6DealState(ds6) + return &ds, nil +} + +func (s *dealStates6) array() adt.Array { + return s.Array +} + +func fromV6DealState(v6 market6.DealState) DealState { + return (DealState)(v6) +} + +type dealProposals6 struct { + adt.Array +} + +func (s *dealProposals6) Get(dealID abi.DealID) (*DealProposal, bool, error) { + var proposal6 market6.DealProposal + found, err := s.Array.Get(uint64(dealID), &proposal6) + if err != nil { + return nil, false, err + } + if !found { + return nil, false, nil + } + proposal := fromV6DealProposal(proposal6) + return &proposal, true, nil +} + +func (s *dealProposals6) ForEach(cb func(dealID abi.DealID, dp DealProposal) error) error { + var dp6 market6.DealProposal + return s.Array.ForEach(&dp6, func(idx int64) error { + return cb(abi.DealID(idx), fromV6DealProposal(dp6)) + }) +} + +func (s *dealProposals6) decode(val *cbg.Deferred) (*DealProposal, error) { + var dp6 market6.DealProposal + if err := dp6.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return nil, err + } + dp := fromV6DealProposal(dp6) + return &dp, nil +} + +func (s *dealProposals6) array() adt.Array { + return s.Array +} + +func fromV6DealProposal(v6 market6.DealProposal) DealProposal { + return (DealProposal)(v6) +} + +func (s *state6) GetState() interface{} { + return &s.State +} + +var _ PublishStorageDealsReturn = (*publishStorageDealsReturn6)(nil) + +func decodePublishStorageDealsReturn6(b []byte) (PublishStorageDealsReturn, error) { + var retval market6.PublishStorageDealsReturn + if err := retval.UnmarshalCBOR(bytes.NewReader(b)); err != nil { + return nil, xerrors.Errorf("failed to unmarshal PublishStorageDealsReturn: %w", err) + } + + return &publishStorageDealsReturn6{retval}, nil +} + +type publishStorageDealsReturn6 struct { + market6.PublishStorageDealsReturn +} + +func (r *publishStorageDealsReturn6) IsDealValid(index uint64) (bool, error) { + + return r.ValidDeals.IsSet(index) + +} + +func (r *publishStorageDealsReturn6) 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 e61b95eef..1c7f47e11 100644 --- a/chain/actors/builtin/miner/miner.go +++ b/chain/actors/builtin/miner/miner.go @@ -33,6 +33,8 @@ 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" ) func init() { @@ -57,9 +59,13 @@ func init() { return load5(store, root) }) + builtin.RegisterActorState(builtin6.StorageMinerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load6(store, root) + }) + } -var Methods = builtin5.MethodsMiner +var Methods = builtin6.MethodsMiner // Unchanged between v0, v2, v3, v4, and v5 actors var WPoStProvingPeriod = miner0.WPoStProvingPeriod @@ -93,6 +99,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin5.StorageMinerActorCodeID: return load5(store, act.Head) + case builtin6.StorageMinerActorCodeID: + return load6(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -115,6 +124,9 @@ func MakeState(store adt.Store, av actors.Version) (State, error) { case actors.Version5: return make5(store) + case actors.Version6: + return make6(store) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -137,6 +149,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version5: return builtin5.StorageMinerActorCodeID, nil + case actors.Version6: + return builtin6.StorageMinerActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) diff --git a/chain/actors/builtin/miner/v6.go b/chain/actors/builtin/miner/v6.go new file mode 100644 index 000000000..de5a22a10 --- /dev/null +++ b/chain/actors/builtin/miner/v6.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" + + builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + + miner6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/miner" + adt6 "github.com/filecoin-project/specs-actors/v6/actors/util/adt" +) + +var _ State = (*state6)(nil) + +func load6(store adt.Store, root cid.Cid) (State, error) { + out := state6{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make6(store adt.Store) (State, error) { + out := state6{store: store} + out.State = miner6.State{} + return &out, nil +} + +type state6 struct { + miner6.State + store adt.Store +} + +type deadline6 struct { + miner6.Deadline + store adt.Store +} + +type partition6 struct { + miner6.Partition + store adt.Store +} + +func (s *state6) 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 *state6) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) { + return s.CheckVestedFunds(s.store, epoch) +} + +func (s *state6) LockedFunds() (LockedFunds, error) { + return LockedFunds{ + VestingFunds: s.State.LockedFunds, + InitialPledgeRequirement: s.State.InitialPledge, + PreCommitDeposits: s.State.PreCommitDeposits, + }, nil +} + +func (s *state6) FeeDebt() (abi.TokenAmount, error) { + return s.State.FeeDebt, nil +} + +func (s *state6) InitialPledge() (abi.TokenAmount, error) { + return s.State.InitialPledge, nil +} + +func (s *state6) PreCommitDeposits() (abi.TokenAmount, error) { + return s.State.PreCommitDeposits, nil +} + +func (s *state6) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) { + info, ok, err := s.State.GetSector(s.store, num) + if !ok || err != nil { + return nil, err + } + + ret := fromV6SectorOnChainInfo(*info) + return &ret, nil +} + +func (s *state6) 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 *state6) 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 *miner6.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 *state6) 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 *miner6.Deadline) error { + partitions, err := dl.PartitionsArray(s.store) + if err != nil { + return err + } + quant := s.State.QuantSpecForDeadline(dlIdx) + var part miner6.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 := miner6.LoadExpirationQueue(s.store, part.ExpirationsEpochs, quant, miner6.PartitionExpirationAmtBitwidth) + if err != nil { + return err + } + var exp miner6.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 *state6) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) { + info, ok, err := s.State.GetPrecommittedSector(s.store, num) + if !ok || err != nil { + return nil, err + } + + ret := fromV6SectorPreCommitOnChainInfo(*info) + + return &ret, nil +} + +func (s *state6) ForEachPrecommittedSector(cb func(SectorPreCommitOnChainInfo) error) error { + precommitted, err := adt6.AsMap(s.store, s.State.PreCommittedSectors, builtin6.DefaultHamtBitwidth) + if err != nil { + return err + } + + var info miner6.SectorPreCommitOnChainInfo + if err := precommitted.ForEach(&info, func(_ string) error { + return cb(fromV6SectorPreCommitOnChainInfo(info)) + }); err != nil { + return err + } + + return nil +} + +func (s *state6) LoadSectors(snos *bitfield.BitField) ([]*SectorOnChainInfo, error) { + sectors, err := miner6.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 info6 miner6.SectorOnChainInfo + if err := sectors.ForEach(&info6, func(_ int64) error { + info := fromV6SectorOnChainInfo(info6) + infos = append(infos, &info) + return nil + }); err != nil { + return nil, err + } + return infos, nil + } + + // Otherwise, load selected. + infos6, err := sectors.Load(*snos) + if err != nil { + return nil, err + } + infos := make([]*SectorOnChainInfo, len(infos6)) + for i, info6 := range infos6 { + info := fromV6SectorOnChainInfo(*info6) + infos[i] = &info + } + return infos, nil +} + +func (s *state6) loadAllocatedSectorNumbers() (bitfield.BitField, error) { + var allocatedSectors bitfield.BitField + err := s.store.Get(s.store.Context(), s.State.AllocatedSectors, &allocatedSectors) + return allocatedSectors, err +} + +func (s *state6) IsAllocated(num abi.SectorNumber) (bool, error) { + allocatedSectors, err := s.loadAllocatedSectorNumbers() + if err != nil { + return false, err + } + + return allocatedSectors.IsSet(uint64(num)) +} + +func (s *state6) GetProvingPeriodStart() (abi.ChainEpoch, error) { + return s.State.ProvingPeriodStart, nil +} + +func (s *state6) 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 *state6) 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 *state6) 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 &deadline6{*dl, s.store}, nil +} + +func (s *state6) 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 *miner6.Deadline) error { + return cb(i, &deadline6{*dl, s.store}) + }) +} + +func (s *state6) NumDeadlines() (uint64, error) { + return miner6.WPoStPeriodDeadlines, nil +} + +func (s *state6) DeadlinesChanged(other State) (bool, error) { + other6, ok := other.(*state6) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + + return !s.State.Deadlines.Equals(other6.Deadlines), nil +} + +func (s *state6) MinerInfoChanged(other State) (bool, error) { + other0, ok := other.(*state6) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + return !s.State.Info.Equals(other0.State.Info), nil +} + +func (s *state6) 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 *state6) DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error) { + return s.State.RecordedDeadlineInfo(epoch), nil +} + +func (s *state6) DeadlineCronActive() (bool, error) { + return s.State.DeadlineCronActive, nil +} + +func (s *state6) sectors() (adt.Array, error) { + return adt6.AsArray(s.store, s.Sectors, miner6.SectorsAmtBitwidth) +} + +func (s *state6) decodeSectorOnChainInfo(val *cbg.Deferred) (SectorOnChainInfo, error) { + var si miner6.SectorOnChainInfo + err := si.UnmarshalCBOR(bytes.NewReader(val.Raw)) + if err != nil { + return SectorOnChainInfo{}, err + } + + return fromV6SectorOnChainInfo(si), nil +} + +func (s *state6) precommits() (adt.Map, error) { + return adt6.AsMap(s.store, s.PreCommittedSectors, builtin6.DefaultHamtBitwidth) +} + +func (s *state6) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) { + var sp miner6.SectorPreCommitOnChainInfo + err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) + if err != nil { + return SectorPreCommitOnChainInfo{}, err + } + + return fromV6SectorPreCommitOnChainInfo(sp), nil +} + +func (s *state6) EraseAllUnproven() error { + + dls, err := s.State.LoadDeadlines(s.store) + if err != nil { + return err + } + + err = dls.ForEach(s.store, func(dindx uint64, dl *miner6.Deadline) error { + ps, err := dl.PartitionsArray(s.store) + if err != nil { + return err + } + + var part miner6.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 *deadline6) LoadPartition(idx uint64) (Partition, error) { + p, err := d.Deadline.LoadPartition(d.store, idx) + if err != nil { + return nil, err + } + return &partition6{*p, d.store}, nil +} + +func (d *deadline6) ForEachPartition(cb func(uint64, Partition) error) error { + ps, err := d.Deadline.PartitionsArray(d.store) + if err != nil { + return err + } + var part miner6.Partition + return ps.ForEach(&part, func(i int64) error { + return cb(uint64(i), &partition6{part, d.store}) + }) +} + +func (d *deadline6) PartitionsChanged(other Deadline) (bool, error) { + other6, ok := other.(*deadline6) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + + return !d.Deadline.Partitions.Equals(other6.Deadline.Partitions), nil +} + +func (d *deadline6) PartitionsPoSted() (bitfield.BitField, error) { + return d.Deadline.PartitionsPoSted, nil +} + +func (d *deadline6) DisputableProofCount() (uint64, error) { + + ops, err := d.OptimisticProofsSnapshotArray(d.store) + if err != nil { + return 0, err + } + + return ops.Length(), nil + +} + +func (p *partition6) AllSectors() (bitfield.BitField, error) { + return p.Partition.Sectors, nil +} + +func (p *partition6) FaultySectors() (bitfield.BitField, error) { + return p.Partition.Faults, nil +} + +func (p *partition6) RecoveringSectors() (bitfield.BitField, error) { + return p.Partition.Recoveries, nil +} + +func (p *partition6) UnprovenSectors() (bitfield.BitField, error) { + return p.Partition.Unproven, nil +} + +func fromV6SectorOnChainInfo(v6 miner6.SectorOnChainInfo) SectorOnChainInfo { + + return SectorOnChainInfo{ + SectorNumber: v6.SectorNumber, + SealProof: v6.SealProof, + SealedCID: v6.SealedCID, + DealIDs: v6.DealIDs, + Activation: v6.Activation, + Expiration: v6.Expiration, + DealWeight: v6.DealWeight, + VerifiedDealWeight: v6.VerifiedDealWeight, + InitialPledge: v6.InitialPledge, + ExpectedDayReward: v6.ExpectedDayReward, + ExpectedStoragePledge: v6.ExpectedStoragePledge, + } + +} + +func fromV6SectorPreCommitOnChainInfo(v6 miner6.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { + + return SectorPreCommitOnChainInfo{ + Info: (SectorPreCommitInfo)(v6.Info), + PreCommitDeposit: v6.PreCommitDeposit, + PreCommitEpoch: v6.PreCommitEpoch, + DealWeight: v6.DealWeight, + VerifiedDealWeight: v6.VerifiedDealWeight, + } + +} + +func (s *state6) GetState() interface{} { + return &s.State +} diff --git a/chain/actors/builtin/multisig/message6.go b/chain/actors/builtin/multisig/message6.go new file mode 100644 index 000000000..b2b95245e --- /dev/null +++ b/chain/actors/builtin/multisig/message6.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" + + builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + init6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/init" + multisig6 "github.com/filecoin-project/specs-actors/v6/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 message6 struct{ message0 } + +func (m message6) 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 := &multisig6.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 := &init6.ExecParams{ + CodeCID: builtin6.MultisigActorCodeID, + ConstructorParams: enc, + } + + enc, actErr = actors.SerializeParams(execParams) + if actErr != nil { + return nil, actErr + } + + return &types.Message{ + To: init_.Address, + From: m.from, + Method: builtin6.MethodsInit.Exec, + Params: enc, + Value: initialAmount, + }, nil +} diff --git a/chain/actors/builtin/multisig/multisig.go b/chain/actors/builtin/multisig/multisig.go index c950ced90..ee725f7e5 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" - msig5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/multisig" + msig6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/multisig" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" @@ -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" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" @@ -52,6 +54,10 @@ func init() { builtin.RegisterActorState(builtin5.MultisigActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load5(store, root) }) + + builtin.RegisterActorState(builtin6.MultisigActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load6(store, root) + }) } func Load(store adt.Store, act *types.Actor) (State, error) { @@ -72,6 +78,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin5.MultisigActorCodeID: return load5(store, act.Head) + case builtin6.MultisigActorCodeID: + return load6(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -94,6 +103,9 @@ func MakeState(store adt.Store, av actors.Version, signers []address.Address, th case actors.Version5: return make5(store, signers, threshold, startEpoch, unlockDuration, initialBalance) + case actors.Version6: + return make6(store, signers, threshold, startEpoch, unlockDuration, initialBalance) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -116,6 +128,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version5: return builtin5.MultisigActorCodeID, nil + case actors.Version6: + return builtin6.MultisigActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) @@ -141,7 +156,7 @@ type State interface { type Transaction = msig0.Transaction -var Methods = builtin5.MethodsMultisig +var Methods = builtin6.MethodsMultisig func Message(version actors.Version, from address.Address) MessageBuilder { switch version { @@ -160,6 +175,9 @@ func Message(version actors.Version, from address.Address) MessageBuilder { case actors.Version5: return message5{message0{from}} + + case actors.Version6: + return message6{message0{from}} default: panic(fmt.Sprintf("unsupported actors version: %d", version)) } @@ -183,13 +201,13 @@ type MessageBuilder interface { } // this type is the same between v0 and v2 -type ProposalHashData = msig5.ProposalHashData -type ProposeReturn = msig5.ProposeReturn -type ProposeParams = msig5.ProposeParams -type ApproveReturn = msig5.ApproveReturn +type ProposalHashData = msig6.ProposalHashData +type ProposeReturn = msig6.ProposeReturn +type ProposeParams = msig6.ProposeParams +type ApproveReturn = msig6.ApproveReturn func txnParams(id uint64, data *ProposalHashData) ([]byte, error) { - params := msig5.TxnIDParams{ID: msig5.TxnID(id)} + params := msig6.TxnIDParams{ID: msig6.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/v6.go b/chain/actors/builtin/multisig/v6.go new file mode 100644 index 000000000..fa16494f8 --- /dev/null +++ b/chain/actors/builtin/multisig/v6.go @@ -0,0 +1,119 @@ +package multisig + +import ( + "bytes" + "encoding/binary" + + adt6 "github.com/filecoin-project/specs-actors/v6/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" + + builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + + msig6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/multisig" +) + +var _ State = (*state6)(nil) + +func load6(store adt.Store, root cid.Cid) (State, error) { + out := state6{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make6(store adt.Store, signers []address.Address, threshold uint64, startEpoch abi.ChainEpoch, unlockDuration abi.ChainEpoch, initialBalance abi.TokenAmount) (State, error) { + out := state6{store: store} + out.State = msig6.State{} + out.State.Signers = signers + out.State.NumApprovalsThreshold = threshold + out.State.StartEpoch = startEpoch + out.State.UnlockDuration = unlockDuration + out.State.InitialBalance = initialBalance + + em, err := adt6.StoreEmptyMap(store, builtin6.DefaultHamtBitwidth) + if err != nil { + return nil, err + } + + out.State.PendingTxns = em + + return &out, nil +} + +type state6 struct { + msig6.State + store adt.Store +} + +func (s *state6) LockedBalance(currEpoch abi.ChainEpoch) (abi.TokenAmount, error) { + return s.State.AmountLocked(currEpoch - s.State.StartEpoch), nil +} + +func (s *state6) StartEpoch() (abi.ChainEpoch, error) { + return s.State.StartEpoch, nil +} + +func (s *state6) UnlockDuration() (abi.ChainEpoch, error) { + return s.State.UnlockDuration, nil +} + +func (s *state6) InitialBalance() (abi.TokenAmount, error) { + return s.State.InitialBalance, nil +} + +func (s *state6) Threshold() (uint64, error) { + return s.State.NumApprovalsThreshold, nil +} + +func (s *state6) Signers() ([]address.Address, error) { + return s.State.Signers, nil +} + +func (s *state6) ForEachPendingTxn(cb func(id int64, txn Transaction) error) error { + arr, err := adt6.AsMap(s.store, s.State.PendingTxns, builtin6.DefaultHamtBitwidth) + if err != nil { + return err + } + var out msig6.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 *state6) PendingTxnChanged(other State) (bool, error) { + other6, ok := other.(*state6) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + return !s.State.PendingTxns.Equals(other6.PendingTxns), nil +} + +func (s *state6) transactions() (adt.Map, error) { + return adt6.AsMap(s.store, s.PendingTxns, builtin6.DefaultHamtBitwidth) +} + +func (s *state6) decodeTransaction(val *cbg.Deferred) (Transaction, error) { + var tx msig6.Transaction + if err := tx.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return Transaction{}, err + } + return tx, nil +} + +func (s *state6) GetState() interface{} { + return &s.State +} diff --git a/chain/actors/builtin/paych/message6.go b/chain/actors/builtin/paych/message6.go new file mode 100644 index 000000000..aecf26983 --- /dev/null +++ b/chain/actors/builtin/paych/message6.go @@ -0,0 +1,74 @@ +package paych + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + init6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/init" + paych6 "github.com/filecoin-project/specs-actors/v6/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 message6 struct{ from address.Address } + +func (m message6) Create(to address.Address, initialAmount abi.TokenAmount) (*types.Message, error) { + params, aerr := actors.SerializeParams(&paych6.ConstructorParams{From: m.from, To: to}) + if aerr != nil { + return nil, aerr + } + enc, aerr := actors.SerializeParams(&init6.ExecParams{ + CodeCID: builtin6.PaymentChannelActorCodeID, + ConstructorParams: params, + }) + if aerr != nil { + return nil, aerr + } + + return &types.Message{ + To: init_.Address, + From: m.from, + Value: initialAmount, + Method: builtin6.MethodsInit.Exec, + Params: enc, + }, nil +} + +func (m message6) Update(paych address.Address, sv *SignedVoucher, secret []byte) (*types.Message, error) { + params, aerr := actors.SerializeParams(&paych6.UpdateChannelStateParams{ + Sv: *sv, + Secret: secret, + }) + if aerr != nil { + return nil, aerr + } + + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin6.MethodsPaych.UpdateChannelState, + Params: params, + }, nil +} + +func (m message6) Settle(paych address.Address) (*types.Message, error) { + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin6.MethodsPaych.Settle, + }, nil +} + +func (m message6) Collect(paych address.Address) (*types.Message, error) { + return &types.Message{ + To: paych, + From: m.from, + Value: abi.NewTokenAmount(0), + Method: builtin6.MethodsPaych.Collect, + }, nil +} diff --git a/chain/actors/builtin/paych/paych.go b/chain/actors/builtin/paych/paych.go index d87f70f0c..eea3659f8 100644 --- a/chain/actors/builtin/paych/paych.go +++ b/chain/actors/builtin/paych/paych.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" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" @@ -52,6 +54,10 @@ func init() { builtin.RegisterActorState(builtin5.PaymentChannelActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load5(store, root) }) + + builtin.RegisterActorState(builtin6.PaymentChannelActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load6(store, root) + }) } // Load returns an abstract copy of payment channel state, irregardless of actor version @@ -73,6 +79,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin5.PaymentChannelActorCodeID: return load5(store, act.Head) + case builtin6.PaymentChannelActorCodeID: + return load6(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -95,6 +104,9 @@ func MakeState(store adt.Store, av actors.Version) (State, error) { case actors.Version5: return make5(store) + case actors.Version6: + return make6(store) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -117,6 +129,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version5: return builtin5.PaymentChannelActorCodeID, nil + case actors.Version6: + return builtin6.PaymentChannelActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) @@ -170,7 +185,7 @@ func DecodeSignedVoucher(s string) (*SignedVoucher, error) { return &sv, nil } -var Methods = builtin5.MethodsPaych +var Methods = builtin6.MethodsPaych func Message(version actors.Version, from address.Address) MessageBuilder { switch version { @@ -190,6 +205,9 @@ func Message(version actors.Version, from address.Address) MessageBuilder { case actors.Version5: return message5{from} + case actors.Version6: + return message6{from} + default: panic(fmt.Sprintf("unsupported actors version: %d", version)) } diff --git a/chain/actors/builtin/paych/v6.go b/chain/actors/builtin/paych/v6.go new file mode 100644 index 000000000..0d60b1f03 --- /dev/null +++ b/chain/actors/builtin/paych/v6.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" + + paych6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/paych" + adt6 "github.com/filecoin-project/specs-actors/v6/actors/util/adt" +) + +var _ State = (*state6)(nil) + +func load6(store adt.Store, root cid.Cid) (State, error) { + out := state6{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make6(store adt.Store) (State, error) { + out := state6{store: store} + out.State = paych6.State{} + return &out, nil +} + +type state6 struct { + paych6.State + store adt.Store + lsAmt *adt6.Array +} + +// Channel owner, who has funded the actor +func (s *state6) From() (address.Address, error) { + return s.State.From, nil +} + +// Recipient of payouts from channel +func (s *state6) To() (address.Address, error) { + return s.State.To, nil +} + +// Height at which the channel can be `Collected` +func (s *state6) SettlingAt() (abi.ChainEpoch, error) { + return s.State.SettlingAt, nil +} + +// Amount successfully redeemed through the payment channel, paid out on `Collect()` +func (s *state6) ToSend() (abi.TokenAmount, error) { + return s.State.ToSend, nil +} + +func (s *state6) getOrLoadLsAmt() (*adt6.Array, error) { + if s.lsAmt != nil { + return s.lsAmt, nil + } + + // Get the lane state from the chain + lsamt, err := adt6.AsArray(s.store, s.State.LaneStates, paych6.LaneStatesAmtBitwidth) + if err != nil { + return nil, err + } + + s.lsAmt = lsamt + return lsamt, nil +} + +// Get total number of lanes +func (s *state6) LaneCount() (uint64, error) { + lsamt, err := s.getOrLoadLsAmt() + if err != nil { + return 0, err + } + return lsamt.Length(), nil +} + +func (s *state6) GetState() interface{} { + return &s.State +} + +// Iterate lane states +func (s *state6) 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 paych6.LaneState + return lsamt.ForEach(&ls, func(i int64) error { + return cb(uint64(i), &laneState6{ls}) + }) +} + +type laneState6 struct { + paych6.LaneState +} + +func (ls *laneState6) Redeemed() (big.Int, error) { + return ls.LaneState.Redeemed, nil +} + +func (ls *laneState6) 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 5b4aa1b04..84bd6948a 100644 --- a/chain/actors/builtin/power/power.go +++ b/chain/actors/builtin/power/power.go @@ -24,6 +24,8 @@ 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" ) func init() { @@ -47,11 +49,15 @@ func init() { builtin.RegisterActorState(builtin5.StoragePowerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load5(store, root) }) + + builtin.RegisterActorState(builtin6.StoragePowerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load6(store, root) + }) } var ( - Address = builtin5.StoragePowerActorAddr - Methods = builtin5.MethodsPower + Address = builtin6.StoragePowerActorAddr + Methods = builtin6.MethodsPower ) func Load(store adt.Store, act *types.Actor) (State, error) { @@ -72,6 +78,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin5.StoragePowerActorCodeID: return load5(store, act.Head) + case builtin6.StoragePowerActorCodeID: + return load6(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -94,6 +103,9 @@ func MakeState(store adt.Store, av actors.Version) (State, error) { case actors.Version5: return make5(store) + case actors.Version6: + return make6(store) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -116,6 +128,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version5: return builtin5.StoragePowerActorCodeID, nil + case actors.Version6: + return builtin6.StoragePowerActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) diff --git a/chain/actors/builtin/power/v6.go b/chain/actors/builtin/power/v6.go new file mode 100644 index 000000000..4273c2c73 --- /dev/null +++ b/chain/actors/builtin/power/v6.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" + + builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + + power6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/power" + adt6 "github.com/filecoin-project/specs-actors/v6/actors/util/adt" +) + +var _ State = (*state6)(nil) + +func load6(store adt.Store, root cid.Cid) (State, error) { + out := state6{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make6(store adt.Store) (State, error) { + out := state6{store: store} + + s, err := power6.ConstructState(store) + if err != nil { + return nil, err + } + + out.State = *s + + return &out, nil +} + +type state6 struct { + power6.State + store adt.Store +} + +func (s *state6) TotalLocked() (abi.TokenAmount, error) { + return s.TotalPledgeCollateral, nil +} + +func (s *state6) 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 *state6) TotalCommitted() (Claim, error) { + return Claim{ + RawBytePower: s.TotalBytesCommitted, + QualityAdjPower: s.TotalQABytesCommitted, + }, nil +} + +func (s *state6) MinerPower(addr address.Address) (Claim, bool, error) { + claims, err := s.claims() + if err != nil { + return Claim{}, false, err + } + var claim power6.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 *state6) MinerNominalPowerMeetsConsensusMinimum(a address.Address) (bool, error) { + return s.State.MinerNominalPowerMeetsConsensusMinimum(s.store, a) +} + +func (s *state6) TotalPowerSmoothed() (builtin.FilterEstimate, error) { + return builtin.FromV6FilterEstimate(s.State.ThisEpochQAPowerSmoothed), nil +} + +func (s *state6) MinerCounts() (uint64, uint64, error) { + return uint64(s.State.MinerAboveMinPowerCount), uint64(s.State.MinerCount), nil +} + +func (s *state6) 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 *state6) ForEachClaim(cb func(miner address.Address, claim Claim) error) error { + claims, err := s.claims() + if err != nil { + return err + } + + var claim power6.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 *state6) ClaimsChanged(other State) (bool, error) { + other6, ok := other.(*state6) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + return !s.State.Claims.Equals(other6.State.Claims), nil +} + +func (s *state6) SetTotalQualityAdjPower(p abi.StoragePower) error { + s.State.TotalQualityAdjPower = p + return nil +} + +func (s *state6) SetTotalRawBytePower(p abi.StoragePower) error { + s.State.TotalRawBytePower = p + return nil +} + +func (s *state6) SetThisEpochQualityAdjPower(p abi.StoragePower) error { + s.State.ThisEpochQualityAdjPower = p + return nil +} + +func (s *state6) SetThisEpochRawBytePower(p abi.StoragePower) error { + s.State.ThisEpochRawBytePower = p + return nil +} + +func (s *state6) GetState() interface{} { + return &s.State +} + +func (s *state6) claims() (adt.Map, error) { + return adt6.AsMap(s.store, s.Claims, builtin6.DefaultHamtBitwidth) +} + +func (s *state6) decodeClaim(val *cbg.Deferred) (Claim, error) { + var ci power6.Claim + if err := ci.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return Claim{}, err + } + return fromV6Claim(ci), nil +} + +func fromV6Claim(v6 power6.Claim) Claim { + return Claim{ + RawBytePower: v6.RawBytePower, + QualityAdjPower: v6.QualityAdjPower, + } +} diff --git a/chain/actors/builtin/reward/reward.go b/chain/actors/builtin/reward/reward.go index ebec85517..38d5b5b87 100644 --- a/chain/actors/builtin/reward/reward.go +++ b/chain/actors/builtin/reward/reward.go @@ -19,6 +19,8 @@ import ( builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" + builtin6 "github.com/filecoin-project/specs-actors/v6/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" @@ -45,11 +47,15 @@ func init() { builtin.RegisterActorState(builtin5.RewardActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { return load5(store, root) }) + + builtin.RegisterActorState(builtin6.RewardActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load6(store, root) + }) } var ( - Address = builtin5.RewardActorAddr - Methods = builtin5.MethodsReward + Address = builtin6.RewardActorAddr + Methods = builtin6.MethodsReward ) func Load(store adt.Store, act *types.Actor) (State, error) { @@ -70,6 +76,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin5.RewardActorCodeID: return load5(store, act.Head) + case builtin6.RewardActorCodeID: + return load6(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -92,6 +101,9 @@ func MakeState(store adt.Store, av actors.Version, currRealizedPower abi.Storage case actors.Version5: return make5(store, currRealizedPower) + case actors.Version6: + return make6(store, currRealizedPower) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -114,6 +126,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version5: return builtin5.RewardActorCodeID, nil + case actors.Version6: + return builtin6.RewardActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) diff --git a/chain/actors/builtin/reward/v6.go b/chain/actors/builtin/reward/v6.go new file mode 100644 index 000000000..010a3a870 --- /dev/null +++ b/chain/actors/builtin/reward/v6.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" + + miner6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/miner" + reward6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/reward" + smoothing6 "github.com/filecoin-project/specs-actors/v6/actors/util/smoothing" +) + +var _ State = (*state6)(nil) + +func load6(store adt.Store, root cid.Cid) (State, error) { + out := state6{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make6(store adt.Store, currRealizedPower abi.StoragePower) (State, error) { + out := state6{store: store} + out.State = *reward6.ConstructState(currRealizedPower) + return &out, nil +} + +type state6 struct { + reward6.State + store adt.Store +} + +func (s *state6) ThisEpochReward() (abi.TokenAmount, error) { + return s.State.ThisEpochReward, nil +} + +func (s *state6) ThisEpochRewardSmoothed() (builtin.FilterEstimate, error) { + + return builtin.FilterEstimate{ + PositionEstimate: s.State.ThisEpochRewardSmoothed.PositionEstimate, + VelocityEstimate: s.State.ThisEpochRewardSmoothed.VelocityEstimate, + }, nil + +} + +func (s *state6) ThisEpochBaselinePower() (abi.StoragePower, error) { + return s.State.ThisEpochBaselinePower, nil +} + +func (s *state6) TotalStoragePowerReward() (abi.TokenAmount, error) { + return s.State.TotalStoragePowerReward, nil +} + +func (s *state6) EffectiveBaselinePower() (abi.StoragePower, error) { + return s.State.EffectiveBaselinePower, nil +} + +func (s *state6) EffectiveNetworkTime() (abi.ChainEpoch, error) { + return s.State.EffectiveNetworkTime, nil +} + +func (s *state6) CumsumBaseline() (reward6.Spacetime, error) { + return s.State.CumsumBaseline, nil +} + +func (s *state6) CumsumRealized() (reward6.Spacetime, error) { + return s.State.CumsumRealized, nil +} + +func (s *state6) InitialPledgeForPower(qaPower abi.StoragePower, networkTotalPledge abi.TokenAmount, networkQAPower *builtin.FilterEstimate, circSupply abi.TokenAmount) (abi.TokenAmount, error) { + return miner6.InitialPledgeForPower( + qaPower, + s.State.ThisEpochBaselinePower, + s.State.ThisEpochRewardSmoothed, + smoothing6.FilterEstimate{ + PositionEstimate: networkQAPower.PositionEstimate, + VelocityEstimate: networkQAPower.VelocityEstimate, + }, + circSupply, + ), nil +} + +func (s *state6) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, sectorWeight abi.StoragePower) (abi.TokenAmount, error) { + return miner6.PreCommitDepositForPower(s.State.ThisEpochRewardSmoothed, + smoothing6.FilterEstimate{ + PositionEstimate: networkQAPower.PositionEstimate, + VelocityEstimate: networkQAPower.VelocityEstimate, + }, + sectorWeight), nil +} + +func (s *state6) GetState() interface{} { + return &s.State +} diff --git a/chain/actors/builtin/system/system.go b/chain/actors/builtin/system/system.go index 289fb4d5d..3d6105c38 100644 --- a/chain/actors/builtin/system/system.go +++ b/chain/actors/builtin/system/system.go @@ -15,10 +15,12 @@ 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" ) var ( - Address = builtin5.SystemActorAddr + Address = builtin6.SystemActorAddr ) func MakeState(store adt.Store, av actors.Version) (State, error) { @@ -39,6 +41,9 @@ func MakeState(store adt.Store, av actors.Version) (State, error) { case actors.Version5: return make5(store) + case actors.Version6: + return make6(store) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -61,6 +66,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version5: return builtin5.SystemActorCodeID, nil + case actors.Version6: + return builtin6.SystemActorCodeID, nil + } return cid.Undef, xerrors.Errorf("unknown actor version %d", av) diff --git a/chain/actors/builtin/system/v6.go b/chain/actors/builtin/system/v6.go new file mode 100644 index 000000000..689620afb --- /dev/null +++ b/chain/actors/builtin/system/v6.go @@ -0,0 +1,35 @@ +package system + +import ( + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/actors/adt" + + system6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/system" +) + +var _ State = (*state6)(nil) + +func load6(store adt.Store, root cid.Cid) (State, error) { + out := state6{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make6(store adt.Store) (State, error) { + out := state6{store: store} + out.State = system6.State{} + return &out, nil +} + +type state6 struct { + system6.State + store adt.Store +} + +func (s *state6) GetState() interface{} { + return &s.State +} diff --git a/chain/actors/builtin/verifreg/v6.go b/chain/actors/builtin/verifreg/v6.go new file mode 100644 index 000000000..b2c5078e7 --- /dev/null +++ b/chain/actors/builtin/verifreg/v6.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" + + builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + verifreg6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/verifreg" + adt6 "github.com/filecoin-project/specs-actors/v6/actors/util/adt" +) + +var _ State = (*state6)(nil) + +func load6(store adt.Store, root cid.Cid) (State, error) { + out := state6{store: store} + err := store.Get(store.Context(), root, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func make6(store adt.Store, rootKeyAddress address.Address) (State, error) { + out := state6{store: store} + + s, err := verifreg6.ConstructState(store, rootKeyAddress) + if err != nil { + return nil, err + } + + out.State = *s + + return &out, nil +} + +type state6 struct { + verifreg6.State + store adt.Store +} + +func (s *state6) RootKey() (address.Address, error) { + return s.State.RootKey, nil +} + +func (s *state6) VerifiedClientDataCap(addr address.Address) (bool, abi.StoragePower, error) { + return getDataCap(s.store, actors.Version6, s.verifiedClients, addr) +} + +func (s *state6) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, error) { + return getDataCap(s.store, actors.Version6, s.verifiers, addr) +} + +func (s *state6) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { + return forEachCap(s.store, actors.Version6, s.verifiers, cb) +} + +func (s *state6) ForEachClient(cb func(addr address.Address, dcap abi.StoragePower) error) error { + return forEachCap(s.store, actors.Version6, s.verifiedClients, cb) +} + +func (s *state6) verifiedClients() (adt.Map, error) { + return adt6.AsMap(s.store, s.VerifiedClients, builtin6.DefaultHamtBitwidth) +} + +func (s *state6) verifiers() (adt.Map, error) { + return adt6.AsMap(s.store, s.Verifiers, builtin6.DefaultHamtBitwidth) +} + +func (s *state6) GetState() interface{} { + return &s.State +} diff --git a/chain/actors/builtin/verifreg/verifreg.go b/chain/actors/builtin/verifreg/verifreg.go index 88104ad69..31e8e5a08 100644 --- a/chain/actors/builtin/verifreg/verifreg.go +++ b/chain/actors/builtin/verifreg/verifreg.go @@ -19,6 +19,8 @@ import ( builtin5 "github.com/filecoin-project/specs-actors/v5/actors/builtin" + builtin6 "github.com/filecoin-project/specs-actors/v6/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" @@ -47,11 +49,15 @@ func init() { return load5(store, root) }) + builtin.RegisterActorState(builtin6.VerifiedRegistryActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) { + return load6(store, root) + }) + } var ( - Address = builtin5.VerifiedRegistryActorAddr - Methods = builtin5.MethodsVerifiedRegistry + Address = builtin6.VerifiedRegistryActorAddr + Methods = builtin6.MethodsVerifiedRegistry ) func Load(store adt.Store, act *types.Actor) (State, error) { @@ -72,6 +78,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) { case builtin5.VerifiedRegistryActorCodeID: return load5(store, act.Head) + case builtin6.VerifiedRegistryActorCodeID: + return load6(store, act.Head) + } return nil, xerrors.Errorf("unknown actor code %s", act.Code) } @@ -94,6 +103,9 @@ func MakeState(store adt.Store, av actors.Version, rootKeyAddress address.Addres case actors.Version5: return make5(store, rootKeyAddress) + case actors.Version6: + return make6(store, rootKeyAddress) + } return nil, xerrors.Errorf("unknown actor version %d", av) } @@ -116,6 +128,9 @@ func GetActorCodeID(av actors.Version) (cid.Cid, error) { case actors.Version5: return builtin5.VerifiedRegistryActorCodeID, nil + case actors.Version6: + return builtin6.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 a67415726..e00a6ae10 100644 --- a/chain/actors/policy/policy.go +++ b/chain/actors/policy/policy.go @@ -35,14 +35,19 @@ import ( miner5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/miner" verifreg5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/verifreg" - paych5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/paych" + builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + market6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/market" + 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" ) const ( - ChainFinality = miner5.ChainFinality + ChainFinality = miner6.ChainFinality SealRandomnessLookback = ChainFinality - PaychSettleDelay = paych5.SettleDelay - MaxPreCommitRandomnessLookback = builtin5.EpochsInDay + SealRandomnessLookback + PaychSettleDelay = paych6.SettleDelay + MaxPreCommitRandomnessLookback = builtin6.EpochsInDay + SealRandomnessLookback ) // SetSupportedProofTypes sets supported proof types, across all actor versions. @@ -65,6 +70,8 @@ func SetSupportedProofTypes(types ...abi.RegisteredSealProof) { miner5.PreCommitSealProofTypesV8 = make(map[abi.RegisteredSealProof]struct{}, len(types)) + miner6.PreCommitSealProofTypesV8 = make(map[abi.RegisteredSealProof]struct{}, len(types)) + AddSupportedProofTypes(types...) } @@ -103,6 +110,15 @@ func AddSupportedProofTypes(types ...abi.RegisteredSealProof) { miner5.WindowPoStProofTypes[wpp] = struct{}{} + miner6.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) + } + + miner6.WindowPoStProofTypes[wpp] = struct{}{} + } } @@ -121,11 +137,13 @@ func SetPreCommitChallengeDelay(delay abi.ChainEpoch) { miner5.PreCommitChallengeDelay = delay + miner6.PreCommitChallengeDelay = delay + } // TODO: this function shouldn't really exist. Instead, the API should expose the precommit delay. func GetPreCommitChallengeDelay() abi.ChainEpoch { - return miner5.PreCommitChallengeDelay + return miner6.PreCommitChallengeDelay } // SetConsensusMinerMinPower sets the minimum power of an individual miner must @@ -151,6 +169,10 @@ func SetConsensusMinerMinPower(p abi.StoragePower) { policy.ConsensusMinerMinPower = p } + for _, policy := range builtin6.PoStProofPolicies { + policy.ConsensusMinerMinPower = p + } + } // SetMinVerifiedDealSize sets the minimum size of a verified deal. This should @@ -167,6 +189,8 @@ func SetMinVerifiedDealSize(size abi.StoragePower) { verifreg5.MinVerifiedDealSize = size + verifreg6.MinVerifiedDealSize = size + } func GetMaxProveCommitDuration(ver actors.Version, t abi.RegisteredSealProof) (abi.ChainEpoch, error) { @@ -192,6 +216,10 @@ func GetMaxProveCommitDuration(ver actors.Version, t abi.RegisteredSealProof) (a return miner5.MaxProveCommitDuration[t], nil + case actors.Version6: + + return miner6.MaxProveCommitDuration[t], nil + default: return 0, xerrors.Errorf("unsupported actors version") } @@ -222,6 +250,11 @@ func SetProviderCollateralSupplyTarget(num, denom big.Int) { Denominator: denom, } + market6.ProviderCollateralSupplyTarget = builtin6.BigFrac{ + Numerator: num, + Denominator: denom, + } + } func DealProviderCollateralBounds( @@ -260,13 +293,18 @@ func DealProviderCollateralBounds( min, max := market5.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil) return min, max, nil + case actors.Version6: + + min, max := market6.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 market5.DealDurationBounds(pieceSize) + return market6.DealDurationBounds(pieceSize) } // Sets the challenge window and scales the proving period to match (such that @@ -300,6 +338,13 @@ func SetWPoStChallengeWindow(period abi.ChainEpoch) { // scale it if we're scaling the challenge period. miner5.WPoStDisputeWindow = period * 30 + miner6.WPoStChallengeWindow = period + miner6.WPoStProvingPeriod = period * abi.ChainEpoch(miner6.WPoStPeriodDeadlines) + + // by default, this is 2x finality which is 30 periods. + // scale it if we're scaling the challenge period. + miner6.WPoStDisputeWindow = period * 30 + } func GetWinningPoStSectorSetLookback(nwVer network.Version) abi.ChainEpoch { @@ -312,15 +357,15 @@ func GetWinningPoStSectorSetLookback(nwVer network.Version) abi.ChainEpoch { } func GetMaxSectorExpirationExtension() abi.ChainEpoch { - return miner5.MaxSectorExpirationExtension + return miner6.MaxSectorExpirationExtension } func GetMinSectorExpiration() abi.ChainEpoch { - return miner5.MinSectorExpiration + return miner6.MinSectorExpiration } func GetMaxPoStPartitions(nv network.Version, p abi.RegisteredPoStProof) (int, error) { - sectorsPerPart, err := builtin5.PoStProofWindowPoStPartitionSectors(p) + sectorsPerPart, err := builtin6.PoStProofWindowPoStPartitionSectors(p) if err != nil { return 0, err } @@ -333,8 +378,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(miner5.PreCommitSealProofTypesV8)) - for spt := range miner5.PreCommitSealProofTypesV8 { + szs := make([]abi.SectorSize, 0, len(miner6.PreCommitSealProofTypesV8)) + for spt := range miner6.PreCommitSealProofTypesV8 { ss, err := spt.SectorSize() if err != nil { panic(err) @@ -359,7 +404,7 @@ func GetSectorMaxLifetime(proof abi.RegisteredSealProof, nwVer network.Version) return builtin4.SealProofPoliciesV0[proof].SectorMaxLifetime } - return builtin5.SealProofPoliciesV11[proof].SectorMaxLifetime + return builtin6.SealProofPoliciesV11[proof].SectorMaxLifetime } func GetAddressedSectorsMax(nwVer network.Version) (int, error) { @@ -384,6 +429,9 @@ func GetAddressedSectorsMax(nwVer network.Version) (int, error) { case actors.Version5: return miner5.AddressedSectorsMax, nil + case actors.Version6: + return miner6.AddressedSectorsMax, nil + default: return 0, xerrors.Errorf("unsupported network version") } @@ -417,12 +465,16 @@ func GetDeclarationsMax(nwVer network.Version) (int, error) { return miner5.DeclarationsMax, nil + case actors.Version6: + + return miner6.DeclarationsMax, nil + default: return 0, xerrors.Errorf("unsupported network version") } } -func AggregateNetworkFee(nwVer network.Version, aggregateSize int, baseFee abi.TokenAmount) (abi.TokenAmount, error) { +func AggregateProveCommitNetworkFee(nwVer network.Version, aggregateSize int, baseFee abi.TokenAmount) (abi.TokenAmount, error) { v, err := actors.VersionForNetwork(nwVer) if err != nil { return big.Zero(), err @@ -449,6 +501,46 @@ func AggregateNetworkFee(nwVer network.Version, aggregateSize int, baseFee abi.T return miner5.AggregateNetworkFee(aggregateSize, baseFee), nil + case actors.Version6: + + return miner6.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil + + default: + return big.Zero(), xerrors.Errorf("unsupported network version") + } +} + +func AggregatePreCommitNetworkFee(nwVer network.Version, aggregateSize int, baseFee abi.TokenAmount) (abi.TokenAmount, error) { + v, err := actors.VersionForNetwork(nwVer) + if err != nil { + return big.Zero(), err + } + switch v { + + case actors.Version0: + + return big.Zero(), nil + + case actors.Version2: + + return big.Zero(), nil + + case actors.Version3: + + return big.Zero(), nil + + case actors.Version4: + + return big.Zero(), nil + + case actors.Version5: + + return big.Zero(), nil + + case actors.Version6: + + return miner6.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil + default: return big.Zero(), xerrors.Errorf("unsupported network version") } diff --git a/chain/actors/policy/policy.go.template b/chain/actors/policy/policy.go.template index 9da91f73f..64c1b7083 100644 --- a/chain/actors/policy/policy.go.template +++ b/chain/actors/policy/policy.go.template @@ -63,7 +63,7 @@ func AddSupportedProofTypes(types ...abi.RegisteredSealProof) { miner{{.}}.PreCommitSealProofTypesV7[t] = struct{}{} miner{{.}}.PreCommitSealProofTypesV7[t+abi.RegisteredSealProof_StackedDrg2KiBV1_1] = struct{}{} miner{{.}}.PreCommitSealProofTypesV8[t+abi.RegisteredSealProof_StackedDrg2KiBV1_1] = struct{}{} - {{else}} + {{else if (eq . 5)}} miner{{.}}.PreCommitSealProofTypesV8[t+abi.RegisteredSealProof_StackedDrg2KiBV1_1] = struct{}{} wpp, err := t.RegisteredWindowPoStProof() if err != nil { @@ -71,6 +71,15 @@ func AddSupportedProofTypes(types ...abi.RegisteredSealProof) { panic(err) } + miner{{.}}.WindowPoStProofTypes[wpp] = struct{}{} + {{else}} + miner{{.}}.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) + } + miner{{.}}.WindowPoStProofTypes[wpp] = struct{}{} {{end}} {{end}} @@ -285,7 +294,7 @@ func GetDeclarationsMax(nwVer network.Version) (int, error) { } } -func AggregateNetworkFee(nwVer network.Version, aggregateSize int, baseFee abi.TokenAmount) (abi.TokenAmount, error) { +func AggregateProveCommitNetworkFee(nwVer network.Version, aggregateSize int, baseFee abi.TokenAmount) (abi.TokenAmount, error) { v, err := actors.VersionForNetwork(nwVer) if err != nil { return big.Zero(), err @@ -293,10 +302,31 @@ func AggregateNetworkFee(nwVer network.Version, aggregateSize int, baseFee abi.T switch v { {{range .versions}} case actors.Version{{.}}: - {{if (le . 4)}} - return big.Zero(), nil - {{else}} + {{if (ge . 6)}} + return miner{{.}}.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil + {{else if (eq . 5)}} return miner{{.}}.AggregateNetworkFee(aggregateSize, baseFee), nil + {{else}} + return big.Zero(), nil + {{end}} + {{end}} + default: + return big.Zero(), xerrors.Errorf("unsupported network version") + } +} + +func AggregatePreCommitNetworkFee(nwVer network.Version, aggregateSize int, baseFee abi.TokenAmount) (abi.TokenAmount, error) { + v, err := actors.VersionForNetwork(nwVer) + if err != nil { + return big.Zero(), err + } + switch v { + {{range .versions}} + case actors.Version{{.}}: + {{if (ge . 6)}} + return miner{{.}}.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil + {{else}} + return big.Zero(), nil {{end}} {{end}} default: diff --git a/chain/actors/version.go b/chain/actors/version.go index 8787089af..95dd09126 100644 --- a/chain/actors/version.go +++ b/chain/actors/version.go @@ -8,9 +8,9 @@ import ( type Version int -var LatestVersion = 5 +var LatestVersion = 6 -var Versions = []int{0, 2, 3, 4, LatestVersion} +var Versions = []int{0, 2, 3, 4, 5, LatestVersion} const ( Version0 Version = 0 @@ -18,6 +18,7 @@ const ( Version3 Version = 3 Version4 Version = 4 Version5 Version = 5 + Version6 Version = 6 ) // Converts a network version into an actors adt version. @@ -33,6 +34,8 @@ func VersionForNetwork(version network.Version) (Version, error) { return Version4, nil case network.Version13: return Version5, nil + case network.Version14: + return Version6, nil default: return -1, fmt.Errorf("unsupported network version %d", version) } diff --git a/chain/beacon/mock.go b/chain/beacon/mock.go index 502ff2ba5..2fc64b956 100644 --- a/chain/beacon/mock.go +++ b/chain/beacon/mock.go @@ -54,7 +54,8 @@ func (mb *mockBeacon) VerifyEntry(from types.BeaconEntry, to types.BeaconEntry) } func (mb *mockBeacon) MaxBeaconRoundForEpoch(epoch abi.ChainEpoch) uint64 { - return uint64(epoch) + // offset for better testing + return uint64(epoch + 100) } var _ RandomBeacon = (*mockBeacon)(nil) diff --git a/chain/consensus/filcns/compute_state.go b/chain/consensus/filcns/compute_state.go index e0557b797..927562840 100644 --- a/chain/consensus/filcns/compute_state.go +++ b/chain/consensus/filcns/compute_state.go @@ -4,6 +4,8 @@ import ( "context" "sync/atomic" + "github.com/filecoin-project/lotus/chain/rand" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "go.opencensus.io/stats" @@ -19,6 +21,7 @@ import ( exported3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/exported" 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" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors" @@ -42,6 +45,7 @@ func NewActorRegistry() *vm.ActorRegistry { inv.Register(vm.ActorsVersionPredicate(actors.Version3), exported3.BuiltinActors()...) inv.Register(vm.ActorsVersionPredicate(actors.Version4), exported4.BuiltinActors()...) inv.Register(vm.ActorsVersionPredicate(actors.Version5), exported5.BuiltinActors()...) + inv.Register(vm.ActorsVersionPredicate(actors.Version6), exported6.BuiltinActors()...) return inv } @@ -278,7 +282,7 @@ func (t *TipSetExecutor) ExecuteTipSet(ctx context.Context, sm *stmgr.StateManag parentEpoch = parent.Height } - r := store.NewChainRand(sm.ChainStore(), ts.Cids()) + r := rand.NewStateRand(sm.ChainStore(), ts.Cids(), sm.Beacon()) blkmsgs, err := sm.ChainStore().BlockMsgsForTipset(ts) if err != nil { diff --git a/chain/consensus/filcns/filecoin.go b/chain/consensus/filcns/filecoin.go index 4b10673fb..7abd2cb77 100644 --- a/chain/consensus/filcns/filecoin.go +++ b/chain/consensus/filcns/filecoin.go @@ -9,6 +9,8 @@ import ( "strings" "time" + "github.com/filecoin-project/lotus/chain/rand" + "github.com/hashicorp/go-multierror" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" @@ -219,7 +221,7 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock) return xerrors.Errorf("failed to marshal miner address to cbor: %w", err) } - vrfBase, err := store.DrawRandomness(rBeacon.Data, crypto.DomainSeparationTag_ElectionProofProduction, h.Height, buf.Bytes()) + vrfBase, err := rand.DrawRandomness(rBeacon.Data, crypto.DomainSeparationTag_ElectionProofProduction, h.Height, buf.Bytes()) if err != nil { return xerrors.Errorf("could not draw randomness: %w", err) } @@ -283,7 +285,7 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock) beaconBase = h.BeaconEntries[len(h.BeaconEntries)-1] } - vrfBase, err := store.DrawRandomness(beaconBase.Data, crypto.DomainSeparationTag_TicketProduction, h.Height-build.TicketRandomnessLookback, buf.Bytes()) + vrfBase, err := rand.DrawRandomness(beaconBase.Data, crypto.DomainSeparationTag_TicketProduction, h.Height-build.TicketRandomnessLookback, buf.Bytes()) if err != nil { return xerrors.Errorf("failed to compute vrf base for ticket: %w", err) } @@ -388,7 +390,7 @@ func (filec *FilecoinEC) VerifyWinningPoStProof(ctx context.Context, nv network. rbase = h.BeaconEntries[len(h.BeaconEntries)-1] } - rand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, h.Height, buf.Bytes()) + rand, err := rand.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, h.Height, buf.Bytes()) if err != nil { return xerrors.Errorf("failed to get randomness for verifying winning post proof: %w", err) } @@ -530,6 +532,12 @@ func (filec *FilecoinEC) checkBlockMessages(ctx context.Context, b *types.FullBl smArr := blockadt.MakeEmptyArray(tmpstore) for i, m := range b.SecpkMessages { + if filec.sm.GetNtwkVersion(ctx, b.Header.Height) >= network.Version14 { + if m.Signature.Type != crypto.SigTypeSecp256k1 { + return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err) + } + } + if err := checkMsg(m); err != nil { return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err) } diff --git a/chain/consensus/filcns/upgrades.go b/chain/consensus/filcns/upgrades.go index c12bb2090..cf4c62bf3 100644 --- a/chain/consensus/filcns/upgrades.go +++ b/chain/consensus/filcns/upgrades.go @@ -5,6 +5,8 @@ import ( "runtime" "time" + "github.com/filecoin-project/specs-actors/v6/actors/migration/nv14" + "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" "golang.org/x/xerrors" @@ -137,7 +139,25 @@ func DefaultUpgradeSchedule() stmgr.UpgradeSchedule { DontStartWithin: 15, StopWithin: 5, }}, - Expensive: true}} + Expensive: true, + }, { + Height: build.UpgradeChocolateHeight, + Network: network.Version14, + Migration: UpgradeActorsV6, + PreMigrations: []stmgr.PreMigration{{ + PreMigration: PreUpgradeActorsV6, + StartWithin: 120, + DontStartWithin: 60, + StopWithin: 35, + }, { + PreMigration: PreUpgradeActorsV6, + StartWithin: 30, + DontStartWithin: 15, + StopWithin: 5, + }}, + Expensive: true, + }, + } for _, u := range updates { if u.Height < 0 { @@ -1091,6 +1111,92 @@ func upgradeActorsV5Common( return newRoot, nil } +func UpgradeActorsV6(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 := upgradeActorsV6Common(ctx, sm, cache, root, epoch, ts, config) + if err != nil { + return cid.Undef, xerrors.Errorf("migrating actors v5 state: %w", err) + } + + return newRoot, nil +} + +func PreUpgradeActorsV6(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 + } + config := nv14.Config{MaxWorkers: uint(workerCount)} + _, err := upgradeActorsV6Common(ctx, sm, cache, root, epoch, ts, config) + return err +} + +func upgradeActorsV6Common( + ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, + root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet, + 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 v6 upgrade, got %d", + stateRoot.Version, + ) + } + + // 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) + } + + // 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 +} + type migrationLogger struct{} func (ml migrationLogger) Log(level rt.LogLevel, msg string, args ...interface{}) { diff --git a/chain/gen/gen.go b/chain/gen/gen.go index 6f111a69e..b7d49f278 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -9,6 +9,8 @@ import ( "sync/atomic" "time" + "github.com/filecoin-project/lotus/chain/rand" + "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/go-address" @@ -246,11 +248,6 @@ func NewGeneratorWithSectorsAndUpgradeSchedule(numSectors int, us stmgr.UpgradeS mgen[genesis2.MinerAddress(uint64(i))] = &wppProvider{} } - sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), sys, us) - if err != nil { - return nil, xerrors.Errorf("initing stmgr: %w", err) - } - miners := []address.Address{maddr1, maddr2} beac := beacon.Schedule{{Start: 0, Beacon: beacon.NewMockBeacon(time.Second)}} @@ -259,6 +256,11 @@ func NewGeneratorWithSectorsAndUpgradeSchedule(numSectors int, us stmgr.UpgradeS //return nil, xerrors.Errorf("creating drand beacon: %w", err) //} + sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), sys, us, beac) + if err != nil { + return nil, xerrors.Errorf("initing stmgr: %w", err) + } + gen := &ChainGen{ bs: bs, cs: cs, @@ -307,6 +309,10 @@ func (cg *ChainGen) ChainStore() *store.ChainStore { return cg.cs } +func (cg *ChainGen) BeaconSchedule() beacon.Schedule { + return cg.beacon +} + func (cg *ChainGen) Genesis() *types.BlockHeader { return cg.genesis } @@ -365,7 +371,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add buf.Write(pts.MinTicket().VRFProof) } - ticketRand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_TicketProduction, round-build.TicketRandomnessLookback, buf.Bytes()) + ticketRand, err := rand.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_TicketProduction, round-build.TicketRandomnessLookback, buf.Bytes()) if err != nil { return nil, nil, nil, err } @@ -397,12 +403,15 @@ type MinedTipSet struct { } func (cg *ChainGen) NextTipSet() (*MinedTipSet, error) { - mts, err := cg.NextTipSetFromMiners(cg.CurTipset.TipSet(), cg.Miners, 0) + return cg.NextTipSetWithNulls(0) +} + +func (cg *ChainGen) NextTipSetWithNulls(nulls abi.ChainEpoch) (*MinedTipSet, error) { + mts, err := cg.NextTipSetFromMiners(cg.CurTipset.TipSet(), cg.Miners, nulls) if err != nil { return nil, err } - cg.CurTipset = mts.TipSet return mts, nil } @@ -586,29 +595,11 @@ type mca struct { } func (mca mca) StateGetRandomnessFromTickets(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte, tsk types.TipSetKey) (abi.Randomness, error) { - pts, err := mca.sm.ChainStore().LoadTipSet(tsk) - if err != nil { - return nil, xerrors.Errorf("loading tipset key: %w", err) - } - - if mca.sm.GetNtwkVersion(ctx, randEpoch) >= network.Version13 { - return mca.sm.ChainStore().GetChainRandomnessLookingForward(ctx, pts.Cids(), personalization, randEpoch, entropy) - } - - return mca.sm.ChainStore().GetChainRandomnessLookingBack(ctx, pts.Cids(), personalization, randEpoch, entropy) + return mca.sm.GetRandomnessFromTickets(ctx, personalization, randEpoch, entropy, tsk) } func (mca mca) StateGetRandomnessFromBeacon(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte, tsk types.TipSetKey) (abi.Randomness, error) { - pts, err := mca.sm.ChainStore().LoadTipSet(tsk) - if err != nil { - return nil, xerrors.Errorf("loading tipset key: %w", err) - } - - if mca.sm.GetNtwkVersion(ctx, randEpoch) >= network.Version13 { - return mca.sm.ChainStore().GetBeaconRandomnessLookingForward(ctx, pts.Cids(), personalization, randEpoch, entropy) - } - - return mca.sm.ChainStore().GetBeaconRandomnessLookingBack(ctx, pts.Cids(), personalization, randEpoch, entropy) + return mca.sm.GetRandomnessFromBeacon(ctx, personalization, randEpoch, entropy, tsk) } func (mca mca) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoch abi.ChainEpoch, tsk types.TipSetKey) (*api.MiningBaseInfo, error) { @@ -644,7 +635,7 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch, return nil, xerrors.Errorf("failed to cbor marshal address: %w", err) } - electionRand, err := store.DrawRandomness(brand.Data, crypto.DomainSeparationTag_ElectionProofProduction, round, buf.Bytes()) + electionRand, err := rand.DrawRandomness(brand.Data, crypto.DomainSeparationTag_ElectionProofProduction, round, buf.Bytes()) if err != nil { return nil, xerrors.Errorf("failed to draw randomness: %w", err) } diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index f79d41824..edacfe304 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -6,6 +6,8 @@ import ( "fmt" "math/rand" + builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" cbg "github.com/whyrusleeping/cbor-gen" @@ -193,12 +195,21 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sys vm.Syscal if err != nil { return xerrors.Errorf("failed to create genesis miner (publish deals): %w", err) } - var ids market.PublishStorageDealsReturn - if err := ids.UnmarshalCBOR(bytes.NewReader(ret)); err != nil { - return xerrors.Errorf("unmarsahling publishStorageDeals result: %w", err) + retval, err := market.DecodePublishStorageDealsReturn(ret, nv) + if err != nil { + return xerrors.Errorf("failed to create genesis miner (decoding published deals): %w", err) } - minerInfos[i].dealIDs = append(minerInfos[i].dealIDs, ids.IDs...) + ids, err := retval.DealIDs() + if err != nil { + return xerrors.Errorf("failed to create genesis miner (getting published dealIDs): %w", err) + } + + if len(ids) != len(params.Deals) { + return xerrors.Errorf("failed to create genesis miner (at least one deal was invalid on publication") + } + + minerInfos[i].dealIDs = append(minerInfos[i].dealIDs, ids...) return nil } @@ -389,11 +400,24 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sys vm.Syscal } // Commit one-by-one, otherwise pledge math tends to explode - confirmParams := &builtin0.ConfirmSectorProofsParams{ - Sectors: []abi.SectorNumber{preseal.SectorID}, + var paramBytes []byte + + if av >= actors.Version6 { + // TODO: fixup + confirmParams := &builtin6.ConfirmSectorProofsParams{ + Sectors: []abi.SectorNumber{preseal.SectorID}, + } + + paramBytes = mustEnc(confirmParams) + } else { + confirmParams := &builtin0.ConfirmSectorProofsParams{ + Sectors: []abi.SectorNumber{preseal.SectorID}, + } + + paramBytes = mustEnc(confirmParams) } - _, err = doExecValue(ctx, vm, minerInfos[i].maddr, power.Address, big.Zero(), miner.Methods.ConfirmSectorProofsValid, mustEnc(confirmParams)) + _, err = doExecValue(ctx, vm, minerInfos[i].maddr, power.Address, big.Zero(), miner.Methods.ConfirmSectorProofsValid, paramBytes) if err != nil { return cid.Undef, xerrors.Errorf("failed to confirm presealed sectors: %w", err) } @@ -485,25 +509,31 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sys vm.Syscal // TODO: copied from actors test harness, deduplicate or remove from here type fakeRand struct{} -func (fr *fakeRand) GetChainRandomnessLookingForward(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) { +func (fr *fakeRand) GetChainRandomnessV2(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) { out := make([]byte, 32) _, _ = rand.New(rand.NewSource(int64(randEpoch * 1000))).Read(out) //nolint return out, nil } -func (fr *fakeRand) GetChainRandomnessLookingBack(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) { +func (fr *fakeRand) GetChainRandomnessV1(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) { out := make([]byte, 32) _, _ = rand.New(rand.NewSource(int64(randEpoch * 1000))).Read(out) //nolint return out, nil } -func (fr *fakeRand) GetBeaconRandomnessLookingForward(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) { +func (fr *fakeRand) GetBeaconRandomnessV3(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) { out := make([]byte, 32) _, _ = rand.New(rand.NewSource(int64(randEpoch))).Read(out) //nolint return out, nil } -func (fr *fakeRand) GetBeaconRandomnessLookingBack(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) { +func (fr *fakeRand) GetBeaconRandomnessV2(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) { + out := make([]byte, 32) + _, _ = rand.New(rand.NewSource(int64(randEpoch))).Read(out) //nolint + return out, nil +} + +func (fr *fakeRand) GetBeaconRandomnessV1(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) { out := make([]byte, 32) _, _ = rand.New(rand.NewSource(int64(randEpoch))).Read(out) //nolint return out, nil diff --git a/chain/rand/rand.go b/chain/rand/rand.go new file mode 100644 index 000000000..90e9a514b --- /dev/null +++ b/chain/rand/rand.go @@ -0,0 +1,202 @@ +package rand + +import ( + "context" + "encoding/binary" + + logging "github.com/ipfs/go-log/v2" + + "github.com/filecoin-project/lotus/chain/beacon" + + "github.com/ipfs/go-cid" + "github.com/minio/blake2b-simd" + "go.opencensus.io/trace" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" +) + +var log = logging.Logger("rand") + +func DrawRandomness(rbase []byte, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { + h := blake2b.New256() + if err := binary.Write(h, binary.BigEndian, int64(pers)); err != nil { + return nil, xerrors.Errorf("deriving randomness: %w", err) + } + VRFDigest := blake2b.Sum256(rbase) + _, err := h.Write(VRFDigest[:]) + if err != nil { + return nil, xerrors.Errorf("hashing VRFDigest: %w", err) + } + if err := binary.Write(h, binary.BigEndian, round); err != nil { + return nil, xerrors.Errorf("deriving randomness: %w", err) + } + _, err = h.Write(entropy) + if err != nil { + return nil, xerrors.Errorf("hashing entropy: %w", err) + } + + return h.Sum(nil), nil +} + +func (sr *stateRand) GetBeaconRandomnessTipset(ctx context.Context, round abi.ChainEpoch, lookback bool) (*types.TipSet, error) { + _, span := trace.StartSpan(ctx, "store.GetBeaconRandomness") + defer span.End() + span.AddAttributes(trace.Int64Attribute("round", int64(round))) + + ts, err := sr.cs.LoadTipSet(types.NewTipSetKey(sr.blks...)) + if err != nil { + return nil, err + } + + if round > ts.Height() { + return nil, xerrors.Errorf("cannot draw randomness from the future") + } + + searchHeight := round + if searchHeight < 0 { + searchHeight = 0 + } + + randTs, err := sr.cs.GetTipsetByHeight(ctx, searchHeight, ts, lookback) + if err != nil { + return nil, err + } + + return randTs, nil +} + +func (sr *stateRand) GetChainRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte, lookback bool) ([]byte, error) { + _, span := trace.StartSpan(ctx, "store.GetChainRandomness") + defer span.End() + span.AddAttributes(trace.Int64Attribute("round", int64(round))) + + ts, err := sr.cs.LoadTipSet(types.NewTipSetKey(sr.blks...)) + if err != nil { + return nil, err + } + + if round > ts.Height() { + return nil, xerrors.Errorf("cannot draw randomness from the future") + } + + searchHeight := round + if searchHeight < 0 { + searchHeight = 0 + } + + randTs, err := sr.cs.GetTipsetByHeight(ctx, searchHeight, ts, lookback) + if err != nil { + return nil, err + } + + mtb := randTs.MinTicketBlock() + + // if at (or just past -- for null epochs) appropriate epoch + // or at genesis (works for negative epochs) + return DrawRandomness(mtb.Ticket.VRFProof, pers, round, entropy) +} + +type stateRand struct { + cs *store.ChainStore + blks []cid.Cid + beacon beacon.Schedule +} + +func NewStateRand(cs *store.ChainStore, blks []cid.Cid, b beacon.Schedule) vm.Rand { + return &stateRand{ + cs: cs, + blks: blks, + beacon: b, + } +} + +// network v0-12 +func (sr *stateRand) GetChainRandomnessV1(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { + return sr.GetChainRandomness(ctx, pers, round, entropy, true) +} + +// network v13 and on +func (sr *stateRand) GetChainRandomnessV2(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { + return sr.GetChainRandomness(ctx, pers, round, entropy, false) +} + +// network v0-12 +func (sr *stateRand) GetBeaconRandomnessV1(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { + randTs, err := sr.GetBeaconRandomnessTipset(ctx, round, true) + if err != nil { + return nil, err + } + + be, err := sr.cs.GetLatestBeaconEntry(randTs) + if err != nil { + return nil, err + } + + // if at (or just past -- for null epochs) appropriate epoch + // or at genesis (works for negative epochs) + return DrawRandomness(be.Data, pers, round, entropy) +} + +// network v13 +func (sr *stateRand) GetBeaconRandomnessV2(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { + randTs, err := sr.GetBeaconRandomnessTipset(ctx, round, false) + if err != nil { + return nil, err + } + + be, err := sr.cs.GetLatestBeaconEntry(randTs) + if err != nil { + return nil, err + } + + // if at (or just past -- for null epochs) appropriate epoch + // or at genesis (works for negative epochs) + return DrawRandomness(be.Data, pers, round, entropy) +} + +// network v14 and on +func (sr *stateRand) GetBeaconRandomnessV3(ctx context.Context, pers crypto.DomainSeparationTag, filecoinEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) { + if filecoinEpoch < 0 { + return sr.GetBeaconRandomnessV2(ctx, pers, filecoinEpoch, entropy) + } + + be, err := sr.extractBeaconEntryForEpoch(ctx, filecoinEpoch) + if err != nil { + log.Errorf("failed to get beacon entry as expected: %w", err) + return nil, err + } + + return DrawRandomness(be.Data, pers, filecoinEpoch, entropy) +} + +func (sr *stateRand) extractBeaconEntryForEpoch(ctx context.Context, filecoinEpoch abi.ChainEpoch) (*types.BeaconEntry, error) { + randTs, err := sr.GetBeaconRandomnessTipset(ctx, filecoinEpoch, false) + if err != nil { + return nil, err + } + + round := sr.beacon.BeaconForEpoch(filecoinEpoch).MaxBeaconRoundForEpoch(filecoinEpoch) + + for i := 0; i < 20; i++ { + cbe := randTs.Blocks()[0].BeaconEntries + for _, v := range cbe { + if v.Round == round { + return &v, nil + } + } + + next, err := sr.cs.LoadTipSet(randTs.Parents()) + if err != nil { + return nil, xerrors.Errorf("failed to load parents when searching back for beacon entry: %w", err) + } + + randTs = next + } + + return nil, xerrors.Errorf("didn't find beacon for round %d (epoch %d)", round, filecoinEpoch) +} diff --git a/chain/rand/rand_test.go b/chain/rand/rand_test.go new file mode 100644 index 000000000..5e5dae3f1 --- /dev/null +++ b/chain/rand/rand_test.go @@ -0,0 +1,238 @@ +package rand_test + +import ( + "context" + "testing" + + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/lotus/chain/consensus/filcns" + "github.com/filecoin-project/lotus/chain/stmgr" + + "github.com/filecoin-project/lotus/chain/rand" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-state-types/crypto" + + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/chain/actors/policy" + "github.com/filecoin-project/lotus/chain/gen" +) + +func init() { + policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) + policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048)) + policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) +} + +// in v12 and before, if the tipset corresponding to round X is null, we fetch the latest beacon entry BEFORE X that's in a non-null ts +func TestNullRandomnessV1(t *testing.T) { + ctx := context.Background() + cg, err := gen.NewGenerator() + if err != nil { + t.Fatal(err) + } + + for i := 0; i < 10; i++ { + _, err := cg.NextTipSet() + if err != nil { + t.Fatal(err) + } + } + + offset := cg.CurTipset.Blocks[0].Header.BeaconEntries[len(cg.CurTipset.Blocks[0].Header.BeaconEntries)-1].Round - uint64(cg.CurTipset.TipSet().Height()) + beforeNullHeight := cg.CurTipset.TipSet().Height() + + ts, err := cg.NextTipSetWithNulls(5) + if err != nil { + t.Fatal(err) + } + + entropy := []byte{0, 2, 3, 4} + // arbitrarily chosen + pers := crypto.DomainSeparationTag_WinningPoStChallengeSeed + + randEpoch := ts.TipSet.TipSet().Height() - 2 + + rand1, err := cg.StateManager().GetRandomnessFromBeacon(ctx, pers, randEpoch, entropy, ts.TipSet.TipSet().Key()) + if err != nil { + t.Fatal(err) + } + + bch := cg.BeaconSchedule().BeaconForEpoch(randEpoch).Entry(ctx, uint64(beforeNullHeight)+offset) + + select { + case resp := <-bch: + if resp.Err != nil { + t.Fatal(resp.Err) + } + + rand2, err := rand.DrawRandomness(resp.Entry.Data, pers, randEpoch, entropy) + if err != nil { + t.Fatal(err) + } + + require.Equal(t, rand1, abi.Randomness(rand2)) + + case <-ctx.Done(): + t.Fatal("timed out") + } +} + +// at v13, if the tipset corresponding to round X is null, we fetch the latest beacon in the first non-null ts after X +func TestNullRandomnessV2(t *testing.T) { + ctx := context.Background() + + sched := stmgr.UpgradeSchedule{ + { + // prepare for upgrade. + Network: network.Version9, + Height: 1, + Migration: filcns.UpgradeActorsV2, + }, { + Network: network.Version10, + Height: 2, + Migration: filcns.UpgradeActorsV3, + }, { + Network: network.Version12, + Height: 3, + Migration: filcns.UpgradeActorsV4, + }, { + Network: network.Version13, + Height: 4, + Migration: filcns.UpgradeActorsV5, + }, + } + + cg, err := gen.NewGeneratorWithUpgradeSchedule(sched) + if err != nil { + t.Fatal(err) + } + + for i := 0; i < 10; i++ { + _, err := cg.NextTipSet() + if err != nil { + t.Fatal(err) + } + + } + + offset := cg.CurTipset.Blocks[0].Header.BeaconEntries[len(cg.CurTipset.Blocks[0].Header.BeaconEntries)-1].Round - uint64(cg.CurTipset.TipSet().Height()) + + ts, err := cg.NextTipSetWithNulls(5) + if err != nil { + t.Fatal(err) + } + + entropy := []byte{0, 2, 3, 4} + // arbitrarily chosen + pers := crypto.DomainSeparationTag_WinningPoStChallengeSeed + + randEpoch := ts.TipSet.TipSet().Height() - 2 + + rand1, err := cg.StateManager().GetRandomnessFromBeacon(ctx, pers, randEpoch, entropy, ts.TipSet.TipSet().Key()) + if err != nil { + t.Fatal(err) + } + + bch := cg.BeaconSchedule().BeaconForEpoch(randEpoch).Entry(ctx, uint64(ts.TipSet.TipSet().Height())+offset) + + select { + case resp := <-bch: + if resp.Err != nil { + t.Fatal(resp.Err) + } + + // note that the randEpoch passed to DrawRandomness is still randEpoch (not the latest ts height) + rand2, err := rand.DrawRandomness(resp.Entry.Data, pers, randEpoch, entropy) + if err != nil { + t.Fatal(err) + } + + require.Equal(t, rand1, abi.Randomness(rand2)) + + case <-ctx.Done(): + t.Fatal("timed out") + } +} + +// after v14, if the tipset corresponding to round X is null, we still fetch the randomness for X (from the next non-null tipset) +func TestNullRandomnessV3(t *testing.T) { + ctx := context.Background() + sched := stmgr.UpgradeSchedule{ + { + // prepare for upgrade. + Network: network.Version9, + Height: 1, + Migration: filcns.UpgradeActorsV2, + }, { + Network: network.Version10, + Height: 2, + Migration: filcns.UpgradeActorsV3, + }, { + Network: network.Version12, + Height: 3, + Migration: filcns.UpgradeActorsV4, + }, { + Network: network.Version13, + Height: 4, + Migration: filcns.UpgradeActorsV5, + }, { + Network: network.Version14, + Height: 5, + Migration: filcns.UpgradeActorsV6, + }, + } + + cg, err := gen.NewGeneratorWithUpgradeSchedule(sched) + + if err != nil { + t.Fatal(err) + } + + for i := 0; i < 10; i++ { + _, err := cg.NextTipSet() + if err != nil { + t.Fatal(err) + } + + } + + ts, err := cg.NextTipSetWithNulls(5) + if err != nil { + t.Fatal(err) + } + + offset := cg.CurTipset.Blocks[0].Header.BeaconEntries[len(cg.CurTipset.Blocks[0].Header.BeaconEntries)-1].Round - uint64(cg.CurTipset.TipSet().Height()) + + entropy := []byte{0, 2, 3, 4} + // arbitrarily chosen + pers := crypto.DomainSeparationTag_WinningPoStChallengeSeed + + randEpoch := ts.TipSet.TipSet().Height() - 2 + + rand1, err := cg.StateManager().GetRandomnessFromBeacon(ctx, pers, randEpoch, entropy, ts.TipSet.TipSet().Key()) + if err != nil { + t.Fatal(err) + } + + bch := cg.BeaconSchedule().BeaconForEpoch(randEpoch).Entry(ctx, uint64(randEpoch)+offset) + + select { + case resp := <-bch: + if resp.Err != nil { + t.Fatal(resp.Err) + } + + rand2, err := rand.DrawRandomness(resp.Entry.Data, pers, randEpoch, entropy) + if err != nil { + t.Fatal(err) + } + + require.Equal(t, rand1, abi.Randomness(rand2)) + + case <-ctx.Done(): + t.Fatal("timed out") + } +} diff --git a/chain/state/statetree.go b/chain/state/statetree.go index 8140cd4db..b4323c04b 100644 --- a/chain/state/statetree.go +++ b/chain/state/statetree.go @@ -152,7 +152,7 @@ func VersionForNetwork(ver network.Version) (types.StateTreeVersion, error) { return types.StateTreeVersion2, nil case network.Version12: return types.StateTreeVersion3, nil - case network.Version13: + case network.Version13, network.Version14: return types.StateTreeVersion4, nil default: panic(fmt.Sprintf("unsupported network version %d", ver)) diff --git a/chain/stmgr/actors.go b/chain/stmgr/actors.go index 0c1e219c8..4d016b7ab 100644 --- a/chain/stmgr/actors.go +++ b/chain/stmgr/actors.go @@ -5,6 +5,8 @@ import ( "context" "os" + "github.com/filecoin-project/lotus/chain/rand" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-state-types/abi" @@ -21,7 +23,6 @@ import ( "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/actors/builtin/power" "github.com/filecoin-project/lotus/chain/beacon" - "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" @@ -351,7 +352,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule return nil, xerrors.Errorf("failed to marshal miner address: %w", err) } - prand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, round, buf.Bytes()) + prand, err := rand.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, round, buf.Bytes()) if err != nil { return nil, xerrors.Errorf("failed to get randomness for winning post: %w", err) } diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index 6a0186715..7cc50e710 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -5,6 +5,8 @@ import ( "errors" "fmt" + "github.com/filecoin-project/lotus/chain/rand" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/crypto" @@ -14,7 +16,6 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" ) @@ -74,7 +75,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types. vmopt := &vm.VMOpts{ StateBase: bstate, Epoch: pheight + 1, - Rand: store.NewChainRand(sm.cs, ts.Cids()), + Rand: rand.NewStateRand(sm.cs, ts.Cids(), sm.beacon), Bstore: sm.cs.StateBlockstore(), Actors: sm.tsExec.NewActorRegistry(), Syscalls: sm.Syscalls, @@ -185,7 +186,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri return nil, fmt.Errorf("failed to handle fork: %w", err) } - r := store.NewChainRand(sm.cs, ts.Cids()) + r := rand.NewStateRand(sm.cs, ts.Cids(), sm.beacon) if span.IsRecordingEvents() { span.AddAttributes( diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index a3e35da4b..4fad1e4fc 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -158,7 +158,7 @@ func TestForkHeightTriggers(t *testing.T) { } return st.Flush(ctx) - }}}) + }}}, cg.BeaconSchedule()) if err != nil { t.Fatal(err) } @@ -273,7 +273,7 @@ func testForkRefuseCall(t *testing.T, nullsBefore, nullsAfter int) { root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) { migrationCount++ return root, nil - }}}) + }}}, cg.BeaconSchedule()) if err != nil { t.Fatal(err) } @@ -488,7 +488,7 @@ func TestForkPreMigration(t *testing.T) { return nil }, }}}, - }) + }, cg.BeaconSchedule()) if err != nil { t.Fatal(err) } diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 4a0f89141..a3f17cd41 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -4,6 +4,10 @@ import ( "context" "sync" + "github.com/filecoin-project/lotus/chain/rand" + + "github.com/filecoin-project/lotus/chain/beacon" + "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" logging "github.com/ipfs/go-log/v2" @@ -11,6 +15,7 @@ import ( "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/go-state-types/network" // Used for genesis. @@ -89,6 +94,7 @@ type StateManager struct { tsExec Executor tsExecMonitor ExecMonitor + beacon beacon.Schedule } // Caches a single state tree @@ -97,7 +103,7 @@ type treeCache struct { tree *state.StateTree } -func NewStateManager(cs *store.ChainStore, exec Executor, sys vm.SyscallBuilder, us UpgradeSchedule) (*StateManager, error) { +func NewStateManager(cs *store.ChainStore, exec Executor, sys vm.SyscallBuilder, us UpgradeSchedule, beacon beacon.Schedule) (*StateManager, error) { // If we have upgrades, make sure they're in-order and make sense. if err := us.Validate(); err != nil { return nil, err @@ -106,7 +112,7 @@ func NewStateManager(cs *store.ChainStore, exec Executor, sys vm.SyscallBuilder, stateMigrations := make(map[abi.ChainEpoch]*migration, len(us)) expensiveUpgrades := make(map[abi.ChainEpoch]struct{}, len(us)) var networkVersions []versionSpec - lastVersion := network.Version0 + lastVersion := build.GenesisNetworkVersion if len(us) > 0 { // If we have any upgrades, process them and create a version // schedule. @@ -143,6 +149,7 @@ func NewStateManager(cs *store.ChainStore, exec Executor, sys vm.SyscallBuilder, cs: cs, tsExec: exec, stCache: make(map[string][]cid.Cid), + beacon: beacon, tCache: treeCache{ root: cid.Undef, tree: nil, @@ -151,8 +158,8 @@ func NewStateManager(cs *store.ChainStore, exec Executor, sys vm.SyscallBuilder, }, nil } -func NewStateManagerWithUpgradeScheduleAndMonitor(cs *store.ChainStore, exec Executor, sys vm.SyscallBuilder, us UpgradeSchedule, em ExecMonitor) (*StateManager, error) { - sm, err := NewStateManager(cs, exec, sys, us) +func NewStateManagerWithUpgradeScheduleAndMonitor(cs *store.ChainStore, exec Executor, sys vm.SyscallBuilder, us UpgradeSchedule, b beacon.Schedule, em ExecMonitor) (*StateManager, error) { + sm, err := NewStateManager(cs, exec, sys, us, b) if err != nil { return nil, err } @@ -199,6 +206,10 @@ func (sm *StateManager) ChainStore() *store.ChainStore { return sm.cs } +func (sm *StateManager) Beacon() beacon.Schedule { + return sm.beacon +} + // ResolveToKeyAddress is similar to `vm.ResolveToKeyAddr` but does not allow `Actor` type of addresses. // Uses the `TipSet` `ts` to generate the VM state. func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { @@ -362,3 +373,38 @@ func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoc func (sm *StateManager) VMSys() vm.SyscallBuilder { return sm.Syscalls } + +func (sm *StateManager) GetRandomnessFromBeacon(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte, tsk types.TipSetKey) (abi.Randomness, error) { + pts, err := sm.ChainStore().GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + + r := rand.NewStateRand(sm.ChainStore(), pts.Cids(), sm.beacon) + rnv := sm.GetNtwkVersion(ctx, randEpoch) + + if rnv >= network.Version14 { + return r.GetBeaconRandomnessV3(ctx, personalization, randEpoch, entropy) + } else if rnv == network.Version13 { + return r.GetBeaconRandomnessV2(ctx, personalization, randEpoch, entropy) + } + + return r.GetBeaconRandomnessV1(ctx, personalization, randEpoch, entropy) + +} + +func (sm *StateManager) GetRandomnessFromTickets(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte, tsk types.TipSetKey) (abi.Randomness, error) { + pts, err := sm.ChainStore().LoadTipSet(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset key: %w", err) + } + + r := rand.NewStateRand(sm.ChainStore(), pts.Cids(), sm.beacon) + rnv := sm.GetNtwkVersion(ctx, randEpoch) + + if rnv >= network.Version13 { + return r.GetChainRandomnessV2(ctx, personalization, randEpoch, entropy) + } + + return r.GetChainRandomnessV1(ctx, personalization, randEpoch, entropy) +} diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index 42ef56e04..ce4f60105 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -5,6 +5,8 @@ import ( "fmt" "reflect" + "github.com/filecoin-project/lotus/chain/rand" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" @@ -77,7 +79,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, // future. It's not guaranteed to be accurate... but that's fine. } - r := store.NewChainRand(sm.cs, ts.Cids()) + r := rand.NewStateRand(sm.cs, ts.Cids(), sm.beacon) vmopt := &vm.VMOpts{ StateBase: base, Epoch: height, diff --git a/chain/store/rand.go b/chain/store/rand.go deleted file mode 100644 index 1fa9e678f..000000000 --- a/chain/store/rand.go +++ /dev/null @@ -1,182 +0,0 @@ -package store - -import ( - "context" - "encoding/binary" - "os" - - "github.com/ipfs/go-cid" - "github.com/minio/blake2b-simd" - "go.opencensus.io/trace" - "golang.org/x/xerrors" - - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/crypto" - "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/chain/vm" -) - -func DrawRandomness(rbase []byte, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { - h := blake2b.New256() - if err := binary.Write(h, binary.BigEndian, int64(pers)); err != nil { - return nil, xerrors.Errorf("deriving randomness: %w", err) - } - VRFDigest := blake2b.Sum256(rbase) - _, err := h.Write(VRFDigest[:]) - if err != nil { - return nil, xerrors.Errorf("hashing VRFDigest: %w", err) - } - if err := binary.Write(h, binary.BigEndian, round); err != nil { - return nil, xerrors.Errorf("deriving randomness: %w", err) - } - _, err = h.Write(entropy) - if err != nil { - return nil, xerrors.Errorf("hashing entropy: %w", err) - } - - return h.Sum(nil), nil -} - -func (cs *ChainStore) GetBeaconRandomnessLookingBack(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { - return cs.GetBeaconRandomness(ctx, blks, pers, round, entropy, true) -} - -func (cs *ChainStore) GetBeaconRandomnessLookingForward(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { - return cs.GetBeaconRandomness(ctx, blks, pers, round, entropy, false) -} - -func (cs *ChainStore) GetBeaconRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte, lookback bool) ([]byte, error) { - _, span := trace.StartSpan(ctx, "store.GetBeaconRandomness") - defer span.End() - span.AddAttributes(trace.Int64Attribute("round", int64(round))) - - ts, err := cs.LoadTipSet(types.NewTipSetKey(blks...)) - if err != nil { - return nil, err - } - - if round > ts.Height() { - return nil, xerrors.Errorf("cannot draw randomness from the future") - } - - searchHeight := round - if searchHeight < 0 { - searchHeight = 0 - } - - randTs, err := cs.GetTipsetByHeight(ctx, searchHeight, ts, lookback) - if err != nil { - return nil, err - } - - be, err := cs.GetLatestBeaconEntry(randTs) - if err != nil { - return nil, err - } - - // if at (or just past -- for null epochs) appropriate epoch - // or at genesis (works for negative epochs) - return DrawRandomness(be.Data, pers, round, entropy) -} - -func (cs *ChainStore) GetChainRandomnessLookingBack(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { - return cs.GetChainRandomness(ctx, blks, pers, round, entropy, true) -} - -func (cs *ChainStore) GetChainRandomnessLookingForward(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { - return cs.GetChainRandomness(ctx, blks, pers, round, entropy, false) -} - -func (cs *ChainStore) GetChainRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte, lookback bool) ([]byte, error) { - _, span := trace.StartSpan(ctx, "store.GetChainRandomness") - defer span.End() - span.AddAttributes(trace.Int64Attribute("round", int64(round))) - - ts, err := cs.LoadTipSet(types.NewTipSetKey(blks...)) - if err != nil { - return nil, err - } - - if round > ts.Height() { - return nil, xerrors.Errorf("cannot draw randomness from the future") - } - - searchHeight := round - if searchHeight < 0 { - searchHeight = 0 - } - - randTs, err := cs.GetTipsetByHeight(ctx, searchHeight, ts, lookback) - if err != nil { - return nil, err - } - - mtb := randTs.MinTicketBlock() - - // if at (or just past -- for null epochs) appropriate epoch - // or at genesis (works for negative epochs) - return DrawRandomness(mtb.Ticket.VRFProof, pers, round, entropy) -} - -func (cs *ChainStore) GetLatestBeaconEntry(ts *types.TipSet) (*types.BeaconEntry, error) { - cur := ts - for i := 0; i < 20; i++ { - cbe := cur.Blocks()[0].BeaconEntries - if len(cbe) > 0 { - return &cbe[len(cbe)-1], nil - } - - if cur.Height() == 0 { - return nil, xerrors.Errorf("made it back to genesis block without finding beacon entry") - } - - next, err := cs.LoadTipSet(cur.Parents()) - if err != nil { - return nil, xerrors.Errorf("failed to load parents when searching back for latest beacon entry: %w", err) - } - cur = next - } - - if os.Getenv("LOTUS_IGNORE_DRAND") == "_yes_" { - return &types.BeaconEntry{ - Data: []byte{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}, - }, nil - } - - return nil, xerrors.Errorf("found NO beacon entries in the 20 latest tipsets") -} - -type chainRand struct { - cs *ChainStore - blks []cid.Cid -} - -func NewChainRand(cs *ChainStore, blks []cid.Cid) vm.Rand { - return &chainRand{ - cs: cs, - blks: blks, - } -} - -func (cr *chainRand) GetChainRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { - return cr.cs.GetChainRandomnessLookingBack(ctx, cr.blks, pers, round, entropy) -} - -func (cr *chainRand) GetChainRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { - return cr.cs.GetChainRandomnessLookingForward(ctx, cr.blks, pers, round, entropy) -} - -func (cr *chainRand) GetBeaconRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { - return cr.cs.GetBeaconRandomnessLookingBack(ctx, cr.blks, pers, round, entropy) -} - -func (cr *chainRand) GetBeaconRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { - return cr.cs.GetBeaconRandomnessLookingForward(ctx, cr.blks, pers, round, entropy) -} - -func (cs *ChainStore) GetTipSetFromKey(tsk types.TipSetKey) (*types.TipSet, error) { - if tsk.IsEmpty() { - return cs.GetHeaviestTipSet(), nil - } - return cs.LoadTipSet(tsk) -} diff --git a/chain/store/store.go b/chain/store/store.go index 4436c1217..f99c7f649 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -424,7 +424,13 @@ func (cs *ChainStore) MaybeTakeHeavierTipSet(ctx context.Context, ts *types.TipS return err } - if w.GreaterThan(heaviestW) { + heavier := w.GreaterThan(heaviestW) + if w.Equals(heaviestW) && !ts.Equals(cs.heaviest) { + log.Errorw("weight draw", "currTs", cs.heaviest, "ts", ts) + heavier = breakWeightTie(ts, cs.heaviest) + } + + if heavier { // TODO: don't do this for initial sync. Now that we don't have a // difference between 'bootstrap sync' and 'caught up' sync, we need // some other heuristic. @@ -438,9 +444,8 @@ func (cs *ChainStore) MaybeTakeHeavierTipSet(ctx context.Context, ts *types.TipS } return cs.takeHeaviestTipSet(ctx, ts) - } else if w.Equals(heaviestW) && !ts.Equals(cs.heaviest) { - log.Errorw("weight draw", "currTs", cs.heaviest, "ts", ts) } + return nil } @@ -1165,3 +1170,57 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h abi.ChainEpoch, t func (cs *ChainStore) Weight(ctx context.Context, hts *types.TipSet) (types.BigInt, error) { // todo remove return cs.weight(ctx, cs.StateBlockstore(), hts) } + +// true if ts1 wins according to the filecoin tie-break rule +func breakWeightTie(ts1, ts2 *types.TipSet) bool { + s := len(ts1.Blocks()) + if s > len(ts2.Blocks()) { + s = len(ts2.Blocks()) + } + + // blocks are already sorted by ticket + for i := 0; i < s; i++ { + if ts1.Blocks()[i].Ticket.Less(ts2.Blocks()[i].Ticket) { + log.Infof("weight tie broken in favour of %s", ts1.Key()) + return true + } + } + + log.Infof("weight tie left unbroken, default to %s", ts2.Key()) + return false +} + +func (cs *ChainStore) GetTipSetFromKey(tsk types.TipSetKey) (*types.TipSet, error) { + if tsk.IsEmpty() { + return cs.GetHeaviestTipSet(), nil + } + return cs.LoadTipSet(tsk) +} + +func (cs *ChainStore) GetLatestBeaconEntry(ts *types.TipSet) (*types.BeaconEntry, error) { + cur := ts + for i := 0; i < 20; i++ { + cbe := cur.Blocks()[0].BeaconEntries + if len(cbe) > 0 { + return &cbe[len(cbe)-1], nil + } + + if cur.Height() == 0 { + return nil, xerrors.Errorf("made it back to genesis block without finding beacon entry") + } + + next, err := cs.LoadTipSet(cur.Parents()) + if err != nil { + return nil, xerrors.Errorf("failed to load parents when searching back for latest beacon entry: %w", err) + } + cur = next + } + + if os.Getenv("LOTUS_IGNORE_DRAND") == "_yes_" { + return &types.BeaconEntry{ + Data: []byte{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}, + }, nil + } + + return nil, xerrors.Errorf("found NO beacon entries in the 20 latest tipsets") +} diff --git a/chain/store/store_test.go b/chain/store/store_test.go index b393e8eb2..2004b266c 100644 --- a/chain/store/store_test.go +++ b/chain/store/store_test.go @@ -77,7 +77,7 @@ func BenchmarkGetRandomness(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - _, err := cs.GetChainRandomnessLookingBack(context.TODO(), last.Cids(), crypto.DomainSeparationTag_SealRandomness, 500, nil) + _, err := cg.StateManager().GetRandomnessFromTickets(context.TODO(), crypto.DomainSeparationTag_SealRandomness, 500, nil, last.Key()) if err != nil { b.Fatal(err) } @@ -158,7 +158,7 @@ func TestChainExportImportFull(t *testing.T) { t.Fatal("imported chain differed from exported chain") } - sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), nil, filcns.DefaultUpgradeSchedule()) + sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), nil, filcns.DefaultUpgradeSchedule(), cg.BeaconSchedule()) if err != nil { t.Fatal(err) } diff --git a/chain/sync_test.go b/chain/sync_test.go index bf84512cf..4175ff5fa 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -7,8 +7,6 @@ import ( "testing" "time" - "github.com/filecoin-project/go-state-types/crypto" - "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/chain/stmgr" @@ -139,6 +137,10 @@ func prepSyncTestWithV5Height(t testing.TB, h int, v5height abi.ChainEpoch) *syn Network: network.Version13, Height: v5height, Migration: filcns.UpgradeActorsV5, + }, { + Network: network.Version14, + Height: v5height + 10, + Migration: filcns.UpgradeActorsV6, }} g, err := gen.NewGeneratorWithUpgradeSchedule(sched) @@ -1033,81 +1035,6 @@ func TestSyncCheckpointEarlierThanHead(t *testing.T) { require.True(tu.t, p1Head.Equals(b.TipSet())) } -func TestDrandNull(t *testing.T) { - H := 10 - v5h := abi.ChainEpoch(50) - ov5h := build.UpgradeHyperdriveHeight - build.UpgradeHyperdriveHeight = v5h - tu := prepSyncTestWithV5Height(t, H, v5h) - - p0 := tu.addClientNode() - p1 := tu.addClientNode() - - tu.loadChainToNode(p0) - tu.loadChainToNode(p1) - - entropy := []byte{0, 2, 3, 4} - // arbitrarily chosen - pers := crypto.DomainSeparationTag_WinningPoStChallengeSeed - - beforeNull := tu.g.CurTipset - afterNull := tu.mineOnBlock(beforeNull, p0, nil, false, false, nil, 2, true) - nullHeight := beforeNull.TipSet().Height() + 1 - if afterNull.TipSet().Height() == nullHeight { - t.Fatal("didn't inject nulls as expected") - } - - rand, err := tu.nds[p0].StateGetRandomnessFromBeacon(tu.ctx, pers, nullHeight, entropy, afterNull.TipSet().Key()) - require.NoError(t, err) - - // calculate the expected randomness based on the beacon BEFORE the null - expectedBE := beforeNull.Blocks[0].Header.BeaconEntries - expectedRand, err := store.DrawRandomness(expectedBE[len(expectedBE)-1].Data, pers, nullHeight, entropy) - require.NoError(t, err) - - require.Equal(t, []byte(rand), expectedRand) - - // zoom zoom to past the v5 upgrade by injecting many many nulls - postUpgrade := tu.mineOnBlock(afterNull, p0, nil, false, false, nil, v5h, true) - nv, err := tu.nds[p0].StateNetworkVersion(tu.ctx, postUpgrade.TipSet().Key()) - require.NoError(t, err) - if nv != network.Version13 { - t.Fatal("expect to be v13 by now") - } - - afterNull = tu.mineOnBlock(postUpgrade, p0, nil, false, false, nil, 2, true) - nullHeight = postUpgrade.TipSet().Height() + 1 - if afterNull.TipSet().Height() == nullHeight { - t.Fatal("didn't inject nulls as expected") - } - - rand0, err := tu.nds[p0].StateGetRandomnessFromBeacon(tu.ctx, pers, nullHeight, entropy, afterNull.TipSet().Key()) - require.NoError(t, err) - - // calculate the expected randomness based on the beacon AFTER the null - expectedBE = afterNull.Blocks[0].Header.BeaconEntries - expectedRand, err = store.DrawRandomness(expectedBE[len(expectedBE)-1].Data, pers, nullHeight, entropy) - require.NoError(t, err) - - require.Equal(t, []byte(rand0), expectedRand) - - // Introduce p1 to friendly p0 who has all the blocks - require.NoError(t, tu.mn.LinkAll()) - tu.connect(p0, p1) - tu.waitUntilNodeHasTs(p1, afterNull.TipSet().Key()) - p1Head := tu.getHead(p1) - - // Yes, p1 syncs well to p0's chain - require.Equal(tu.t, p1Head.Key(), afterNull.TipSet().Key()) - - // Yes, p1 sources the same randomness as p0 - rand1, err := tu.nds[p1].StateGetRandomnessFromBeacon(tu.ctx, pers, nullHeight, entropy, afterNull.TipSet().Key()) - require.NoError(t, err) - require.Equal(t, rand0, rand1) - - build.UpgradeHyperdriveHeight = ov5h -} - func TestInvalidHeight(t *testing.T) { H := 50 tu := prepSyncTest(t, H) diff --git a/chain/types/state.go b/chain/types/state.go index c8f8f1cd9..9381fa6f3 100644 --- a/chain/types/state.go +++ b/chain/types/state.go @@ -15,7 +15,7 @@ const ( StateTreeVersion2 // StateTreeVersion3 corresponds to actors v4. StateTreeVersion3 - // StateTreeVersion4 corresponds to actors v5. + // StateTreeVersion4 corresponds to actors v5, v6. StateTreeVersion4 ) diff --git a/chain/vm/mkactor.go b/chain/vm/mkactor.go index e461a2b4c..b75f290dc 100644 --- a/chain/vm/mkactor.go +++ b/chain/vm/mkactor.go @@ -19,6 +19,7 @@ import ( builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin" 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" "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/chain/actors/aerrors" @@ -113,6 +114,8 @@ func newAccountActor(ver actors.Version) *types.Actor { code = builtin4.AccountActorCodeID case actors.Version5: code = builtin5.AccountActorCodeID + case actors.Version6: + code = builtin6.AccountActorCodeID default: panic("unsupported actors version") } diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index c0ace4907..6e94030bd 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -17,6 +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" "github.com/ipfs/go-cid" ipldcbor "github.com/ipfs/go-ipld-cbor" "go.opencensus.io/trace" @@ -141,6 +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) func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.ActorError) { defer func() { @@ -216,10 +218,11 @@ func (rt *Runtime) GetRandomnessFromTickets(personalization crypto.DomainSeparat var res []byte rnv := rt.vm.ntwkVersion(rt.ctx, randEpoch) + if rnv >= network.Version13 { - res, err = rt.vm.rand.GetChainRandomnessLookingForward(rt.ctx, personalization, randEpoch, entropy) + res, err = rt.vm.rand.GetChainRandomnessV2(rt.ctx, personalization, randEpoch, entropy) } else { - res, err = rt.vm.rand.GetChainRandomnessLookingBack(rt.ctx, personalization, randEpoch, entropy) + res, err = rt.vm.rand.GetChainRandomnessV1(rt.ctx, personalization, randEpoch, entropy) } if err != nil { @@ -233,10 +236,12 @@ func (rt *Runtime) GetRandomnessFromBeacon(personalization crypto.DomainSeparati var res []byte rnv := rt.vm.ntwkVersion(rt.ctx, randEpoch) - if rnv >= network.Version13 { - res, err = rt.vm.rand.GetBeaconRandomnessLookingForward(rt.ctx, personalization, randEpoch, entropy) + if rnv >= network.Version14 { + res, err = rt.vm.rand.GetBeaconRandomnessV3(rt.ctx, personalization, randEpoch, entropy) + } else if rnv == network.Version13 { + res, err = rt.vm.rand.GetBeaconRandomnessV2(rt.ctx, personalization, randEpoch, entropy) } else { - res, err = rt.vm.rand.GetBeaconRandomnessLookingBack(rt.ctx, personalization, randEpoch, entropy) + res, err = rt.vm.rand.GetBeaconRandomnessV1(rt.ctx, personalization, randEpoch, entropy) } if err != nil { diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 80bad39dc..36308fe03 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -256,10 +256,11 @@ func NewVM(ctx context.Context, opts *VMOpts) (*VM, error) { } type Rand interface { - GetChainRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) - GetChainRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) - GetBeaconRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) - GetBeaconRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) + GetChainRandomnessV1(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) + GetChainRandomnessV2(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) + GetBeaconRandomnessV1(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) + GetBeaconRandomnessV2(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) + GetBeaconRandomnessV3(ctx context.Context, pers crypto.DomainSeparationTag, filecoinEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) } type ApplyRet struct { diff --git a/cli/wallet.go b/cli/wallet.go index 802d85702..f0f4e11f9 100644 --- a/cli/wallet.go +++ b/cli/wallet.go @@ -2,6 +2,7 @@ package cli import ( "bufio" + "bytes" "encoding/hex" "encoding/json" "fmt" @@ -9,6 +10,8 @@ import ( "os" "strings" + "github.com/filecoin-project/lotus/build" + "github.com/urfave/cli/v2" "golang.org/x/xerrors" @@ -528,6 +531,11 @@ var walletMarketWithdraw = &cli.Command{ Usage: "Market address to withdraw from (account or miner actor address, defaults to --wallet address)", Aliases: []string{"a"}, }, + &cli.IntFlag{ + Name: "confidence", + Usage: "number of block confirmations to wait for", + Value: int(build.MessageConfidence), + }, }, Action: func(cctx *cli.Context) error { api, closer, err := GetFullNodeAPI(cctx) @@ -614,6 +622,28 @@ var walletMarketWithdraw = &cli.Command{ fmt.Printf("WithdrawBalance message cid: %s\n", smsg) + // wait for it to get mined into a block + wait, err := api.StateWaitMsg(ctx, smsg, uint64(cctx.Int("confidence"))) + if err != nil { + return err + } + + // check it executed successfully + if wait.Receipt.ExitCode != 0 { + fmt.Println(cctx.App.Writer, "withdrawal failed!") + return err + } + + var withdrawn abi.TokenAmount + if err := withdrawn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil { + return err + } + + fmt.Printf("Successfully withdrew %s FIL\n", withdrawn) + if withdrawn != amt { + fmt.Printf("Note that this is less than the requested amount of %s FIL\n", amt) + } + return nil }, } diff --git a/cmd/lotus-bench/import.go b/cmd/lotus-bench/import.go index 7047866cb..c66b90deb 100644 --- a/cmd/lotus-bench/import.go +++ b/cmd/lotus-bench/import.go @@ -257,7 +257,8 @@ var importBenchCmd = &cli.Command{ cs := store.NewChainStore(bs, bs, metadataDs, filcns.Weight, nil) defer cs.Close() //nolint:errcheck - stm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(verifier), filcns.DefaultUpgradeSchedule()) + // TODO: We need to supply the actual beacon after v14 + stm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(verifier), filcns.DefaultUpgradeSchedule(), nil) if err != nil { return err } diff --git a/cmd/lotus-miner/actor.go b/cmd/lotus-miner/actor.go index 56a58052a..29c5a4bf4 100644 --- a/cmd/lotus-miner/actor.go +++ b/cmd/lotus-miner/actor.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "fmt" "os" "strings" @@ -207,6 +208,13 @@ var actorWithdrawCmd = &cli.Command{ Name: "withdraw", Usage: "withdraw available balance", ArgsUsage: "[amount (FIL)]", + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "confidence", + Usage: "number of block confirmations to wait for", + Value: int(build.MessageConfidence), + }, + }, Action: func(cctx *cli.Context) error { nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) if err != nil { @@ -271,6 +279,28 @@ var actorWithdrawCmd = &cli.Command{ fmt.Printf("Requested rewards withdrawal in message %s\n", smsg.Cid()) + // wait for it to get mined into a block + wait, err := api.StateWaitMsg(ctx, smsg.Cid(), uint64(cctx.Int("confidence"))) + if err != nil { + return err + } + + // check it executed successfully + if wait.Receipt.ExitCode != 0 { + fmt.Println(cctx.App.Writer, "withdrawal failed!") + return err + } + + var withdrawn abi.TokenAmount + if err := withdrawn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil { + return err + } + + fmt.Printf("Successfully withdrew %s FIL\n", withdrawn) + if withdrawn != amount { + fmt.Printf("Note that this is less than the requested amount of %s FIL\n", amount) + } + return nil }, } diff --git a/cmd/lotus-shed/actor.go b/cmd/lotus-shed/actor.go index b78f28349..fd7410c24 100644 --- a/cmd/lotus-shed/actor.go +++ b/cmd/lotus-shed/actor.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "fmt" "os" @@ -44,6 +45,11 @@ var actorWithdrawCmd = &cli.Command{ Name: "actor", Usage: "specify the address of miner actor", }, + &cli.IntFlag{ + Name: "confidence", + Usage: "number of block confirmations to wait for", + Value: int(build.MessageConfidence), + }, }, Action: func(cctx *cli.Context) error { var maddr address.Address @@ -120,6 +126,28 @@ var actorWithdrawCmd = &cli.Command{ fmt.Printf("Requested rewards withdrawal in message %s\n", smsg.Cid()) + // wait for it to get mined into a block + wait, err := nodeAPI.StateWaitMsg(ctx, smsg.Cid(), uint64(cctx.Int("confidence"))) + if err != nil { + return err + } + + // check it executed successfully + if wait.Receipt.ExitCode != 0 { + fmt.Println(cctx.App.Writer, "withdrawal failed!") + return err + } + + var withdrawn abi.TokenAmount + if err := withdrawn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil { + return err + } + + fmt.Printf("Successfully withdrew %s FIL\n", withdrawn) + if withdrawn != amount { + fmt.Printf("Note that this is less than the requested amount of %s FIL\n", amount) + } + return nil }, } diff --git a/cmd/lotus-shed/balances.go b/cmd/lotus-shed/balances.go index 0de2e03b4..1a22be3c3 100644 --- a/cmd/lotus-shed/balances.go +++ b/cmd/lotus-shed/balances.go @@ -517,7 +517,7 @@ var chainBalanceStateCmd = &cli.Command{ cst := cbor.NewCborStore(bs) store := adt.WrapStore(ctx, cst) - sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule()) + sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil) if err != nil { return err } @@ -741,7 +741,7 @@ var chainPledgeCmd = &cli.Command{ cst := cbor.NewCborStore(bs) store := adt.WrapStore(ctx, cst) - sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule()) + sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil) if err != nil { return err } diff --git a/cmd/lotus-shed/math.go b/cmd/lotus-shed/math.go index c6d4ed0c9..4b53495f0 100644 --- a/cmd/lotus-shed/math.go +++ b/cmd/lotus-shed/math.go @@ -7,11 +7,12 @@ import ( "os" "strings" + miner6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/miner" + "github.com/urfave/cli/v2" "golang.org/x/xerrors" "github.com/filecoin-project/lotus/chain/types" - miner5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/miner" ) var mathCmd = &cli.Command{ @@ -19,7 +20,8 @@ var mathCmd = &cli.Command{ Usage: "utility commands around doing math on a list of numbers", Subcommands: []*cli.Command{ mathSumCmd, - mathAggFeesCmd, + mathPreCommitAggFeesCmd, + mathProveCommitAggFeesCmd, }, } @@ -105,8 +107,8 @@ var mathSumCmd = &cli.Command{ }, } -var mathAggFeesCmd = &cli.Command{ - Name: "agg-fees", +var mathProveCommitAggFeesCmd = &cli.Command{ + Name: "agg-fees-commit", Flags: []cli.Flag{ &cli.IntFlag{ Name: "size", @@ -117,6 +119,11 @@ var mathAggFeesCmd = &cli.Command{ Usage: "baseFee aFIL", Required: true, }, + &cli.StringFlag{ + Name: "base-fee", + Usage: "baseFee aFIL", + Required: true, + }, }, Action: func(cctx *cli.Context) error { as := cctx.Int("size") @@ -126,7 +133,39 @@ var mathAggFeesCmd = &cli.Command{ return xerrors.Errorf("parsing basefee: %w", err) } - fmt.Println(types.FIL(miner5.AggregateNetworkFee(as, bf))) + fmt.Println(types.FIL(miner6.AggregateProveCommitNetworkFee(as, bf))) + + return nil + }, +} + +var mathPreCommitAggFeesCmd = &cli.Command{ + Name: "agg-fees-precommit", + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "size", + Required: true, + }, + &cli.StringFlag{ + Name: "base-fee", + Usage: "baseFee aFIL", + Required: true, + }, + &cli.StringFlag{ + Name: "base-fee", + Usage: "baseFee aFIL", + Required: true, + }, + }, + Action: func(cctx *cli.Context) error { + as := cctx.Int("size") + + bf, err := types.BigFromString(cctx.String("base-fee")) + if err != nil { + return xerrors.Errorf("parsing basefee: %w", err) + } + + fmt.Println(types.FIL(miner6.AggregatePreCommitNetworkFee(as, bf))) return nil }, diff --git a/cmd/lotus-sim/simulation/blockbuilder/blockbuilder.go b/cmd/lotus-sim/simulation/blockbuilder/blockbuilder.go index 1abf940e3..a6353e4f4 100644 --- a/cmd/lotus-sim/simulation/blockbuilder/blockbuilder.go +++ b/cmd/lotus-sim/simulation/blockbuilder/blockbuilder.go @@ -17,10 +17,11 @@ import ( "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/builtin/account" + lrand "github.com/filecoin-project/lotus/chain/rand" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/stmgr" - "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" ) @@ -78,7 +79,7 @@ func NewBlockBuilder(ctx context.Context, logger *zap.SugaredLogger, sm *stmgr.S // 1. We don't charge a fee. // 2. The runtime has "fake" proof logic. // 3. We don't actually save any of the results. - r := store.NewChainRand(sm.ChainStore(), parentTs.Cids()) + r := lrand.NewStateRand(sm.ChainStore(), parentTs.Cids(), sm.Beacon()) vmopt := &vm.VMOpts{ StateBase: parentState, Epoch: parentTs.Height() + 1, diff --git a/cmd/lotus-sim/simulation/node.go b/cmd/lotus-sim/simulation/node.go index 22463512a..c18f27a33 100644 --- a/cmd/lotus-sim/simulation/node.go +++ b/cmd/lotus-sim/simulation/node.go @@ -106,7 +106,7 @@ func (nd *Node) LoadSim(ctx context.Context, name string) (*Simulation, error) { if err != nil { return nil, xerrors.Errorf("failed to create upgrade schedule for simulation %s: %w", name, err) } - sim.StateManager, err = stmgr.NewStateManager(nd.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), us) + sim.StateManager, err = stmgr.NewStateManager(nd.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), us, nil) if err != nil { return nil, xerrors.Errorf("failed to create state manager for simulation %s: %w", name, err) } @@ -125,7 +125,7 @@ func (nd *Node) CreateSim(ctx context.Context, name string, head *types.TipSet) if err != nil { return nil, err } - sm, err := stmgr.NewStateManager(nd.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), filcns.DefaultUpgradeSchedule()) + sm, err := stmgr.NewStateManager(nd.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), filcns.DefaultUpgradeSchedule(), nil) if err != nil { return nil, xerrors.Errorf("creating state manager: %w", err) } diff --git a/cmd/lotus-sim/simulation/simulation.go b/cmd/lotus-sim/simulation/simulation.go index 56030fa23..02792e332 100644 --- a/cmd/lotus-sim/simulation/simulation.go +++ b/cmd/lotus-sim/simulation/simulation.go @@ -201,7 +201,7 @@ func (sim *Simulation) SetUpgradeHeight(nv network.Version, epoch abi.ChainEpoch if err != nil { return err } - sm, err := stmgr.NewStateManager(sim.Node.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), newUpgradeSchedule) + sm, err := stmgr.NewStateManager(sim.Node.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), newUpgradeSchedule, nil) if err != nil { return err } diff --git a/cmd/lotus-sim/simulation/stages/util.go b/cmd/lotus-sim/simulation/stages/util.go index 97c1e57af..0c17823c0 100644 --- a/cmd/lotus-sim/simulation/stages/util.go +++ b/cmd/lotus-sim/simulation/stages/util.go @@ -44,8 +44,7 @@ func sectorsFromClaim(sectorSize abi.SectorSize, c power.Claim) int64 { } func postChainCommitInfo(ctx context.Context, bb *blockbuilder.BlockBuilder, epoch abi.ChainEpoch) (abi.Randomness, error) { - cs := bb.StateManager().ChainStore() ts := bb.ParentTipSet() - commitRand, err := cs.GetChainRandomness(ctx, ts.Cids(), crypto.DomainSeparationTag_PoStChainCommit, epoch, nil, true) + commitRand, err := bb.StateManager().GetRandomnessFromTickets(ctx, crypto.DomainSeparationTag_PoStChainCommit, epoch, nil, ts.Key()) return commitRand, err } diff --git a/cmd/lotus/daemon.go b/cmd/lotus/daemon.go index 51aeca3c4..3f5de8138 100644 --- a/cmd/lotus/daemon.go +++ b/cmd/lotus/daemon.go @@ -520,7 +520,8 @@ func ImportChain(ctx context.Context, r repo.Repo, fname string, snapshot bool) return err } - stm, err := stmgr.NewStateManager(cst, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule()) + // TODO: We need to supply the actual beacon after v14 + stm, err := stmgr.NewStateManager(cst, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil) if err != nil { return err } diff --git a/conformance/driver.go b/conformance/driver.go index 6fef5a76d..8669089da 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -104,7 +104,7 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params cs = store.NewChainStore(bs, bs, ds, filcns.Weight, nil) tse = filcns.NewTipSetExecutor() - sm, err = stmgr.NewStateManager(cs, tse, syscalls, filcns.DefaultUpgradeSchedule()) + sm, err = stmgr.NewStateManager(cs, tse, syscalls, filcns.DefaultUpgradeSchedule(), nil) ) if err != nil { return nil, err @@ -204,7 +204,7 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP // dummy state manager; only to reference the GetNetworkVersion method, // which does not depend on state. - sm, err := stmgr.NewStateManager(nil, filcns.NewTipSetExecutor(), nil, filcns.DefaultUpgradeSchedule()) + sm, err := stmgr.NewStateManager(nil, filcns.NewTipSetExecutor(), nil, filcns.DefaultUpgradeSchedule(), nil) if err != nil { return nil, cid.Cid{}, err } diff --git a/conformance/rand_fixed.go b/conformance/rand_fixed.go index f15910e1d..c34980efe 100644 --- a/conformance/rand_fixed.go +++ b/conformance/rand_fixed.go @@ -19,18 +19,22 @@ func NewFixedRand() vm.Rand { return &fixedRand{} } -func (r *fixedRand) GetChainRandomnessLookingForward(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) { +func (r *fixedRand) GetChainRandomnessV1(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) { return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes. } -func (r *fixedRand) GetChainRandomnessLookingBack(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) { +func (r *fixedRand) GetChainRandomnessV2(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) { return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes. } -func (r *fixedRand) GetBeaconRandomnessLookingForward(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) { +func (r *fixedRand) GetBeaconRandomnessV3(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) { return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes. } -func (r *fixedRand) GetBeaconRandomnessLookingBack(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) { +func (r *fixedRand) GetBeaconRandomnessV1(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) { + return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes. +} + +func (r *fixedRand) GetBeaconRandomnessV2(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) { return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes. } diff --git a/conformance/rand_record.go b/conformance/rand_record.go index 906d6b73d..97bd93eb4 100644 --- a/conformance/rand_record.go +++ b/conformance/rand_record.go @@ -45,11 +45,11 @@ func (r *RecordingRand) loadHead() { r.head = head.Key() } -func (r *RecordingRand) GetChainRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { +func (r *RecordingRand) GetChainRandomnessV2(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { return r.getChainRandomness(ctx, pers, round, entropy) } -func (r *RecordingRand) GetChainRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { +func (r *RecordingRand) GetChainRandomnessV1(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { return r.getChainRandomness(ctx, pers, round, entropy) } @@ -79,17 +79,21 @@ func (r *RecordingRand) getChainRandomness(ctx context.Context, pers crypto.Doma return ret, err } -func (r *RecordingRand) GetBeaconRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { +func (r *RecordingRand) GetBeaconRandomnessV3(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { return r.getBeaconRandomness(ctx, pers, round, entropy) } -func (r *RecordingRand) GetBeaconRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { +func (r *RecordingRand) GetBeaconRandomnessV1(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { + return r.getBeaconRandomness(ctx, pers, round, entropy) +} + +func (r *RecordingRand) GetBeaconRandomnessV2(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { return r.getBeaconRandomness(ctx, pers, round, entropy) } func (r *RecordingRand) getBeaconRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { r.once.Do(r.loadHead) - ret, err := r.api.ChainGetRandomnessFromBeacon(ctx, r.head, pers, round, entropy) + ret, err := r.api.StateGetRandomnessFromBeacon(ctx, pers, round, entropy, r.head) if err != nil { return ret, err } diff --git a/conformance/rand_replay.go b/conformance/rand_replay.go index faae1d090..5d850f7eb 100644 --- a/conformance/rand_replay.go +++ b/conformance/rand_replay.go @@ -43,11 +43,11 @@ func (r *ReplayingRand) match(requested schema.RandomnessRule) ([]byte, bool) { return nil, false } -func (r *ReplayingRand) GetChainRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { +func (r *ReplayingRand) GetChainRandomnessV1(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { return r.getChainRandomness(ctx, pers, round, entropy, false) } -func (r *ReplayingRand) GetChainRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { +func (r *ReplayingRand) GetChainRandomnessV2(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { return r.getChainRandomness(ctx, pers, round, entropy, true) } @@ -67,17 +67,21 @@ func (r *ReplayingRand) getChainRandomness(ctx context.Context, pers crypto.Doma r.reporter.Logf("returning fallback chain randomness: dst=%d, epoch=%d, entropy=%x", pers, round, entropy) if lookback { - return r.fallback.GetChainRandomnessLookingBack(ctx, pers, round, entropy) + return r.fallback.GetChainRandomnessV1(ctx, pers, round, entropy) } - return r.fallback.GetChainRandomnessLookingForward(ctx, pers, round, entropy) + return r.fallback.GetChainRandomnessV2(ctx, pers, round, entropy) } -func (r *ReplayingRand) GetBeaconRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { +func (r *ReplayingRand) GetBeaconRandomnessV3(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { return r.getBeaconRandomness(ctx, pers, round, entropy, false) } -func (r *ReplayingRand) GetBeaconRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { +func (r *ReplayingRand) GetBeaconRandomnessV1(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { + return r.getBeaconRandomness(ctx, pers, round, entropy, true) +} + +func (r *ReplayingRand) GetBeaconRandomnessV2(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { return r.getBeaconRandomness(ctx, pers, round, entropy, true) } @@ -97,8 +101,8 @@ func (r *ReplayingRand) getBeaconRandomness(ctx context.Context, pers crypto.Dom r.reporter.Logf("returning fallback beacon randomness: dst=%d, epoch=%d, entropy=%x", pers, round, entropy) if lookback { - return r.fallback.GetBeaconRandomnessLookingBack(ctx, pers, round, entropy) + return r.fallback.GetBeaconRandomnessV1(ctx, pers, round, entropy) } - return r.fallback.GetBeaconRandomnessLookingForward(ctx, pers, round, entropy) + return r.fallback.GetBeaconRandomnessV3(ctx, pers, round, entropy) } diff --git a/documentation/en/cli-lotus-miner.md b/documentation/en/cli-lotus-miner.md index e9181cdda..95ad4c33f 100644 --- a/documentation/en/cli-lotus-miner.md +++ b/documentation/en/cli-lotus-miner.md @@ -7,7 +7,7 @@ USAGE: lotus-miner [global options] command [command options] [arguments...] VERSION: - 1.11.4-dev + 1.13.0-dev COMMANDS: init Initialize a lotus miner repo @@ -278,7 +278,8 @@ USAGE: lotus-miner actor withdraw [command options] [amount (FIL)] OPTIONS: - --help, -h show help (default: false) + --confidence value number of block confirmations to wait for (default: 5) + --help, -h show help (default: false) ``` diff --git a/documentation/en/cli-lotus-worker.md b/documentation/en/cli-lotus-worker.md index ae64e23e4..cdb6c2290 100644 --- a/documentation/en/cli-lotus-worker.md +++ b/documentation/en/cli-lotus-worker.md @@ -7,7 +7,7 @@ USAGE: lotus-worker [global options] command [command options] [arguments...] VERSION: - 1.11.4-dev + 1.13.0-dev COMMANDS: run Start lotus worker diff --git a/documentation/en/cli-lotus.md b/documentation/en/cli-lotus.md index 7423f11d6..d6fdb9e8a 100644 --- a/documentation/en/cli-lotus.md +++ b/documentation/en/cli-lotus.md @@ -7,7 +7,7 @@ USAGE: lotus [global options] command [command options] [arguments...] VERSION: - 1.11.4-dev + 1.13.0-dev COMMANDS: daemon Start a lotus daemon process @@ -388,6 +388,7 @@ USAGE: OPTIONS: --wallet value, -w value Specify address to withdraw funds to, otherwise it will use the default wallet address --address value, -a value Market address to withdraw from (account or miner actor address, defaults to --wallet address) + --confidence value number of block confirmations to wait for (default: 5) --help, -h show help (default: false) ``` diff --git a/documentation/en/default-lotus-config.toml b/documentation/en/default-lotus-config.toml index 1074bd117..3cb8977b2 100644 --- a/documentation/en/default-lotus-config.toml +++ b/documentation/en/default-lotus-config.toml @@ -108,11 +108,18 @@ #IpfsUseForRetrieval = false # The maximum number of simultaneous data transfers between the client - # and storage providers + # and storage providers for storage deals # # type: uint64 - # env var: LOTUS_CLIENT_SIMULTANEOUSTRANSFERS - #SimultaneousTransfers = 20 + # env var: LOTUS_CLIENT_SIMULTANEOUSTRANSFERSFORSTORAGE + #SimultaneousTransfersForStorage = 20 + + # The maximum number of simultaneous data transfers between the client + # and storage providers for retrieval deals + # + # type: uint64 + # env var: LOTUS_CLIENT_SIMULTANEOUSTRANSFERSFORRETRIEVAL + #SimultaneousTransfersForRetrieval = 20 [Wallet] diff --git a/documentation/en/default-lotus-miner-config.toml b/documentation/en/default-lotus-miner-config.toml index 7748d94c4..d402f65ed 100644 --- a/documentation/en/default-lotus-miner-config.toml +++ b/documentation/en/default-lotus-miner-config.toml @@ -201,11 +201,17 @@ # env var: LOTUS_DEALMAKING_MAXSTAGINGDEALSBYTES #MaxStagingDealsBytes = 0 - # The maximum number of parallel online data transfers (storage+retrieval) + # The maximum number of parallel online data transfers for storage deals # # type: uint64 - # env var: LOTUS_DEALMAKING_SIMULTANEOUSTRANSFERS - #SimultaneousTransfers = 20 + # env var: LOTUS_DEALMAKING_SIMULTANEOUSTRANSFERSFORSTORAGE + #SimultaneousTransfersForStorage = 20 + + # The maximum number of parallel online data transfers for retrieval deals + # + # type: uint64 + # env var: LOTUS_DEALMAKING_SIMULTANEOUSTRANSFERSFORRETRIEVAL + #SimultaneousTransfersForRetrieval = 20 # Minimum start epoch buffer to give time for sealing of sector with deal. # @@ -361,12 +367,19 @@ # env var: LOTUS_SEALING_COMMITBATCHSLACK #CommitBatchSlack = "1h0m0s" + # network BaseFee below which to stop doing precommit batching, instead + # sending precommit messages to the chain individually + # + # type: types.FIL + # env var: LOTUS_SEALING_BATCHPRECOMMITABOVEBASEFEE + #BatchPreCommitAboveBaseFee = "0.00000000032 FIL" + # network BaseFee below which to stop doing commit aggregation, instead # submitting proofs to the chain individually # # type: types.FIL # env var: LOTUS_SEALING_AGGREGATEABOVEBASEFEE - #AggregateAboveBaseFee = "0.00000000015 FIL" + #AggregateAboveBaseFee = "0.00000000032 FIL" # type: uint64 # env var: LOTUS_SEALING_TERMINATEBATCHMAX diff --git a/extern/storage-sealing/commit_batch.go b/extern/storage-sealing/commit_batch.go index 3a97f7d68..1c55b6700 100644 --- a/extern/storage-sealing/commit_batch.go +++ b/extern/storage-sealing/commit_batch.go @@ -347,11 +347,12 @@ func (b *CommitBatcher) processBatch(cfg sealiface.Config) ([]sealiface.CommitBa return []sealiface.CommitBatchRes{res}, xerrors.Errorf("getting network version: %s", err) } - aggFeeRaw, err := policy.AggregateNetworkFee(nv, len(infos), bf) + aggFeeRaw, err := policy.AggregateProveCommitNetworkFee(nv, len(infos), bf) if err != nil { - log.Errorf("getting aggregate network fee: %s", err) - return []sealiface.CommitBatchRes{res}, xerrors.Errorf("getting aggregate network fee: %s", err) + log.Errorf("getting aggregate commit network fee: %s", err) + return []sealiface.CommitBatchRes{res}, xerrors.Errorf("getting aggregate commit network fee: %s", err) } + aggFee := big.Div(big.Mul(aggFeeRaw, aggFeeNum), aggFeeDen) needFunds := big.Add(collateral, aggFee) diff --git a/extern/storage-sealing/commit_batch_test.go b/extern/storage-sealing/commit_batch_test.go index aea6d455e..e03c34693 100644 --- a/extern/storage-sealing/commit_batch_test.go +++ b/extern/storage-sealing/commit_batch_test.go @@ -59,7 +59,8 @@ func TestCommitBatcher(t *testing.T) { CommitBatchWait: 24 * time.Hour, CommitBatchSlack: 1 * time.Hour, - AggregateAboveBaseFee: types.BigMul(types.PicoFil, types.NewInt(150)), // 0.15 nFIL + AggregateAboveBaseFee: types.BigMul(types.PicoFil, types.NewInt(150)), // 0.15 nFIL + BatchPreCommitAboveBaseFee: types.BigMul(types.PicoFil, types.NewInt(150)), // 0.15 nFIL TerminateBatchMin: 1, TerminateBatchMax: 100, diff --git a/extern/storage-sealing/currentdealinfo.go b/extern/storage-sealing/currentdealinfo.go index ed93512c2..6863b47b3 100644 --- a/extern/storage-sealing/currentdealinfo.go +++ b/extern/storage-sealing/currentdealinfo.go @@ -4,6 +4,8 @@ import ( "bytes" "context" + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/exitcode" @@ -20,6 +22,7 @@ type CurrentDealInfoAPI interface { StateLookupID(context.Context, address.Address, TipSetToken) (address.Address, error) StateMarketStorageDeal(context.Context, abi.DealID, TipSetToken) (*api.MarketDeal, error) StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error) + StateNetworkVersion(ctx context.Context, tok TipSetToken) (network.Version, error) } type CurrentDealInfo struct { @@ -77,27 +80,38 @@ func (mgr *CurrentDealInfoManager) dealIDFromPublishDealsMsg(ctx context.Context return dealID, nil, xerrors.Errorf("looking for publish deal message %s: non-ok exit code: %s", publishCid, lookup.Receipt.ExitCode) } - var retval market.PublishStorageDealsReturn - if err := retval.UnmarshalCBOR(bytes.NewReader(lookup.Receipt.Return)); err != nil { - return dealID, nil, xerrors.Errorf("looking for publish deal message %s: unmarshalling message return: %w", publishCid, err) + nv, err := mgr.CDAPI.StateNetworkVersion(ctx, lookup.TipSetTok) + if err != nil { + return dealID, nil, xerrors.Errorf("getting network version: %w", err) } + retval, err := market.DecodePublishStorageDealsReturn(lookup.Receipt.Return, nv) + if err != nil { + return dealID, nil, xerrors.Errorf("looking for publish deal message %s: decoding message return: %w", publishCid, err) + } + + dealIDs, err := retval.DealIDs() + if err != nil { + return dealID, nil, xerrors.Errorf("looking for publish deal message %s: getting dealIDs: %w", publishCid, err) + } + + // TODO: Can we delete this? We're well past the point when we first introduced the proposals into sealing deal info // Previously, publish deals messages contained a single deal, and the // deal proposal was not included in the sealing deal info. // So check if the proposal is nil and check the number of deals published // in the message. if proposal == nil { - if len(retval.IDs) > 1 { + if len(dealIDs) > 1 { return dealID, nil, xerrors.Errorf( "getting deal ID from publish deal message %s: "+ "no deal proposal supplied but message return value has more than one deal (%d deals)", - publishCid, len(retval.IDs)) + publishCid, len(dealIDs)) } // There is a single deal in this publish message and no deal proposal // was supplied, so we have nothing to compare against. Just assume - // the deal ID is correct. - return retval.IDs[0], lookup.TipSetTok, nil + // the deal ID is correct and that it was valid + return dealIDs[0], lookup.TipSetTok, nil } // Get the parameters to the publish deals message @@ -129,13 +143,22 @@ func (mgr *CurrentDealInfoManager) dealIDFromPublishDealsMsg(ctx context.Context return dealID, nil, xerrors.Errorf("could not find deal in publish deals message %s", publishCid) } - if dealIdx >= len(retval.IDs) { + if dealIdx >= len(dealIDs) { return dealID, nil, xerrors.Errorf( "deal index %d out of bounds of deals (len %d) in publish deals message %s", - dealIdx, len(retval.IDs), publishCid) + dealIdx, len(dealIDs), publishCid) } - return retval.IDs[dealIdx], lookup.TipSetTok, nil + valid, err := retval.IsDealValid(uint64(dealIdx)) + if err != nil { + return dealID, nil, xerrors.Errorf("determining deal validity: %w", err) + } + + if !valid { + return dealID, nil, xerrors.New("deal was invalid at publication") + } + + return dealIDs[dealIdx], lookup.TipSetTok, nil } func (mgr *CurrentDealInfoManager) CheckDealEquality(ctx context.Context, tok TipSetToken, p1, p2 market.DealProposal) (bool, error) { @@ -165,6 +188,7 @@ type CurrentDealInfoTskAPI interface { StateLookupID(context.Context, address.Address, types.TipSetKey) (address.Address, error) StateMarketStorageDeal(context.Context, abi.DealID, types.TipSetKey) (*api.MarketDeal, error) StateSearchMsg(ctx context.Context, from types.TipSetKey, msg cid.Cid, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error) + StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error) } type CurrentDealInfoAPIAdapter struct { @@ -210,4 +234,13 @@ func (c *CurrentDealInfoAPIAdapter) StateSearchMsg(ctx context.Context, k cid.Ci }, nil } +func (c *CurrentDealInfoAPIAdapter) StateNetworkVersion(ctx context.Context, tok TipSetToken) (network.Version, error) { + tsk, err := types.TipSetKeyFromBytes(tok) + if err != nil { + return network.VersionMax, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) + } + + return c.CurrentDealInfoTskAPI.StateNetworkVersion(ctx, tsk) +} + var _ CurrentDealInfoAPI = (*CurrentDealInfoAPIAdapter)(nil) diff --git a/extern/storage-sealing/currentdealinfo_test.go b/extern/storage-sealing/currentdealinfo_test.go index b28dd461a..4d8022adb 100644 --- a/extern/storage-sealing/currentdealinfo_test.go +++ b/extern/storage-sealing/currentdealinfo_test.go @@ -8,6 +8,10 @@ import ( "testing" "time" + "github.com/filecoin-project/go-state-types/network" + + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" + "golang.org/x/net/context" "golang.org/x/xerrors" @@ -207,7 +211,7 @@ func TestGetCurrentDealInfo(t *testing.T) { }, targetProposal: &proposal, expectedDealID: zeroDealID, - expectedError: xerrors.Errorf("looking for publish deal message %s: unmarshalling message return: cbor input should be of type array", dummyCid), + expectedError: xerrors.Errorf("looking for publish deal message %s: decoding message return: failed to unmarshal PublishStorageDealsReturn: cbor input should be of type array", dummyCid), }, } runTestCase := func(testCase string, data testCaseData) { @@ -305,9 +309,13 @@ func (mapi *CurrentDealInfoMockAPI) StateSearchMsg(ctx context.Context, c cid.Ci return mapi.SearchMessageLookup, mapi.SearchMessageErr } +func (mapi *CurrentDealInfoMockAPI) StateNetworkVersion(ctx context.Context, tok TipSetToken) (network.Version, error) { + return network.Version0, nil +} + func makePublishDealsReturnBytes(t *testing.T, dealIDs []abi.DealID) []byte { buf := new(bytes.Buffer) - dealsReturn := market.PublishStorageDealsReturn{ + dealsReturn := market0.PublishStorageDealsReturn{ IDs: dealIDs, } err := dealsReturn.MarshalCBOR(buf) diff --git a/extern/storage-sealing/mocks/mock_precommit_batcher.go b/extern/storage-sealing/mocks/mock_precommit_batcher.go index ed97229b4..fe7424d35 100644 --- a/extern/storage-sealing/mocks/mock_precommit_batcher.go +++ b/extern/storage-sealing/mocks/mock_precommit_batcher.go @@ -11,6 +11,7 @@ import ( address "github.com/filecoin-project/go-address" abi "github.com/filecoin-project/go-state-types/abi" big "github.com/filecoin-project/go-state-types/big" + network "github.com/filecoin-project/go-state-types/network" miner "github.com/filecoin-project/lotus/chain/actors/builtin/miner" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" gomock "github.com/golang/mock/gomock" @@ -40,6 +41,21 @@ func (m *MockPreCommitBatcherApi) EXPECT() *MockPreCommitBatcherApiMockRecorder return m.recorder } +// ChainBaseFee mocks base method. +func (m *MockPreCommitBatcherApi) ChainBaseFee(arg0 context.Context, arg1 sealing.TipSetToken) (big.Int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ChainBaseFee", arg0, arg1) + ret0, _ := ret[0].(big.Int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ChainBaseFee indicates an expected call of ChainBaseFee. +func (mr *MockPreCommitBatcherApiMockRecorder) ChainBaseFee(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainBaseFee", reflect.TypeOf((*MockPreCommitBatcherApi)(nil).ChainBaseFee), arg0, arg1) +} + // ChainHead mocks base method. func (m *MockPreCommitBatcherApi) ChainHead(arg0 context.Context) (sealing.TipSetToken, abi.ChainEpoch, error) { m.ctrl.T.Helper() @@ -100,3 +116,18 @@ func (mr *MockPreCommitBatcherApiMockRecorder) StateMinerInfo(arg0, arg1, arg2 i mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateMinerInfo", reflect.TypeOf((*MockPreCommitBatcherApi)(nil).StateMinerInfo), arg0, arg1, arg2) } + +// StateNetworkVersion mocks base method. +func (m *MockPreCommitBatcherApi) StateNetworkVersion(arg0 context.Context, arg1 sealing.TipSetToken) (network.Version, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StateNetworkVersion", arg0, arg1) + ret0, _ := ret[0].(network.Version) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StateNetworkVersion indicates an expected call of StateNetworkVersion. +func (mr *MockPreCommitBatcherApiMockRecorder) StateNetworkVersion(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateNetworkVersion", reflect.TypeOf((*MockPreCommitBatcherApi)(nil).StateNetworkVersion), arg0, arg1) +} diff --git a/extern/storage-sealing/precommit_batch.go b/extern/storage-sealing/precommit_batch.go index 719455b90..07d2e796e 100644 --- a/extern/storage-sealing/precommit_batch.go +++ b/extern/storage-sealing/precommit_batch.go @@ -7,6 +7,8 @@ import ( "sync" "time" + "github.com/filecoin-project/go-state-types/network" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" @@ -20,6 +22,7 @@ import ( "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/actors/policy" + "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/extern/storage-sealing/sealiface" "github.com/filecoin-project/lotus/node/config" ) @@ -31,6 +34,8 @@ type PreCommitBatcherApi interface { StateMinerInfo(context.Context, address.Address, TipSetToken) (miner.MinerInfo, error) StateMinerAvailableBalance(context.Context, address.Address, TipSetToken) (big.Int, error) ChainHead(ctx context.Context) (TipSetToken, abi.ChainEpoch, error) + ChainBaseFee(context.Context, TipSetToken) (abi.TokenAmount, error) + StateNetworkVersion(ctx context.Context, tok TipSetToken) (network.Version, error) } type preCommitEntry struct { @@ -185,8 +190,34 @@ func (b *PreCommitBatcher) maybeStartBatch(notif bool) ([]sealiface.PreCommitBat return nil, nil } + tok, _, err := b.api.ChainHead(b.mctx) + if err != nil { + return nil, err + } + + bf, err := b.api.ChainBaseFee(b.mctx, tok) + if err != nil { + return nil, xerrors.Errorf("couldn't get base fee: %w", err) + } + + // TODO: Drop this once nv14 has come and gone + nv, err := b.api.StateNetworkVersion(b.mctx, tok) + if err != nil { + return nil, xerrors.Errorf("couldn't get network version: %w", err) + } + + individual := false + if !cfg.BatchPreCommitAboveBaseFee.Equals(big.Zero()) && bf.LessThan(cfg.BatchPreCommitAboveBaseFee) && nv >= network.Version14 { + individual = true + } + // todo support multiple batches - res, err := b.processBatch(cfg) + var res []sealiface.PreCommitBatchRes + if !individual { + res, err = b.processBatch(cfg, tok, bf, nv) + } else { + res, err = b.processIndividually(cfg) + } if err != nil && len(res) == 0 { return nil, err } @@ -210,7 +241,83 @@ func (b *PreCommitBatcher) maybeStartBatch(notif bool) ([]sealiface.PreCommitBat return res, nil } -func (b *PreCommitBatcher) processBatch(cfg sealiface.Config) ([]sealiface.PreCommitBatchRes, error) { +func (b *PreCommitBatcher) processIndividually(cfg sealiface.Config) ([]sealiface.PreCommitBatchRes, error) { + mi, err := b.api.StateMinerInfo(b.mctx, b.maddr, nil) + if err != nil { + return nil, xerrors.Errorf("couldn't get miner info: %w", err) + } + + avail := types.TotalFilecoinInt + + if cfg.CollateralFromMinerBalance && !cfg.DisableCollateralFallback { + avail, err = b.api.StateMinerAvailableBalance(b.mctx, b.maddr, nil) + if err != nil { + return nil, xerrors.Errorf("getting available miner balance: %w", err) + } + + avail = big.Sub(avail, cfg.AvailableBalanceBuffer) + if avail.LessThan(big.Zero()) { + avail = big.Zero() + } + } + + var res []sealiface.PreCommitBatchRes + + for sn, info := range b.todo { + r := sealiface.PreCommitBatchRes{ + Sectors: []abi.SectorNumber{sn}, + } + + mcid, err := b.processSingle(cfg, mi, &avail, info) + if err != nil { + r.Error = err.Error() + } else { + r.Msg = &mcid + } + + res = append(res, r) + } + + return res, nil +} + +func (b *PreCommitBatcher) processSingle(cfg sealiface.Config, mi miner.MinerInfo, avail *abi.TokenAmount, params *preCommitEntry) (cid.Cid, error) { + enc := new(bytes.Buffer) + + if err := params.pci.MarshalCBOR(enc); err != nil { + return cid.Undef, xerrors.Errorf("marshaling precommit params: %w", err) + } + + deposit := params.deposit + if cfg.CollateralFromMinerBalance { + c := big.Sub(deposit, *avail) + *avail = big.Sub(*avail, deposit) + deposit = c + + if deposit.LessThan(big.Zero()) { + deposit = big.Zero() + } + if (*avail).LessThan(big.Zero()) { + *avail = big.Zero() + } + } + + goodFunds := big.Add(deposit, big.Int(b.feeCfg.MaxPreCommitGasFee)) + + from, _, err := b.addrSel(b.mctx, mi, api.PreCommitAddr, goodFunds, deposit) + if err != nil { + return cid.Undef, xerrors.Errorf("no good address to send precommit message from: %w", err) + } + + mcid, err := b.api.SendMsg(b.mctx, from, b.maddr, miner.Methods.PreCommitSector, deposit, big.Int(b.feeCfg.MaxPreCommitGasFee), enc.Bytes()) + if err != nil { + return cid.Undef, xerrors.Errorf("pushing message to mpool: %w", err) + } + + return mcid, nil +} + +func (b *PreCommitBatcher) processBatch(cfg sealiface.Config, tok TipSetToken, bf abi.TokenAmount, nv network.Version) ([]sealiface.PreCommitBatchRes, error) { params := miner5.PreCommitSectorBatchParams{} deposit := big.Zero() var res sealiface.PreCommitBatchRes @@ -226,11 +333,6 @@ func (b *PreCommitBatcher) processBatch(cfg sealiface.Config) ([]sealiface.PreCo deposit = big.Add(deposit, p.deposit) } - deposit, err := collateralSendAmount(b.mctx, b.api, b.maddr, cfg, deposit) - if err != nil { - return []sealiface.PreCommitBatchRes{res}, err - } - enc := new(bytes.Buffer) if err := params.MarshalCBOR(enc); err != nil { return []sealiface.PreCommitBatchRes{res}, xerrors.Errorf("couldn't serialize PreCommitSectorBatchParams: %w", err) @@ -242,14 +344,29 @@ func (b *PreCommitBatcher) processBatch(cfg sealiface.Config) ([]sealiface.PreCo } maxFee := b.feeCfg.MaxPreCommitBatchGasFee.FeeForSectors(len(params.Sectors)) - goodFunds := big.Add(deposit, maxFee) + + aggFeeRaw, err := policy.AggregatePreCommitNetworkFee(nv, len(params.Sectors), bf) + if err != nil { + log.Errorf("getting aggregate precommit network fee: %s", err) + return []sealiface.PreCommitBatchRes{res}, xerrors.Errorf("getting aggregate precommit network fee: %s", err) + } + + aggFee := big.Div(big.Mul(aggFeeRaw, aggFeeNum), aggFeeDen) + + needFunds := big.Add(deposit, aggFee) + needFunds, err = collateralSendAmount(b.mctx, b.api, b.maddr, cfg, needFunds) + if err != nil { + return []sealiface.PreCommitBatchRes{res}, err + } + + goodFunds := big.Add(maxFee, needFunds) from, _, err := b.addrSel(b.mctx, mi, api.PreCommitAddr, goodFunds, deposit) if err != nil { return []sealiface.PreCommitBatchRes{res}, xerrors.Errorf("no good address found: %w", err) } - mcid, err := b.api.SendMsg(b.mctx, from, b.maddr, miner.Methods.PreCommitSectorBatch, deposit, maxFee, enc.Bytes()) + mcid, err := b.api.SendMsg(b.mctx, from, b.maddr, miner.Methods.PreCommitSectorBatch, needFunds, maxFee, enc.Bytes()) if err != nil { return []sealiface.PreCommitBatchRes{res}, xerrors.Errorf("sending message failed: %w", err) } diff --git a/extern/storage-sealing/precommit_batch_test.go b/extern/storage-sealing/precommit_batch_test.go index b6c35362e..f6440996e 100644 --- a/extern/storage-sealing/precommit_batch_test.go +++ b/extern/storage-sealing/precommit_batch_test.go @@ -8,13 +8,16 @@ import ( "testing" "time" + miner6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/miner" + + "github.com/filecoin-project/go-state-types/network" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" - miner5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/miner" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" @@ -44,7 +47,7 @@ func TestPrecommitBatcher(t *testing.T) { return t0123, big.Zero(), nil } - maxBatch := miner5.PreCommitSectorBatchMaxSize + maxBatch := miner6.PreCommitSectorBatchMaxSize cfg := func() (sealiface.Config, error) { return sealiface.Config{ @@ -54,14 +57,15 @@ func TestPrecommitBatcher(t *testing.T) { WaitDealsDelay: time.Hour * 6, AlwaysKeepUnsealedCopy: true, - BatchPreCommits: true, - MaxPreCommitBatch: maxBatch, - PreCommitBatchWait: 24 * time.Hour, - PreCommitBatchSlack: 3 * time.Hour, + BatchPreCommits: true, + MaxPreCommitBatch: maxBatch, + PreCommitBatchWait: 24 * time.Hour, + PreCommitBatchSlack: 3 * time.Hour, + BatchPreCommitAboveBaseFee: big.NewInt(10000), AggregateCommits: true, - MinCommitBatch: miner5.MinAggregatedSectors, - MaxCommitBatch: miner5.MaxAggregatedSectors, + MinCommitBatch: miner6.MinAggregatedSectors, + MaxCommitBatch: miner6.MaxAggregatedSectors, CommitBatchWait: 24 * time.Hour, CommitBatchSlack: 1 * time.Hour, @@ -149,10 +153,14 @@ func TestPrecommitBatcher(t *testing.T) { expectSend := func(expect []abi.SectorNumber) action { return func(t *testing.T, s *mocks.MockPreCommitBatcherApi, pcb *sealing.PreCommitBatcher) promise { + s.EXPECT().ChainHead(gomock.Any()).Return(nil, abi.ChainEpoch(1), nil) + s.EXPECT().ChainBaseFee(gomock.Any(), gomock.Any()).Return(big.NewInt(10001), nil) + s.EXPECT().StateNetworkVersion(gomock.Any(), gomock.Any()).Return(network.Version14, nil) + s.EXPECT().StateMinerInfo(gomock.Any(), gomock.Any(), gomock.Any()).Return(miner.MinerInfo{Owner: t0123, Worker: t0123}, nil) s.EXPECT().SendMsg(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), funMatcher(func(i interface{}) bool { b := i.([]byte) - var params miner5.PreCommitSectorBatchParams + var params miner6.PreCommitSectorBatchParams require.NoError(t, params.UnmarshalCBOR(bytes.NewReader(b))) for s, number := range expect { require.Equal(t, number, params.Sectors[s].SectorNumber) @@ -163,6 +171,27 @@ func TestPrecommitBatcher(t *testing.T) { } } + expectSendsSingle := func(expect []abi.SectorNumber) action { + return func(t *testing.T, s *mocks.MockPreCommitBatcherApi, pcb *sealing.PreCommitBatcher) promise { + s.EXPECT().ChainHead(gomock.Any()).Return(nil, abi.ChainEpoch(1), nil) + s.EXPECT().ChainBaseFee(gomock.Any(), gomock.Any()).Return(big.NewInt(9999), nil) + s.EXPECT().StateNetworkVersion(gomock.Any(), gomock.Any()).Return(network.Version14, nil) + + s.EXPECT().StateMinerInfo(gomock.Any(), gomock.Any(), gomock.Any()).Return(miner.MinerInfo{Owner: t0123, Worker: t0123}, nil) + for _, number := range expect { + numClone := number + s.EXPECT().SendMsg(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), funMatcher(func(i interface{}) bool { + b := i.([]byte) + var params miner6.PreCommitSectorParams + require.NoError(t, params.UnmarshalCBOR(bytes.NewReader(b))) + require.Equal(t, numClone, params.SectorNumber) + return true + })) + } + return nil + } + } + flush := func(expect []abi.SectorNumber) action { return func(t *testing.T, s *mocks.MockPreCommitBatcherApi, pcb *sealing.PreCommitBatcher) promise { _ = expectSend(expect)(t, s, pcb) @@ -211,6 +240,12 @@ func TestPrecommitBatcher(t *testing.T) { addSectors(getSectors(maxBatch)), }, }, + "addMax-belowBaseFee": { + actions: []action{ + expectSendsSingle(getSectors(maxBatch)), + addSectors(getSectors(maxBatch)), + }, + }, } for name, tc := range tcs { diff --git a/extern/storage-sealing/sealiface/config.go b/extern/storage-sealing/sealiface/config.go index bedb89085..d8a12283c 100644 --- a/extern/storage-sealing/sealiface/config.go +++ b/extern/storage-sealing/sealiface/config.go @@ -43,7 +43,8 @@ type Config struct { CommitBatchWait time.Duration CommitBatchSlack time.Duration - AggregateAboveBaseFee abi.TokenAmount + AggregateAboveBaseFee abi.TokenAmount + BatchPreCommitAboveBaseFee abi.TokenAmount TerminateBatchMax uint64 TerminateBatchMin uint64 diff --git a/extern/storage-sealing/states_failed_test.go b/extern/storage-sealing/states_failed_test.go index 8613269b3..22c245afd 100644 --- a/extern/storage-sealing/states_failed_test.go +++ b/extern/storage-sealing/states_failed_test.go @@ -3,9 +3,12 @@ package sealing_test import ( "bytes" "context" - "errors" "testing" + "github.com/filecoin-project/go-state-types/network" + + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" + "github.com/golang/mock/gomock" "github.com/ipfs/go-cid" mh "github.com/multiformats/go-multihash" @@ -21,64 +24,6 @@ import ( "github.com/filecoin-project/lotus/extern/storage-sealing/mocks" ) -func TestStateRecoverDealIDsErredDealInfo(t *testing.T) { - mockCtrl := gomock.NewController(t) - defer mockCtrl.Finish() - - ctx := context.Background() - - api := mocks.NewMockSealingAPI(mockCtrl) - - fakeSealing := &sealing.Sealing{ - Api: api, - DealInfo: &sealing.CurrentDealInfoManager{CDAPI: api}, - } - - sctx := mocks.NewMockContext(mockCtrl) - sctx.EXPECT().Context().AnyTimes().Return(ctx) - - api.EXPECT().ChainHead(ctx).Times(1).Return(nil, abi.ChainEpoch(10), nil) - - var dealId abi.DealID = 12 - dealProposal := market.DealProposal{ - PieceCID: idCid("newPieceCID"), - } - - api.EXPECT().StateMarketStorageDealProposal(ctx, dealId, nil).Return(dealProposal, nil) - - pc := idCid("publishCID") - - // expect GetCurrentDealInfo - { - api.EXPECT().StateSearchMsg(ctx, pc).Return(&sealing.MsgLookup{ - Receipt: sealing.MessageReceipt{ - ExitCode: exitcode.Ok, - Return: cborRet(&market.PublishStorageDealsReturn{ - IDs: []abi.DealID{dealId}, - }), - }, - }, nil) - api.EXPECT().StateMarketStorageDeal(ctx, dealId, nil).Return(nil, errors.New("deal may not have completed sealing or slashed")) - } - - sctx.EXPECT().Send(sealing.SectorRemove{}).Return(nil) - - err := fakeSealing.HandleRecoverDealIDs(sctx, sealing.SectorInfo{ - Pieces: []sealing.Piece{ - { - DealInfo: &api2.PieceDealInfo{ - DealID: dealId, - PublishCid: &pc, - }, - Piece: abi.PieceInfo{ - PieceCID: idCid("oldPieceCID"), - }, - }, - }, - }) - require.NoError(t, err) -} - func TestStateRecoverDealIDs(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -111,11 +56,12 @@ func TestStateRecoverDealIDs(t *testing.T) { api.EXPECT().StateSearchMsg(ctx, pc).Return(&sealing.MsgLookup{ Receipt: sealing.MessageReceipt{ ExitCode: exitcode.Ok, - Return: cborRet(&market.PublishStorageDealsReturn{ + Return: cborRet(&market0.PublishStorageDealsReturn{ IDs: []abi.DealID{dealId}, }), }, }, nil) + api.EXPECT().StateNetworkVersion(ctx, nil).Return(network.Version0, nil) api.EXPECT().StateMarketStorageDeal(ctx, dealId, nil).Return(&api2.MarketDeal{ Proposal: dealProposal, }, nil) diff --git a/go.mod b/go.mod index 8f8b1e2fe..431aad90c 100644 --- a/go.mod +++ b/go.mod @@ -33,14 +33,14 @@ require ( github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 github.com/filecoin-project/go-commp-utils v0.1.1-0.20210427191551-70bf140d31c7 github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 - github.com/filecoin-project/go-data-transfer v1.11.0 + github.com/filecoin-project/go-data-transfer v1.11.1 github.com/filecoin-project/go-fil-commcid v0.1.0 github.com/filecoin-project/go-fil-commp-hashhash v0.1.0 - github.com/filecoin-project/go-fil-markets v1.13.0 + github.com/filecoin-project/go-fil-markets v1.13.1 github.com/filecoin-project/go-jsonrpc v0.1.4-0.20210217175800-45ea43ac2bec github.com/filecoin-project/go-padreader v0.0.0-20210723183308-812a16dc01b1 github.com/filecoin-project/go-paramfetch v0.0.2 - github.com/filecoin-project/go-state-types v0.1.1-0.20210810190654-139e0e79e69e + github.com/filecoin-project/go-state-types v0.1.1-0.20210915140513-d354ccf10379 github.com/filecoin-project/go-statemachine v1.0.1 github.com/filecoin-project/go-statestore v0.1.1 github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b @@ -49,6 +49,7 @@ require ( github.com/filecoin-project/specs-actors/v3 v3.1.1 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.0-20211001193936-c3afe7fa3c5c 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.0-beta.1 @@ -78,7 +79,7 @@ require ( github.com/ipfs/go-ds-pebble v0.0.2-0.20200921225637-ce220f8ac459 github.com/ipfs/go-filestore v1.0.0 github.com/ipfs/go-fs-lock v0.0.6 - github.com/ipfs/go-graphsync v0.10.0-rc3 + github.com/ipfs/go-graphsync v0.10.0 github.com/ipfs/go-ipfs-blockstore v1.0.4 github.com/ipfs/go-ipfs-blocksutil v0.0.1 github.com/ipfs/go-ipfs-chunker v0.0.5 diff --git a/go.sum b/go.sum index 9171c38fc..9d7b4162a 100644 --- a/go.sum +++ b/go.sum @@ -302,8 +302,8 @@ github.com/filecoin-project/go-commp-utils v0.1.1-0.20210427191551-70bf140d31c7/ 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-data-transfer v1.0.1/go.mod h1:UxvfUAY9v3ub0a21BSK9u3pB2aq30Y0KMsG+w9/ysyo= -github.com/filecoin-project/go-data-transfer v1.11.0 h1:b1gxCn66QfKjcOnZZfGFT2Sk/x6Kqg1C5RRU6VWHQHk= -github.com/filecoin-project/go-data-transfer v1.11.0/go.mod h1:W9IRDgaqmvrhLyV/nHhGvFWBuCq74SAEZNkqmSQbn54= +github.com/filecoin-project/go-data-transfer v1.11.1 h1:fiw2FHDVSDrt427cGp7+Ax3TTZk0e6HvF9Odcl2etBM= +github.com/filecoin-project/go-data-transfer v1.11.1/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= @@ -313,8 +313,8 @@ github.com/filecoin-project/go-fil-commcid v0.1.0/go.mod h1:Eaox7Hvus1JgPrL5+M3+ github.com/filecoin-project/go-fil-commp-hashhash v0.1.0 h1:imrrpZWEHRnNqqv0tN7LXep5bFEVOVmQWHJvl2mgsGo= github.com/filecoin-project/go-fil-commp-hashhash v0.1.0/go.mod h1:73S8WSEWh9vr0fDJVnKADhfIv/d6dCbAGaAGWbdJEI8= 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.13.0 h1:Ke7FGcJM9TKN617oqdmlF0Ffj0hzLgi+xhJCHqgL+JE= -github.com/filecoin-project/go-fil-markets v1.13.0/go.mod h1:8363CMUWSVu3AUPPO/2ppmchkpcLr9ch584sbDYHk3w= +github.com/filecoin-project/go-fil-markets v1.13.1 h1:KjarxgKp/RN4iYXT2pMcMq6veIa1guGJMoVtnwru4BQ= +github.com/filecoin-project/go-fil-markets v1.13.1/go.mod h1:58OjtsWtDt3xlN1QLmgDQxtfCDtDS4RIyHepIUbqXhM= 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= @@ -336,8 +336,9 @@ github.com/filecoin-project/go-state-types v0.0.0-20200928172055-2df22083d8ab/go github.com/filecoin-project/go-state-types v0.0.0-20201102161440-c8033295a1fc/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= 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 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 h1:UmKkt13NrtulubqfNXhG7SQ7Pjza8BeKdNBxngqAo64= +github.com/filecoin-project/go-state-types v0.1.1-0.20210915140513-d354ccf10379/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= @@ -364,6 +365,8 @@ 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-20211001193936-c3afe7fa3c5c h1:29m9oz0AP3TglBFC9Sii9M3skIAbhZhZr+2FyomSTTo= +github.com/filecoin-project/specs-actors/v6 v6.0.0-20211001193936-c3afe7fa3c5c/go.mod h1:V1AYfi5GkHXipx1mnVivoICZh3wtwPxDVuds+fbfQtk= 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= @@ -686,8 +689,8 @@ github.com/ipfs/go-fs-lock v0.0.6/go.mod h1:OTR+Rj9sHiRubJh3dRhD15Juhd/+w6VPOY28 github.com/ipfs/go-graphsync v0.1.0/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= github.com/ipfs/go-graphsync v0.4.2/go.mod h1:/VmbZTUdUMTbNkgzAiCEucIIAU3BkLE2cZrDCVUhyi0= github.com/ipfs/go-graphsync v0.4.3/go.mod h1:mPOwDYv128gf8gxPFgXnz4fNrSYPsWyqisJ7ych+XDY= -github.com/ipfs/go-graphsync v0.10.0-rc3 h1:rMu7cZ19JGLoqscBkLXJwkP2h1chHMLlJx450dFLCdQ= -github.com/ipfs/go-graphsync v0.10.0-rc3/go.mod h1:pA673SIspz4lHNAPgYxyMKXdpWcdIe5aL1OJCsCNejE= +github.com/ipfs/go-graphsync v0.10.0 h1:VXljS1ETYp1GmAJ6N45hlcKO+tlvPFUzz3xzEQ0jMbM= +github.com/ipfs/go-graphsync v0.10.0/go.mod h1:cKIshzTaa5rCZjryH5xmSKZVGX9uk1wvwGvz2WEha5Y= 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= @@ -814,7 +817,6 @@ github.com/ipld/go-ipld-prime v0.5.1-0.20201021195245-109253e8a018/go.mod h1:0xE github.com/ipld/go-ipld-prime v0.9.0/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.3-0.20210929125341-05d5528bd84e/go.mod h1:PaeLYq8k6dJLmDUSLrzkEpoGV4PEfe/1OtFN/eALOc8= 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 h1:furVobw7UBLQZwlEwfE26tYORy3PAK8VYSgZOSr3JMQ= github.com/ipld/go-ipld-prime v0.12.3/go.mod h1:PaeLYq8k6dJLmDUSLrzkEpoGV4PEfe/1OtFN/eALOc8= diff --git a/itests/deals_concurrent_test.go b/itests/deals_concurrent_test.go index ff8bab257..c0458e8d1 100644 --- a/itests/deals_concurrent_test.go +++ b/itests/deals_concurrent_test.go @@ -139,8 +139,8 @@ func TestSimultanenousTransferLimit(t *testing.T) { ) runTest := func(t *testing.T) { client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ConstructorOpts( - node.ApplyIf(node.IsType(repo.StorageMiner), node.Override(new(dtypes.StagingGraphsync), modules.StagingGraphsync(graphsyncThrottle))), - node.Override(new(dtypes.Graphsync), modules.Graphsync(graphsyncThrottle)), + node.ApplyIf(node.IsType(repo.StorageMiner), node.Override(new(dtypes.StagingGraphsync), modules.StagingGraphsync(graphsyncThrottle, graphsyncThrottle))), + node.Override(new(dtypes.Graphsync), modules.Graphsync(graphsyncThrottle, graphsyncThrottle)), )) ens.InterconnectAll().BeginMining(250 * time.Millisecond) dh := kit.NewDealHarness(t, client, miner, miner) diff --git a/itests/sector_miner_collateral_test.go b/itests/sector_miner_collateral_test.go index 891356ef1..de3da21f6 100644 --- a/itests/sector_miner_collateral_test.go +++ b/itests/sector_miner_collateral_test.go @@ -53,6 +53,7 @@ func TestMinerBalanceCollateral(t *testing.T) { AvailableBalanceBuffer: big.Zero(), DisableCollateralFallback: false, AggregateAboveBaseFee: big.Zero(), + BatchPreCommitAboveBaseFee: big.Zero(), }, nil }, nil })), diff --git a/lotuspond/front/src/chain/methods.json b/lotuspond/front/src/chain/methods.json index 5aced814a..c0f69d58c 100644 --- a/lotuspond/front/src/chain/methods.json +++ b/lotuspond/front/src/chain/methods.json @@ -516,5 +516,111 @@ "AddVerifiedClient", "UseBytes", "RestoreBytes" + ], + "fil/6/account": [ + "Send", + "Constructor", + "PubkeyAddress" + ], + "fil/6/cron": [ + "Send", + "Constructor", + "EpochTick" + ], + "fil/6/init": [ + "Send", + "Constructor", + "Exec" + ], + "fil/6/multisig": [ + "Send", + "Constructor", + "Propose", + "Approve", + "Cancel", + "AddSigner", + "RemoveSigner", + "SwapSigner", + "ChangeNumApprovalsThreshold", + "LockBalance" + ], + "fil/6/paymentchannel": [ + "Send", + "Constructor", + "UpdateChannelState", + "Settle", + "Collect" + ], + "fil/6/reward": [ + "Send", + "Constructor", + "AwardBlockReward", + "ThisEpochReward", + "UpdateNetworkKPI" + ], + "fil/6/storagemarket": [ + "Send", + "Constructor", + "AddBalance", + "WithdrawBalance", + "PublishStorageDeals", + "VerifyDealsForActivation", + "ActivateDeals", + "OnMinerSectorsTerminate", + "ComputeDataCommitment", + "CronTick" + ], + "fil/6/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" + ], + "fil/6/storagepower": [ + "Send", + "Constructor", + "CreateMiner", + "UpdateClaimedPower", + "EnrollCronEvent", + "OnEpochTickEnd", + "UpdatePledgeTotal", + "SubmitPoRepForBulkVerify", + "CurrentTotalPower" + ], + "fil/6/system": [ + "Send", + "Constructor" + ], + "fil/6/verifiedregistry": [ + "Send", + "Constructor", + "AddVerifier", + "RemoveVerifier", + "AddVerifiedClient", + "UseBytes", + "RestoreBytes" ] } \ No newline at end of file diff --git a/markets/storageadapter/client.go b/markets/storageadapter/client.go index 2ffa56f5f..75061b1c1 100644 --- a/markets/storageadapter/client.go +++ b/markets/storageadapter/client.go @@ -6,6 +6,9 @@ import ( "bytes" "context" + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" + builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin" + "github.com/ipfs/go-cid" "go.uber.org/fx" "golang.org/x/xerrors" @@ -19,9 +22,6 @@ import ( "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/exitcode" - miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" - market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market" - "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" marketactor "github.com/filecoin-project/lotus/chain/actors/builtin/market" @@ -108,10 +108,10 @@ func (c *ClientNodeAdapter) VerifySignature(ctx context.Context, sig crypto.Sign func (c *ClientNodeAdapter) AddFunds(ctx context.Context, addr address.Address, amount abi.TokenAmount) (cid.Cid, error) { // (Provider Node API) smsg, err := c.MpoolPushMessage(ctx, &types.Message{ - To: miner2.StorageMarketActorAddr, + To: marketactor.Address, From: addr, Value: amount, - Method: miner2.MethodsMarket.AddBalance, + Method: builtin6.MethodsMarket.AddBalance, }, nil) if err != nil { return cid.Undef, err @@ -171,19 +171,20 @@ func (c *ClientNodeAdapter) ValidatePublishedDeal(ctx context.Context, deal stor break } } + if !pubOk { return 0, xerrors.Errorf("deal wasn't published by storage provider: from=%s, provider=%s,%+v", pubmsg.From, deal.Proposal.Provider, pubAddrs) } - if pubmsg.To != miner2.StorageMarketActorAddr { + if pubmsg.To != marketactor.Address { return 0, xerrors.Errorf("deal publish message wasn't set to StorageMarket actor (to=%s)", pubmsg.To) } - if pubmsg.Method != miner2.MethodsMarket.PublishStorageDeals { + if pubmsg.Method != builtin6.MethodsMarket.PublishStorageDeals { return 0, xerrors.Errorf("deal publish message called incorrect method (method=%s)", pubmsg.Method) } - var params market2.PublishStorageDealsParams + var params marketactor.PublishStorageDealsParams if err := params.UnmarshalCBOR(bytes.NewReader(pubmsg.Params)); err != nil { return 0, err } @@ -215,12 +216,37 @@ func (c *ClientNodeAdapter) ValidatePublishedDeal(ctx context.Context, deal stor return 0, xerrors.Errorf("deal publish failed: exit=%d", ret.Receipt.ExitCode) } - var res market2.PublishStorageDealsReturn - if err := res.UnmarshalCBOR(bytes.NewReader(ret.Receipt.Return)); err != nil { - return 0, err + nv, err := c.StateNetworkVersion(ctx, ret.TipSet) + if err != nil { + return 0, xerrors.Errorf("getting network version: %w", err) } - return res.IDs[dealIdx], nil + res, err := marketactor.DecodePublishStorageDealsReturn(ret.Receipt.Return, nv) + if err != nil { + return 0, xerrors.Errorf("decoding deal publish return: %w", err) + } + + dealIDs, err := res.DealIDs() + if err != nil { + return 0, xerrors.Errorf("getting dealIDs: %w", err) + } + + if dealIdx >= len(dealIDs) { + return 0, xerrors.Errorf( + "deal index %d out of bounds of deals (len %d) in publish deals message %s", + dealIdx, len(dealIDs), pubmsg.Cid()) + } + + valid, err := res.IsDealValid(uint64(dealIdx)) + if err != nil { + return 0, xerrors.Errorf("determining deal validity: %w", err) + } + + if !valid { + return 0, xerrors.New("deal was invalid at publication") + } + + return dealIDs[dealIdx], nil } var clientOverestimation = struct { @@ -243,12 +269,12 @@ func (c *ClientNodeAdapter) DealProviderCollateralBounds(ctx context.Context, si } // TODO: Remove dealID parameter, change publishCid to be cid.Cid (instead of pointer) -func (c *ClientNodeAdapter) OnDealSectorPreCommitted(ctx context.Context, provider address.Address, dealID abi.DealID, proposal market2.DealProposal, publishCid *cid.Cid, cb storagemarket.DealSectorPreCommittedCallback) error { +func (c *ClientNodeAdapter) OnDealSectorPreCommitted(ctx context.Context, provider address.Address, dealID abi.DealID, proposal market0.DealProposal, publishCid *cid.Cid, cb storagemarket.DealSectorPreCommittedCallback) error { return c.scMgr.OnDealSectorPreCommitted(ctx, provider, marketactor.DealProposal(proposal), *publishCid, cb) } // TODO: Remove dealID parameter, change publishCid to be cid.Cid (instead of pointer) -func (c *ClientNodeAdapter) OnDealSectorCommitted(ctx context.Context, provider address.Address, dealID abi.DealID, sectorNumber abi.SectorNumber, proposal market2.DealProposal, publishCid *cid.Cid, cb storagemarket.DealSectorCommittedCallback) error { +func (c *ClientNodeAdapter) OnDealSectorCommitted(ctx context.Context, provider address.Address, dealID abi.DealID, sectorNumber abi.SectorNumber, proposal market0.DealProposal, publishCid *cid.Cid, cb storagemarket.DealSectorCommittedCallback) error { return c.scMgr.OnDealSectorCommitted(ctx, provider, sectorNumber, marketactor.DealProposal(proposal), *publishCid, cb) } @@ -342,7 +368,7 @@ func (c *ClientNodeAdapter) OnDealExpiredOrSlashed(ctx context.Context, dealID a return nil } -func (c *ClientNodeAdapter) SignProposal(ctx context.Context, signer address.Address, proposal market2.DealProposal) (*market2.ClientDealProposal, error) { +func (c *ClientNodeAdapter) SignProposal(ctx context.Context, signer address.Address, proposal market0.DealProposal) (*marketactor.ClientDealProposal, error) { // TODO: output spec signed proposal buf, err := cborutil.Dump(&proposal) if err != nil { @@ -361,7 +387,7 @@ func (c *ClientNodeAdapter) SignProposal(ctx context.Context, signer address.Add return nil, err } - return &market2.ClientDealProposal{ + return &marketactor.ClientDealProposal{ Proposal: proposal, ClientSignature: *sig, }, nil diff --git a/miner/miner.go b/miner/miner.go index 1727f6942..582ade723 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -10,6 +10,8 @@ import ( "sync" "time" + lrand "github.com/filecoin-project/lotus/chain/rand" + "github.com/filecoin-project/lotus/api/v1api" proof2 "github.com/filecoin-project/specs-actors/v2/actors/runtime/proof" @@ -27,7 +29,6 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/gen" - "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/journal" @@ -525,7 +526,7 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (minedBlock *type return nil, err } - rand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, round, buf.Bytes()) + rand, err := lrand.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, round, buf.Bytes()) if err != nil { err = xerrors.Errorf("failed to get randomness for winning post: %w", err) return nil, err @@ -590,7 +591,7 @@ func (m *Miner) computeTicket(ctx context.Context, brand *types.BeaconEntry, bas buf.Write(base.TipSet.MinTicket().VRFProof) } - input, err := store.DrawRandomness(brand.Data, crypto.DomainSeparationTag_TicketProduction, round-build.TicketRandomnessLookback, buf.Bytes()) + input, err := lrand.DrawRandomness(brand.Data, crypto.DomainSeparationTag_TicketProduction, round-build.TicketRandomnessLookback, buf.Bytes()) if err != nil { return nil, err } diff --git a/node/builder_chain.go b/node/builder_chain.go index 4137e3248..11283ec3a 100644 --- a/node/builder_chain.go +++ b/node/builder_chain.go @@ -100,7 +100,7 @@ var ChainNode = Options( Override(new(*dtypes.MpoolLocker), new(dtypes.MpoolLocker)), // Shared graphsync (markets, serving chain) - Override(new(dtypes.Graphsync), modules.Graphsync(config.DefaultFullNode().Client.SimultaneousTransfers)), + Override(new(dtypes.Graphsync), modules.Graphsync(config.DefaultFullNode().Client.SimultaneousTransfersForStorage, config.DefaultFullNode().Client.SimultaneousTransfersForRetrieval)), // Service: Wallet Override(new(*messagesigner.MessageSigner), messagesigner.NewMessageSigner), @@ -219,7 +219,7 @@ func ConfigFullNode(c interface{}) Option { Override(new(retrievalmarket.BlockstoreAccessor), modules.IpfsRetrievalBlockstoreAccessor), ), ), - Override(new(dtypes.Graphsync), modules.Graphsync(cfg.Client.SimultaneousTransfers)), + Override(new(dtypes.Graphsync), modules.Graphsync(cfg.Client.SimultaneousTransfersForStorage, cfg.Client.SimultaneousTransfersForRetrieval)), If(cfg.Wallet.RemoteBackend != "", Override(new(*remotewallet.RemoteWallet), remotewallet.SetupRemoteWallet(cfg.Wallet.RemoteBackend)), diff --git a/node/builder_miner.go b/node/builder_miner.go index ae0a61875..3447eb3e6 100644 --- a/node/builder_miner.go +++ b/node/builder_miner.go @@ -136,7 +136,7 @@ func ConfigStorageMiner(c interface{}) Option { If(cfg.Subsystems.EnableMarkets, // Markets Override(new(dtypes.StagingBlockstore), modules.StagingBlockstore), - Override(new(dtypes.StagingGraphsync), modules.StagingGraphsync(cfg.Dealmaking.SimultaneousTransfers)), + Override(new(dtypes.StagingGraphsync), modules.StagingGraphsync(cfg.Dealmaking.SimultaneousTransfersForStorage, cfg.Dealmaking.SimultaneousTransfersForRetrieval)), Override(new(dtypes.ProviderPieceStore), modules.NewProviderPieceStore), Override(new(*sectorblocks.SectorBlocks), sectorblocks.NewSectorBlocks), diff --git a/node/config/def.go b/node/config/def.go index 20444346a..735107e29 100644 --- a/node/config/def.go +++ b/node/config/def.go @@ -2,6 +2,8 @@ package config import ( "encoding" + "os" + "strconv" "time" "github.com/ipfs/go-cid" @@ -24,6 +26,16 @@ const ( RetrievalPricingExternalMode = "external" ) +// MaxTraversalLinks configures the maximum number of links to traverse in a DAG while calculating +// CommP and traversing a DAG with graphsync; invokes a budget on DAG depth and density. +var MaxTraversalLinks uint64 = 32 * (1 << 20) + +func init() { + if envMaxTraversal, err := strconv.ParseUint(os.Getenv("LOTUS_MAX_TRAVERSAL_LINKS"), 10, 64); err == nil { + MaxTraversalLinks = envMaxTraversal + } +} + func (b *BatchFeeConfig) FeeForSectors(nSectors int) abi.TokenAmount { return big.Add(big.Int(b.Base), big.Mul(big.NewInt(int64(nSectors)), big.Int(b.PerSector))) } @@ -65,7 +77,8 @@ func DefaultFullNode() *FullNode { DefaultMaxFee: DefaultDefaultMaxFee, }, Client: Client{ - SimultaneousTransfers: DefaultSimultaneousTransfers, + SimultaneousTransfersForStorage: DefaultSimultaneousTransfers, + SimultaneousTransfersForRetrieval: DefaultSimultaneousTransfers, }, Chainstore: Chainstore{ EnableSplitstore: false, @@ -109,7 +122,8 @@ func DefaultStorageMiner() *StorageMiner { CommitBatchWait: Duration(24 * time.Hour), // this can be up to 30 days CommitBatchSlack: Duration(1 * time.Hour), // time buffer for forceful batch submission before sectors/deals in batch would start expiring, higher value will lower the chances for message fail due to expiration - AggregateAboveBaseFee: types.FIL(types.BigMul(types.PicoFil, types.NewInt(150))), // 0.15 nFIL + BatchPreCommitAboveBaseFee: types.FIL(types.BigMul(types.PicoFil, types.NewInt(320))), // 0.32 nFIL + AggregateAboveBaseFee: types.FIL(types.BigMul(types.PicoFil, types.NewInt(320))), // 0.32 nFIL TerminateBatchMin: 1, TerminateBatchMax: 100, @@ -146,7 +160,8 @@ func DefaultStorageMiner() *StorageMiner { MaxDealsPerPublishMsg: 8, MaxProviderCollateralMultiplier: 2, - SimultaneousTransfers: DefaultSimultaneousTransfers, + SimultaneousTransfersForStorage: DefaultSimultaneousTransfers, + SimultaneousTransfersForRetrieval: DefaultSimultaneousTransfers, StartEpochSealingBuffer: 480, // 480 epochs buffer == 4 hours from adding deal to sector to sector being sealed diff --git a/node/config/doc_gen.go b/node/config/doc_gen.go index c8ac3f28f..296501edc 100644 --- a/node/config/doc_gen.go +++ b/node/config/doc_gen.go @@ -92,11 +92,18 @@ your node if metadata log is disabled`, Comment: ``, }, { - Name: "SimultaneousTransfers", + Name: "SimultaneousTransfersForStorage", Type: "uint64", Comment: `The maximum number of simultaneous data transfers between the client -and storage providers`, +and storage providers for storage deals`, + }, + { + Name: "SimultaneousTransfersForRetrieval", + Type: "uint64", + + Comment: `The maximum number of simultaneous data transfers between the client +and storage providers for retrieval deals`, }, }, "Common": []DocField{ @@ -260,10 +267,16 @@ as a multiplier of the minimum collateral bound`, passed to the sealing node by the markets service. 0 is unlimited.`, }, { - Name: "SimultaneousTransfers", + Name: "SimultaneousTransfersForStorage", Type: "uint64", - Comment: `The maximum number of parallel online data transfers (storage+retrieval)`, + Comment: `The maximum number of parallel online data transfers for storage deals`, + }, + { + Name: "SimultaneousTransfersForRetrieval", + Type: "uint64", + + Comment: `The maximum number of parallel online data transfers for retrieval deals`, }, { Name: "StartEpochSealingBuffer", @@ -717,6 +730,13 @@ avoid the relatively high cost of unsealing the data later, at the cost of more Comment: `time buffer for forceful batch submission before sectors/deals in batch would start expiring`, }, + { + Name: "BatchPreCommitAboveBaseFee", + Type: "types.FIL", + + Comment: `network BaseFee below which to stop doing precommit batching, instead +sending precommit messages to the chain individually`, + }, { Name: "AggregateAboveBaseFee", Type: "types.FIL", diff --git a/node/config/types.go b/node/config/types.go index aeaefd8ce..1be40029e 100644 --- a/node/config/types.go +++ b/node/config/types.go @@ -129,8 +129,10 @@ type DealmakingConfig struct { // The maximum allowed disk usage size in bytes of staging deals not yet // passed to the sealing node by the markets service. 0 is unlimited. MaxStagingDealsBytes int64 - // The maximum number of parallel online data transfers (storage+retrieval) - SimultaneousTransfers uint64 + // The maximum number of parallel online data transfers for storage deals + SimultaneousTransfersForStorage uint64 + // The maximum number of parallel online data transfers for retrieval deals + SimultaneousTransfersForRetrieval uint64 // Minimum start epoch buffer to give time for sealing of sector with deal. StartEpochSealingBuffer uint64 @@ -221,6 +223,10 @@ type SealingConfig struct { // time buffer for forceful batch submission before sectors/deals in batch would start expiring CommitBatchSlack Duration + // network BaseFee below which to stop doing precommit batching, instead + // sending precommit messages to the chain individually + BatchPreCommitAboveBaseFee types.FIL + // network BaseFee below which to stop doing commit aggregation, instead // submitting proofs to the chain individually AggregateAboveBaseFee types.FIL @@ -360,8 +366,11 @@ type Client struct { IpfsMAddr string IpfsUseForRetrieval bool // The maximum number of simultaneous data transfers between the client - // and storage providers - SimultaneousTransfers uint64 + // and storage providers for storage deals + SimultaneousTransfersForStorage uint64 + // The maximum number of simultaneous data transfers between the client + // and storage providers for retrieval deals + SimultaneousTransfersForRetrieval uint64 } type Wallet struct { diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 09f52280b..303a038a3 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -59,6 +59,7 @@ import ( "github.com/filecoin-project/specs-actors/v3/actors/builtin/market" marketevents "github.com/filecoin-project/lotus/markets/loggers" + "github.com/filecoin-project/lotus/node/config" "github.com/filecoin-project/lotus/node/repo/imports" "github.com/filecoin-project/lotus/api" @@ -1011,6 +1012,7 @@ func (a *API) clientRetrieve(ctx context.Context, order api.RetrievalOrder, ref Root: order.Root, Selector: sel, }}, + car.MaxTraversalLinks(config.MaxTraversalLinks), ).Write(f) if err != nil { finish(err) @@ -1302,7 +1304,11 @@ func (a *API) ClientGenCar(ctx context.Context, ref api.FileRef, outputPath stri allSelector := ssb.ExploreRecursive( selector.RecursionLimitNone(), ssb.ExploreAll(ssb.ExploreRecursiveEdge())).Node() - sc := car.NewSelectiveCar(ctx, fs, []car.Dag{{Root: root, Selector: allSelector}}) + sc := car.NewSelectiveCar(ctx, + fs, + []car.Dag{{Root: root, Selector: allSelector}}, + car.MaxTraversalLinks(config.MaxTraversalLinks), + ) f, err := os.Create(outputPath) if err != nil { return err diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 2981c0162..e251fa3d5 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -1422,32 +1422,10 @@ func (m *StateModule) StateNetworkVersion(ctx context.Context, tsk types.TipSetK } func (a *StateAPI) StateGetRandomnessFromTickets(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte, tsk types.TipSetKey) (abi.Randomness, error) { - pts, err := a.Chain.LoadTipSet(tsk) - if err != nil { - return nil, xerrors.Errorf("loading tipset key: %w", err) - } - - rnv := a.StateManager.GetNtwkVersion(ctx, randEpoch) - - if rnv >= network.Version13 { - return a.Chain.GetChainRandomnessLookingForward(ctx, pts.Cids(), personalization, randEpoch, entropy) - } - - return a.Chain.GetChainRandomnessLookingBack(ctx, pts.Cids(), personalization, randEpoch, entropy) + return a.StateManager.GetRandomnessFromTickets(ctx, personalization, randEpoch, entropy, tsk) } func (a *StateAPI) StateGetRandomnessFromBeacon(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte, tsk types.TipSetKey) (abi.Randomness, error) { - pts, err := a.Chain.GetTipSetFromKey(tsk) - if err != nil { - return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) - } - - rnv := a.StateManager.GetNtwkVersion(ctx, randEpoch) - - if rnv >= network.Version13 { - return a.Chain.GetBeaconRandomnessLookingForward(ctx, pts.Cids(), personalization, randEpoch, entropy) - } - - return a.Chain.GetBeaconRandomnessLookingBack(ctx, pts.Cids(), personalization, randEpoch, entropy) + return a.StateManager.GetRandomnessFromBeacon(ctx, personalization, randEpoch, entropy, tsk) } diff --git a/node/modules/chain.go b/node/modules/chain.go index f9baf76cf..3518c3b29 100644 --- a/node/modules/chain.go +++ b/node/modules/chain.go @@ -120,7 +120,7 @@ func NetworkName(mctx helpers.MetricsCtx, ctx := helpers.LifecycleCtx(mctx, lc) - sm, err := stmgr.NewStateManager(cs, tsexec, syscalls, us) + sm, err := stmgr.NewStateManager(cs, tsexec, syscalls, us, nil) if err != nil { return "", err } diff --git a/node/modules/client.go b/node/modules/client.go index 0a1c1039b..4d988d98a 100644 --- a/node/modules/client.go +++ b/node/modules/client.go @@ -36,6 +36,7 @@ import ( "github.com/filecoin-project/lotus/markets" marketevents "github.com/filecoin-project/lotus/markets/loggers" "github.com/filecoin-project/lotus/markets/retrievaladapter" + "github.com/filecoin-project/lotus/node/config" "github.com/filecoin-project/lotus/node/impl/full" payapi "github.com/filecoin-project/lotus/node/impl/paych" "github.com/filecoin-project/lotus/node/modules/dtypes" @@ -182,7 +183,7 @@ func StorageClient(lc fx.Lifecycle, h host.Host, dataTransfer dtypes.ClientDataT marketsRetryParams := smnet.RetryParameters(time.Second, 5*time.Minute, 15, 5) net := smnet.NewFromLibp2pHost(h, marketsRetryParams) - c, err := storageimpl.NewClient(net, dataTransfer, discovery, deals, scn, accessor, storageimpl.DealPollingInterval(time.Second)) + c, err := storageimpl.NewClient(net, dataTransfer, discovery, deals, scn, accessor, storageimpl.DealPollingInterval(time.Second), storageimpl.MaxTraversalLinks(config.MaxTraversalLinks)) if err != nil { return nil, err } diff --git a/node/modules/graphsync.go b/node/modules/graphsync.go index ff2b41867..839508900 100644 --- a/node/modules/graphsync.go +++ b/node/modules/graphsync.go @@ -9,18 +9,26 @@ import ( "github.com/libp2p/go-libp2p-core/peer" "go.uber.org/fx" + "github.com/filecoin-project/lotus/node/config" "github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/lotus/node/modules/helpers" "github.com/filecoin-project/lotus/node/repo" ) // Graphsync creates a graphsync instance from the given loader and storer -func Graphsync(parallelTransfers uint64) func(mctx helpers.MetricsCtx, lc fx.Lifecycle, r repo.LockedRepo, clientBs dtypes.ClientBlockstore, chainBs dtypes.ExposedBlockstore, h host.Host) (dtypes.Graphsync, error) { +func Graphsync(parallelTransfersForStorage uint64, parallelTransfersForRetrieval uint64) func(mctx helpers.MetricsCtx, lc fx.Lifecycle, r repo.LockedRepo, clientBs dtypes.ClientBlockstore, chainBs dtypes.ExposedBlockstore, h host.Host) (dtypes.Graphsync, error) { return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, r repo.LockedRepo, clientBs dtypes.ClientBlockstore, chainBs dtypes.ExposedBlockstore, h host.Host) (dtypes.Graphsync, error) { graphsyncNetwork := gsnet.NewFromLibp2pHost(h) lsys := storeutil.LinkSystemForBlockstore(clientBs) - gs := graphsyncimpl.New(helpers.LifecycleCtx(mctx, lc), graphsyncNetwork, lsys, graphsyncimpl.RejectAllRequestsByDefault(), graphsyncimpl.MaxInProgressIncomingRequests(parallelTransfers)) + gs := graphsyncimpl.New(helpers.LifecycleCtx(mctx, lc), + graphsyncNetwork, + lsys, + graphsyncimpl.RejectAllRequestsByDefault(), + graphsyncimpl.MaxInProgressIncomingRequests(parallelTransfersForStorage), + graphsyncimpl.MaxInProgressOutgoingRequests(parallelTransfersForRetrieval), + graphsyncimpl.MaxLinksPerIncomingRequests(config.MaxTraversalLinks), + graphsyncimpl.MaxLinksPerOutgoingRequests(config.MaxTraversalLinks)) chainLinkSystem := storeutil.LinkSystemForBlockstore(chainBs) err := gs.RegisterPersistenceOption("chainstore", chainLinkSystem) if err != nil { diff --git a/node/modules/stmgr.go b/node/modules/stmgr.go index d2f812ad4..daef52b42 100644 --- a/node/modules/stmgr.go +++ b/node/modules/stmgr.go @@ -1,6 +1,7 @@ package modules import ( + "github.com/filecoin-project/lotus/chain/beacon" "github.com/filecoin-project/lotus/chain/vm" "go.uber.org/fx" @@ -8,8 +9,8 @@ import ( "github.com/filecoin-project/lotus/chain/store" ) -func StateManager(lc fx.Lifecycle, cs *store.ChainStore, exec stmgr.Executor, sys vm.SyscallBuilder, us stmgr.UpgradeSchedule) (*stmgr.StateManager, error) { - sm, err := stmgr.NewStateManager(cs, exec, sys, us) +func StateManager(lc fx.Lifecycle, cs *store.ChainStore, exec stmgr.Executor, sys vm.SyscallBuilder, us stmgr.UpgradeSchedule, b beacon.Schedule) (*stmgr.StateManager, error) { + sm, err := stmgr.NewStateManager(cs, exec, sys, us, b) if err != nil { return nil, err } diff --git a/node/modules/storageminer.go b/node/modules/storageminer.go index f5dd1ad9a..b32cbe9e0 100644 --- a/node/modules/storageminer.go +++ b/node/modules/storageminer.go @@ -38,6 +38,7 @@ import ( "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/namespace" graphsync "github.com/ipfs/go-graphsync/impl" + graphsyncimpl "github.com/ipfs/go-graphsync/impl" gsnet "github.com/ipfs/go-graphsync/network" "github.com/ipfs/go-graphsync/storeutil" "github.com/libp2p/go-libp2p-core/host" @@ -394,11 +395,18 @@ func StagingBlockstore(lc fx.Lifecycle, mctx helpers.MetricsCtx, r repo.LockedRe // StagingGraphsync creates a graphsync instance which reads and writes blocks // to the StagingBlockstore -func StagingGraphsync(parallelTransfers uint64) func(mctx helpers.MetricsCtx, lc fx.Lifecycle, ibs dtypes.StagingBlockstore, h host.Host) dtypes.StagingGraphsync { +func StagingGraphsync(parallelTransfersForStorage uint64, parallelTransfersForRetrieval uint64) func(mctx helpers.MetricsCtx, lc fx.Lifecycle, ibs dtypes.StagingBlockstore, h host.Host) dtypes.StagingGraphsync { return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, ibs dtypes.StagingBlockstore, h host.Host) dtypes.StagingGraphsync { graphsyncNetwork := gsnet.NewFromLibp2pHost(h) lsys := storeutil.LinkSystemForBlockstore(ibs) - gs := graphsync.New(helpers.LifecycleCtx(mctx, lc), graphsyncNetwork, lsys, graphsync.RejectAllRequestsByDefault(), graphsync.MaxInProgressIncomingRequests(parallelTransfers)) + gs := graphsync.New(helpers.LifecycleCtx(mctx, lc), + graphsyncNetwork, + lsys, + graphsync.RejectAllRequestsByDefault(), + graphsync.MaxInProgressIncomingRequests(parallelTransfersForRetrieval), + graphsync.MaxInProgressOutgoingRequests(parallelTransfersForStorage), + graphsyncimpl.MaxLinksPerIncomingRequests(config.MaxTraversalLinks), + graphsyncimpl.MaxLinksPerOutgoingRequests(config.MaxTraversalLinks)) return gs } @@ -887,12 +895,13 @@ func NewSetSealConfigFunc(r repo.LockedRepo) (dtypes.SetSealingConfigFunc, error PreCommitBatchWait: config.Duration(cfg.PreCommitBatchWait), PreCommitBatchSlack: config.Duration(cfg.PreCommitBatchSlack), - AggregateCommits: cfg.AggregateCommits, - MinCommitBatch: cfg.MinCommitBatch, - MaxCommitBatch: cfg.MaxCommitBatch, - CommitBatchWait: config.Duration(cfg.CommitBatchWait), - CommitBatchSlack: config.Duration(cfg.CommitBatchSlack), - AggregateAboveBaseFee: types.FIL(cfg.AggregateAboveBaseFee), + AggregateCommits: cfg.AggregateCommits, + MinCommitBatch: cfg.MinCommitBatch, + MaxCommitBatch: cfg.MaxCommitBatch, + CommitBatchWait: config.Duration(cfg.CommitBatchWait), + CommitBatchSlack: config.Duration(cfg.CommitBatchSlack), + AggregateAboveBaseFee: types.FIL(cfg.AggregateAboveBaseFee), + BatchPreCommitAboveBaseFee: types.FIL(cfg.BatchPreCommitAboveBaseFee), TerminateBatchMax: cfg.TerminateBatchMax, TerminateBatchMin: cfg.TerminateBatchMin, @@ -922,12 +931,13 @@ func ToSealingConfig(cfg *config.StorageMiner) sealiface.Config { PreCommitBatchWait: time.Duration(cfg.Sealing.PreCommitBatchWait), PreCommitBatchSlack: time.Duration(cfg.Sealing.PreCommitBatchSlack), - AggregateCommits: cfg.Sealing.AggregateCommits, - MinCommitBatch: cfg.Sealing.MinCommitBatch, - MaxCommitBatch: cfg.Sealing.MaxCommitBatch, - CommitBatchWait: time.Duration(cfg.Sealing.CommitBatchWait), - CommitBatchSlack: time.Duration(cfg.Sealing.CommitBatchSlack), - AggregateAboveBaseFee: types.BigInt(cfg.Sealing.AggregateAboveBaseFee), + AggregateCommits: cfg.Sealing.AggregateCommits, + MinCommitBatch: cfg.Sealing.MinCommitBatch, + MaxCommitBatch: cfg.Sealing.MaxCommitBatch, + CommitBatchWait: time.Duration(cfg.Sealing.CommitBatchWait), + CommitBatchSlack: time.Duration(cfg.Sealing.CommitBatchSlack), + AggregateAboveBaseFee: types.BigInt(cfg.Sealing.AggregateAboveBaseFee), + BatchPreCommitAboveBaseFee: types.BigInt(cfg.Sealing.BatchPreCommitAboveBaseFee), TerminateBatchMax: cfg.Sealing.TerminateBatchMax, TerminateBatchMin: cfg.Sealing.TerminateBatchMin, diff --git a/testplans/lotus-soup/go.mod b/testplans/lotus-soup/go.mod index 2a51ed104..7f4a53630 100644 --- a/testplans/lotus-soup/go.mod +++ b/testplans/lotus-soup/go.mod @@ -11,7 +11,7 @@ require ( 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.20210810190654-139e0e79e69e + github.com/filecoin-project/go-state-types v0.1.1-0.20210915140513-d354ccf10379 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 diff --git a/tools/packer/repo/config.toml b/tools/packer/repo/config.toml index 4a4fb510e..900dad218 100644 --- a/tools/packer/repo/config.toml +++ b/tools/packer/repo/config.toml @@ -20,7 +20,8 @@ ListenAddresses = ["/ip4/0.0.0.0/tcp/5678", "/ip6/::/tcp/5678"] # IpfsOnlineMode = false # IpfsMAddr = "" # IpfsUseForRetrieval = false -# SimultaneousTransfers = 20 +# SimultaneousTransfersForStorage = 20 +# SimultaneousTransfersForRetrieval = 20 # [Metrics] # Nickname = ""