diff --git a/.circleci/config.yml b/.circleci/config.yml index 4fdb3e38f..acd447f69 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -254,6 +254,25 @@ jobs: path: /tmp/test-reports - store_artifacts: path: /tmp/test-artifacts/conformance-coverage.html + build-lotus-soup: + description: | + Compile `lotus-soup` Testground test plan using the current version of Lotus. + parameters: + <<: *test-params + executor: << parameters.executor >> + steps: + - install-deps + - prepare + - run: cd extern/oni && git submodule sync + - run: cd extern/oni && git submodule update --init + - run: cd extern/filecoin-ffi && make + - run: + name: "replace lotus, filecoin-ffi, blst and fil-blst deps" + command: cd extern/oni/lotus-soup && go mod edit -replace github.com/filecoin-project/lotus=../../../ && go mod edit -replace github.com/filecoin-project/filecoin-ffi=../../filecoin-ffi && go mod edit -replace github.com/supranational/blst=../../fil-blst/blst && go mod edit -replace github.com/filecoin-project/fil-blst=../../fil-blst + - run: + name: "build lotus-soup testplan" + command: pushd extern/oni/lotus-soup && go build -tags=testground . + build-macos: description: build darwin lotus binary @@ -428,6 +447,7 @@ workflows: test-suite-name: conformance-bleeding-edge packages: "./conformance" vectors-branch: master + - build-lotus-soup - build-debug - build-all: requires: diff --git a/.gitignore b/.gitignore index 940f37b3f..05f762d8d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ /lotus-stats /lotus-bench /lotus-gateway +/lotus-pcr /bench.json /lotuspond/front/node_modules /lotuspond/front/build diff --git a/.gitmodules b/.gitmodules index 4b450aaf3..35f5a3d3f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -11,3 +11,6 @@ [submodule "extern/fil-blst"] path = extern/fil-blst url = https://github.com/filecoin-project/fil-blst.git +[submodule "extern/oni"] + path = extern/oni + url = https://github.com/filecoin-project/oni diff --git a/CHANGELOG.md b/CHANGELOG.md index 8617554a9..16ced709b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,64 @@ # Lotus changelog +# 0.7.2 / 2020-09-23 + +This optional release of Lotus introduces a major refactor around how a Lotus node interacts with code from the specs-actors repo. We now use interfaces to read the state of actors, which is required to be able to reason about different versions of actors code at the same time. + +Additionally, this release introduces various improvements to the sync process, as well as changes to better the overall UX experience. + +## Changes + +#### Core Lotus + +- Network upgrade support (https://github.com/filecoin-project/lotus/pull/3781) +- Upgrade markets to `v0.6.2` (https://github.com/filecoin-project/lotus/pull/3974) +- Validate chain sync response indices when fetching messages (https://github.com/filecoin-project/lotus/pull/3939) +- Add height diff to sync wait (https://github.com/filecoin-project/lotus/pull/3926) +- Replace Requires with Wants (https://github.com/filecoin-project/lotus/pull/3898) +- Update state diffing for market actor (https://github.com/filecoin-project/lotus/pull/3889) +- Parallel fetch for sync (https://github.com/filecoin-project/lotus/pull/3887) +- Fix SectorState (https://github.com/filecoin-project/lotus/pull/3881) + +#### User Experience + +- Add basic deal stats api server for spacerace slingshot (https://github.com/filecoin-project/lotus/pull/3963) +- When doing `sectors update-state`, show a list of existing states if user inputs an invalid one (https://github.com/filecoin-project/lotus/pull/3944) +- Fix `lotus-miner storage find` error (https://github.com/filecoin-project/lotus/pull/3927) +- Log shutdown method for lotus daemon and miner (https://github.com/filecoin-project/lotus/pull/3925) +- Update build and setup instruction link (https://github.com/filecoin-project/lotus/pull/3919) +- Add an option to hide removed sectors from `sectors list` output (https://github.com/filecoin-project/lotus/pull/3903) + +#### Testing and validation + +- Add init.State#Remove() for testing (https://github.com/filecoin-project/lotus/pull/3971) +- lotus-shed: add consensus check command (https://github.com/filecoin-project/lotus/pull/3933) +- Add keyinfo verify and jwt token command to lotus-shed (https://github.com/filecoin-project/lotus/pull/3914) +- Fix conformance gen (https://github.com/filecoin-project/lotus/pull/3892) + +# 0.7.1 / 2020-09-17 + +This optional release of Lotus introduces some critical fixes to the window PoSt process. It also upgrades some core dependencies, and introduces many improvements to the mining process, deal-making cycle, and overall User Experience. + +## Changes + +#### Some notable improvements: + +- Correctly construct params for `SubmitWindowedPoSt` messages (https://github.com/filecoin-project/lotus/pull/3909) +- Skip sectors correctly for Window PoSt (https://github.com/filecoin-project/lotus/pull/3839) +- Split window PoST submission into multiple messages (https://github.com/filecoin-project/lotus/pull/3689) +- Improve journal coverage (https://github.com/filecoin-project/lotus/pull/2455) +- Allow retrievals while sealing (https://github.com/filecoin-project/lotus/pull/3778) +- Don't prune locally published messages (https://github.com/filecoin-project/lotus/pull/3772) +- Add get-ask, set-ask retrieval commands (https://github.com/filecoin-project/lotus/pull/3886) +- Consistently name winning and window post in logs (https://github.com/filecoin-project/lotus/pull/3873)) +- Add auto flag to mpool replace (https://github.com/filecoin-project/lotus/pull/3752)) + +#### Dependencies + +- Upgrade markets to `v0.6.1` (https://github.com/filecoin-project/lotus/pull/3906) +- Upgrade specs-actors to `v0.9.10` (https://github.com/filecoin-project/lotus/pull/3846) +- Upgrade badger (https://github.com/filecoin-project/lotus/pull/3739) + # 0.7.0 / 2020-09-10 This consensus-breaking release of Lotus is designed to test a network upgrade on the space race testnet. The changes that break consensus are: diff --git a/README.md b/README.md index 6c1e23efa..766317e4f 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Lotus is an implementation of the Filecoin Distributed Storage Network. For more ## Building & Documentation -For instructions on how to build lotus from source, please visit [https://lotu.sh](https://lotu.sh) or read the source [here](https://github.com/filecoin-project/lotus/tree/master/documentation). +For instructions on how to build lotus from source, please visit [Lotus build and setup instruction](https://docs.filecoin.io/get-started/lotus/installation/#minimal-requirements) or read the source [here](https://github.com/filecoin-project/lotus/tree/master/documentation). ## Reporting a Vulnerability diff --git a/api/api_full.go b/api/api_full.go index dace85ed3..6d2d0c7b5 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -5,9 +5,7 @@ import ( "fmt" "time" - "github.com/filecoin-project/go-state-types/dline" - - "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/filecoin-project/go-state-types/network" "github.com/ipfs/go-cid" "github.com/libp2p/go-libp2p-core/peer" @@ -20,12 +18,13 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" - "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/lotus/chain/actors/builtin/market" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" + "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors/builtin/power" "github.com/filecoin-project/lotus/chain/types" marketevents "github.com/filecoin-project/lotus/markets/loggers" "github.com/filecoin-project/lotus/node/modules/dtypes" @@ -77,6 +76,9 @@ type FullNode interface { // blockstore and returns raw bytes. ChainReadObj(context.Context, cid.Cid) ([]byte, error) + // ChainDeleteObj deletes node referenced by the given CID + ChainDeleteObj(context.Context, cid.Cid) error + // ChainHasObj checks if a given CID exists in the chain blockstore. ChainHasObj(context.Context, cid.Cid) (bool, error) @@ -231,7 +233,7 @@ type FullNode interface { WalletSignMessage(context.Context, address.Address, *types.Message) (*types.SignedMessage, error) // WalletVerify takes an address, a signature, and some bytes, and indicates whether the signature is valid. // The address does not have to be in the wallet. - WalletVerify(context.Context, address.Address, []byte, *crypto.Signature) bool + WalletVerify(context.Context, address.Address, []byte, *crypto.Signature) (bool, error) // WalletDefaultAddress returns the address marked as default in the wallet. WalletDefaultAddress(context.Context) (address.Address, error) // WalletSetDefault marks the given address as as the default one. @@ -314,22 +316,20 @@ type FullNode interface { // StateNetworkName returns the name of the network the node is synced to StateNetworkName(context.Context) (dtypes.NetworkName, error) // StateMinerSectors returns info about the given miner's sectors. If the filter bitfield is nil, all sectors are included. - // If the filterOut boolean is set to true, any sectors in the filter are excluded. - // If false, only those sectors in the filter are included. - StateMinerSectors(context.Context, address.Address, *bitfield.BitField, bool, types.TipSetKey) ([]*ChainSectorInfo, error) + StateMinerSectors(context.Context, address.Address, *bitfield.BitField, types.TipSetKey) ([]*miner.SectorOnChainInfo, error) // StateMinerActiveSectors returns info about sectors that a given miner is actively proving. - StateMinerActiveSectors(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error) + StateMinerActiveSectors(context.Context, address.Address, types.TipSetKey) ([]*miner.SectorOnChainInfo, error) // StateMinerProvingDeadline calculates the deadline at some epoch for a proving period // and returns the deadline-related calculations. StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*dline.Info, error) // StateMinerPower returns the power of the indicated miner StateMinerPower(context.Context, address.Address, types.TipSetKey) (*MinerPower, error) // StateMinerInfo returns info about the indicated miner - StateMinerInfo(context.Context, address.Address, types.TipSetKey) (MinerInfo, error) + StateMinerInfo(context.Context, address.Address, types.TipSetKey) (miner.MinerInfo, error) // StateMinerDeadlines returns all the proving deadlines for the given miner - StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) ([]*miner.Deadline, error) - // StateMinerPartitions loads miner partitions for the specified miner/deadline - StateMinerPartitions(context.Context, address.Address, uint64, types.TipSetKey) ([]*miner.Partition, error) + StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) ([]Deadline, error) + // StateMinerPartitions returns all partitions in the specified deadline + StateMinerPartitions(ctx context.Context, m address.Address, dlIdx uint64, tsk types.TipSetKey) ([]Partition, error) // StateMinerFaults returns a bitfield indicating the faulty sectors of the given miner StateMinerFaults(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error) // StateAllMinerFaults returns all non-expired Faults that occur within lookback epochs of the given tipset @@ -349,9 +349,9 @@ type FullNode interface { // expiration epoch StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error) // StateSectorExpiration returns epoch at which given sector will expire - StateSectorExpiration(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*SectorExpiration, error) + StateSectorExpiration(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorExpiration, error) // StateSectorPartition finds deadline/partition with the specified sector - StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*SectorLocation, error) + StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*miner.SectorLocation, error) // StateSearchMsg searches for a message in the chain, and returns its receipt and the tipset where it was executed StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error) // StateMsgGasCost searches for a message in the chain, and returns details of the messages gas costs, including the penalty and miner tip @@ -388,13 +388,15 @@ type FullNode interface { // StateVerifiedClientStatus returns the data cap for the given address. // Returns nil if there is no entry in the data cap table for the // address. - StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*verifreg.DataCap, error) + StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) // StateDealProviderCollateralBounds returns the min and max collateral a storage provider // can issue. It takes the deal size and verified status as parameters. StateDealProviderCollateralBounds(context.Context, abi.PaddedPieceSize, bool, types.TipSetKey) (DealCollateralBounds, error) // StateCirculatingSupply returns the circulating supply of Filecoin at the given tipset StateCirculatingSupply(context.Context, types.TipSetKey) (CirculatingSupply, error) + // StateNetworkVersion returns the network version at the given tipset + StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error) // MethodGroup: Msig // The Msig methods are used to interact with multisig wallets on the @@ -476,21 +478,12 @@ type FileRef struct { } type MinerSectors struct { - Sectors uint64 - Active uint64 -} - -type SectorExpiration struct { - OnTime abi.ChainEpoch - - // non-zero if sector is faulty, epoch at which it will be permanently - // removed if it doesn't recover - Early abi.ChainEpoch -} - -type SectorLocation struct { - Deadline uint64 - Partition uint64 + // Live sectors that should be proven. + Live uint64 + // Sectors actively contributing to power. + Active uint64 + // Sectors with failed proofs. + Faulty uint64 } type ImportRes struct { @@ -556,11 +549,6 @@ type Message struct { Message *types.Message } -type ChainSectorInfo struct { - Info miner.SectorOnChainInfo - ID abi.SectorNumber -} - type ActorState struct { Balance types.BigInt State interface{} @@ -632,8 +620,9 @@ type VoucherCreateResult struct { } type MinerPower struct { - MinerPower power.Claim - TotalPower power.Claim + MinerPower power.Claim + TotalPower power.Claim + HasMinPower bool } type QueryOffer struct { @@ -736,6 +725,8 @@ type ActiveSync struct { type SyncState struct { ActiveSyncs []ActiveSync + + VMApplied uint64 } type SyncStateStage int @@ -802,7 +793,7 @@ type CirculatingSupply struct { type MiningBaseInfo struct { MinerPower types.BigInt NetworkPower types.BigInt - Sectors []proof.SectorInfo + Sectors []builtin.SectorInfo WorkerKey address.Address SectorSize abi.SectorSize PrevBeaconEntry types.BeaconEntry @@ -819,7 +810,7 @@ type BlockTemplate struct { Messages []*types.SignedMessage Epoch abi.ChainEpoch Timestamp uint64 - WinningPoStProof []proof.PoStProof + WinningPoStProof []builtin.PoStProof } type DataSize struct { @@ -843,6 +834,18 @@ const ( MsigCancel ) +type Deadline struct { + PostSubmissions bitfield.BitField +} + +type Partition struct { + AllSectors bitfield.BitField + FaultySectors bitfield.BitField + RecoveringSectors bitfield.BitField + LiveSectors bitfield.BitField + ActiveSectors bitfield.BitField +} + type Fault struct { Miner address.Address Epoch abi.ChainEpoch diff --git a/api/api_storage.go b/api/api_storage.go index 37bef2d6c..824772181 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -71,7 +71,7 @@ type StorageMiner interface { stores.SectorIndex MarketImportDealData(ctx context.Context, propcid cid.Cid, path string) error - MarketListDeals(ctx context.Context) ([]storagemarket.StorageDeal, error) + MarketListDeals(ctx context.Context) ([]MarketDeal, error) MarketListRetrievalDeals(ctx context.Context) ([]retrievalmarket.ProviderDealState, error) MarketGetDealUpdates(ctx context.Context) (<-chan storagemarket.MinerDeal, error) MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, error) @@ -83,7 +83,7 @@ type StorageMiner interface { MarketDataTransferUpdates(ctx context.Context) (<-chan DataTransferChannel, error) DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error - DealsList(ctx context.Context) ([]storagemarket.StorageDeal, error) + DealsList(ctx context.Context) ([]MarketDeal, error) DealsConsiderOnlineStorageDeals(context.Context) (bool, error) DealsSetConsiderOnlineStorageDeals(context.Context, bool) error DealsConsiderOnlineRetrievalDeals(context.Context) (bool, error) diff --git a/api/api_test.go b/api/api_test.go index 1b438258a..34c47f432 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -1,12 +1,16 @@ package api import ( + "encoding/json" "os" "os/exec" "path/filepath" + "reflect" "runtime" "strings" "testing" + + "github.com/stretchr/testify/require" ) func goCmd() string { @@ -32,3 +36,68 @@ func TestDoesntDependOnFFI(t *testing.T) { } } } + +func TestReturnTypes(t *testing.T) { + errType := reflect.TypeOf(new(error)).Elem() + bareIface := reflect.TypeOf(new(interface{})).Elem() + jmarsh := reflect.TypeOf(new(json.Marshaler)).Elem() + + tst := func(api interface{}) func(t *testing.T) { + return func(t *testing.T) { + ra := reflect.TypeOf(api).Elem() + for i := 0; i < ra.NumMethod(); i++ { + m := ra.Method(i) + switch m.Type.NumOut() { + case 1: // if 1 return value, it must be an error + require.Equal(t, errType, m.Type.Out(0), m.Name) + + case 2: // if 2 return values, first cant be an interface/function, second must be an error + seen := map[reflect.Type]struct{}{} + todo := []reflect.Type{m.Type.Out(0)} + for len(todo) > 0 { + typ := todo[len(todo)-1] + todo = todo[:len(todo)-1] + + if _, ok := seen[typ]; ok { + continue + } + seen[typ] = struct{}{} + + if typ.Kind() == reflect.Interface && typ != bareIface && !typ.Implements(jmarsh) { + t.Error("methods can't return interfaces", m.Name) + } + + switch typ.Kind() { + case reflect.Ptr: + fallthrough + case reflect.Array: + fallthrough + case reflect.Slice: + fallthrough + case reflect.Chan: + todo = append(todo, typ.Elem()) + case reflect.Map: + todo = append(todo, typ.Elem()) + todo = append(todo, typ.Key()) + case reflect.Struct: + for i := 0; i < typ.NumField(); i++ { + todo = append(todo, typ.Field(i).Type) + } + } + } + + require.NotEqual(t, reflect.Func.String(), m.Type.Out(0).Kind().String(), m.Name) + require.Equal(t, errType, m.Type.Out(1), m.Name) + + default: + t.Error("methods can only have 1 or 2 return values", m.Name) + } + } + } + } + + t.Run("common", tst(new(Common))) + t.Run("full", tst(new(FullNode))) + t.Run("miner", tst(new(StorageMiner))) + t.Run("worker", tst(new(WorkerAPI))) +} diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index b37c667e9..d5b6950ad 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -5,7 +5,7 @@ import ( "io" "time" - "github.com/filecoin-project/go-state-types/dline" + stnetwork "github.com/filecoin-project/go-state-types/network" "github.com/ipfs/go-cid" metrics "github.com/libp2p/go-libp2p-core/metrics" @@ -23,18 +23,18 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/dline" "github.com/filecoin-project/lotus/extern/sector-storage/fsutil" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" "github.com/filecoin-project/lotus/extern/sector-storage/stores" "github.com/filecoin-project/lotus/extern/sector-storage/storiface" marketevents "github.com/filecoin-project/lotus/markets/loggers" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/modules/dtypes" ) @@ -87,6 +87,7 @@ type FullNodeStruct struct { ChainGetParentMessages func(context.Context, cid.Cid) ([]api.Message, error) `perm:"read"` ChainGetTipSetByHeight func(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) `perm:"read"` ChainReadObj func(context.Context, cid.Cid) ([]byte, error) `perm:"read"` + ChainDeleteObj func(context.Context, cid.Cid) error `perm:"admin"` ChainHasObj func(context.Context, cid.Cid) (bool, error) `perm:"read"` ChainStatObj func(context.Context, cid.Cid, cid.Cid) (api.ObjStat, error) `perm:"read"` ChainSetHead func(context.Context, types.TipSetKey) error `perm:"admin"` @@ -134,7 +135,7 @@ type FullNodeStruct struct { WalletBalance func(context.Context, address.Address) (types.BigInt, error) `perm:"read"` WalletSign func(context.Context, address.Address, []byte) (*crypto.Signature, error) `perm:"sign"` WalletSignMessage func(context.Context, address.Address, *types.Message) (*types.SignedMessage, error) `perm:"sign"` - WalletVerify func(context.Context, address.Address, []byte, *crypto.Signature) bool `perm:"read"` + WalletVerify func(context.Context, address.Address, []byte, *crypto.Signature) (bool, error) `perm:"read"` WalletDefaultAddress func(context.Context) (address.Address, error) `perm:"write"` WalletSetDefault func(context.Context, address.Address) error `perm:"admin"` WalletExport func(context.Context, address.Address) (*types.KeyInfo, error) `perm:"admin"` @@ -162,13 +163,13 @@ type FullNodeStruct struct { ClientRetrieveTryRestartInsufficientFunds func(ctx context.Context, paymentChannel address.Address) error `perm:"write"` StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"` - StateMinerSectors func(context.Context, address.Address, *bitfield.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"` - StateMinerActiveSectors func(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"` + StateMinerSectors func(context.Context, address.Address, *bitfield.BitField, types.TipSetKey) ([]*miner.SectorOnChainInfo, error) `perm:"read"` + StateMinerActiveSectors func(context.Context, address.Address, types.TipSetKey) ([]*miner.SectorOnChainInfo, error) `perm:"read"` StateMinerProvingDeadline func(context.Context, address.Address, types.TipSetKey) (*dline.Info, error) `perm:"read"` StateMinerPower func(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) `perm:"read"` - StateMinerInfo func(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error) `perm:"read"` - StateMinerDeadlines func(context.Context, address.Address, types.TipSetKey) ([]*miner.Deadline, error) `perm:"read"` - StateMinerPartitions func(context.Context, address.Address, uint64, types.TipSetKey) ([]*miner.Partition, error) `perm:"read"` + StateMinerInfo func(context.Context, address.Address, types.TipSetKey) (miner.MinerInfo, error) `perm:"read"` + StateMinerDeadlines func(context.Context, address.Address, types.TipSetKey) ([]api.Deadline, error) `perm:"read"` + StateMinerPartitions func(ctx context.Context, m address.Address, dlIdx uint64, tsk types.TipSetKey) ([]api.Partition, error) `perm:"read"` StateMinerFaults func(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error) `perm:"read"` StateAllMinerFaults func(context.Context, abi.ChainEpoch, types.TipSetKey) ([]*api.Fault, error) `perm:"read"` StateMinerRecoveries func(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error) `perm:"read"` @@ -177,8 +178,8 @@ type FullNodeStruct struct { StateMinerAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"` StateSectorPreCommitInfo func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) `perm:"read"` StateSectorGetInfo func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error) `perm:"read"` - StateSectorExpiration func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*api.SectorExpiration, error) `perm:"read"` - StateSectorPartition func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*api.SectorLocation, error) `perm:"read"` + StateSectorExpiration func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorExpiration, error) `perm:"read"` + StateSectorPartition func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorLocation, error) `perm:"read"` StateCall func(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error) `perm:"read"` StateReplay func(context.Context, types.TipSetKey, cid.Cid) (*api.InvocResult, error) `perm:"read"` StateGetActor func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) `perm:"read"` @@ -199,9 +200,10 @@ type FullNodeStruct struct { StateMinerSectorCount func(context.Context, address.Address, types.TipSetKey) (api.MinerSectors, error) `perm:"read"` StateListMessages func(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error) `perm:"read"` StateCompute func(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*api.ComputeStateOutput, error) `perm:"read"` - StateVerifiedClientStatus func(context.Context, address.Address, types.TipSetKey) (*verifreg.DataCap, error) `perm:"read"` + StateVerifiedClientStatus func(context.Context, address.Address, types.TipSetKey) (*abi.StoragePower, error) `perm:"read"` StateDealProviderCollateralBounds func(context.Context, abi.PaddedPieceSize, bool, types.TipSetKey) (api.DealCollateralBounds, error) `perm:"read"` StateCirculatingSupply func(context.Context, types.TipSetKey) (api.CirculatingSupply, error) `perm:"read"` + StateNetworkVersion func(context.Context, types.TipSetKey) (stnetwork.Version, error) `perm:"read"` MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"` MsigGetVested func(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error) `perm:"read"` @@ -252,7 +254,7 @@ type StorageMinerStruct struct { MiningBase func(context.Context) (*types.TipSet, error) `perm:"read"` MarketImportDealData func(context.Context, cid.Cid, string) error `perm:"write"` - MarketListDeals func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"` + MarketListDeals func(ctx context.Context) ([]api.MarketDeal, error) `perm:"read"` MarketListRetrievalDeals func(ctx context.Context) ([]retrievalmarket.ProviderDealState, error) `perm:"read"` MarketGetDealUpdates func(ctx context.Context) (<-chan storagemarket.MinerDeal, error) `perm:"read"` MarketListIncompleteDeals func(ctx context.Context) ([]storagemarket.MinerDeal, error) `perm:"read"` @@ -297,7 +299,7 @@ type StorageMinerStruct struct { StorageTryLock func(ctx context.Context, sector abi.SectorID, read stores.SectorFileType, write stores.SectorFileType) (bool, error) `perm:"admin"` DealsImportData func(ctx context.Context, dealPropCid cid.Cid, file string) error `perm:"write"` - DealsList func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"` + DealsList func(ctx context.Context) ([]api.MarketDeal, error) `perm:"read"` DealsConsiderOnlineStorageDeals func(context.Context) (bool, error) `perm:"read"` DealsSetConsiderOnlineStorageDeals func(context.Context, bool) error `perm:"admin"` DealsConsiderOnlineRetrievalDeals func(context.Context) (bool, error) `perm:"read"` @@ -605,7 +607,7 @@ func (c *FullNodeStruct) WalletSignMessage(ctx context.Context, k address.Addres return c.Internal.WalletSignMessage(ctx, k, msg) } -func (c *FullNodeStruct) WalletVerify(ctx context.Context, k address.Address, msg []byte, sig *crypto.Signature) bool { +func (c *FullNodeStruct) WalletVerify(ctx context.Context, k address.Address, msg []byte, sig *crypto.Signature) (bool, error) { return c.Internal.WalletVerify(ctx, k, msg, sig) } @@ -661,6 +663,10 @@ func (c *FullNodeStruct) ChainReadObj(ctx context.Context, obj cid.Cid) ([]byte, return c.Internal.ChainReadObj(ctx, obj) } +func (c *FullNodeStruct) ChainDeleteObj(ctx context.Context, obj cid.Cid) error { + return c.Internal.ChainDeleteObj(ctx, obj) +} + func (c *FullNodeStruct) ChainHasObj(ctx context.Context, o cid.Cid) (bool, error) { return c.Internal.ChainHasObj(ctx, o) } @@ -733,11 +739,11 @@ func (c *FullNodeStruct) StateNetworkName(ctx context.Context) (dtypes.NetworkNa return c.Internal.StateNetworkName(ctx) } -func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Address, filter *bitfield.BitField, filterOut bool, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) { - return c.Internal.StateMinerSectors(ctx, addr, filter, filterOut, tsk) +func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Address, sectorNos *bitfield.BitField, tsk types.TipSetKey) ([]*miner.SectorOnChainInfo, error) { + return c.Internal.StateMinerSectors(ctx, addr, sectorNos, tsk) } -func (c *FullNodeStruct) StateMinerActiveSectors(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) { +func (c *FullNodeStruct) StateMinerActiveSectors(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*miner.SectorOnChainInfo, error) { return c.Internal.StateMinerActiveSectors(ctx, addr, tsk) } @@ -749,15 +755,15 @@ func (c *FullNodeStruct) StateMinerPower(ctx context.Context, a address.Address, return c.Internal.StateMinerPower(ctx, a, tsk) } -func (c *FullNodeStruct) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (api.MinerInfo, error) { +func (c *FullNodeStruct) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) { return c.Internal.StateMinerInfo(ctx, actor, tsk) } -func (c *FullNodeStruct) StateMinerDeadlines(ctx context.Context, m address.Address, tsk types.TipSetKey) ([]*miner.Deadline, error) { - return c.Internal.StateMinerDeadlines(ctx, m, tsk) +func (c *FullNodeStruct) StateMinerDeadlines(ctx context.Context, actor address.Address, tsk types.TipSetKey) ([]api.Deadline, error) { + return c.Internal.StateMinerDeadlines(ctx, actor, tsk) } -func (c *FullNodeStruct) StateMinerPartitions(ctx context.Context, m address.Address, dlIdx uint64, tsk types.TipSetKey) ([]*miner.Partition, error) { +func (c *FullNodeStruct) StateMinerPartitions(ctx context.Context, m address.Address, dlIdx uint64, tsk types.TipSetKey) ([]api.Partition, error) { return c.Internal.StateMinerPartitions(ctx, m, dlIdx, tsk) } @@ -793,11 +799,11 @@ func (c *FullNodeStruct) StateSectorGetInfo(ctx context.Context, maddr address.A return c.Internal.StateSectorGetInfo(ctx, maddr, n, tsk) } -func (c *FullNodeStruct) StateSectorExpiration(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*api.SectorExpiration, error) { +func (c *FullNodeStruct) StateSectorExpiration(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorExpiration, error) { return c.Internal.StateSectorExpiration(ctx, maddr, n, tsk) } -func (c *FullNodeStruct) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*api.SectorLocation, error) { +func (c *FullNodeStruct) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*miner.SectorLocation, error) { return c.Internal.StateSectorPartition(ctx, maddr, sectorNumber, tok) } @@ -877,7 +883,7 @@ func (c *FullNodeStruct) StateCompute(ctx context.Context, height abi.ChainEpoch return c.Internal.StateCompute(ctx, height, msgs, tsk) } -func (c *FullNodeStruct) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*verifreg.DataCap, error) { +func (c *FullNodeStruct) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) { return c.Internal.StateVerifiedClientStatus(ctx, addr, tsk) } @@ -889,6 +895,10 @@ func (c *FullNodeStruct) StateCirculatingSupply(ctx context.Context, tsk types.T return c.Internal.StateCirculatingSupply(ctx, tsk) } +func (c *FullNodeStruct) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (stnetwork.Version, error) { + return c.Internal.StateNetworkVersion(ctx, tsk) +} + func (c *FullNodeStruct) MsigGetAvailableBalance(ctx context.Context, a address.Address, tsk types.TipSetKey) (types.BigInt, error) { return c.Internal.MsigGetAvailableBalance(ctx, a, tsk) } @@ -1137,7 +1147,7 @@ func (c *StorageMinerStruct) MarketImportDealData(ctx context.Context, propcid c return c.Internal.MarketImportDealData(ctx, propcid, path) } -func (c *StorageMinerStruct) MarketListDeals(ctx context.Context) ([]storagemarket.StorageDeal, error) { +func (c *StorageMinerStruct) MarketListDeals(ctx context.Context) ([]api.MarketDeal, error) { return c.Internal.MarketListDeals(ctx) } @@ -1181,7 +1191,7 @@ func (c *StorageMinerStruct) DealsImportData(ctx context.Context, dealPropCid ci return c.Internal.DealsImportData(ctx, dealPropCid, file) } -func (c *StorageMinerStruct) DealsList(ctx context.Context) ([]storagemarket.StorageDeal, error) { +func (c *StorageMinerStruct) DealsList(ctx context.Context) ([]api.MarketDeal, error) { return c.Internal.DealsList(ctx) } diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index d00643a02..ced536cc3 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -114,6 +114,7 @@ func init() { addExample(retrievalmarket.ClientEventDealAccepted) addExample(retrievalmarket.DealStatusNew) addExample(network.ReachabilityPublic) + addExample(build.NewestNetworkVersion) addExample(&types.ExecutionTrace{ Msg: exampleValue(reflect.TypeOf(&types.Message{}), nil).(*types.Message), MsgRct: exampleValue(reflect.TypeOf(&types.MessageReceipt{}), nil).(*types.MessageReceipt), diff --git a/api/test/ccupgrade.go b/api/test/ccupgrade.go index 130b55cb8..b281f30a0 100644 --- a/api/test/ccupgrade.go +++ b/api/test/ccupgrade.go @@ -85,6 +85,7 @@ func TestCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration) { { exp, err := client.StateSectorExpiration(ctx, maddr, CC, types.EmptyTSK) require.NoError(t, err) + require.NotNil(t, exp) require.Greater(t, 50000, int(exp.OnTime)) } { diff --git a/api/test/window_post.go b/api/test/window_post.go index 3f15c754b..683489a91 100644 --- a/api/test/window_post.go +++ b/api/test/window_post.go @@ -15,7 +15,6 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/mock" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - miner2 "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" @@ -159,7 +158,7 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector head, err := client.ChainHead(ctx) require.NoError(t, err) - if head.Height() > di.PeriodStart+(miner2.WPoStProvingPeriod)+2 { + if head.Height() > di.PeriodStart+(di.WPoStProvingPeriod)+2 { break } @@ -186,12 +185,14 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector require.NoError(t, err) require.Greater(t, len(parts), 0) - n, err := parts[0].Sectors.Count() + secs := parts[0].AllSectors + require.NoError(t, err) + n, err := secs.Count() require.NoError(t, err) require.Equal(t, uint64(2), n) // Drop the partition - err = parts[0].Sectors.ForEach(func(sid uint64) error { + err = secs.ForEach(func(sid uint64) error { return miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkCorrupted(abi.SectorID{ Miner: abi.ActorID(mid), Number: abi.SectorNumber(sid), @@ -208,15 +209,17 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector require.NoError(t, err) require.Greater(t, len(parts), 0) - n, err := parts[0].Sectors.Count() + secs := parts[0].AllSectors + require.NoError(t, err) + n, err := secs.Count() require.NoError(t, err) require.Equal(t, uint64(2), n) // Drop the sector - sn, err := parts[0].Sectors.First() + sn, err := secs.First() require.NoError(t, err) - all, err := parts[0].Sectors.All(2) + all, err := secs.All(2) require.NoError(t, err) fmt.Println("the sectors", all) @@ -238,7 +241,7 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector head, err := client.ChainHead(ctx) require.NoError(t, err) - if head.Height() > di.PeriodStart+(miner2.WPoStProvingPeriod)+2 { + if head.Height() > di.PeriodStart+(di.WPoStProvingPeriod)+2 { break } @@ -268,7 +271,7 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector head, err := client.ChainHead(ctx) require.NoError(t, err) - if head.Height() > di.PeriodStart+(miner2.WPoStProvingPeriod)+2 { + if head.Height() > di.PeriodStart+di.WPoStProvingPeriod+2 { break } diff --git a/api/types.go b/api/types.go index dc8432818..a69aa28d9 100644 --- a/api/types.go +++ b/api/types.go @@ -4,11 +4,9 @@ import ( "encoding/json" "fmt" - "github.com/filecoin-project/go-address" datatransfer "github.com/filecoin-project/go-data-transfer" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/ipfs/go-cid" "github.com/libp2p/go-libp2p-core/peer" @@ -49,48 +47,6 @@ type PubsubScore struct { Score *pubsub.PeerScoreSnapshot } -type MinerInfo struct { - Owner address.Address // Must be an ID-address. - Worker address.Address // Must be an ID-address. - NewWorker address.Address // Must be an ID-address. - ControlAddresses []address.Address // Must be an ID-addresses. - WorkerChangeEpoch abi.ChainEpoch - PeerId *peer.ID - Multiaddrs []abi.Multiaddrs - SealProofType abi.RegisteredSealProof - SectorSize abi.SectorSize - WindowPoStPartitionSectors uint64 -} - -func NewApiMinerInfo(info *miner.MinerInfo) MinerInfo { - var pid *peer.ID - if peerID, err := peer.IDFromBytes(info.PeerId); err == nil { - pid = &peerID - } - - mi := MinerInfo{ - Owner: info.Owner, - Worker: info.Worker, - ControlAddresses: info.ControlAddresses, - - NewWorker: address.Undef, - WorkerChangeEpoch: -1, - - PeerId: pid, - Multiaddrs: info.Multiaddrs, - SealProofType: info.SealProofType, - SectorSize: info.SectorSize, - WindowPoStPartitionSectors: info.WindowPoStPartitionSectors, - } - - if info.PendingWorkerKey != nil { - mi.NewWorker = info.PendingWorkerKey.NewWorker - mi.WorkerChangeEpoch = info.PendingWorkerKey.EffectiveAt - } - - return mi -} - type MessageSendSpec struct { MaxFee abi.TokenAmount } diff --git a/build/params_2k.go b/build/params_2k.go index 9913374e1..3edd0fb82 100644 --- a/build/params_2k.go +++ b/build/params_2k.go @@ -4,10 +4,8 @@ package build import ( "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + + "github.com/filecoin-project/lotus/chain/actors/policy" ) const UpgradeBreezeHeight = -1 @@ -20,11 +18,9 @@ var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ } func init() { - power.ConsensusMinerMinPower = big.NewInt(2048) - miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ - abi.RegisteredSealProof_StackedDrg2KiBV1: {}, - } - verifreg.MinVerifiedDealSize = big.NewInt(256) + policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) + policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048)) + policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) BuildType |= Build2k } diff --git a/build/params_shared_funcs.go b/build/params_shared_funcs.go index 2c585271a..0e9739914 100644 --- a/build/params_shared_funcs.go +++ b/build/params_shared_funcs.go @@ -6,14 +6,14 @@ import ( "github.com/libp2p/go-libp2p-core/protocol" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/node/modules/dtypes" ) func DefaultSectorSize() abi.SectorSize { - szs := make([]abi.SectorSize, 0, len(miner.SupportedProofTypes)) - for spt := range miner.SupportedProofTypes { + szs := make([]abi.SectorSize, 0, len(miner0.SupportedProofTypes)) + for spt := range miner0.SupportedProofTypes { ss, err := spt.SectorSize() if err != nil { panic(err) diff --git a/build/params_shared_vals.go b/build/params_shared_vals.go index 4a46b7fd1..3ee9f52ec 100644 --- a/build/params_shared_vals.go +++ b/build/params_shared_vals.go @@ -9,7 +9,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) // ///// @@ -23,6 +23,7 @@ const UnixfsLinksPerLevel = 1024 const AllowableClockDriftSecs = uint64(1) const NewestNetworkVersion = network.Version2 +const ActorUpgradeNetworkVersion = network.Version3 // Epochs const ForkLengthThreshold = Finality @@ -31,7 +32,7 @@ const ForkLengthThreshold = Finality var BlocksPerEpoch = uint64(builtin.ExpectedLeadersPerEpoch) // Epochs -const Finality = miner.ChainFinality +const Finality = miner0.ChainFinality const MessageConfidence = uint64(5) // constants for Weight calculation diff --git a/build/params_testground.go b/build/params_testground.go index 395d2a855..954b5ccfd 100644 --- a/build/params_testground.go +++ b/build/params_testground.go @@ -13,7 +13,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) var ( @@ -32,7 +32,7 @@ var ( AllowableClockDriftSecs = uint64(1) - Finality = miner.ChainFinality + Finality = miner0.ChainFinality ForkLengthThreshold = Finality SlashablePowerDelay = 20 @@ -80,5 +80,6 @@ var ( 0: DrandMainnet, } - NewestNetworkVersion = network.Version2 + NewestNetworkVersion = network.Version2 + ActorUpgradeNetworkVersion = network.Version3 ) diff --git a/build/params_testnet.go b/build/params_testnet.go index 932ad7a7d..13d2ff62e 100644 --- a/build/params_testnet.go +++ b/build/params_testnet.go @@ -6,10 +6,9 @@ package build import ( "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/power" + "github.com/filecoin-project/lotus/chain/actors/policy" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" ) var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ @@ -23,13 +22,13 @@ const BreezeGasTampingDuration = 120 const UpgradeSmokeHeight = 51000 func init() { - power.ConsensusMinerMinPower = big.NewInt(10 << 40) - miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ - abi.RegisteredSealProof_StackedDrg32GiBV1: {}, - abi.RegisteredSealProof_StackedDrg64GiBV1: {}, - } + policy.SetConsensusMinerMinPower(abi.NewStoragePower(10 << 40)) + policy.SetSupportedProofTypes( + abi.RegisteredSealProof_StackedDrg32GiBV1, + abi.RegisteredSealProof_StackedDrg64GiBV1, + ) } -const BlockDelaySecs = uint64(builtin.EpochDurationSeconds) +const BlockDelaySecs = uint64(builtin0.EpochDurationSeconds) const PropagationDelaySecs = uint64(6) diff --git a/build/version.go b/build/version.go index 2466d8023..cfc8c3ab9 100644 --- a/build/version.go +++ b/build/version.go @@ -29,7 +29,7 @@ func buildType() string { } // BuildVersion is the local build version, set by build system -const BuildVersion = "0.7.0" +const BuildVersion = "0.7.2" func UserVersion() string { return BuildVersion + buildType() + CurrentCommit @@ -83,9 +83,9 @@ func VersionForType(nodeType NodeType) (Version, error) { // semver versions of the rpc api exposed var ( - FullAPIVersion = newVer(0, 14, 0) - MinerAPIVersion = newVer(0, 14, 0) - WorkerAPIVersion = newVer(0, 14, 0) + FullAPIVersion = newVer(0, 16, 0) + MinerAPIVersion = newVer(0, 15, 0) + WorkerAPIVersion = newVer(0, 15, 0) ) //nolint:varcheck,deadcode diff --git a/chain/actors/adt/adt.go b/chain/actors/adt/adt.go new file mode 100644 index 000000000..39dd5cebc --- /dev/null +++ b/chain/actors/adt/adt.go @@ -0,0 +1,65 @@ +package adt + +import ( + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/cbor" + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/lotus/chain/actors/builtin" + adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +type Map interface { + Root() (cid.Cid, error) + + Put(k abi.Keyer, v cbor.Marshaler) error + Get(k abi.Keyer, v cbor.Unmarshaler) (bool, error) + Delete(k abi.Keyer) error + + ForEach(v cbor.Unmarshaler, fn func(key string) error) error +} + +func AsMap(store Store, root cid.Cid, version builtin.Version) (Map, error) { + switch version { + case builtin.Version0: + return adt0.AsMap(store, root) + } + return nil, xerrors.Errorf("unknown network version: %d", version) +} + +func NewMap(store Store, version builtin.Version) (Map, error) { + switch version { + case builtin.Version0: + return adt0.MakeEmptyMap(store), nil + } + return nil, xerrors.Errorf("unknown network version: %d", version) +} + +type Array interface { + Root() (cid.Cid, error) + + Set(idx uint64, v cbor.Marshaler) error + Get(idx uint64, v cbor.Unmarshaler) (bool, error) + Delete(idx uint64) error + Length() uint64 + + ForEach(v cbor.Unmarshaler, fn func(idx int64) error) error +} + +func AsArray(store Store, root cid.Cid, version network.Version) (Array, error) { + switch builtin.VersionForNetwork(version) { + case builtin.Version0: + return adt0.AsArray(store, root) + } + return nil, xerrors.Errorf("unknown network version: %d", version) +} + +func NewArray(store Store, version builtin.Version) (Array, error) { + switch version { + case builtin.Version0: + return adt0.MakeEmptyArray(store), nil + } + return nil, xerrors.Errorf("unknown network version: %d", version) +} diff --git a/chain/events/state/diff_adt.go b/chain/actors/adt/diff_adt.go similarity index 89% rename from chain/events/state/diff_adt.go rename to chain/actors/adt/diff_adt.go index 519c61c2d..160e12e19 100644 --- a/chain/events/state/diff_adt.go +++ b/chain/actors/adt/diff_adt.go @@ -1,10 +1,9 @@ -package state +package adt import ( "bytes" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/specs-actors/actors/util/adt" typegen "github.com/whyrusleeping/cbor-gen" ) @@ -27,7 +26,8 @@ type AdtArrayDiff interface { // - All values that exist in curArr nnd not in prevArr are passed to adtArrayDiff.Add() // - All values that exist in preArr and in curArr are passed to AdtArrayDiff.Modify() // - It is the responsibility of AdtArrayDiff.Modify() to determine if the values it was passed have been modified. -func DiffAdtArray(preArr, curArr *adt.Array, out AdtArrayDiff) error { +func DiffAdtArray(preArr, curArr Array, out AdtArrayDiff) error { + notNew := make(map[int64]struct{}, curArr.Length()) prevVal := new(typegen.Deferred) if err := preArr.ForEach(prevVal, func(i int64) error { curVal := new(typegen.Deferred) @@ -48,14 +48,17 @@ func DiffAdtArray(preArr, curArr *adt.Array, out AdtArrayDiff) error { return err } } - - return curArr.Delete(uint64(i)) + notNew[i] = struct{}{} + return nil }); err != nil { return err } curVal := new(typegen.Deferred) return curArr.ForEach(curVal, func(i int64) error { + if _, ok := notNew[i]; ok { + return nil + } return out.Add(uint64(i), curVal) }) } @@ -76,7 +79,8 @@ type AdtMapDiff interface { Remove(key string, val *typegen.Deferred) error } -func DiffAdtMap(preMap, curMap *adt.Map, out AdtMapDiff) error { +func DiffAdtMap(preMap, curMap Map, out AdtMapDiff) error { + notNew := make(map[string]struct{}) prevVal := new(typegen.Deferred) if err := preMap.ForEach(prevVal, func(key string) error { curVal := new(typegen.Deferred) @@ -102,14 +106,17 @@ func DiffAdtMap(preMap, curMap *adt.Map, out AdtMapDiff) error { return err } } - - return curMap.Delete(k) + notNew[key] = struct{}{} + return nil }); err != nil { return err } curVal := new(typegen.Deferred) return curMap.ForEach(curVal, func(key string) error { + if _, ok := notNew[key]; ok { + return nil + } return out.Add(key, curVal) }) } diff --git a/chain/events/state/diff_adt_test.go b/chain/actors/adt/diff_adt_test.go similarity index 96% rename from chain/events/state/diff_adt_test.go rename to chain/actors/adt/diff_adt_test.go index 55926afb9..1c0726003 100644 --- a/chain/events/state/diff_adt_test.go +++ b/chain/actors/adt/diff_adt_test.go @@ -1,4 +1,4 @@ -package state +package adt import ( "bytes" @@ -13,7 +13,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/runtime" - "github.com/filecoin-project/specs-actors/actors/util/adt" + adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" bstore "github.com/filecoin-project/lotus/lib/blockstore" ) @@ -22,8 +22,8 @@ func TestDiffAdtArray(t *testing.T) { ctxstoreA := newContextStore() ctxstoreB := newContextStore() - arrA := adt.MakeEmptyArray(ctxstoreA) - arrB := adt.MakeEmptyArray(ctxstoreB) + arrA := adt0.MakeEmptyArray(ctxstoreA) + arrB := adt0.MakeEmptyArray(ctxstoreB) require.NoError(t, arrA.Set(0, runtime.CBORBytes([]byte{0}))) // delete @@ -76,8 +76,8 @@ func TestDiffAdtMap(t *testing.T) { ctxstoreA := newContextStore() ctxstoreB := newContextStore() - mapA := adt.MakeEmptyMap(ctxstoreA) - mapB := adt.MakeEmptyMap(ctxstoreB) + mapA := adt0.MakeEmptyMap(ctxstoreA) + mapB := adt0.MakeEmptyMap(ctxstoreB) require.NoError(t, mapA.Put(abi.UIntKey(0), runtime.CBORBytes([]byte{0}))) // delete @@ -292,12 +292,9 @@ func (t *TestDiffArray) Remove(key uint64, val *typegen.Deferred) error { return nil } -func newContextStore() *contextStore { +func newContextStore() Store { ctx := context.Background() bs := bstore.NewTemporarySync() store := cbornode.NewCborStore(bs) - return &contextStore{ - ctx: ctx, - cst: store, - } + return WrapStore(ctx, store) } diff --git a/chain/actors/adt/store.go b/chain/actors/adt/store.go new file mode 100644 index 000000000..8dd9841a1 --- /dev/null +++ b/chain/actors/adt/store.go @@ -0,0 +1,17 @@ +package adt + +import ( + "context" + + adt "github.com/filecoin-project/specs-actors/actors/util/adt" + cbor "github.com/ipfs/go-ipld-cbor" +) + +type Store interface { + Context() context.Context + cbor.IpldStore +} + +func WrapStore(ctx context.Context, store cbor.IpldStore) Store { + return adt.WrapStore(ctx, store) +} diff --git a/chain/actors/builtin/README.md b/chain/actors/builtin/README.md new file mode 100644 index 000000000..21b3fd38f --- /dev/null +++ b/chain/actors/builtin/README.md @@ -0,0 +1,29 @@ +# Actors + +This package contains shims for abstracting over different actor versions. + +## Design + +Shims in this package follow a few common design principles. + +### Structure Agnostic + +Shims interfaces defined in this package should (ideally) not change even if the +structure of the underlying data changes. For example: + +* All shims store an internal "store" object. That way, state can be moved into + a separate object without needing to add a store to the function signature. +* All functions must return an error, even if unused for now. + +### Minimal + +These interfaces should be expanded only as necessary to reduce maintenance burden. + +### Queries, not field assessors. + +When possible, functions should query the state instead of simply acting as +field assessors. These queries are more likely to remain stable across +specs-actor upgrades than specific state fields. + +Note: there is a trade-off here. Avoid implementing _complicated_ query logic +inside these shims, as it will need to be replicated in every shim. diff --git a/chain/actors/builtin/account/account.go b/chain/actors/builtin/account/account.go new file mode 100644 index 000000000..5b90580ec --- /dev/null +++ b/chain/actors/builtin/account/account.go @@ -0,0 +1,31 @@ +package account + +import ( + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/cbor" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/types" +) + +func Load(store adt.Store, act *types.Actor) (State, error) { + switch act.Code { + case builtin0.AccountActorCodeID: + out := state0{store: store} + err := store.Get(store.Context(), act.Head, &out) + if err != nil { + return nil, err + } + return &out, nil + } + return nil, xerrors.Errorf("unknown actor code %s", act.Code) +} + +type State interface { + cbor.Marshaler + + PubkeyAddress() (address.Address, error) +} diff --git a/chain/actors/builtin/account/v0.go b/chain/actors/builtin/account/v0.go new file mode 100644 index 000000000..30bafbfd3 --- /dev/null +++ b/chain/actors/builtin/account/v0.go @@ -0,0 +1,18 @@ +package account + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/specs-actors/actors/builtin/account" +) + +var _ State = (*state0)(nil) + +type state0 struct { + account.State + store adt.Store +} + +func (s *state0) PubkeyAddress() (address.Address, error) { + return s.Address, nil +} diff --git a/chain/actors/builtin/builtin.go b/chain/actors/builtin/builtin.go new file mode 100644 index 000000000..4079e694a --- /dev/null +++ b/chain/actors/builtin/builtin.go @@ -0,0 +1,43 @@ +package builtin + +import ( + "fmt" + + "github.com/filecoin-project/go-state-types/abi" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof" + + smoothing0 "github.com/filecoin-project/specs-actors/actors/util/smoothing" + + "github.com/filecoin-project/go-state-types/network" +) + +type Version int + +const ( + Version0 = iota +) + +// Converts a network version into a specs-actors version. +func VersionForNetwork(version network.Version) Version { + switch version { + case network.Version0, network.Version1, network.Version2: + return Version0 + default: + panic(fmt.Sprintf("unsupported network version %d", version)) + } +} + +// TODO: Why does actors have 2 different versions of this? +type SectorInfo = proof0.SectorInfo +type PoStProof = proof0.PoStProof +type FilterEstimate = smoothing0.FilterEstimate + +func FromV0FilterEstimate(v0 smoothing0.FilterEstimate) FilterEstimate { + return (FilterEstimate)(v0) +} + +// Doesn't change between actors v0 and v1 +func QAPowerForWeight(size abi.SectorSize, duration abi.ChainEpoch, dealWeight, verifiedWeight abi.DealWeight) abi.StoragePower { + return miner0.QAPowerForWeight(size, duration, dealWeight, verifiedWeight) +} diff --git a/chain/actors/builtin/init/init.go b/chain/actors/builtin/init/init.go new file mode 100644 index 000000000..f235450c2 --- /dev/null +++ b/chain/actors/builtin/init/init.go @@ -0,0 +1,44 @@ +package init + +import ( + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/cbor" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/modules/dtypes" +) + +var Address = builtin0.InitActorAddr + +func Load(store adt.Store, act *types.Actor) (State, error) { + switch act.Code { + case builtin0.InitActorCodeID: + out := state0{store: store} + err := store.Get(store.Context(), act.Head, &out) + if err != nil { + return nil, err + } + return &out, nil + } + return nil, xerrors.Errorf("unknown actor code %s", act.Code) +} + +type State interface { + cbor.Marshaler + + ResolveAddress(address address.Address) (address.Address, bool, error) + MapAddressToNewID(address address.Address) (address.Address, error) + NetworkName() (dtypes.NetworkName, error) + + ForEachActor(func(id abi.ActorID, address address.Address) error) error + + // Remove exists to support tooling that manipulates state for testing. + // It should not be used in production code, as init actor entries are + // immutable. + Remove(addrs ...address.Address) error +} diff --git a/chain/actors/builtin/init/v0.go b/chain/actors/builtin/init/v0.go new file mode 100644 index 000000000..425ba654c --- /dev/null +++ b/chain/actors/builtin/init/v0.go @@ -0,0 +1,67 @@ +package init + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/node/modules/dtypes" + + adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +var _ State = (*state0)(nil) + +type state0 struct { + init_.State + store adt.Store +} + +func (s *state0) ResolveAddress(address address.Address) (address.Address, bool, error) { + return s.State.ResolveAddress(s.store, address) +} + +func (s *state0) MapAddressToNewID(address address.Address) (address.Address, error) { + return s.State.MapAddressToNewID(s.store, address) +} + +func (s *state0) ForEachActor(cb func(id abi.ActorID, address address.Address) error) error { + addrs, err := adt0.AsMap(s.store, s.State.AddressMap) + 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 *state0) NetworkName() (dtypes.NetworkName, error) { + return dtypes.NetworkName(s.State.NetworkName), nil +} + +func (s *state0) Remove(addrs ...address.Address) (err error) { + m, err := adt0.AsMap(s.store, s.State.AddressMap) + 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 +} diff --git a/chain/actors/builtin/market/diff.go b/chain/actors/builtin/market/diff.go new file mode 100644 index 000000000..d0b4a2fd3 --- /dev/null +++ b/chain/actors/builtin/market/diff.go @@ -0,0 +1,91 @@ +package market + +import ( + "fmt" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/actors/adt" + cbg "github.com/whyrusleeping/cbor-gen" +) + +func DiffDealProposals(pre, cur DealProposals) (*DealProposalChanges, error) { + results := new(DealProposalChanges) + if err := adt.DiffAdtArray(pre.array(), cur.array(), &marketProposalsDiffer{results, pre, cur}); err != nil { + return nil, fmt.Errorf("diffing deal states: %w", err) + } + return results, nil +} + +type marketProposalsDiffer struct { + Results *DealProposalChanges + pre, cur DealProposals +} + +func (d *marketProposalsDiffer) Add(key uint64, val *cbg.Deferred) error { + dp, err := d.cur.decode(val) + if err != nil { + return err + } + d.Results.Added = append(d.Results.Added, ProposalIDState{abi.DealID(key), *dp}) + return nil +} + +func (d *marketProposalsDiffer) Modify(key uint64, from, to *cbg.Deferred) error { + // short circuit, DealProposals are static + return nil +} + +func (d *marketProposalsDiffer) Remove(key uint64, val *cbg.Deferred) error { + dp, err := d.pre.decode(val) + if err != nil { + return err + } + d.Results.Removed = append(d.Results.Removed, ProposalIDState{abi.DealID(key), *dp}) + return nil +} + +func DiffDealStates(pre, cur DealStates) (*DealStateChanges, error) { + results := new(DealStateChanges) + if err := adt.DiffAdtArray(pre.array(), cur.array(), &marketStatesDiffer{results, pre, cur}); err != nil { + return nil, fmt.Errorf("diffing deal states: %w", err) + } + return results, nil +} + +type marketStatesDiffer struct { + Results *DealStateChanges + pre, cur DealStates +} + +func (d *marketStatesDiffer) Add(key uint64, val *cbg.Deferred) error { + ds, err := d.cur.decode(val) + if err != nil { + return err + } + d.Results.Added = append(d.Results.Added, DealIDState{abi.DealID(key), *ds}) + return nil +} + +func (d *marketStatesDiffer) Modify(key uint64, from, to *cbg.Deferred) error { + dsFrom, err := d.pre.decode(from) + if err != nil { + return err + } + dsTo, err := d.cur.decode(to) + if err != nil { + return err + } + if *dsFrom != *dsTo { + d.Results.Modified = append(d.Results.Modified, DealStateChange{abi.DealID(key), dsFrom, dsTo}) + } + return nil +} + +func (d *marketStatesDiffer) Remove(key uint64, val *cbg.Deferred) error { + ds, err := d.pre.decode(val) + if err != nil { + return err + } + d.Results.Removed = append(d.Results.Removed, DealIDState{abi.DealID(key), *ds}) + return nil +} diff --git a/chain/actors/builtin/market/market.go b/chain/actors/builtin/market/market.go new file mode 100644 index 000000000..fef0c03f9 --- /dev/null +++ b/chain/actors/builtin/market/market.go @@ -0,0 +1,129 @@ +package market + +import ( + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/cbor" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" + "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/types" +) + +var Address = builtin0.StorageMarketActorAddr + +func Load(store adt.Store, act *types.Actor) (st State, err error) { + switch act.Code { + case builtin0.StorageMarketActorCodeID: + out := state0{store: store} + err := store.Get(store.Context(), act.Head, &out) + if err != nil { + return nil, err + } + return &out, nil + } + return nil, xerrors.Errorf("unknown actor code %s", act.Code) +} + +type State interface { + cbor.Marshaler + BalancesChanged(State) (bool, error) + EscrowTable() (BalanceTable, error) + LockedTable() (BalanceTable, error) + TotalLocked() (abi.TokenAmount, error) + StatesChanged(State) (bool, error) + States() (DealStates, error) + ProposalsChanged(State) (bool, error) + Proposals() (DealProposals, error) + VerifyDealsForActivation( + minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch, + ) (weight, verifiedWeight abi.DealWeight, err error) +} + +type BalanceTable interface { + ForEach(cb func(address.Address, abi.TokenAmount) error) error + Get(key address.Address) (abi.TokenAmount, error) +} + +type DealStates interface { + ForEach(cb func(id abi.DealID, ds DealState) error) error + Get(id abi.DealID) (*DealState, bool, error) + + array() adt.Array + decode(*cbg.Deferred) (*DealState, error) +} + +type DealProposals interface { + ForEach(cb func(id abi.DealID, dp DealProposal) error) error + Get(id abi.DealID) (*DealProposal, bool, error) + + array() adt.Array + decode(*cbg.Deferred) (*DealProposal, error) +} + +type PublishStorageDealsParams = market0.PublishStorageDealsParams +type PublishStorageDealsReturn = market0.PublishStorageDealsReturn +type VerifyDealsForActivationParams = market0.VerifyDealsForActivationParams + +type ClientDealProposal = market0.ClientDealProposal + +type DealState struct { + SectorStartEpoch abi.ChainEpoch // -1 if not yet included in proven sector + LastUpdatedEpoch abi.ChainEpoch // -1 if deal state never updated + SlashEpoch abi.ChainEpoch // -1 if deal never slashed +} + +type DealProposal struct { + PieceCID cid.Cid + PieceSize abi.PaddedPieceSize + VerifiedDeal bool + Client address.Address + Provider address.Address + Label string + StartEpoch abi.ChainEpoch + EndEpoch abi.ChainEpoch + StoragePricePerEpoch abi.TokenAmount + ProviderCollateral abi.TokenAmount + ClientCollateral abi.TokenAmount +} + +type DealStateChanges struct { + Added []DealIDState + Modified []DealStateChange + Removed []DealIDState +} + +type DealIDState struct { + ID abi.DealID + Deal DealState +} + +// DealStateChange is a change in deal state from -> to +type DealStateChange struct { + ID abi.DealID + From *DealState + To *DealState +} + +type DealProposalChanges struct { + Added []ProposalIDState + Removed []ProposalIDState +} + +type ProposalIDState struct { + ID abi.DealID + Proposal DealProposal +} + +func EmptyDealState() *DealState { + return &DealState{ + SectorStartEpoch: -1, + SlashEpoch: -1, + LastUpdatedEpoch: -1, + } +} diff --git a/chain/actors/builtin/market/v0.go b/chain/actors/builtin/market/v0.go new file mode 100644 index 000000000..2727f513d --- /dev/null +++ b/chain/actors/builtin/market/v0.go @@ -0,0 +1,192 @@ +package market + +import ( + "bytes" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/specs-actors/actors/builtin/market" + adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" + cbg "github.com/whyrusleeping/cbor-gen" +) + +var _ State = (*state0)(nil) + +type state0 struct { + market.State + store adt.Store +} + +func (s *state0) TotalLocked() (abi.TokenAmount, error) { + fml := types.BigAdd(s.TotalClientLockedCollateral, s.TotalProviderLockedCollateral) + fml = types.BigAdd(fml, s.TotalClientStorageFee) + return fml, nil +} + +func (s *state0) BalancesChanged(otherState State) (bool, error) { + otherState0, ok := otherState.(*state0) + 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(otherState0.State.EscrowTable) || !s.State.LockedTable.Equals(otherState0.State.LockedTable), nil +} + +func (s *state0) StatesChanged(otherState State) (bool, error) { + otherState0, ok := otherState.(*state0) + 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(otherState0.State.States), nil +} + +func (s *state0) States() (DealStates, error) { + stateArray, err := adt0.AsArray(s.store, s.State.States) + if err != nil { + return nil, err + } + return &dealStates0{stateArray}, nil +} + +func (s *state0) ProposalsChanged(otherState State) (bool, error) { + otherState0, ok := otherState.(*state0) + 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(otherState0.State.Proposals), nil +} + +func (s *state0) Proposals() (DealProposals, error) { + proposalArray, err := adt0.AsArray(s.store, s.State.Proposals) + if err != nil { + return nil, err + } + return &dealProposals0{proposalArray}, nil +} + +func (s *state0) EscrowTable() (BalanceTable, error) { + bt, err := adt0.AsBalanceTable(s.store, s.State.EscrowTable) + if err != nil { + return nil, err + } + return &balanceTable0{bt}, nil +} + +func (s *state0) LockedTable() (BalanceTable, error) { + bt, err := adt0.AsBalanceTable(s.store, s.State.LockedTable) + if err != nil { + return nil, err + } + return &balanceTable0{bt}, nil +} + +func (s *state0) VerifyDealsForActivation( + minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch, +) (weight, verifiedWeight abi.DealWeight, err error) { + return market.ValidateDealsForActivation(&s.State, s.store, deals, minerAddr, sectorExpiry, currEpoch) +} + +type balanceTable0 struct { + *adt0.BalanceTable +} + +func (bt *balanceTable0) ForEach(cb func(address.Address, abi.TokenAmount) error) error { + asMap := (*adt0.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 dealStates0 struct { + adt.Array +} + +func (s *dealStates0) Get(dealID abi.DealID) (*DealState, bool, error) { + var deal0 market.DealState + found, err := s.Array.Get(uint64(dealID), &deal0) + if err != nil { + return nil, false, err + } + if !found { + return nil, false, nil + } + deal := fromV0DealState(deal0) + return &deal, true, nil +} + +func (s *dealStates0) ForEach(cb func(dealID abi.DealID, ds DealState) error) error { + var ds0 market.DealState + return s.Array.ForEach(&ds0, func(idx int64) error { + return cb(abi.DealID(idx), fromV0DealState(ds0)) + }) +} + +func (s *dealStates0) decode(val *cbg.Deferred) (*DealState, error) { + var ds0 market.DealState + if err := ds0.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return nil, err + } + ds := fromV0DealState(ds0) + return &ds, nil +} + +func (s *dealStates0) array() adt.Array { + return s.Array +} + +func fromV0DealState(v0 market.DealState) DealState { + return (DealState)(v0) +} + +type dealProposals0 struct { + adt.Array +} + +func (s *dealProposals0) Get(dealID abi.DealID) (*DealProposal, bool, error) { + var proposal0 market.DealProposal + found, err := s.Array.Get(uint64(dealID), &proposal0) + if err != nil { + return nil, false, err + } + if !found { + return nil, false, nil + } + proposal := fromV0DealProposal(proposal0) + return &proposal, true, nil +} + +func (s *dealProposals0) ForEach(cb func(dealID abi.DealID, dp DealProposal) error) error { + var dp0 market.DealProposal + return s.Array.ForEach(&dp0, func(idx int64) error { + return cb(abi.DealID(idx), fromV0DealProposal(dp0)) + }) +} + +func (s *dealProposals0) decode(val *cbg.Deferred) (*DealProposal, error) { + var dp0 market.DealProposal + if err := dp0.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return nil, err + } + dp := fromV0DealProposal(dp0) + return &dp, nil +} + +func (s *dealProposals0) array() adt.Array { + return s.Array +} + +func fromV0DealProposal(v0 market.DealProposal) DealProposal { + return (DealProposal)(v0) +} diff --git a/chain/actors/builtin/miner/diff.go b/chain/actors/builtin/miner/diff.go new file mode 100644 index 000000000..dde4db890 --- /dev/null +++ b/chain/actors/builtin/miner/diff.go @@ -0,0 +1,127 @@ +package miner + +import ( + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/actors/adt" + cbg "github.com/whyrusleeping/cbor-gen" +) + +func DiffPreCommits(pre, cur State) (*PreCommitChanges, error) { + results := new(PreCommitChanges) + + prep, err := pre.precommits() + if err != nil { + return nil, err + } + + curp, err := cur.precommits() + if err != nil { + return nil, err + } + + err = adt.DiffAdtMap(prep, curp, &preCommitDiffer{results, pre, cur}) + if err != nil { + return nil, err + } + + return results, nil +} + +type preCommitDiffer struct { + Results *PreCommitChanges + pre, after State +} + +func (m *preCommitDiffer) AsKey(key string) (abi.Keyer, error) { + sector, err := abi.ParseUIntKey(key) + if err != nil { + return nil, err + } + return abi.UIntKey(sector), nil +} + +func (m *preCommitDiffer) Add(key string, val *cbg.Deferred) error { + sp, err := m.after.decodeSectorPreCommitOnChainInfo(val) + if err != nil { + return err + } + m.Results.Added = append(m.Results.Added, sp) + return nil +} + +func (m *preCommitDiffer) Modify(key string, from, to *cbg.Deferred) error { + return nil +} + +func (m *preCommitDiffer) Remove(key string, val *cbg.Deferred) error { + sp, err := m.pre.decodeSectorPreCommitOnChainInfo(val) + if err != nil { + return err + } + m.Results.Removed = append(m.Results.Removed, sp) + return nil +} + +func DiffSectors(pre, cur State) (*SectorChanges, error) { + results := new(SectorChanges) + + pres, err := pre.sectors() + if err != nil { + return nil, err + } + + curs, err := cur.sectors() + if err != nil { + return nil, err + } + + err = adt.DiffAdtArray(pres, curs, §orDiffer{results, pre, cur}) + if err != nil { + return nil, err + } + + return results, nil +} + +type sectorDiffer struct { + Results *SectorChanges + pre, after State +} + +func (m *sectorDiffer) Add(key uint64, val *cbg.Deferred) error { + si, err := m.after.decodeSectorOnChainInfo(val) + if err != nil { + return err + } + m.Results.Added = append(m.Results.Added, si) + return nil +} + +func (m *sectorDiffer) Modify(key uint64, from, to *cbg.Deferred) error { + siFrom, err := m.pre.decodeSectorOnChainInfo(from) + if err != nil { + return err + } + + siTo, err := m.after.decodeSectorOnChainInfo(to) + if err != nil { + return err + } + + if siFrom.Expiration != siTo.Expiration { + m.Results.Extended = append(m.Results.Extended, SectorExtensions{ + From: siFrom, + To: siTo, + }) + } + return nil +} + +func (m *sectorDiffer) Remove(key uint64, val *cbg.Deferred) error { + si, err := m.pre.decodeSectorOnChainInfo(val) + if err != nil { + return err + } + m.Results.Removed = append(m.Results.Removed, si) + return nil +} diff --git a/chain/actors/builtin/miner/miner.go b/chain/actors/builtin/miner/miner.go new file mode 100644 index 000000000..1a4c466b9 --- /dev/null +++ b/chain/actors/builtin/miner/miner.go @@ -0,0 +1,169 @@ +package miner + +import ( + "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/go-address" + "github.com/filecoin-project/go-bitfield" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/cbor" + "github.com/filecoin-project/go-state-types/dline" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/types" +) + +// Unchanged between v0 and v1 actors +var WPoStProvingPeriod = miner0.WPoStProvingPeriod + +const MinSectorExpiration = miner0.MinSectorExpiration + +func Load(store adt.Store, act *types.Actor) (st State, err error) { + switch act.Code { + case builtin0.StorageMinerActorCodeID: + out := state0{store: store} + err := store.Get(store.Context(), act.Head, &out) + if err != nil { + return nil, err + } + return &out, nil + } + return nil, xerrors.Errorf("unknown actor code %s", act.Code) +} + +type State interface { + cbor.Marshaler + + // Total available balance to spend. + AvailableBalance(abi.TokenAmount) (abi.TokenAmount, error) + // Funds that will vest by the given epoch. + VestedFunds(abi.ChainEpoch) (abi.TokenAmount, error) + // Funds locked for various reasons. + LockedFunds() (LockedFunds, error) + + GetSector(abi.SectorNumber) (*SectorOnChainInfo, error) + FindSector(abi.SectorNumber) (*SectorLocation, error) + GetSectorExpiration(abi.SectorNumber) (*SectorExpiration, error) + GetPrecommittedSector(abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) + LoadSectors(sectorNos *bitfield.BitField) ([]*SectorOnChainInfo, error) + NumLiveSectors() (uint64, error) + IsAllocated(abi.SectorNumber) (bool, error) + + LoadDeadline(idx uint64) (Deadline, error) + ForEachDeadline(cb func(idx uint64, dl Deadline) error) error + NumDeadlines() (uint64, error) + DeadlinesChanged(State) (bool, error) + + Info() (MinerInfo, error) + + DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error) + + // Diff helpers. Used by Diff* functions internally. + sectors() (adt.Array, error) + decodeSectorOnChainInfo(*cbg.Deferred) (SectorOnChainInfo, error) + precommits() (adt.Map, error) + decodeSectorPreCommitOnChainInfo(*cbg.Deferred) (SectorPreCommitOnChainInfo, error) +} + +type Deadline interface { + LoadPartition(idx uint64) (Partition, error) + ForEachPartition(cb func(idx uint64, part Partition) error) error + PostSubmissions() (bitfield.BitField, error) + + PartitionsChanged(Deadline) (bool, error) +} + +type Partition interface { + AllSectors() (bitfield.BitField, error) + FaultySectors() (bitfield.BitField, error) + RecoveringSectors() (bitfield.BitField, error) + LiveSectors() (bitfield.BitField, error) + ActiveSectors() (bitfield.BitField, error) +} + +type SectorOnChainInfo struct { + SectorNumber abi.SectorNumber + SealProof abi.RegisteredSealProof + SealedCID cid.Cid + DealIDs []abi.DealID + Activation abi.ChainEpoch + Expiration abi.ChainEpoch + DealWeight abi.DealWeight + VerifiedDealWeight abi.DealWeight + InitialPledge abi.TokenAmount + ExpectedDayReward abi.TokenAmount + ExpectedStoragePledge abi.TokenAmount +} + +type SectorPreCommitInfo = miner0.SectorPreCommitInfo + +type SectorPreCommitOnChainInfo struct { + Info SectorPreCommitInfo + PreCommitDeposit abi.TokenAmount + PreCommitEpoch abi.ChainEpoch + DealWeight abi.DealWeight + VerifiedDealWeight abi.DealWeight +} + +type PoStPartition = miner0.PoStPartition +type RecoveryDeclaration = miner0.RecoveryDeclaration +type FaultDeclaration = miner0.FaultDeclaration + +// Params +type DeclareFaultsParams = miner0.DeclareFaultsParams +type DeclareFaultsRecoveredParams = miner0.DeclareFaultsRecoveredParams +type SubmitWindowedPoStParams = miner0.SubmitWindowedPoStParams +type ProveCommitSectorParams = miner0.ProveCommitSectorParams + +type MinerInfo struct { + Owner address.Address // Must be an ID-address. + Worker address.Address // Must be an ID-address. + NewWorker address.Address // Must be an ID-address. + ControlAddresses []address.Address // Must be an ID-addresses. + WorkerChangeEpoch abi.ChainEpoch + PeerId *peer.ID + Multiaddrs []abi.Multiaddrs + SealProofType abi.RegisteredSealProof + SectorSize abi.SectorSize + WindowPoStPartitionSectors uint64 +} + +type SectorExpiration struct { + OnTime abi.ChainEpoch + + // non-zero if sector is faulty, epoch at which it will be permanently + // removed if it doesn't recover + Early abi.ChainEpoch +} + +type SectorLocation struct { + Deadline uint64 + Partition uint64 +} + +type SectorChanges struct { + Added []SectorOnChainInfo + Extended []SectorExtensions + Removed []SectorOnChainInfo +} + +type SectorExtensions struct { + From SectorOnChainInfo + To SectorOnChainInfo +} + +type PreCommitChanges struct { + Added []SectorPreCommitOnChainInfo + Removed []SectorPreCommitOnChainInfo +} + +type LockedFunds struct { + VestingFunds abi.TokenAmount + InitialPledgeRequirement abi.TokenAmount + PreCommitDeposits abi.TokenAmount +} diff --git a/chain/actors/builtin/miner/utils.go b/chain/actors/builtin/miner/utils.go new file mode 100644 index 000000000..f9c6b3da3 --- /dev/null +++ b/chain/actors/builtin/miner/utils.go @@ -0,0 +1,28 @@ +package miner + +import ( + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-bitfield" +) + +func AllPartSectors(mas State, sget func(Partition) (bitfield.BitField, error)) (bitfield.BitField, error) { + var parts []bitfield.BitField + + err := mas.ForEachDeadline(func(dlidx uint64, dl Deadline) error { + return dl.ForEachPartition(func(partidx uint64, part Partition) error { + s, err := sget(part) + if err != nil { + return xerrors.Errorf("getting sector list (dl: %d, part %d): %w", dlidx, partidx, err) + } + + parts = append(parts, s) + return nil + }) + }) + if err != nil { + return bitfield.BitField{}, err + } + + return bitfield.MultiMerge(parts...) +} diff --git a/chain/actors/builtin/miner/v0.go b/chain/actors/builtin/miner/v0.go new file mode 100644 index 000000000..9cdfc25bc --- /dev/null +++ b/chain/actors/builtin/miner/v0.go @@ -0,0 +1,374 @@ +package miner + +import ( + "bytes" + "errors" + + "github.com/libp2p/go-libp2p-core/peer" + cbg "github.com/whyrusleeping/cbor-gen" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-bitfield" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/dline" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" + + "github.com/filecoin-project/lotus/chain/actors/adt" +) + +var _ State = (*state0)(nil) + +type state0 struct { + miner0.State + store adt.Store +} + +type deadline0 struct { + miner0.Deadline + store adt.Store +} + +type partition0 struct { + miner0.Partition + store adt.Store +} + +func (s *state0) AvailableBalance(bal abi.TokenAmount) (abi.TokenAmount, error) { + return s.GetAvailableBalance(bal), nil +} + +func (s *state0) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) { + return s.CheckVestedFunds(s.store, epoch) +} + +func (s *state0) LockedFunds() (LockedFunds, error) { + return LockedFunds{ + VestingFunds: s.State.LockedFunds, + InitialPledgeRequirement: s.State.InitialPledgeRequirement, + PreCommitDeposits: s.State.PreCommitDeposits, + }, nil +} + +func (s *state0) InitialPledge() (abi.TokenAmount, error) { + return s.State.InitialPledgeRequirement, nil +} + +func (s *state0) PreCommitDeposits() (abi.TokenAmount, error) { + return s.State.PreCommitDeposits, nil +} + +func (s *state0) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) { + info, ok, err := s.State.GetSector(s.store, num) + if !ok || err != nil { + return nil, err + } + + ret := fromV0SectorOnChainInfo(*info) + return &ret, nil +} + +func (s *state0) 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 *state0) 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 *miner0.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 isn't found or has already been terminated, this method returns +// nil and no error. If the sector does not expire early, the Early expiration +// field is 0. +func (s *state0) 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 *miner0.Deadline) error { + partitions, err := dl.PartitionsArray(s.store) + if err != nil { + return err + } + quant := s.State.QuantSpecForDeadline(dlIdx) + var part miner0.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 := miner0.LoadExpirationQueue(s.store, part.ExpirationsEpochs, quant) + if err != nil { + return err + } + var exp miner0.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, nil + } + return &out, nil +} + +func (s *state0) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) { + info, ok, err := s.State.GetPrecommittedSector(s.store, num) + if !ok || err != nil { + return nil, err + } + + ret := fromV0SectorPreCommitOnChainInfo(*info) + return &ret, nil +} + +func (s *state0) LoadSectors(snos *bitfield.BitField) ([]*SectorOnChainInfo, error) { + sectors, err := miner0.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 info0 miner0.SectorOnChainInfo + if err := sectors.ForEach(&info0, func(_ int64) error { + info := fromV0SectorOnChainInfo(info0) + infos = append(infos, &info) + return nil + }); err != nil { + return nil, err + } + return infos, nil + } + + // Otherwise, load selected. + infos0, err := sectors.Load(*snos) + if err != nil { + return nil, err + } + infos := make([]*SectorOnChainInfo, len(infos0)) + for i, info0 := range infos0 { + info := fromV0SectorOnChainInfo(*info0) + infos[i] = &info + } + return infos, nil +} + +func (s *state0) IsAllocated(num abi.SectorNumber) (bool, error) { + var allocatedSectors bitfield.BitField + if err := s.store.Get(s.store.Context(), s.State.AllocatedSectors, &allocatedSectors); err != nil { + return false, err + } + + return allocatedSectors.IsSet(uint64(num)) +} + +func (s *state0) 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 &deadline0{*dl, s.store}, nil +} + +func (s *state0) 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 *miner0.Deadline) error { + return cb(i, &deadline0{*dl, s.store}) + }) +} + +func (s *state0) NumDeadlines() (uint64, error) { + return miner0.WPoStPeriodDeadlines, nil +} + +func (s *state0) DeadlinesChanged(other State) (bool, error) { + other0, ok := other.(*state0) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + + return s.State.Deadlines.Equals(other0.Deadlines), nil +} + +func (s *state0) 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, + SealProofType: info.SealProofType, + SectorSize: info.SectorSize, + WindowPoStPartitionSectors: info.WindowPoStPartitionSectors, + } + + if info.PendingWorkerKey != nil { + mi.NewWorker = info.PendingWorkerKey.NewWorker + mi.WorkerChangeEpoch = info.PendingWorkerKey.EffectiveAt + } + + return mi, nil +} + +func (s *state0) DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error) { + return s.State.DeadlineInfo(epoch), nil +} + +func (s *state0) sectors() (adt.Array, error) { + return adt0.AsArray(s.store, s.Sectors) +} + +func (s *state0) decodeSectorOnChainInfo(val *cbg.Deferred) (SectorOnChainInfo, error) { + var si miner0.SectorOnChainInfo + err := si.UnmarshalCBOR(bytes.NewReader(val.Raw)) + if err != nil { + return SectorOnChainInfo{}, err + } + + return fromV0SectorOnChainInfo(si), nil +} + +func (s *state0) precommits() (adt.Map, error) { + return adt0.AsMap(s.store, s.PreCommittedSectors) +} + +func (s *state0) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) { + var sp miner0.SectorPreCommitOnChainInfo + err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) + if err != nil { + return SectorPreCommitOnChainInfo{}, err + } + + return fromV0SectorPreCommitOnChainInfo(sp), nil +} + +func (d *deadline0) LoadPartition(idx uint64) (Partition, error) { + p, err := d.Deadline.LoadPartition(d.store, idx) + if err != nil { + return nil, err + } + return &partition0{*p, d.store}, nil +} + +func (d *deadline0) ForEachPartition(cb func(uint64, Partition) error) error { + ps, err := d.Deadline.PartitionsArray(d.store) + if err != nil { + return err + } + var part miner0.Partition + return ps.ForEach(&part, func(i int64) error { + return cb(uint64(i), &partition0{part, d.store}) + }) +} + +func (d *deadline0) PartitionsChanged(other Deadline) (bool, error) { + other0, ok := other.(*deadline0) + if !ok { + // treat an upgrade as a change, always + return true, nil + } + + return d.Deadline.Partitions.Equals(other0.Deadline.Partitions), nil +} + +func (d *deadline0) PostSubmissions() (bitfield.BitField, error) { + return d.Deadline.PostSubmissions, nil +} + +func (p *partition0) AllSectors() (bitfield.BitField, error) { + return p.Partition.Sectors, nil +} + +func (p *partition0) FaultySectors() (bitfield.BitField, error) { + return p.Partition.Faults, nil +} + +func (p *partition0) RecoveringSectors() (bitfield.BitField, error) { + return p.Partition.Recoveries, nil +} + +func fromV0SectorOnChainInfo(v0 miner0.SectorOnChainInfo) SectorOnChainInfo { + return (SectorOnChainInfo)(v0) +} + +func fromV0SectorPreCommitOnChainInfo(v0 miner0.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo { + return (SectorPreCommitOnChainInfo)(v0) +} diff --git a/chain/actors/builtin/multisig/multisig.go b/chain/actors/builtin/multisig/multisig.go new file mode 100644 index 000000000..884b6f493 --- /dev/null +++ b/chain/actors/builtin/multisig/multisig.go @@ -0,0 +1,43 @@ +package multisig + +import ( + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/cbor" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/types" +) + +func Load(store adt.Store, act *types.Actor) (State, error) { + switch act.Code { + case builtin0.MultisigActorCodeID: + out := state0{store: store} + err := store.Get(store.Context(), act.Head, &out) + if err != nil { + return nil, err + } + return &out, nil + } + return nil, xerrors.Errorf("unknown actor code %s", act.Code) +} + +type State interface { + cbor.Marshaler + + LockedBalance(epoch abi.ChainEpoch) (abi.TokenAmount, error) + StartEpoch() (abi.ChainEpoch, error) + UnlockDuration() (abi.ChainEpoch, error) + InitialBalance() (abi.TokenAmount, error) + Threshold() (uint64, error) + Signers() ([]address.Address, error) + + ForEachPendingTxn(func(id int64, txn Transaction) error) error +} + +type Transaction = msig0.Transaction diff --git a/chain/actors/builtin/multisig/v0.go b/chain/actors/builtin/multisig/v0.go new file mode 100644 index 000000000..ae0a7ac0e --- /dev/null +++ b/chain/actors/builtin/multisig/v0.go @@ -0,0 +1,59 @@ +package multisig + +import ( + "encoding/binary" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/actors/adt" + "golang.org/x/xerrors" + + msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" + adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +var _ State = (*state0)(nil) + +type state0 struct { + msig0.State + store adt.Store +} + +func (s *state0) LockedBalance(currEpoch abi.ChainEpoch) (abi.TokenAmount, error) { + return s.State.AmountLocked(currEpoch - s.State.StartEpoch), nil +} + +func (s *state0) StartEpoch() (abi.ChainEpoch, error) { + return s.State.StartEpoch, nil +} + +func (s *state0) UnlockDuration() (abi.ChainEpoch, error) { + return s.State.UnlockDuration, nil +} + +func (s *state0) InitialBalance() (abi.TokenAmount, error) { + return s.State.InitialBalance, nil +} + +func (s *state0) Threshold() (uint64, error) { + return s.State.NumApprovalsThreshold, nil +} + +func (s *state0) Signers() ([]address.Address, error) { + return s.State.Signers, nil +} + +func (s *state0) ForEachPendingTxn(cb func(id int64, txn Transaction) error) error { + arr, err := adt0.AsMap(s.store, s.State.PendingTxns) + if err != nil { + return err + } + var out msig0.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)) + }) +} diff --git a/chain/actors/builtin/paych/mock/mock.go b/chain/actors/builtin/paych/mock/mock.go new file mode 100644 index 000000000..c4903f3ac --- /dev/null +++ b/chain/actors/builtin/paych/mock/mock.go @@ -0,0 +1,89 @@ +package mock + +import ( + "io" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" +) + +type mockState struct { + from address.Address + to address.Address + settlingAt abi.ChainEpoch + toSend abi.TokenAmount + lanes map[uint64]paych.LaneState +} + +type mockLaneState struct { + redeemed big.Int + nonce uint64 +} + +// NewMockPayChState constructs a state for a payment channel with the set fixed values +// that satisfies the paych.State interface. +func NewMockPayChState(from address.Address, + to address.Address, + settlingAt abi.ChainEpoch, + toSend abi.TokenAmount, + lanes map[uint64]paych.LaneState, +) paych.State { + return &mockState{from, to, settlingAt, toSend, lanes} +} + +// NewMockLaneState constructs a state for a payment channel lane with the set fixed values +// that satisfies the paych.LaneState interface. Useful for populating lanes when +// calling NewMockPayChState +func NewMockLaneState(redeemed big.Int, nonce uint64) paych.LaneState { + return &mockLaneState{redeemed, nonce} +} + +func (ms *mockState) MarshalCBOR(io.Writer) error { + panic("not implemented") +} + +// Channel owner, who has funded the actor +func (ms *mockState) From() (address.Address, error) { + return ms.from, nil +} + +// Recipient of payouts from channel +func (ms *mockState) To() (address.Address, error) { + return ms.to, nil +} + +// Height at which the channel can be `Collected` +func (ms *mockState) SettlingAt() (abi.ChainEpoch, error) { + return ms.settlingAt, nil +} + +// Amount successfully redeemed through the payment channel, paid out on `Collect()` +func (ms *mockState) ToSend() (abi.TokenAmount, error) { + return ms.toSend, nil +} + +// Get total number of lanes +func (ms *mockState) LaneCount() (uint64, error) { + return uint64(len(ms.lanes)), nil +} + +// Iterate lane states +func (ms *mockState) ForEachLaneState(cb func(idx uint64, dl paych.LaneState) error) error { + var lastErr error + for lane, state := range ms.lanes { + if err := cb(lane, state); err != nil { + lastErr = err + } + } + return lastErr +} + +func (mls *mockLaneState) Redeemed() (big.Int, error) { + return mls.redeemed, nil +} + +func (mls *mockLaneState) Nonce() (uint64, error) { + return mls.nonce, nil +} diff --git a/chain/actors/builtin/paych/paych.go b/chain/actors/builtin/paych/paych.go new file mode 100644 index 000000000..dad54163f --- /dev/null +++ b/chain/actors/builtin/paych/paych.go @@ -0,0 +1,60 @@ +package paych + +import ( + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + big "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/cbor" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/types" +) + +// Load returns an abstract copy of payment channel state, irregardless of actor version +func Load(store adt.Store, act *types.Actor) (State, error) { + switch act.Code { + case builtin0.PaymentChannelActorCodeID: + out := state0{store: store} + err := store.Get(store.Context(), act.Head, &out) + if err != nil { + return nil, err + } + return &out, nil + } + return nil, xerrors.Errorf("unknown actor code %s", act.Code) +} + +// State is an abstract version of payment channel state that works across +// versions +type State interface { + cbor.Marshaler + // Channel owner, who has funded the actor + From() (address.Address, error) + // Recipient of payouts from channel + To() (address.Address, error) + + // Height at which the channel can be `Collected` + SettlingAt() (abi.ChainEpoch, error) + + // Amount successfully redeemed through the payment channel, paid out on `Collect()` + ToSend() (abi.TokenAmount, error) + + // Get total number of lanes + LaneCount() (uint64, error) + + // Iterate lane states + ForEachLaneState(cb func(idx uint64, dl LaneState) error) error +} + +// LaneState is an abstract copy of the state of a single lane +type LaneState interface { + Redeemed() (big.Int, error) + Nonce() (uint64, error) +} + +type SignedVoucher = paych0.SignedVoucher +type ModVerifyParams = paych0.ModVerifyParams diff --git a/chain/actors/builtin/paych/v0.go b/chain/actors/builtin/paych/v0.go new file mode 100644 index 000000000..c0eea1000 --- /dev/null +++ b/chain/actors/builtin/paych/v0.go @@ -0,0 +1,91 @@ +package paych + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + big "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/specs-actors/actors/builtin/paych" + adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +var _ State = (*state0)(nil) + +type state0 struct { + paych.State + store adt.Store + lsAmt *adt0.Array +} + +// Channel owner, who has funded the actor +func (s *state0) From() (address.Address, error) { + return s.State.From, nil +} + +// Recipient of payouts from channel +func (s *state0) To() (address.Address, error) { + return s.State.To, nil +} + +// Height at which the channel can be `Collected` +func (s *state0) SettlingAt() (abi.ChainEpoch, error) { + return s.State.SettlingAt, nil +} + +// Amount successfully redeemed through the payment channel, paid out on `Collect()` +func (s *state0) ToSend() (abi.TokenAmount, error) { + return s.State.ToSend, nil +} + +func (s *state0) getOrLoadLsAmt() (*adt0.Array, error) { + if s.lsAmt != nil { + return s.lsAmt, nil + } + + // Get the lane state from the chain + lsamt, err := adt0.AsArray(s.store, s.State.LaneStates) + if err != nil { + return nil, err + } + + s.lsAmt = lsamt + return lsamt, nil +} + +// Get total number of lanes +func (s *state0) LaneCount() (uint64, error) { + lsamt, err := s.getOrLoadLsAmt() + if err != nil { + return 0, err + } + return lsamt.Length(), nil +} + +// Iterate lane states +func (s *state0) 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 paych.LaneState + return lsamt.ForEach(&ls, func(i int64) error { + return cb(uint64(i), &laneState0{ls}) + }) +} + +type laneState0 struct { + paych.LaneState +} + +func (ls *laneState0) Redeemed() (big.Int, error) { + return ls.LaneState.Redeemed, nil +} + +func (ls *laneState0) Nonce() (uint64, error) { + return ls.LaneState.Nonce, nil +} diff --git a/chain/actors/builtin/power/power.go b/chain/actors/builtin/power/power.go new file mode 100644 index 000000000..e4bb52d44 --- /dev/null +++ b/chain/actors/builtin/power/power.go @@ -0,0 +1,53 @@ +package power + +import ( + "github.com/filecoin-project/go-address" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/cbor" + builtin0 "github.com/filecoin-project/specs-actors/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" +) + +var Address = builtin0.StoragePowerActorAddr + +func Load(store adt.Store, act *types.Actor) (st State, err error) { + switch act.Code { + case builtin0.StoragePowerActorCodeID: + out := state0{store: store} + err := store.Get(store.Context(), act.Head, &out) + if err != nil { + return nil, err + } + return &out, nil + } + return nil, xerrors.Errorf("unknown actor code %s", act.Code) +} + +type State interface { + cbor.Marshaler + + TotalLocked() (abi.TokenAmount, error) + TotalPower() (Claim, error) + TotalCommitted() (Claim, error) + TotalPowerSmoothed() (builtin.FilterEstimate, error) + + // MinerCounts returns the number of miners. Participating is the number + // with power above the minimum miner threshold. + MinerCounts() (participating, total uint64, err error) + MinerPower(address.Address) (Claim, bool, error) + MinerNominalPowerMeetsConsensusMinimum(address.Address) (bool, error) + ListAllMiners() ([]address.Address, error) +} + +type Claim struct { + // Sum of raw byte power for a miner's sectors. + RawBytePower abi.StoragePower + + // Sum of quality adjusted power for a miner's sectors. + QualityAdjPower abi.StoragePower +} diff --git a/chain/actors/builtin/power/v0.go b/chain/actors/builtin/power/v0.go new file mode 100644 index 000000000..f2fe96dad --- /dev/null +++ b/chain/actors/builtin/power/v0.go @@ -0,0 +1,85 @@ +package power + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/actors/builtin" + power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" + "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +var _ State = (*state0)(nil) + +type state0 struct { + power0.State + store adt.Store +} + +func (s *state0) TotalLocked() (abi.TokenAmount, error) { + return s.TotalPledgeCollateral, nil +} + +func (s *state0) 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 *state0) TotalCommitted() (Claim, error) { + return Claim{ + RawBytePower: s.TotalBytesCommitted, + QualityAdjPower: s.TotalQABytesCommitted, + }, nil +} + +func (s *state0) MinerPower(addr address.Address) (Claim, bool, error) { + claims, err := adt.AsMap(s.store, s.Claims) + if err != nil { + return Claim{}, false, err + } + var claim power0.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 *state0) MinerNominalPowerMeetsConsensusMinimum(a address.Address) (bool, error) { + return s.State.MinerNominalPowerMeetsConsensusMinimum(s.store, a) +} + +func (s *state0) TotalPowerSmoothed() (builtin.FilterEstimate, error) { + return builtin.FromV0FilterEstimate(*s.State.ThisEpochQAPowerSmoothed), nil +} + +func (s *state0) MinerCounts() (uint64, uint64, error) { + return uint64(s.State.MinerAboveMinPowerCount), uint64(s.State.MinerCount), nil +} + +func (s *state0) ListAllMiners() ([]address.Address, error) { + claims, err := adt.AsMap(s.store, 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 +} diff --git a/chain/actors/builtin/reward/reward.go b/chain/actors/builtin/reward/reward.go new file mode 100644 index 000000000..cfa82c774 --- /dev/null +++ b/chain/actors/builtin/reward/reward.go @@ -0,0 +1,50 @@ +package reward + +import ( + "github.com/filecoin-project/go-state-types/abi" + reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-state-types/cbor" + builtin0 "github.com/filecoin-project/specs-actors/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" +) + +var Address = builtin0.RewardActorAddr + +func Load(store adt.Store, act *types.Actor) (st State, err error) { + switch act.Code { + case builtin0.RewardActorCodeID: + out := state0{store: store} + err := store.Get(store.Context(), act.Head, &out) + if err != nil { + return nil, err + } + return &out, nil + } + return nil, xerrors.Errorf("unknown actor code %s", act.Code) +} + +type State interface { + cbor.Marshaler + + ThisEpochBaselinePower() (abi.StoragePower, error) + ThisEpochReward() (abi.StoragePower, error) + ThisEpochRewardSmoothed() (builtin.FilterEstimate, error) + + EffectiveBaselinePower() (abi.StoragePower, error) + EffectiveNetworkTime() (abi.ChainEpoch, error) + + TotalStoragePowerReward() (abi.TokenAmount, error) + + CumsumBaseline() (abi.StoragePower, error) + CumsumRealized() (abi.StoragePower, error) + + InitialPledgeForPower(abi.StoragePower, abi.TokenAmount, *builtin.FilterEstimate, abi.TokenAmount) (abi.TokenAmount, error) + PreCommitDepositForPower(builtin.FilterEstimate, abi.StoragePower) (abi.TokenAmount, error) +} + +type AwardBlockRewardParams = reward0.AwardBlockRewardParams diff --git a/chain/actors/builtin/reward/v0.go b/chain/actors/builtin/reward/v0.go new file mode 100644 index 000000000..df7117b67 --- /dev/null +++ b/chain/actors/builtin/reward/v0.go @@ -0,0 +1,71 @@ +package reward + +import ( + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/actors/builtin" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/builtin/reward" + "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/specs-actors/actors/util/smoothing" +) + +var _ State = (*state0)(nil) + +type state0 struct { + reward.State + store adt.Store +} + +func (s *state0) ThisEpochReward() (abi.StoragePower, error) { + return s.State.ThisEpochReward, nil +} + +func (s *state0) ThisEpochRewardSmoothed() (builtin.FilterEstimate, error) { + return builtin.FromV0FilterEstimate(*s.State.ThisEpochRewardSmoothed), nil +} + +func (s *state0) ThisEpochBaselinePower() (abi.StoragePower, error) { + return s.State.ThisEpochBaselinePower, nil +} + +func (s *state0) TotalStoragePowerReward() (abi.TokenAmount, error) { + return s.State.TotalMined, nil +} + +func (s *state0) EffectiveBaselinePower() (abi.StoragePower, error) { + return s.State.EffectiveBaselinePower, nil +} + +func (s *state0) EffectiveNetworkTime() (abi.ChainEpoch, error) { + return s.State.EffectiveNetworkTime, nil +} + +func (s *state0) CumsumBaseline() (abi.StoragePower, error) { + return s.State.CumsumBaseline, nil +} + +func (s *state0) CumsumRealized() (abi.StoragePower, error) { + return s.State.CumsumBaseline, nil +} + +func (s *state0) InitialPledgeForPower(sectorWeight abi.StoragePower, networkTotalPledge abi.TokenAmount, networkQAPower *builtin.FilterEstimate, circSupply abi.TokenAmount) (abi.TokenAmount, error) { + return miner0.InitialPledgeForPower( + sectorWeight, + s.State.ThisEpochBaselinePower, + networkTotalPledge, + s.State.ThisEpochRewardSmoothed, + &smoothing.FilterEstimate{ + PositionEstimate: networkQAPower.PositionEstimate, + VelocityEstimate: networkQAPower.VelocityEstimate, + }, + circSupply), nil +} + +func (s *state0) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, sectorWeight abi.StoragePower) (abi.TokenAmount, error) { + return miner0.PreCommitDepositForPower(s.State.ThisEpochRewardSmoothed, + &smoothing.FilterEstimate{ + PositionEstimate: networkQAPower.PositionEstimate, + VelocityEstimate: networkQAPower.VelocityEstimate, + }, + sectorWeight), nil +} diff --git a/chain/actors/builtin/verifreg/v0.go b/chain/actors/builtin/verifreg/v0.go new file mode 100644 index 000000000..c59a58811 --- /dev/null +++ b/chain/actors/builtin/verifreg/v0.go @@ -0,0 +1,71 @@ +package verifreg + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/actors/adt" +) + +var _ State = (*state0)(nil) + +type state0 struct { + verifreg0.State + store adt.Store +} + +func getDataCap(store adt.Store, root cid.Cid, addr address.Address) (bool, abi.StoragePower, error) { + if addr.Protocol() != address.ID { + return false, big.Zero(), xerrors.Errorf("can only look up ID addresses") + } + + vh, err := adt0.AsMap(store, root) + if err != nil { + return false, big.Zero(), xerrors.Errorf("loading verifreg: %w", err) + } + + var dcap abi.StoragePower + if found, err := vh.Get(abi.AddrKey(addr), &dcap); err != nil { + return false, big.Zero(), xerrors.Errorf("looking up addr: %w", err) + } else if !found { + return false, big.Zero(), nil + } + + return true, dcap, nil +} + +func (s *state0) VerifiedClientDataCap(addr address.Address) (bool, abi.StoragePower, error) { + return getDataCap(s.store, s.State.VerifiedClients, addr) +} + +func (s *state0) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, error) { + return getDataCap(s.store, s.State.Verifiers, addr) +} + +func forEachCap(store adt.Store, root cid.Cid, cb func(addr address.Address, dcap abi.StoragePower) error) error { + vh, err := adt0.AsMap(store, root) + if err != nil { + return xerrors.Errorf("loading verified clients: %w", err) + } + var dcap abi.StoragePower + return vh.ForEach(&dcap, func(key string) error { + a, err := address.NewFromBytes([]byte(key)) + if err != nil { + return err + } + return cb(a, dcap) + }) +} + +func (s *state0) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error { + return forEachCap(s.store, s.State.Verifiers, cb) +} + +func (s *state0) ForEachClient(cb func(addr address.Address, dcap abi.StoragePower) error) error { + return forEachCap(s.store, s.State.VerifiedClients, cb) +} diff --git a/chain/actors/builtin/verifreg/verifreg.go b/chain/actors/builtin/verifreg/verifreg.go new file mode 100644 index 000000000..c861f862f --- /dev/null +++ b/chain/actors/builtin/verifreg/verifreg.go @@ -0,0 +1,37 @@ +package verifreg + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-state-types/cbor" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/types" +) + +var Address = builtin0.VerifiedRegistryActorAddr + +func Load(store adt.Store, act *types.Actor) (State, error) { + switch act.Code { + case builtin0.VerifiedRegistryActorCodeID: + out := state0{store: store} + err := store.Get(store.Context(), act.Head, &out) + if err != nil { + return nil, err + } + return &out, nil + } + return nil, xerrors.Errorf("unknown actor code %s", act.Code) +} + +type State interface { + cbor.Marshaler + + VerifiedClientDataCap(address.Address) (bool, abi.StoragePower, error) + VerifierDataCap(address.Address) (bool, abi.StoragePower, error) + ForEachVerifier(func(addr address.Address, dcap abi.StoragePower) error) error + ForEachClient(func(addr address.Address, dcap abi.StoragePower) error) error +} diff --git a/chain/actors/policy/policy.go b/chain/actors/policy/policy.go new file mode 100644 index 000000000..eec52e855 --- /dev/null +++ b/chain/actors/policy/policy.go @@ -0,0 +1,56 @@ +package policy + +import ( + "github.com/filecoin-project/go-state-types/abi" + + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" + verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" +) + +// SetSupportedProofTypes sets supported proof types, across all actor versions. +// This should only be used for testing. +func SetSupportedProofTypes(types ...abi.RegisteredSealProof) { + newTypes := make(map[abi.RegisteredSealProof]struct{}, len(types)) + for _, t := range types { + newTypes[t] = struct{}{} + } + // Set for all miner versions. + miner0.SupportedProofTypes = newTypes +} + +// AddSupportedProofTypes sets supported proof types, across all actor versions. +// This should only be used for testing. +func AddSupportedProofTypes(types ...abi.RegisteredSealProof) { + newTypes := make(map[abi.RegisteredSealProof]struct{}, len(types)) + for _, t := range types { + newTypes[t] = struct{}{} + } + // Set for all miner versions. + miner0.SupportedProofTypes = newTypes +} + +// SetPreCommitChallengeDelay sets the pre-commit challenge delay across all +// actors versions. Use for testing. +func SetPreCommitChallengeDelay(delay abi.ChainEpoch) { + // Set for all miner versions. + miner0.PreCommitChallengeDelay = delay +} + +// TODO: this function shouldn't really exist. Instead, the API should expose the precommit delay. +func GetPreCommitChallengeDelay() abi.ChainEpoch { + return miner0.PreCommitChallengeDelay +} + +// SetConsensusMinerMinPower sets the minimum power of an individual miner must +// meet for leader election, across all actor versions. This should only be used +// for testing. +func SetConsensusMinerMinPower(p abi.StoragePower) { + power0.ConsensusMinerMinPower = p +} + +// SetMinVerifiedDealSize sets the minimum size of a verified deal. This should +// only be used for testing. +func SetMinVerifiedDealSize(size abi.StoragePower) { + verifreg0.MinVerifiedDealSize = size +} diff --git a/chain/events/state/predicates.go b/chain/events/state/predicates.go index 0858793d8..99b8480dc 100644 --- a/chain/events/state/predicates.go +++ b/chain/events/state/predicates.go @@ -4,20 +4,19 @@ import ( "bytes" "context" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "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/specs-actors/actors/builtin" - init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" - "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" - "github.com/filecoin-project/specs-actors/actors/util/adt" - "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" typegen "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/lotus/api/apibstore" + "github.com/filecoin-project/lotus/chain/actors/adt" + init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" + "github.com/filecoin-project/lotus/chain/actors/builtin/market" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/types" ) @@ -49,7 +48,7 @@ func NewStatePredicates(api ChainAPI) *StatePredicates { // - err type DiffTipSetKeyFunc func(ctx context.Context, oldState, newState types.TipSetKey) (changed bool, user UserData, err error) -type DiffActorStateFunc func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) +type DiffActorStateFunc func(ctx context.Context, oldActorState *types.Actor, newActorState *types.Actor) (changed bool, user UserData, err error) // OnActorStateChanged calls diffStateFunc when the state changes for the given actor func (sp *StatePredicates) OnActorStateChanged(addr address.Address, diffStateFunc DiffActorStateFunc) DiffTipSetKeyFunc { @@ -66,30 +65,30 @@ func (sp *StatePredicates) OnActorStateChanged(addr address.Address, diffStateFu if oldActor.Head.Equals(newActor.Head) { return false, nil, nil } - return diffStateFunc(ctx, oldActor.Head, newActor.Head) + return diffStateFunc(ctx, oldActor, newActor) } } -type DiffStorageMarketStateFunc func(ctx context.Context, oldState *market.State, newState *market.State) (changed bool, user UserData, err error) +type DiffStorageMarketStateFunc func(ctx context.Context, oldState market.State, newState market.State) (changed bool, user UserData, err error) // OnStorageMarketActorChanged calls diffStorageMarketState when the state changes for the market actor func (sp *StatePredicates) OnStorageMarketActorChanged(diffStorageMarketState DiffStorageMarketStateFunc) DiffTipSetKeyFunc { - return sp.OnActorStateChanged(builtin.StorageMarketActorAddr, func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) { - var oldState market.State - if err := sp.cst.Get(ctx, oldActorStateHead, &oldState); err != nil { + return sp.OnActorStateChanged(market.Address, func(ctx context.Context, oldActorState, newActorState *types.Actor) (changed bool, user UserData, err error) { + oldState, err := market.Load(adt.WrapStore(ctx, sp.cst), oldActorState) + if err != nil { return false, nil, err } - var newState market.State - if err := sp.cst.Get(ctx, newActorStateHead, &newState); err != nil { + newState, err := market.Load(adt.WrapStore(ctx, sp.cst), newActorState) + if err != nil { return false, nil, err } - return diffStorageMarketState(ctx, &oldState, &newState) + return diffStorageMarketState(ctx, oldState, newState) }) } type BalanceTables struct { - EscrowTable *adt.BalanceTable - LockedTable *adt.BalanceTable + EscrowTable market.BalanceTable + LockedTable market.BalanceTable } // DiffBalanceTablesFunc compares two balance tables @@ -97,32 +96,32 @@ type DiffBalanceTablesFunc func(ctx context.Context, oldBalanceTable, newBalance // OnBalanceChanged runs when the escrow table for available balances changes func (sp *StatePredicates) OnBalanceChanged(diffBalances DiffBalanceTablesFunc) DiffStorageMarketStateFunc { - return func(ctx context.Context, oldState *market.State, newState *market.State) (changed bool, user UserData, err error) { - if oldState.EscrowTable.Equals(newState.EscrowTable) && oldState.LockedTable.Equals(newState.LockedTable) { + return func(ctx context.Context, oldState market.State, newState market.State) (changed bool, user UserData, err error) { + bc, err := oldState.BalancesChanged(newState) + if err != nil { + return false, nil, err + } + + if !bc { return false, nil, nil } - ctxStore := &contextStore{ - ctx: ctx, - cst: sp.cst, - } - - oldEscrowRoot, err := adt.AsBalanceTable(ctxStore, oldState.EscrowTable) + oldEscrowRoot, err := oldState.EscrowTable() if err != nil { return false, nil, err } - oldLockedRoot, err := adt.AsBalanceTable(ctxStore, oldState.LockedTable) + oldLockedRoot, err := oldState.LockedTable() if err != nil { return false, nil, err } - newEscrowRoot, err := adt.AsBalanceTable(ctxStore, newState.EscrowTable) + newEscrowRoot, err := newState.EscrowTable() if err != nil { return false, nil, err } - newLockedRoot, err := adt.AsBalanceTable(ctxStore, newState.LockedTable) + newLockedRoot, err := newState.LockedTable() if err != nil { return false, nil, err } @@ -131,25 +130,27 @@ func (sp *StatePredicates) OnBalanceChanged(diffBalances DiffBalanceTablesFunc) } } -type DiffAdtArraysFunc func(ctx context.Context, oldDealStateRoot, newDealStateRoot *adt.Array) (changed bool, user UserData, err error) +type DiffDealStatesFunc func(ctx context.Context, oldDealStateRoot, newDealStateRoot market.DealStates) (changed bool, user UserData, err error) +type DiffDealProposalsFunc func(ctx context.Context, oldDealStateRoot, newDealStateRoot market.DealProposals) (changed bool, user UserData, err error) +type DiffAdtArraysFunc func(ctx context.Context, oldDealStateRoot, newDealStateRoot adt.Array) (changed bool, user UserData, err error) // OnDealStateChanged calls diffDealStates when the market deal state changes -func (sp *StatePredicates) OnDealStateChanged(diffDealStates DiffAdtArraysFunc) DiffStorageMarketStateFunc { - return func(ctx context.Context, oldState *market.State, newState *market.State) (changed bool, user UserData, err error) { - if oldState.States.Equals(newState.States) { - return false, nil, nil - } - - ctxStore := &contextStore{ - ctx: ctx, - cst: sp.cst, - } - - oldRoot, err := adt.AsArray(ctxStore, oldState.States) +func (sp *StatePredicates) OnDealStateChanged(diffDealStates DiffDealStatesFunc) DiffStorageMarketStateFunc { + return func(ctx context.Context, oldState market.State, newState market.State) (changed bool, user UserData, err error) { + sc, err := oldState.StatesChanged(newState) if err != nil { return false, nil, err } - newRoot, err := adt.AsArray(ctxStore, newState.States) + + if !sc { + return false, nil, nil + } + + oldRoot, err := oldState.States() + if err != nil { + return false, nil, err + } + newRoot, err := newState.States() if err != nil { return false, nil, err } @@ -159,22 +160,22 @@ func (sp *StatePredicates) OnDealStateChanged(diffDealStates DiffAdtArraysFunc) } // OnDealProposalChanged calls diffDealProps when the market proposal state changes -func (sp *StatePredicates) OnDealProposalChanged(diffDealProps DiffAdtArraysFunc) DiffStorageMarketStateFunc { - return func(ctx context.Context, oldState *market.State, newState *market.State) (changed bool, user UserData, err error) { - if oldState.Proposals.Equals(newState.Proposals) { - return false, nil, nil - } - - ctxStore := &contextStore{ - ctx: ctx, - cst: sp.cst, - } - - oldRoot, err := adt.AsArray(ctxStore, oldState.Proposals) +func (sp *StatePredicates) OnDealProposalChanged(diffDealProps DiffDealProposalsFunc) DiffStorageMarketStateFunc { + return func(ctx context.Context, oldState market.State, newState market.State) (changed bool, user UserData, err error) { + pc, err := oldState.ProposalsChanged(newState) if err != nil { return false, nil, err } - newRoot, err := adt.AsArray(ctxStore, newState.Proposals) + + if !pc { + return false, nil, nil + } + + oldRoot, err := oldState.Proposals() + if err != nil { + return false, nil, err + } + newRoot, err := newState.Proposals() if err != nil { return false, nil, err } @@ -183,51 +184,14 @@ func (sp *StatePredicates) OnDealProposalChanged(diffDealProps DiffAdtArraysFunc } } -var _ AdtArrayDiff = &MarketDealProposalChanges{} - -type MarketDealProposalChanges struct { - Added []ProposalIDState - Removed []ProposalIDState -} - -type ProposalIDState struct { - ID abi.DealID - Proposal market.DealProposal -} - -func (m *MarketDealProposalChanges) Add(key uint64, val *typegen.Deferred) error { - dp := new(market.DealProposal) - err := dp.UnmarshalCBOR(bytes.NewReader(val.Raw)) - if err != nil { - return err - } - m.Added = append(m.Added, ProposalIDState{abi.DealID(key), *dp}) - return nil -} - -func (m *MarketDealProposalChanges) Modify(key uint64, from, to *typegen.Deferred) error { - // short circuit, DealProposals are static - return nil -} - -func (m *MarketDealProposalChanges) Remove(key uint64, val *typegen.Deferred) error { - dp := new(market.DealProposal) - err := dp.UnmarshalCBOR(bytes.NewReader(val.Raw)) - if err != nil { - return err - } - m.Removed = append(m.Removed, ProposalIDState{abi.DealID(key), *dp}) - return nil -} - // OnDealProposalAmtChanged detects changes in the deal proposal AMT for all deal proposals and returns a MarketProposalsChanges structure containing: // - Added Proposals // - Modified Proposals // - Removed Proposals -func (sp *StatePredicates) OnDealProposalAmtChanged() DiffAdtArraysFunc { - return func(ctx context.Context, oldDealProps, newDealProps *adt.Array) (changed bool, user UserData, err error) { - proposalChanges := new(MarketDealProposalChanges) - if err := DiffAdtArray(oldDealProps, newDealProps, proposalChanges); err != nil { +func (sp *StatePredicates) OnDealProposalAmtChanged() DiffDealProposalsFunc { + return func(ctx context.Context, oldDealProps, newDealProps market.DealProposals) (changed bool, user UserData, err error) { + proposalChanges, err := market.DiffDealProposals(oldDealProps, newDealProps) + if err != nil { return false, nil, err } @@ -239,64 +203,14 @@ func (sp *StatePredicates) OnDealProposalAmtChanged() DiffAdtArraysFunc { } } -var _ AdtArrayDiff = &MarketDealStateChanges{} - -type MarketDealStateChanges struct { - Added []DealIDState - Modified []DealStateChange - Removed []DealIDState -} - -type DealIDState struct { - ID abi.DealID - Deal market.DealState -} - -func (m *MarketDealStateChanges) Add(key uint64, val *typegen.Deferred) error { - ds := new(market.DealState) - err := ds.UnmarshalCBOR(bytes.NewReader(val.Raw)) - if err != nil { - return err - } - m.Added = append(m.Added, DealIDState{abi.DealID(key), *ds}) - return nil -} - -func (m *MarketDealStateChanges) Modify(key uint64, from, to *typegen.Deferred) error { - dsFrom := new(market.DealState) - if err := dsFrom.UnmarshalCBOR(bytes.NewReader(from.Raw)); err != nil { - return err - } - - dsTo := new(market.DealState) - if err := dsTo.UnmarshalCBOR(bytes.NewReader(to.Raw)); err != nil { - return err - } - - if *dsFrom != *dsTo { - m.Modified = append(m.Modified, DealStateChange{abi.DealID(key), dsFrom, dsTo}) - } - return nil -} - -func (m *MarketDealStateChanges) Remove(key uint64, val *typegen.Deferred) error { - ds := new(market.DealState) - err := ds.UnmarshalCBOR(bytes.NewReader(val.Raw)) - if err != nil { - return err - } - m.Removed = append(m.Removed, DealIDState{abi.DealID(key), *ds}) - return nil -} - // OnDealStateAmtChanged detects changes in the deal state AMT for all deal states and returns a MarketDealStateChanges structure containing: // - Added Deals // - Modified Deals // - Removed Deals -func (sp *StatePredicates) OnDealStateAmtChanged() DiffAdtArraysFunc { - return func(ctx context.Context, oldDealStates, newDealStates *adt.Array) (changed bool, user UserData, err error) { - dealStateChanges := new(MarketDealStateChanges) - if err := DiffAdtArray(oldDealStates, newDealStates, dealStateChanges); err != nil { +func (sp *StatePredicates) OnDealStateAmtChanged() DiffDealStatesFunc { + return func(ctx context.Context, oldDealStates, newDealStates market.DealStates) (changed bool, user UserData, err error) { + dealStateChanges, err := market.DiffDealStates(oldDealStates, newDealStates) + if err != nil { return false, nil, err } @@ -309,42 +223,29 @@ func (sp *StatePredicates) OnDealStateAmtChanged() DiffAdtArraysFunc { } // ChangedDeals is a set of changes to deal state -type ChangedDeals map[abi.DealID]DealStateChange - -// DealStateChange is a change in deal state from -> to -type DealStateChange struct { - ID abi.DealID - From *market.DealState - To *market.DealState -} +type ChangedDeals map[abi.DealID]market.DealStateChange // DealStateChangedForIDs detects changes in the deal state AMT for the given deal IDs -func (sp *StatePredicates) DealStateChangedForIDs(dealIds []abi.DealID) DiffAdtArraysFunc { - return func(ctx context.Context, oldDealStateArray, newDealStateArray *adt.Array) (changed bool, user UserData, err error) { +func (sp *StatePredicates) DealStateChangedForIDs(dealIds []abi.DealID) DiffDealStatesFunc { + return func(ctx context.Context, oldDealStates, newDealStates market.DealStates) (changed bool, user UserData, err error) { changedDeals := make(ChangedDeals) for _, dealID := range dealIds { - var oldDealPtr, newDealPtr *market.DealState - var oldDeal, newDeal market.DealState // If the deal has been removed, we just set it to nil - found, err := oldDealStateArray.Get(uint64(dealID), &oldDeal) + oldDeal, oldFound, err := oldDealStates.Get(dealID) if err != nil { return false, nil, err } - if found { - oldDealPtr = &oldDeal - } - found, err = newDealStateArray.Get(uint64(dealID), &newDeal) + newDeal, newFound, err := newDealStates.Get(dealID) if err != nil { return false, nil, err } - if found { - newDealPtr = &newDeal - } - if oldDeal != newDeal { - changedDeals[dealID] = DealStateChange{dealID, oldDealPtr, newDealPtr} + existenceChanged := oldFound != newFound + valueChanged := (oldFound && newFound) && *oldDeal != *newDeal + if existenceChanged || valueChanged { + changedDeals[dealID] = market.DealStateChange{ID: dealID, From: oldDeal, To: newDeal} } } if len(changedDeals) > 0 { @@ -405,124 +306,43 @@ func (sp *StatePredicates) AvailableBalanceChangedForAddresses(getAddrs func() [ } } -type DiffMinerActorStateFunc func(ctx context.Context, oldState *miner.State, newState *miner.State) (changed bool, user UserData, err error) +type DiffMinerActorStateFunc func(ctx context.Context, oldState miner.State, newState miner.State) (changed bool, user UserData, err error) func (sp *StatePredicates) OnInitActorChange(diffInitActorState DiffInitActorStateFunc) DiffTipSetKeyFunc { - return sp.OnActorStateChanged(builtin.InitActorAddr, func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) { - var oldState init_.State - if err := sp.cst.Get(ctx, oldActorStateHead, &oldState); err != nil { + return sp.OnActorStateChanged(init_.Address, func(ctx context.Context, oldActorState, newActorState *types.Actor) (changed bool, user UserData, err error) { + oldState, err := init_.Load(adt.WrapStore(ctx, sp.cst), oldActorState) + if err != nil { return false, nil, err } - var newState init_.State - if err := sp.cst.Get(ctx, newActorStateHead, &newState); err != nil { + newState, err := init_.Load(adt.WrapStore(ctx, sp.cst), newActorState) + if err != nil { return false, nil, err } - return diffInitActorState(ctx, &oldState, &newState) + return diffInitActorState(ctx, oldState, newState) }) } func (sp *StatePredicates) OnMinerActorChange(minerAddr address.Address, diffMinerActorState DiffMinerActorStateFunc) DiffTipSetKeyFunc { - return sp.OnActorStateChanged(minerAddr, func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) { - var oldState miner.State - if err := sp.cst.Get(ctx, oldActorStateHead, &oldState); err != nil { + return sp.OnActorStateChanged(minerAddr, func(ctx context.Context, oldActorState, newActorState *types.Actor) (changed bool, user UserData, err error) { + oldState, err := miner.Load(adt.WrapStore(ctx, sp.cst), oldActorState) + if err != nil { return false, nil, err } - var newState miner.State - if err := sp.cst.Get(ctx, newActorStateHead, &newState); err != nil { + newState, err := miner.Load(adt.WrapStore(ctx, sp.cst), newActorState) + if err != nil { return false, nil, err } - return diffMinerActorState(ctx, &oldState, &newState) + return diffMinerActorState(ctx, oldState, newState) }) } -type MinerSectorChanges struct { - Added []miner.SectorOnChainInfo - Extended []SectorExtensions - Removed []miner.SectorOnChainInfo -} - -var _ AdtArrayDiff = &MinerSectorChanges{} - -type SectorExtensions struct { - From miner.SectorOnChainInfo - To miner.SectorOnChainInfo -} - -func (m *MinerSectorChanges) Add(key uint64, val *typegen.Deferred) error { - si := new(miner.SectorOnChainInfo) - err := si.UnmarshalCBOR(bytes.NewReader(val.Raw)) - if err != nil { - return err - } - m.Added = append(m.Added, *si) - return nil -} - -func (m *MinerSectorChanges) Modify(key uint64, from, to *typegen.Deferred) error { - siFrom := new(miner.SectorOnChainInfo) - err := siFrom.UnmarshalCBOR(bytes.NewReader(from.Raw)) - if err != nil { - return err - } - - siTo := new(miner.SectorOnChainInfo) - err = siTo.UnmarshalCBOR(bytes.NewReader(to.Raw)) - if err != nil { - return err - } - - if siFrom.Expiration != siTo.Expiration { - m.Extended = append(m.Extended, SectorExtensions{ - From: *siFrom, - To: *siTo, - }) - } - return nil -} - -func (m *MinerSectorChanges) Remove(key uint64, val *typegen.Deferred) error { - si := new(miner.SectorOnChainInfo) - err := si.UnmarshalCBOR(bytes.NewReader(val.Raw)) - if err != nil { - return err - } - m.Removed = append(m.Removed, *si) - return nil -} - func (sp *StatePredicates) OnMinerSectorChange() DiffMinerActorStateFunc { - return func(ctx context.Context, oldState, newState *miner.State) (changed bool, user UserData, err error) { - ctxStore := &contextStore{ - ctx: ctx, - cst: sp.cst, - } - - sectorChanges := &MinerSectorChanges{ - Added: []miner.SectorOnChainInfo{}, - Extended: []SectorExtensions{}, - Removed: []miner.SectorOnChainInfo{}, - } - - // no sector changes - if oldState.Sectors.Equals(newState.Sectors) { - return false, nil, nil - } - - oldSectors, err := adt.AsArray(ctxStore, oldState.Sectors) + return func(ctx context.Context, oldState, newState miner.State) (changed bool, user UserData, err error) { + sectorChanges, err := miner.DiffSectors(oldState, newState) if err != nil { return false, nil, err } - - newSectors, err := adt.AsArray(ctxStore, newState.Sectors) - if err != nil { - return false, nil, err - } - - if err := DiffAdtArray(oldSectors, newSectors, sectorChanges); err != nil { - return false, nil, err - } - // nothing changed if len(sectorChanges.Added)+len(sectorChanges.Extended)+len(sectorChanges.Removed) == 0 { return false, nil, nil @@ -532,73 +352,13 @@ func (sp *StatePredicates) OnMinerSectorChange() DiffMinerActorStateFunc { } } -type MinerPreCommitChanges struct { - Added []miner.SectorPreCommitOnChainInfo - Removed []miner.SectorPreCommitOnChainInfo -} - -func (m *MinerPreCommitChanges) AsKey(key string) (abi.Keyer, error) { - sector, err := abi.ParseUIntKey(key) - if err != nil { - return nil, err - } - return miner.SectorKey(abi.SectorNumber(sector)), nil -} - -func (m *MinerPreCommitChanges) Add(key string, val *typegen.Deferred) error { - sp := new(miner.SectorPreCommitOnChainInfo) - err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) - if err != nil { - return err - } - m.Added = append(m.Added, *sp) - return nil -} - -func (m *MinerPreCommitChanges) Modify(key string, from, to *typegen.Deferred) error { - return nil -} - -func (m *MinerPreCommitChanges) Remove(key string, val *typegen.Deferred) error { - sp := new(miner.SectorPreCommitOnChainInfo) - err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw)) - if err != nil { - return err - } - m.Removed = append(m.Removed, *sp) - return nil -} - func (sp *StatePredicates) OnMinerPreCommitChange() DiffMinerActorStateFunc { - return func(ctx context.Context, oldState, newState *miner.State) (changed bool, user UserData, err error) { - ctxStore := &contextStore{ - ctx: ctx, - cst: sp.cst, - } - - precommitChanges := &MinerPreCommitChanges{ - Added: []miner.SectorPreCommitOnChainInfo{}, - Removed: []miner.SectorPreCommitOnChainInfo{}, - } - - if oldState.PreCommittedSectors.Equals(newState.PreCommittedSectors) { - return false, nil, nil - } - - oldPrecommits, err := adt.AsMap(ctxStore, oldState.PreCommittedSectors) + return func(ctx context.Context, oldState, newState miner.State) (changed bool, user UserData, err error) { + precommitChanges, err := miner.DiffPreCommits(oldState, newState) if err != nil { return false, nil, err } - newPrecommits, err := adt.AsMap(ctxStore, newState.PreCommittedSectors) - if err != nil { - return false, nil, err - } - - if err := DiffAdtMap(oldPrecommits, newPrecommits, precommitChanges); err != nil { - return false, nil, err - } - if len(precommitChanges.Added)+len(precommitChanges.Removed) == 0 { return false, nil, nil } @@ -608,20 +368,20 @@ func (sp *StatePredicates) OnMinerPreCommitChange() DiffMinerActorStateFunc { } // DiffPaymentChannelStateFunc is function that compares two states for the payment channel -type DiffPaymentChannelStateFunc func(ctx context.Context, oldState *paych.State, newState *paych.State) (changed bool, user UserData, err error) +type DiffPaymentChannelStateFunc func(ctx context.Context, oldState paych.State, newState paych.State) (changed bool, user UserData, err error) // OnPaymentChannelActorChanged calls diffPaymentChannelState when the state changes for the the payment channel actor func (sp *StatePredicates) OnPaymentChannelActorChanged(paychAddr address.Address, diffPaymentChannelState DiffPaymentChannelStateFunc) DiffTipSetKeyFunc { - return sp.OnActorStateChanged(paychAddr, func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) { - var oldState paych.State - if err := sp.cst.Get(ctx, oldActorStateHead, &oldState); err != nil { + return sp.OnActorStateChanged(paychAddr, func(ctx context.Context, oldActorState, newActorState *types.Actor) (changed bool, user UserData, err error) { + oldState, err := paych.Load(adt.WrapStore(ctx, sp.cst), oldActorState) + if err != nil { return false, nil, err } - var newState paych.State - if err := sp.cst.Get(ctx, newActorStateHead, &newState); err != nil { + newState, err := paych.Load(adt.WrapStore(ctx, sp.cst), newActorState) + if err != nil { return false, nil, err } - return diffPaymentChannelState(ctx, &oldState, &newState) + return diffPaymentChannelState(ctx, oldState, newState) }) } @@ -633,13 +393,23 @@ type PayChToSendChange struct { // OnToSendAmountChanges monitors changes on the total amount to send from one party to the other on a payment channel func (sp *StatePredicates) OnToSendAmountChanges() DiffPaymentChannelStateFunc { - return func(ctx context.Context, oldState *paych.State, newState *paych.State) (changed bool, user UserData, err error) { - if oldState.ToSend.Equals(newState.ToSend) { + return func(ctx context.Context, oldState paych.State, newState paych.State) (changed bool, user UserData, err error) { + ots, err := oldState.ToSend() + if err != nil { + return false, nil, err + } + + nts, err := newState.ToSend() + if err != nil { + return false, nil, err + } + + if ots.Equals(nts) { return false, nil, nil } return true, &PayChToSendChange{ - OldToSend: oldState.ToSend, - NewToSend: newState.ToSend, + OldToSend: ots, + NewToSend: nts, }, nil } } @@ -660,7 +430,7 @@ type AddressChange struct { To AddressPair } -type DiffInitActorStateFunc func(ctx context.Context, oldState *init_.State, newState *init_.State) (changed bool, user UserData, err error) +type DiffInitActorStateFunc func(ctx context.Context, oldState init_.State, newState init_.State) (changed bool, user UserData, err error) func (i *InitActorAddressChanges) AsKey(key string) (abi.Keyer, error) { addr, err := address.NewFromBytes([]byte(key)) @@ -748,33 +518,73 @@ func (i *InitActorAddressChanges) Remove(key string, val *typegen.Deferred) erro } func (sp *StatePredicates) OnAddressMapChange() DiffInitActorStateFunc { - return func(ctx context.Context, oldState, newState *init_.State) (changed bool, user UserData, err error) { - ctxStore := &contextStore{ - ctx: ctx, - cst: sp.cst, - } - + return func(ctx context.Context, oldState, newState init_.State) (changed bool, user UserData, err error) { addressChanges := &InitActorAddressChanges{ Added: []AddressPair{}, Modified: []AddressChange{}, Removed: []AddressPair{}, } - if oldState.AddressMap.Equals(newState.AddressMap) { - return false, nil, nil - } + err = oldState.ForEachActor(func(oldId abi.ActorID, oldAddress address.Address) error { + oldIdAddress, err := address.NewIDAddress(uint64(oldId)) + if err != nil { + return err + } + + newIdAddress, found, err := newState.ResolveAddress(oldAddress) + if err != nil { + return err + } + + if !found { + addressChanges.Removed = append(addressChanges.Removed, AddressPair{ + ID: oldIdAddress, + PK: oldAddress, + }) + } + + if oldIdAddress != newIdAddress { + addressChanges.Modified = append(addressChanges.Modified, AddressChange{ + From: AddressPair{ + ID: oldIdAddress, + PK: oldAddress, + }, + To: AddressPair{ + ID: newIdAddress, + PK: oldAddress, + }, + }) + } + + return nil + }) - oldAddrs, err := adt.AsMap(ctxStore, oldState.AddressMap) if err != nil { return false, nil, err } - newAddrs, err := adt.AsMap(ctxStore, newState.AddressMap) - if err != nil { - return false, nil, err - } + err = newState.ForEachActor(func(newId abi.ActorID, newAddress address.Address) error { + newIdAddress, err := address.NewIDAddress(uint64(newId)) + if err != nil { + return err + } - if err := DiffAdtMap(oldAddrs, newAddrs, addressChanges); err != nil { + _, found, err := newState.ResolveAddress(newAddress) + if err != nil { + return err + } + + if !found { + addressChanges.Added = append(addressChanges.Added, AddressPair{ + ID: newIdAddress, + PK: newAddress, + }) + } + + return nil + }) + + if err != nil { return false, nil, err } diff --git a/chain/events/state/predicates_test.go b/chain/events/state/predicates_test.go index a1dccfadc..461ac4997 100644 --- a/chain/events/state/predicates_test.go +++ b/chain/events/state/predicates_test.go @@ -4,6 +4,8 @@ import ( "context" "testing" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/go-bitfield" "github.com/stretchr/testify/require" @@ -16,8 +18,11 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" - "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/builtin/market" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" + + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/util/adt" tutils "github.com/filecoin-project/specs-actors/support/testing" @@ -69,22 +74,22 @@ func TestMarketPredicates(t *testing.T) { bs := bstore.NewTemporarySync() store := adt.WrapStore(ctx, cbornode.NewCborStore(bs)) - oldDeal1 := &market.DealState{ + oldDeal1 := &market0.DealState{ SectorStartEpoch: 1, LastUpdatedEpoch: 2, SlashEpoch: 0, } - oldDeal2 := &market.DealState{ + oldDeal2 := &market0.DealState{ SectorStartEpoch: 4, LastUpdatedEpoch: 5, SlashEpoch: 0, } - oldDeals := map[abi.DealID]*market.DealState{ + oldDeals := map[abi.DealID]*market0.DealState{ abi.DealID(1): oldDeal1, abi.DealID(2): oldDeal2, } - oldProp1 := &market.DealProposal{ + oldProp1 := &market0.DealProposal{ PieceCID: dummyCid, PieceSize: 0, VerifiedDeal: false, @@ -96,7 +101,7 @@ func TestMarketPredicates(t *testing.T) { ProviderCollateral: big.Zero(), ClientCollateral: big.Zero(), } - oldProp2 := &market.DealProposal{ + oldProp2 := &market0.DealProposal{ PieceCID: dummyCid, PieceSize: 0, VerifiedDeal: false, @@ -108,7 +113,7 @@ func TestMarketPredicates(t *testing.T) { ProviderCollateral: big.Zero(), ClientCollateral: big.Zero(), } - oldProps := map[abi.DealID]*market.DealProposal{ + oldProps := map[abi.DealID]*market0.DealProposal{ abi.DealID(1): oldProp1, abi.DealID(2): oldProp2, } @@ -122,7 +127,7 @@ func TestMarketPredicates(t *testing.T) { oldStateC := createMarketState(ctx, t, store, oldDeals, oldProps, oldBalances) - newDeal1 := &market.DealState{ + newDeal1 := &market0.DealState{ SectorStartEpoch: 1, LastUpdatedEpoch: 3, SlashEpoch: 0, @@ -131,19 +136,19 @@ func TestMarketPredicates(t *testing.T) { // deal 2 removed // added - newDeal3 := &market.DealState{ + newDeal3 := &market0.DealState{ SectorStartEpoch: 1, LastUpdatedEpoch: 2, SlashEpoch: 3, } - newDeals := map[abi.DealID]*market.DealState{ + newDeals := map[abi.DealID]*market0.DealState{ abi.DealID(1): newDeal1, // deal 2 was removed abi.DealID(3): newDeal3, } // added - newProp3 := &market.DealProposal{ + newProp3 := &market0.DealProposal{ PieceCID: dummyCid, PieceSize: 0, VerifiedDeal: false, @@ -155,7 +160,7 @@ func TestMarketPredicates(t *testing.T) { ProviderCollateral: big.Zero(), ClientCollateral: big.Zero(), } - newProps := map[abi.DealID]*market.DealProposal{ + newProps := map[abi.DealID]*market0.DealProposal{ abi.DealID(1): oldProp1, // 1 was persisted // prop 2 was removed abi.DealID(3): newProp3, // new @@ -178,8 +183,8 @@ func TestMarketPredicates(t *testing.T) { require.NoError(t, err) api := newMockAPI(bs) - api.setActor(oldState.Key(), &types.Actor{Head: oldStateC}) - api.setActor(newState.Key(), &types.Actor{Head: newStateC}) + api.setActor(oldState.Key(), &types.Actor{Code: builtin0.StorageMarketActorCodeID, Head: oldStateC}) + api.setActor(newState.Key(), &types.Actor{Code: builtin0.StorageMarketActorCodeID, Head: newStateC}) t.Run("deal ID predicate", func(t *testing.T) { preds := NewStatePredicates(api) @@ -221,7 +226,7 @@ func TestMarketPredicates(t *testing.T) { // Test that OnActorStateChanged does not call the callback if the state has not changed mockAddr, err := address.NewFromString("t01") require.NoError(t, err) - actorDiffFn := preds.OnActorStateChanged(mockAddr, func(context.Context, cid.Cid, cid.Cid) (bool, UserData, error) { + actorDiffFn := preds.OnActorStateChanged(mockAddr, func(context.Context, *types.Actor, *types.Actor) (bool, UserData, error) { t.Fatal("No state change so this should not be called") return false, nil, nil }) @@ -230,11 +235,18 @@ func TestMarketPredicates(t *testing.T) { require.False(t, changed) // Test that OnDealStateChanged does not call the callback if the state has not changed - diffDealStateFn := preds.OnDealStateChanged(func(context.Context, *adt.Array, *adt.Array) (bool, UserData, error) { + diffDealStateFn := preds.OnDealStateChanged(func(context.Context, market.DealStates, market.DealStates) (bool, UserData, error) { t.Fatal("No state change so this should not be called") return false, nil, nil }) - marketState := createEmptyMarketState(t, store) + marketState0 := createEmptyMarketState(t, store) + marketCid, err := store.Put(ctx, marketState0) + require.NoError(t, err) + marketState, err := market.Load(store, &types.Actor{ + Code: builtin0.StorageMarketActorCodeID, + Head: marketCid, + }) + require.NoError(t, err) changed, _, err = diffDealStateFn(ctx, marketState, marketState) require.NoError(t, err) require.False(t, changed) @@ -252,18 +264,18 @@ func TestMarketPredicates(t *testing.T) { require.NoError(t, err) require.True(t, changed) - changedDeals, ok := valArr.(*MarketDealStateChanges) + changedDeals, ok := valArr.(*market.DealStateChanges) require.True(t, ok) require.Len(t, changedDeals.Added, 1) require.Equal(t, abi.DealID(3), changedDeals.Added[0].ID) - require.Equal(t, *newDeal3, changedDeals.Added[0].Deal) + require.True(t, dealEquality(*newDeal3, changedDeals.Added[0].Deal)) require.Len(t, changedDeals.Removed, 1) require.Len(t, changedDeals.Modified, 1) require.Equal(t, abi.DealID(1), changedDeals.Modified[0].ID) - require.Equal(t, newDeal1, changedDeals.Modified[0].To) - require.Equal(t, oldDeal1, changedDeals.Modified[0].From) + require.True(t, dealEquality(*newDeal1, *changedDeals.Modified[0].To)) + require.True(t, dealEquality(*oldDeal1, *changedDeals.Modified[0].From)) require.Equal(t, abi.DealID(2), changedDeals.Removed[0].ID) }) @@ -279,17 +291,15 @@ func TestMarketPredicates(t *testing.T) { require.NoError(t, err) require.True(t, changed) - changedProps, ok := valArr.(*MarketDealProposalChanges) + changedProps, ok := valArr.(*market.DealProposalChanges) require.True(t, ok) require.Len(t, changedProps.Added, 1) require.Equal(t, abi.DealID(3), changedProps.Added[0].ID) - require.Equal(t, *newProp3, changedProps.Added[0].Proposal) // proposals cannot be modified -- no modified testing require.Len(t, changedProps.Removed, 1) require.Equal(t, abi.DealID(2), changedProps.Removed[0].ID) - require.Equal(t, *oldProp2, changedProps.Removed[0].Proposal) }) t.Run("balances predicate", func(t *testing.T) { @@ -342,7 +352,14 @@ func TestMarketPredicates(t *testing.T) { t.Fatal("No state change so this should not be called") return false, nil, nil }) - marketState := createEmptyMarketState(t, store) + marketState0 := createEmptyMarketState(t, store) + marketCid, err := store.Put(ctx, marketState0) + require.NoError(t, err) + marketState, err := market.Load(store, &types.Actor{ + Code: builtin0.StorageMarketActorCodeID, + Head: marketCid, + }) + require.NoError(t, err) changed, _, err = diffDealBalancesFn(ctx, marketState, marketState) require.NoError(t, err) require.False(t, changed) @@ -362,12 +379,12 @@ func TestMinerSectorChange(t *testing.T) { } owner, worker := nextIDAddrF(), nextIDAddrF() - si0 := newSectorOnChainInfo(0, tutils.MakeCID("0", &miner.SealedCIDPrefix), big.NewInt(0), abi.ChainEpoch(0), abi.ChainEpoch(10)) - si1 := newSectorOnChainInfo(1, tutils.MakeCID("1", &miner.SealedCIDPrefix), big.NewInt(1), abi.ChainEpoch(1), abi.ChainEpoch(11)) - si2 := newSectorOnChainInfo(2, tutils.MakeCID("2", &miner.SealedCIDPrefix), big.NewInt(2), abi.ChainEpoch(2), abi.ChainEpoch(11)) + si0 := newSectorOnChainInfo(0, tutils.MakeCID("0", &miner0.SealedCIDPrefix), big.NewInt(0), abi.ChainEpoch(0), abi.ChainEpoch(10)) + si1 := newSectorOnChainInfo(1, tutils.MakeCID("1", &miner0.SealedCIDPrefix), big.NewInt(1), abi.ChainEpoch(1), abi.ChainEpoch(11)) + si2 := newSectorOnChainInfo(2, tutils.MakeCID("2", &miner0.SealedCIDPrefix), big.NewInt(2), abi.ChainEpoch(2), abi.ChainEpoch(11)) oldMinerC := createMinerState(ctx, t, store, owner, worker, []miner.SectorOnChainInfo{si0, si1, si2}) - si3 := newSectorOnChainInfo(3, tutils.MakeCID("3", &miner.SealedCIDPrefix), big.NewInt(3), abi.ChainEpoch(3), abi.ChainEpoch(12)) + si3 := newSectorOnChainInfo(3, tutils.MakeCID("3", &miner0.SealedCIDPrefix), big.NewInt(3), abi.ChainEpoch(3), abi.ChainEpoch(12)) // 0 delete // 1 extend // 2 same @@ -383,8 +400,8 @@ func TestMinerSectorChange(t *testing.T) { require.NoError(t, err) api := newMockAPI(bs) - api.setActor(oldState.Key(), &types.Actor{Head: oldMinerC}) - api.setActor(newState.Key(), &types.Actor{Head: newMinerC}) + api.setActor(oldState.Key(), &types.Actor{Head: oldMinerC, Code: builtin0.StorageMinerActorCodeID}) + api.setActor(newState.Key(), &types.Actor{Head: newMinerC, Code: builtin0.StorageMinerActorCodeID}) preds := NewStatePredicates(api) @@ -394,7 +411,7 @@ func TestMinerSectorChange(t *testing.T) { require.True(t, change) require.NotNil(t, val) - sectorChanges, ok := val.(*MinerSectorChanges) + sectorChanges, ok := val.(*miner.SectorChanges) require.True(t, ok) require.Equal(t, len(sectorChanges.Added), 1) @@ -418,7 +435,7 @@ func TestMinerSectorChange(t *testing.T) { require.True(t, change) require.NotNil(t, val) - sectorChanges, ok = val.(*MinerSectorChanges) + sectorChanges, ok = val.(*miner.SectorChanges) require.True(t, ok) require.Equal(t, 1, len(sectorChanges.Added)) @@ -450,7 +467,7 @@ type balance struct { locked abi.TokenAmount } -func createMarketState(ctx context.Context, t *testing.T, store adt.Store, deals map[abi.DealID]*market.DealState, props map[abi.DealID]*market.DealProposal, balances map[address.Address]balance) cid.Cid { +func createMarketState(ctx context.Context, t *testing.T, store adt.Store, deals map[abi.DealID]*market0.DealState, props map[abi.DealID]*market0.DealProposal, balances map[address.Address]balance) cid.Cid { dealRootCid := createDealAMT(ctx, t, store, deals) propRootCid := createProposalAMT(ctx, t, store, props) balancesCids := createBalanceTable(ctx, t, store, balances) @@ -465,15 +482,15 @@ func createMarketState(ctx context.Context, t *testing.T, store adt.Store, deals return stateC } -func createEmptyMarketState(t *testing.T, store adt.Store) *market.State { +func createEmptyMarketState(t *testing.T, store adt.Store) *market0.State { emptyArrayCid, err := adt.MakeEmptyArray(store).Root() require.NoError(t, err) emptyMap, err := adt.MakeEmptyMap(store).Root() require.NoError(t, err) - return market.ConstructState(emptyArrayCid, emptyMap, emptyMap) + return market0.ConstructState(emptyArrayCid, emptyMap, emptyMap) } -func createDealAMT(ctx context.Context, t *testing.T, store adt.Store, deals map[abi.DealID]*market.DealState) cid.Cid { +func createDealAMT(ctx context.Context, t *testing.T, store adt.Store, deals map[abi.DealID]*market0.DealState) cid.Cid { root := adt.MakeEmptyArray(store) for dealID, dealState := range deals { err := root.Set(uint64(dealID), dealState) @@ -484,7 +501,7 @@ func createDealAMT(ctx context.Context, t *testing.T, store adt.Store, deals map return rootCid } -func createProposalAMT(ctx context.Context, t *testing.T, store adt.Store, props map[abi.DealID]*market.DealProposal) cid.Cid { +func createProposalAMT(ctx context.Context, t *testing.T, store adt.Store, props map[abi.DealID]*market0.DealProposal) cid.Cid { root := adt.MakeEmptyArray(store) for dealID, prop := range props { err := root.Set(uint64(dealID), prop) @@ -532,20 +549,20 @@ func createMinerState(ctx context.Context, t *testing.T, store adt.Store, owner, return stateC } -func createEmptyMinerState(ctx context.Context, t *testing.T, store adt.Store, owner, worker address.Address) *miner.State { +func createEmptyMinerState(ctx context.Context, t *testing.T, store adt.Store, owner, worker address.Address) *miner0.State { emptyArrayCid, err := adt.MakeEmptyArray(store).Root() require.NoError(t, err) emptyMap, err := adt.MakeEmptyMap(store).Root() require.NoError(t, err) - emptyDeadline, err := store.Put(store.Context(), miner.ConstructDeadline(emptyArrayCid)) + emptyDeadline, err := store.Put(store.Context(), miner0.ConstructDeadline(emptyArrayCid)) require.NoError(t, err) - emptyVestingFunds := miner.ConstructVestingFunds() + emptyVestingFunds := miner0.ConstructVestingFunds() emptyVestingFundsCid, err := store.Put(store.Context(), emptyVestingFunds) require.NoError(t, err) - emptyDeadlines := miner.ConstructDeadlines(emptyDeadline) + emptyDeadlines := miner0.ConstructDeadlines(emptyDeadline) emptyDeadlinesCid, err := store.Put(store.Context(), emptyDeadlines) require.NoError(t, err) @@ -555,7 +572,7 @@ func createEmptyMinerState(ctx context.Context, t *testing.T, store adt.Store, o emptyBitfieldCid, err := store.Put(store.Context(), emptyBitfield) require.NoError(t, err) - state, err := miner.ConstructState(minerInfo, 123, emptyBitfieldCid, emptyArrayCid, emptyMap, emptyDeadlinesCid, emptyVestingFundsCid) + state, err := miner0.ConstructState(minerInfo, 123, emptyBitfieldCid, emptyArrayCid, emptyMap, emptyDeadlinesCid, emptyVestingFundsCid) require.NoError(t, err) return state @@ -564,7 +581,7 @@ func createEmptyMinerState(ctx context.Context, t *testing.T, store adt.Store, o func createSectorsAMT(ctx context.Context, t *testing.T, store adt.Store, sectors []miner.SectorOnChainInfo) cid.Cid { root := adt.MakeEmptyArray(store) for _, sector := range sectors { - sector := sector + sector := (miner0.SectorOnChainInfo)(sector) err := root.Set(uint64(sector.SectorNumber), §or) require.NoError(t, err) } @@ -597,8 +614,8 @@ const ( ) // returns a unique SectorPreCommitInfo with each invocation with SectorNumber set to `sectorNo`. -func newSectorPreCommitInfo(sectorNo abi.SectorNumber, sealed cid.Cid, expiration abi.ChainEpoch) *miner.SectorPreCommitInfo { - return &miner.SectorPreCommitInfo{ +func newSectorPreCommitInfo(sectorNo abi.SectorNumber, sealed cid.Cid, expiration abi.ChainEpoch) *miner0.SectorPreCommitInfo { + return &miner0.SectorPreCommitInfo{ SealProof: abi.RegisteredSealProof_StackedDrg32GiBV1, SectorNumber: sectorNo, SealedCID: sealed, @@ -607,3 +624,9 @@ func newSectorPreCommitInfo(sectorNo abi.SectorNumber, sealed cid.Cid, expiratio Expiration: expiration, } } + +func dealEquality(expected market0.DealState, actual market.DealState) bool { + return expected.LastUpdatedEpoch == actual.LastUpdatedEpoch && + expected.SectorStartEpoch == actual.SectorStartEpoch && + expected.SlashEpoch == actual.SlashEpoch +} diff --git a/chain/exchange/cbor_gen.go b/chain/exchange/cbor_gen.go index dc91babe3..29b258081 100644 --- a/chain/exchange/cbor_gen.go +++ b/chain/exchange/cbor_gen.go @@ -146,7 +146,7 @@ func (t *Response) MarshalCBOR(w io.Writer) error { scratch := make([]byte, 9) - // t.Status (blocksync.status) (uint64) + // t.Status (exchange.status) (uint64) if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Status)); err != nil { return err @@ -164,7 +164,7 @@ func (t *Response) MarshalCBOR(w io.Writer) error { return err } - // t.Chain ([]*blocksync.BSTipSet) (slice) + // t.Chain ([]*exchange.BSTipSet) (slice) if len(t.Chain) > cbg.MaxLength { return xerrors.Errorf("Slice value in field t.Chain was too long") } @@ -198,7 +198,7 @@ func (t *Response) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("cbor input had wrong number of fields") } - // t.Status (blocksync.status) (uint64) + // t.Status (exchange.status) (uint64) { @@ -222,7 +222,7 @@ func (t *Response) UnmarshalCBOR(r io.Reader) error { t.ErrorMessage = string(sval) } - // t.Chain ([]*blocksync.BSTipSet) (slice) + // t.Chain ([]*exchange.BSTipSet) (slice) maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) if err != nil { @@ -567,7 +567,7 @@ func (t *BSTipSet) MarshalCBOR(w io.Writer) error { } } - // t.Messages (blocksync.CompactedMessages) (struct) + // t.Messages (exchange.CompactedMessages) (struct) if err := t.Messages.MarshalCBOR(w); err != nil { return err } @@ -621,7 +621,7 @@ func (t *BSTipSet) UnmarshalCBOR(r io.Reader) error { t.Blocks[i] = &v } - // t.Messages (blocksync.CompactedMessages) (struct) + // t.Messages (exchange.CompactedMessages) (struct) { diff --git a/chain/exchange/client.go b/chain/exchange/client.go index 22f7a9457..371c50aed 100644 --- a/chain/exchange/client.go +++ b/chain/exchange/client.go @@ -7,6 +7,7 @@ import ( "math/rand" "time" + "github.com/libp2p/go-libp2p-core/helpers" "github.com/libp2p/go-libp2p-core/host" "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" @@ -64,7 +65,15 @@ func NewClient(lc fx.Lifecycle, host host.Host, pmgr peermgr.MaybePeerMgr) Clien // request options without disrupting external calls. In the future the // consumers should be forced to use a more standardized service and // adhere to a single API derived from this function. -func (c *client) doRequest(ctx context.Context, req *Request, singlePeer *peer.ID) (*validatedResponse, error) { +func (c *client) doRequest( + ctx context.Context, + req *Request, + singlePeer *peer.ID, + // In the `GetChainMessages` case, we won't request the headers but we still + // need them to check the integrity of the `CompactedMessages` in the response + // so the tipset blocks need to be provided by the caller. + tipsets []*types.TipSet, +) (*validatedResponse, error) { // Validate request. if req.Length == 0 { return nil, xerrors.Errorf("invalid request of length 0") @@ -115,7 +124,7 @@ func (c *client) doRequest(ctx context.Context, req *Request, singlePeer *peer.I } // Process and validate response. - validRes, err := c.processResponse(req, res) + validRes, err := c.processResponse(req, res, tipsets) if err != nil { log.Warnf("processing peer %s response failed: %s", peer.String(), err) @@ -143,7 +152,7 @@ func (c *client) doRequest(ctx context.Context, req *Request, singlePeer *peer.I // errors. Peer penalization should happen here then, before returning, so // we can apply the correct penalties depending on the cause of the error. // FIXME: Add the `peer` as argument once we implement penalties. -func (c *client) processResponse(req *Request, res *Response) (*validatedResponse, error) { +func (c *client) processResponse(req *Request, res *Response, tipsets []*types.TipSet) (*validatedResponse, error) { err := res.statusToError() if err != nil { return nil, xerrors.Errorf("status error: %s", err) @@ -175,6 +184,16 @@ func (c *client) processResponse(req *Request, res *Response) (*validatedRespons // Check for valid block sets and extract them into `TipSet`s. validRes.tipsets = make([]*types.TipSet, resLength) for i := 0; i < resLength; i++ { + if res.Chain[i] == nil { + return nil, xerrors.Errorf("response with nil tipset in pos %d", i) + } + for blockIdx, block := range res.Chain[i].Blocks { + if block == nil { + return nil, xerrors.Errorf("tipset with nil block in pos %d", blockIdx) + // FIXME: Maybe we should move this check to `NewTipSet`. + } + } + validRes.tipsets[i], err = types.NewTipSet(res.Chain[i].Blocks) if err != nil { return nil, xerrors.Errorf("invalid tipset blocks at height (head - %d): %w", i, err) @@ -209,31 +228,28 @@ func (c *client) processResponse(req *Request, res *Response) (*validatedRespons // If the headers were also returned check that the compression // indexes are valid before `toFullTipSets()` is called by the // consumer. - for tipsetIdx := 0; tipsetIdx < resLength; tipsetIdx++ { - msgs := res.Chain[tipsetIdx].Messages - blocksNum := len(res.Chain[tipsetIdx].Blocks) - if len(msgs.BlsIncludes) != blocksNum { - return nil, xerrors.Errorf("BlsIncludes (%d) does not match number of blocks (%d)", - len(msgs.BlsIncludes), blocksNum) - } - if len(msgs.SecpkIncludes) != blocksNum { - return nil, xerrors.Errorf("SecpkIncludes (%d) does not match number of blocks (%d)", - len(msgs.SecpkIncludes), blocksNum) - } - for blockIdx := 0; blockIdx < blocksNum; blockIdx++ { - for _, mi := range msgs.BlsIncludes[blockIdx] { - if int(mi) >= len(msgs.Bls) { - return nil, xerrors.Errorf("index in BlsIncludes (%d) exceeds number of messages (%d)", - mi, len(msgs.Bls)) - } - } - for _, mi := range msgs.SecpkIncludes[blockIdx] { - if int(mi) >= len(msgs.Secpk) { - return nil, xerrors.Errorf("index in SecpkIncludes (%d) exceeds number of messages (%d)", - mi, len(msgs.Secpk)) - } - } + err := c.validateCompressedIndices(res.Chain) + if err != nil { + return nil, err + } + } else { + // If we didn't request the headers they should have been provided + // by the caller. + if len(tipsets) < len(res.Chain) { + return nil, xerrors.Errorf("not enought tipsets provided for message response validation, needed %d, have %d", len(res.Chain), len(tipsets)) + } + chain := make([]*BSTipSet, 0, resLength) + for i, resChain := range res.Chain { + next := &BSTipSet{ + Blocks: tipsets[i].Blocks(), + Messages: resChain.Messages, } + chain = append(chain, next) + } + + err := c.validateCompressedIndices(chain) + if err != nil { + return nil, err } } } @@ -241,6 +257,42 @@ func (c *client) processResponse(req *Request, res *Response) (*validatedRespons return validRes, nil } +func (c *client) validateCompressedIndices(chain []*BSTipSet) error { + resLength := len(chain) + for tipsetIdx := 0; tipsetIdx < resLength; tipsetIdx++ { + msgs := chain[tipsetIdx].Messages + blocksNum := len(chain[tipsetIdx].Blocks) + + if len(msgs.BlsIncludes) != blocksNum { + return xerrors.Errorf("BlsIncludes (%d) does not match number of blocks (%d)", + len(msgs.BlsIncludes), blocksNum) + } + + if len(msgs.SecpkIncludes) != blocksNum { + return xerrors.Errorf("SecpkIncludes (%d) does not match number of blocks (%d)", + len(msgs.SecpkIncludes), blocksNum) + } + + for blockIdx := 0; blockIdx < blocksNum; blockIdx++ { + for _, mi := range msgs.BlsIncludes[blockIdx] { + if int(mi) >= len(msgs.Bls) { + return xerrors.Errorf("index in BlsIncludes (%d) exceeds number of messages (%d)", + mi, len(msgs.Bls)) + } + } + + for _, mi := range msgs.SecpkIncludes[blockIdx] { + if int(mi) >= len(msgs.Secpk) { + return xerrors.Errorf("index in SecpkIncludes (%d) exceeds number of messages (%d)", + mi, len(msgs.Secpk)) + } + } + } + } + + return nil +} + // GetBlocks implements Client.GetBlocks(). Refer to the godocs there. func (c *client) GetBlocks(ctx context.Context, tsk types.TipSetKey, count int) ([]*types.TipSet, error) { ctx, span := trace.StartSpan(ctx, "bsync.GetBlocks") @@ -258,7 +310,7 @@ func (c *client) GetBlocks(ctx context.Context, tsk types.TipSetKey, count int) Options: Headers, } - validRes, err := c.doRequest(ctx, req, nil) + validRes, err := c.doRequest(ctx, req, nil, nil) if err != nil { return nil, err } @@ -276,7 +328,7 @@ func (c *client) GetFullTipSet(ctx context.Context, peer peer.ID, tsk types.TipS Options: Headers | Messages, } - validRes, err := c.doRequest(ctx, req, &peer) + validRes, err := c.doRequest(ctx, req, &peer, nil) if err != nil { return nil, err } @@ -287,7 +339,10 @@ func (c *client) GetFullTipSet(ctx context.Context, peer peer.ID, tsk types.TipS } // GetChainMessages implements Client.GetChainMessages(). Refer to the godocs there. -func (c *client) GetChainMessages(ctx context.Context, head *types.TipSet, length uint64) ([]*CompactedMessages, error) { +func (c *client) GetChainMessages(ctx context.Context, tipsets []*types.TipSet) ([]*CompactedMessages, error) { + head := tipsets[0] + length := uint64(len(tipsets)) + ctx, span := trace.StartSpan(ctx, "GetChainMessages") if span.IsRecordingEvents() { span.AddAttributes( @@ -303,7 +358,7 @@ func (c *client) GetChainMessages(ctx context.Context, head *types.TipSet, lengt Options: Messages, } - validRes, err := c.doRequest(ctx, req, nil) + validRes, err := c.doRequest(ctx, req, nil, tipsets) if err != nil { return nil, err } @@ -357,6 +412,12 @@ func (c *client) sendRequestToPeer(ctx context.Context, peer peer.ID, req *Reque return nil, xerrors.Errorf("failed to open stream to peer: %w", err) } + defer func() { + // Note: this will become just stream.Close once we've completed the go-libp2p migration to + // go-libp2p-core 0.7.0 + go helpers.FullClose(stream) //nolint:errcheck + }() + // Write request. _ = stream.SetWriteDeadline(time.Now().Add(WriteReqDeadline)) if err := cborutil.WriteCborRPC(stream, req); err != nil { diff --git a/chain/exchange/interfaces.go b/chain/exchange/interfaces.go index 79d8fd4b1..acc0854da 100644 --- a/chain/exchange/interfaces.go +++ b/chain/exchange/interfaces.go @@ -32,10 +32,9 @@ type Client interface { // or less. GetBlocks(ctx context.Context, tsk types.TipSetKey, count int) ([]*types.TipSet, error) - // GetChainMessages fetches messages from the network, from the provided - // tipset *backwards*, returning the messages from as many tipsets as the - // count parameter, or less. - GetChainMessages(ctx context.Context, head *types.TipSet, length uint64) ([]*CompactedMessages, error) + // GetChainMessages fetches messages from the network, starting from the first provided tipset + // and returning messages from as many tipsets as requested or less. + GetChainMessages(ctx context.Context, tipsets []*types.TipSet) ([]*CompactedMessages, error) // GetFullTipSet fetches a full tipset from a given peer. If successful, // the fetched object contains block headers and all messages in full form. diff --git a/chain/exchange/protocol.go b/chain/exchange/protocol.go index ca4b61836..211479335 100644 --- a/chain/exchange/protocol.go +++ b/chain/exchange/protocol.go @@ -40,7 +40,7 @@ const ( WriteReqDeadline = 5 * time.Second ReadResDeadline = WriteReqDeadline ReadResMinSpeed = 50 << 10 - ShufflePeersPrefix = 5 + ShufflePeersPrefix = 16 WriteResDeadline = 60 * time.Second ) @@ -139,6 +139,8 @@ func (res *Response) statusToError() error { // FIXME: Rename. type BSTipSet struct { + // List of blocks belonging to a single tipset to which the + // `CompactedMessages` are linked. Blocks []*types.BlockHeader Messages *CompactedMessages } diff --git a/chain/exchange/server.go b/chain/exchange/server.go index 54e169b3f..dcdb5b3a5 100644 --- a/chain/exchange/server.go +++ b/chain/exchange/server.go @@ -15,6 +15,7 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/ipfs/go-cid" + "github.com/libp2p/go-libp2p-core/helpers" inet "github.com/libp2p/go-libp2p-core/network" ) @@ -39,7 +40,9 @@ func (s *server) HandleStream(stream inet.Stream) { ctx, span := trace.StartSpan(context.Background(), "chainxchg.HandleStream") defer span.End() - defer stream.Close() //nolint:errcheck + // Note: this will become just stream.Close once we've completed the go-libp2p migration to + // go-libp2p-core 0.7.0 + defer helpers.FullClose(stream) //nolint:errcheck var req Request if err := cborutil.ReadCborRPC(bufio.NewReader(stream), &req); err != nil { diff --git a/chain/gen/gen.go b/chain/gen/gen.go index d661411fe..d05165ab1 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -14,7 +14,6 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" - saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner" block "github.com/ipfs/go-block-format" "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" @@ -28,6 +27,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/beacon" genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis" "github.com/filecoin-project/lotus/chain/stmgr" @@ -121,9 +121,8 @@ var DefaultRemainderAccountActor = genesis.Actor{ } func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) { - saminer.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ - abi.RegisteredSealProof_StackedDrg2KiBV1: {}, - } + // TODO: we really shouldn't modify a global variable here. + policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) mr := repo.NewMemory(nil) lr, err := mr.Lock(repo.StorageMiner) @@ -489,13 +488,16 @@ func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticke // ResyncBankerNonce is used for dealing with messages made when // simulating forks func (cg *ChainGen) ResyncBankerNonce(ts *types.TipSet) error { - var act types.Actor - err := cg.sm.WithParentState(ts, cg.sm.WithActor(cg.banker, stmgr.GetActor(&act))) + st, err := cg.sm.ParentState(ts) + if err != nil { + return err + } + act, err := st.GetActor(cg.banker) if err != nil { return err } - cg.bankerNonce = act.Nonce + return nil } diff --git a/chain/gen/gen_test.go b/chain/gen/gen_test.go index ebc28a990..8c38328d0 100644 --- a/chain/gen/gen_test.go +++ b/chain/gen/gen_test.go @@ -4,21 +4,16 @@ import ( "testing" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + "github.com/filecoin-project/lotus/chain/actors/policy" _ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/secp" ) func init() { - miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ - abi.RegisteredSealProof_StackedDrg2KiBV1: {}, - } - power.ConsensusMinerMinPower = big.NewInt(2048) - verifreg.MinVerifiedDealSize = big.NewInt(256) + policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) + policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048)) + policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) } func testGeneration(t testing.TB, n int, msgs int, sectors int) { diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 0a9d58924..039e284cd 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -6,8 +6,6 @@ import ( "encoding/json" "fmt" - "github.com/filecoin-project/go-state-types/network" - "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" cbor "github.com/ipfs/go-ipld-cbor" @@ -19,13 +17,14 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/account" - "github.com/filecoin-project/specs-actors/actors/builtin/multisig" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" - "github.com/filecoin-project/specs-actors/actors/util/adt" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + account0 "github.com/filecoin-project/specs-actors/actors/builtin/account" + multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" + verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" @@ -116,7 +115,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge return nil, nil, xerrors.Errorf("putting empty object: %w", err) } - state, err := state.NewStateTree(cst) + state, err := state.NewStateTree(cst, builtin.Version0) if err != nil { return nil, nil, xerrors.Errorf("making new state tree: %w", err) } @@ -127,7 +126,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge if err != nil { return nil, nil, xerrors.Errorf("setup init actor: %w", err) } - if err := state.SetActor(builtin.SystemActorAddr, sysact); err != nil { + if err := state.SetActor(builtin0.SystemActorAddr, sysact); err != nil { return nil, nil, xerrors.Errorf("set init actor: %w", err) } @@ -137,7 +136,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge if err != nil { return nil, nil, xerrors.Errorf("setup init actor: %w", err) } - if err := state.SetActor(builtin.InitActorAddr, initact); err != nil { + if err := state.SetActor(builtin0.InitActorAddr, initact); err != nil { return nil, nil, xerrors.Errorf("set init actor: %w", err) } @@ -148,7 +147,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge return nil, nil, xerrors.Errorf("setup init actor: %w", err) } - err = state.SetActor(builtin.RewardActorAddr, rewact) + err = state.SetActor(builtin0.RewardActorAddr, rewact) if err != nil { return nil, nil, xerrors.Errorf("set network account actor: %w", err) } @@ -158,7 +157,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge if err != nil { return nil, nil, xerrors.Errorf("setup cron actor: %w", err) } - if err := state.SetActor(builtin.CronActorAddr, cronact); err != nil { + if err := state.SetActor(builtin0.CronActorAddr, cronact); err != nil { return nil, nil, xerrors.Errorf("set cron actor: %w", err) } @@ -167,7 +166,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge if err != nil { return nil, nil, xerrors.Errorf("setup storage market actor: %w", err) } - if err := state.SetActor(builtin.StoragePowerActorAddr, spact); err != nil { + if err := state.SetActor(builtin0.StoragePowerActorAddr, spact); err != nil { return nil, nil, xerrors.Errorf("set storage market actor: %w", err) } @@ -176,7 +175,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge if err != nil { return nil, nil, xerrors.Errorf("setup storage market actor: %w", err) } - if err := state.SetActor(builtin.StorageMarketActorAddr, marketact); err != nil { + if err := state.SetActor(builtin0.StorageMarketActorAddr, marketact); err != nil { return nil, nil, xerrors.Errorf("set market actor: %w", err) } @@ -185,20 +184,20 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge if err != nil { return nil, nil, xerrors.Errorf("setup storage market actor: %w", err) } - if err := state.SetActor(builtin.VerifiedRegistryActorAddr, verifact); err != nil { + if err := state.SetActor(builtin0.VerifiedRegistryActorAddr, verifact); err != nil { return nil, nil, xerrors.Errorf("set market actor: %w", err) } - burntRoot, err := cst.Put(ctx, &account.State{ - Address: builtin.BurntFundsActorAddr, + burntRoot, err := cst.Put(ctx, &account0.State{ + Address: builtin0.BurntFundsActorAddr, }) if err != nil { return nil, nil, xerrors.Errorf("failed to setup burnt funds actor state: %w", err) } // Setup burnt-funds - err = state.SetActor(builtin.BurntFundsActorAddr, &types.Actor{ - Code: builtin.AccountActorCodeID, + err = state.SetActor(builtin0.BurntFundsActorAddr, &types.Actor{ + Code: builtin0.AccountActorCodeID, Balance: types.NewInt(0), Head: burntRoot, }) @@ -263,13 +262,13 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge return nil, nil, err } - verifierState, err := cst.Put(ctx, &account.State{Address: verifierAd}) + verifierState, err := cst.Put(ctx, &account0.State{Address: verifierAd}) if err != nil { return nil, nil, err } err = state.SetActor(verifierId, &types.Actor{ - Code: builtin.AccountActorCodeID, + Code: builtin0.AccountActorCodeID, Balance: types.NewInt(0), Head: verifierState, }) @@ -316,7 +315,7 @@ func createAccountActor(ctx context.Context, cst cbor.IpldStore, state *state.St if err := json.Unmarshal(info.Meta, &ainfo); err != nil { return xerrors.Errorf("unmarshaling account meta: %w", err) } - st, err := cst.Put(ctx, &account.State{Address: ainfo.Owner}) + st, err := cst.Put(ctx, &account0.State{Address: ainfo.Owner}) if err != nil { return err } @@ -327,7 +326,7 @@ func createAccountActor(ctx context.Context, cst cbor.IpldStore, state *state.St } err = state.SetActor(ida, &types.Actor{ - Code: builtin.AccountActorCodeID, + Code: builtin0.AccountActorCodeID, Balance: info.Balance, Head: st, }) @@ -345,7 +344,7 @@ func createMultisigAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.I if err := json.Unmarshal(info.Meta, &ainfo); err != nil { return xerrors.Errorf("unmarshaling account meta: %w", err) } - pending, err := adt.MakeEmptyMap(adt.WrapStore(ctx, cst)).Root() + pending, err := adt0.MakeEmptyMap(adt0.WrapStore(ctx, cst)).Root() if err != nil { return xerrors.Errorf("failed to create empty map: %v", err) } @@ -365,12 +364,12 @@ func createMultisigAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.I continue } - st, err := cst.Put(ctx, &account.State{Address: e}) + st, err := cst.Put(ctx, &account0.State{Address: e}) if err != nil { return err } err = state.SetActor(idAddress, &types.Actor{ - Code: builtin.AccountActorCodeID, + Code: builtin0.AccountActorCodeID, Balance: types.NewInt(0), Head: st, }) @@ -380,7 +379,7 @@ func createMultisigAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.I signers = append(signers, idAddress) } - st, err := cst.Put(ctx, &multisig.State{ + st, err := cst.Put(ctx, &multisig0.State{ Signers: signers, NumApprovalsThreshold: uint64(ainfo.Threshold), StartEpoch: abi.ChainEpoch(ainfo.VestingStart), @@ -392,7 +391,7 @@ func createMultisigAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.I return err } err = state.SetActor(ida, &types.Actor{ - Code: builtin.MultisigActorCodeID, + Code: builtin0.MultisigActorCodeID, Balance: info.Balance, Head: st, }) @@ -406,10 +405,6 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci verifNeeds := make(map[address.Address]abi.PaddedPieceSize) var sum abi.PaddedPieceSize - nwv := func(context.Context, abi.ChainEpoch) network.Version { - return build.NewestNetworkVersion - } - vmopt := vm.VMOpts{ StateBase: stateroot, Epoch: 0, @@ -417,10 +412,10 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci Bstore: cs.Blockstore(), Syscalls: mkFakedSigSyscalls(cs.VMSys()), CircSupplyCalc: nil, - NtwkVersion: nwv, + NtwkVersion: genesisNetworkVersion, BaseFee: types.NewInt(0), } - vm, err := vm.NewVM(&vmopt) + vm, err := vm.NewVM(ctx, &vmopt) if err != nil { return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err) } @@ -447,7 +442,7 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci return cid.Undef, err } - _, err = doExecValue(ctx, vm, builtin.VerifiedRegistryActorAddr, verifregRoot, types.NewInt(0), builtin.MethodsVerifiedRegistry.AddVerifier, mustEnc(&verifreg.AddVerifierParams{ + _, err = doExecValue(ctx, vm, builtin0.VerifiedRegistryActorAddr, verifregRoot, types.NewInt(0), builtin0.MethodsVerifiedRegistry.AddVerifier, mustEnc(&verifreg0.AddVerifierParams{ Address: verifier, Allowance: abi.NewStoragePower(int64(sum)), // eh, close enough @@ -458,7 +453,7 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci } for c, amt := range verifNeeds { - _, err := doExecValue(ctx, vm, builtin.VerifiedRegistryActorAddr, verifier, types.NewInt(0), builtin.MethodsVerifiedRegistry.AddVerifiedClient, mustEnc(&verifreg.AddVerifiedClientParams{ + _, err := doExecValue(ctx, vm, builtin0.VerifiedRegistryActorAddr, verifier, types.NewInt(0), builtin0.MethodsVerifiedRegistry.AddVerifiedClient, mustEnc(&verifreg0.AddVerifiedClientParams{ Address: c, Allowance: abi.NewStoragePower(int64(amt)), })) @@ -500,8 +495,8 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallB return nil, xerrors.Errorf("setup miners failed: %w", err) } - store := adt.WrapStore(ctx, cbor.NewCborStore(bs)) - emptyroot, err := adt.MakeEmptyArray(store).Root() + store := adt0.WrapStore(ctx, cbor.NewCborStore(bs)) + emptyroot, err := adt0.MakeEmptyArray(store).Root() if err != nil { return nil, xerrors.Errorf("amt build failed: %w", err) } @@ -549,7 +544,7 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallB } b := &types.BlockHeader{ - Miner: builtin.SystemActorAddr, + Miner: builtin0.SystemActorAddr, Ticket: genesisticket, Parents: []cid.Cid{filecoinGenesisCid}, Height: 0, diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index b57608a5f..1023e5efa 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -6,11 +6,13 @@ import ( "fmt" "math/rand" - "github.com/filecoin-project/lotus/build" + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/lotus/chain/actors/builtin/power" + "github.com/filecoin-project/lotus/chain/actors/builtin/reward" - "github.com/filecoin-project/lotus/chain/state" + "github.com/filecoin-project/lotus/chain/actors/builtin/market" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" @@ -23,12 +25,12 @@ import ( "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/builtin/reward" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" + reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward" "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" @@ -65,10 +67,6 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid return big.Zero(), nil } - nwv := func(context.Context, abi.ChainEpoch) network.Version { - return build.NewestNetworkVersion - } - vmopt := &vm.VMOpts{ StateBase: sroot, Epoch: 0, @@ -76,11 +74,11 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid Bstore: cs.Blockstore(), Syscalls: mkFakedSigSyscalls(cs.VMSys()), CircSupplyCalc: csc, - NtwkVersion: nwv, + NtwkVersion: genesisNetworkVersion, BaseFee: types.NewInt(0), } - vm, err := vm.NewVM(vmopt) + vm, err := vm.NewVM(ctx, vmopt) if err != nil { return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err) } @@ -108,7 +106,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid } { - constructorParams := &power.CreateMinerParams{ + constructorParams := &power0.CreateMinerParams{ Owner: m.Worker, Worker: m.Worker, Peer: []byte(m.PeerId), @@ -116,12 +114,12 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid } params := mustEnc(constructorParams) - rval, err := doExecValue(ctx, vm, builtin.StoragePowerActorAddr, m.Owner, m.PowerBalance, builtin.MethodsPower.CreateMiner, params) + rval, err := doExecValue(ctx, vm, power.Address, m.Owner, m.PowerBalance, builtin.MethodsPower.CreateMiner, params) if err != nil { return cid.Undef, xerrors.Errorf("failed to create genesis miner: %w", err) } - var ma power.CreateMinerReturn + var ma power0.CreateMinerReturn if err := ma.UnmarshalCBOR(bytes.NewReader(rval)); err != nil { return cid.Undef, xerrors.Errorf("unmarshaling CreateMinerReturn: %w", err) } @@ -132,9 +130,10 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid } minerInfos[i].maddr = ma.IDAddress - err = vm.MutateState(ctx, minerInfos[i].maddr, func(cst cbor.IpldStore, st *miner.State) error { - maxPeriods := miner.MaxSectorExpirationExtension / miner.WPoStProvingPeriod - minerInfos[i].presealExp = (maxPeriods-1)*miner.WPoStProvingPeriod + st.ProvingPeriodStart - 1 + // TODO: ActorUpgrade + err = vm.MutateState(ctx, minerInfos[i].maddr, func(cst cbor.IpldStore, st *miner0.State) error { + maxPeriods := miner0.MaxSectorExpirationExtension / miner0.WPoStProvingPeriod + minerInfos[i].presealExp = (maxPeriods-1)*miner0.WPoStProvingPeriod + st.ProvingPeriodStart - 1 return nil }) @@ -147,7 +146,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid if m.MarketBalance.GreaterThan(big.Zero()) { params := mustEnc(&minerInfos[i].maddr) - _, err := doExecValue(ctx, vm, builtin.StorageMarketActorAddr, m.Worker, m.MarketBalance, builtin.MethodsMarket.AddBalance, params) + _, err := doExecValue(ctx, vm, market.Address, m.Worker, m.MarketBalance, builtin.MethodsMarket.AddBalance, params) if err != nil { return cid.Undef, xerrors.Errorf("failed to create genesis miner (add balance): %w", err) } @@ -159,7 +158,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid publish := func(params *market.PublishStorageDealsParams) error { fmt.Printf("publishing %d storage deals on miner %s with worker %s\n", len(params.Deals), params.Deals[0].Proposal.Provider, m.Worker) - ret, err := doExecValue(ctx, vm, builtin.StorageMarketActorAddr, m.Worker, big.Zero(), builtin.MethodsMarket.PublishStorageDeals, mustEnc(params)) + ret, err := doExecValue(ctx, vm, market.Address, m.Worker, big.Zero(), builtin.MethodsMarket.PublishStorageDeals, mustEnc(params)) if err != nil { return xerrors.Errorf("failed to create genesis miner (publish deals): %w", err) } @@ -210,13 +209,13 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid return cid.Undef, xerrors.Errorf("getting deal weight: %w", err) } - sectorWeight := miner.QAPowerForWeight(m.SectorSize, minerInfos[i].presealExp, dweight.DealWeight, dweight.VerifiedDealWeight) + sectorWeight := miner0.QAPowerForWeight(m.SectorSize, minerInfos[i].presealExp, dweight.DealWeight, dweight.VerifiedDealWeight) qaPow = types.BigAdd(qaPow, sectorWeight) } } - err = vm.MutateState(ctx, builtin.StoragePowerActorAddr, func(cst cbor.IpldStore, st *power.State) error { + err = vm.MutateState(ctx, power.Address, func(cst cbor.IpldStore, st *power0.State) error { st.TotalQualityAdjPower = qaPow st.TotalRawBytePower = rawPow @@ -228,8 +227,8 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid return cid.Undef, xerrors.Errorf("mutating state: %w", err) } - err = vm.MutateState(ctx, builtin.RewardActorAddr, func(sct cbor.IpldStore, st *reward.State) error { - *st = *reward.ConstructState(qaPow) + err = vm.MutateState(ctx, reward.Address, func(sct cbor.IpldStore, st *reward0.State) error { + *st = *reward0.ConstructState(qaPow) return nil }) if err != nil { @@ -255,10 +254,10 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid return cid.Undef, xerrors.Errorf("getting deal weight: %w", err) } - sectorWeight := miner.QAPowerForWeight(m.SectorSize, minerInfos[i].presealExp, dweight.DealWeight, dweight.VerifiedDealWeight) + sectorWeight := miner0.QAPowerForWeight(m.SectorSize, minerInfos[i].presealExp, dweight.DealWeight, dweight.VerifiedDealWeight) // we've added fake power for this sector above, remove it now - err = vm.MutateState(ctx, builtin.StoragePowerActorAddr, func(cst cbor.IpldStore, st *power.State) error { + err = vm.MutateState(ctx, power.Address, func(cst cbor.IpldStore, st *power0.State) error { st.TotalQualityAdjPower = types.BigSub(st.TotalQualityAdjPower, sectorWeight) //nolint:scopelint st.TotalRawBytePower = types.BigSub(st.TotalRawBytePower, types.NewInt(uint64(m.SectorSize))) return nil @@ -277,9 +276,9 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid return cid.Undef, xerrors.Errorf("getting current total power: %w", err) } - pcd := miner.PreCommitDepositForPower(epochReward.ThisEpochRewardSmoothed, tpow.QualityAdjPowerSmoothed, sectorWeight) + pcd := miner0.PreCommitDepositForPower(epochReward.ThisEpochRewardSmoothed, tpow.QualityAdjPowerSmoothed, sectorWeight) - pledge := miner.InitialPledgeForPower( + pledge := miner0.InitialPledgeForPower( sectorWeight, epochReward.ThisEpochBaselinePower, tpow.PledgeCollateral, @@ -301,7 +300,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid Sectors: []abi.SectorNumber{preseal.SectorID}, } - _, err = doExecValue(ctx, vm, minerInfos[i].maddr, builtin.StoragePowerActorAddr, big.Zero(), builtin.MethodsMiner.ConfirmSectorProofsValid, mustEnc(confirmParams)) + _, err = doExecValue(ctx, vm, minerInfos[i].maddr, power.Address, big.Zero(), builtin.MethodsMiner.ConfirmSectorProofsValid, mustEnc(confirmParams)) if err != nil { return cid.Undef, xerrors.Errorf("failed to confirm presealed sectors: %w", err) } @@ -310,7 +309,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid } // Sanity-check total network power - err = vm.MutateState(ctx, builtin.StoragePowerActorAddr, func(cst cbor.IpldStore, st *power.State) error { + err = vm.MutateState(ctx, power.Address, func(cst cbor.IpldStore, st *power0.State) error { if !st.TotalRawBytePower.Equals(rawPow) { return xerrors.Errorf("st.TotalRawBytePower doesn't match previously calculated rawPow") } @@ -349,12 +348,12 @@ func (fr *fakeRand) GetBeaconRandomness(ctx context.Context, personalization cry return out, nil } -func currentTotalPower(ctx context.Context, vm *vm.VM, maddr address.Address) (*power.CurrentTotalPowerReturn, error) { - pwret, err := doExecValue(ctx, vm, builtin.StoragePowerActorAddr, maddr, big.Zero(), builtin.MethodsPower.CurrentTotalPower, nil) +func currentTotalPower(ctx context.Context, vm *vm.VM, maddr address.Address) (*power0.CurrentTotalPowerReturn, error) { + pwret, err := doExecValue(ctx, vm, power.Address, maddr, big.Zero(), builtin.MethodsPower.CurrentTotalPower, nil) if err != nil { return nil, err } - var pwr power.CurrentTotalPowerReturn + var pwr power0.CurrentTotalPowerReturn if err := pwr.UnmarshalCBOR(bytes.NewReader(pwret)); err != nil { return nil, err } @@ -362,38 +361,38 @@ func currentTotalPower(ctx context.Context, vm *vm.VM, maddr address.Address) (* return &pwr, nil } -func dealWeight(ctx context.Context, vm *vm.VM, maddr address.Address, dealIDs []abi.DealID, sectorStart, sectorExpiry abi.ChainEpoch) (market.VerifyDealsForActivationReturn, error) { +func dealWeight(ctx context.Context, vm *vm.VM, maddr address.Address, dealIDs []abi.DealID, sectorStart, sectorExpiry abi.ChainEpoch) (market0.VerifyDealsForActivationReturn, error) { params := &market.VerifyDealsForActivationParams{ DealIDs: dealIDs, SectorStart: sectorStart, SectorExpiry: sectorExpiry, } - var dealWeights market.VerifyDealsForActivationReturn + var dealWeights market0.VerifyDealsForActivationReturn ret, err := doExecValue(ctx, vm, - builtin.StorageMarketActorAddr, + market.Address, maddr, abi.NewTokenAmount(0), builtin.MethodsMarket.VerifyDealsForActivation, mustEnc(params), ) if err != nil { - return market.VerifyDealsForActivationReturn{}, err + return market0.VerifyDealsForActivationReturn{}, err } if err := dealWeights.UnmarshalCBOR(bytes.NewReader(ret)); err != nil { - return market.VerifyDealsForActivationReturn{}, err + return market0.VerifyDealsForActivationReturn{}, err } return dealWeights, nil } -func currentEpochBlockReward(ctx context.Context, vm *vm.VM, maddr address.Address) (*reward.ThisEpochRewardReturn, error) { - rwret, err := doExecValue(ctx, vm, builtin.RewardActorAddr, maddr, big.Zero(), builtin.MethodsReward.ThisEpochReward, nil) +func currentEpochBlockReward(ctx context.Context, vm *vm.VM, maddr address.Address) (*reward0.ThisEpochRewardReturn, error) { + rwret, err := doExecValue(ctx, vm, reward.Address, maddr, big.Zero(), builtin.MethodsReward.ThisEpochReward, nil) if err != nil { return nil, err } - var epochReward reward.ThisEpochRewardReturn + var epochReward reward0.ThisEpochRewardReturn if err := epochReward.UnmarshalCBOR(bytes.NewReader(rwret)); err != nil { return nil, err } diff --git a/chain/gen/genesis/t02_reward.go b/chain/gen/genesis/t02_reward.go index d499b24d0..92531051b 100644 --- a/chain/gen/genesis/t02_reward.go +++ b/chain/gen/genesis/t02_reward.go @@ -6,7 +6,7 @@ import ( "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/reward" + reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward" cbor "github.com/ipfs/go-ipld-cbor" "github.com/filecoin-project/lotus/build" @@ -17,7 +17,7 @@ import ( func SetupRewardActor(bs bstore.Blockstore, qaPower big.Int) (*types.Actor, error) { cst := cbor.NewCborStore(bs) - st := reward.ConstructState(qaPower) + st := reward0.ConstructState(qaPower) hcid, err := cst.Put(context.TODO(), st) if err != nil { diff --git a/chain/gen/genesis/t04_power.go b/chain/gen/genesis/t04_power.go index 86ba684e0..2f1303ba4 100644 --- a/chain/gen/genesis/t04_power.go +++ b/chain/gen/genesis/t04_power.go @@ -6,7 +6,7 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/util/adt" - "github.com/filecoin-project/specs-actors/actors/builtin/power" + power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" cbor "github.com/ipfs/go-ipld-cbor" "github.com/filecoin-project/lotus/chain/types" @@ -30,7 +30,7 @@ func SetupStoragePowerActor(bs bstore.Blockstore) (*types.Actor, error) { return nil, err } - sms := power.ConstructState(emptyMap, emptyMultiMap) + sms := power0.ConstructState(emptyMap, emptyMultiMap) stcid, err := store.Put(store.Context(), sms) if err != nil { diff --git a/chain/gen/genesis/t06_vreg.go b/chain/gen/genesis/t06_vreg.go index 6636fa05f..1709b205f 100644 --- a/chain/gen/genesis/t06_vreg.go +++ b/chain/gen/genesis/t06_vreg.go @@ -7,7 +7,7 @@ import ( cbor "github.com/ipfs/go-ipld-cbor" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/chain/types" @@ -34,7 +34,7 @@ func SetupVerifiedRegistryActor(bs bstore.Blockstore) (*types.Actor, error) { return nil, err } - sms := verifreg.ConstructState(h, RootVerifierID) + sms := verifreg0.ConstructState(h, RootVerifierID) stcid, err := store.Put(store.Context(), sms) if err != nil { diff --git a/chain/gen/genesis/util.go b/chain/gen/genesis/util.go index 67a4e9579..bcafb007e 100644 --- a/chain/gen/genesis/util.go +++ b/chain/gen/genesis/util.go @@ -3,6 +3,9 @@ package genesis import ( "context" + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" cbg "github.com/whyrusleeping/cbor-gen" @@ -46,3 +49,14 @@ func doExecValue(ctx context.Context, vm *vm.VM, to, from address.Address, value return ret.Return, nil } + +var GenesisNetworkVersion = func() network.Version { // TODO: Get from build/ + if build.UseNewestNetwork() { // TODO: Get from build/ + return build.NewestNetworkVersion // TODO: Get from build/ + } // TODO: Get from build/ + return network.Version1 // TODO: Get from build/ +}() // TODO: Get from build/ + +func genesisNetworkVersion(context.Context, abi.ChainEpoch) network.Version { // TODO: Get from build/ + return GenesisNetworkVersion // TODO: Get from build/ +} // TODO: Get from build/ diff --git a/chain/market/fundmgr.go b/chain/market/fundmgr.go index edf73d9bd..aef3b98eb 100644 --- a/chain/market/fundmgr.go +++ b/chain/market/fundmgr.go @@ -15,6 +15,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/builtin/market" "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/events/state" "github.com/filecoin-project/lotus/chain/types" @@ -151,7 +152,7 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add } smsg, err := fm.api.MpoolPushMessage(ctx, &types.Message{ - To: builtin.StorageMarketActorAddr, + To: market.Address, From: wallet, Value: toAdd, Method: builtin.MethodsMarket.AddBalance, diff --git a/chain/market/fundmgr_test.go b/chain/market/fundmgr_test.go index c0e69c51c..b05db55d8 100644 --- a/chain/market/fundmgr_test.go +++ b/chain/market/fundmgr_test.go @@ -17,6 +17,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/builtin/market" "github.com/filecoin-project/lotus/chain/types" ) @@ -47,7 +48,7 @@ func (fapi *fakeAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, s func addFundsMsg(toAdd abi.TokenAmount, addr address.Address, wallet address.Address) *types.Message { params, _ := actors.SerializeParams(&addr) return &types.Message{ - To: builtin.StorageMarketActorAddr, + To: market.Address, From: wallet, Value: toAdd, Method: builtin.MethodsMarket.AddBalance, diff --git a/chain/messagepool/provider.go b/chain/messagepool/provider.go index 80b9a4297..347e90044 100644 --- a/chain/messagepool/provider.go +++ b/chain/messagepool/provider.go @@ -47,13 +47,15 @@ func (mpp *mpoolProvider) PubSubPublish(k string, v []byte) error { } func (mpp *mpoolProvider) GetActorAfter(addr address.Address, ts *types.TipSet) (*types.Actor, error) { - var act types.Actor stcid, _, err := mpp.sm.TipSetState(context.TODO(), ts) if err != nil { return nil, xerrors.Errorf("computing tipset state for GetActor: %w", err) } - - return &act, mpp.sm.WithStateTree(stcid, mpp.sm.WithActor(addr, stmgr.GetActor(&act))) + st, err := mpp.sm.StateTree(stcid) + if err != nil { + return nil, xerrors.Errorf("failed to load state tree: %w", err) + } + return st.GetActor(addr) } func (mpp *mpoolProvider) StateAccountKey(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 5e372fc85..ea19dad9c 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -1216,6 +1216,9 @@ func makeZipfPremiumDistribution(rng *rand.Rand) func() uint64 { } func TestCompetitiveMessageSelectionExp(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } var capacityBoost, rewardBoost, tqReward float64 seeds := []int64{1947, 1976, 2020, 2100, 10000, 143324, 432432, 131, 32, 45} for _, seed := range seeds { diff --git a/chain/state/statetree.go b/chain/state/statetree.go index 445f3765a..a654d224b 100644 --- a/chain/state/statetree.go +++ b/chain/state/statetree.go @@ -1,14 +1,10 @@ package state import ( + "bytes" "context" "fmt" - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/specs-actors/actors/builtin" - init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" - - "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" logging "github.com/ipfs/go-log/v2" @@ -16,6 +12,12 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/actors/builtin" + init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" + cbg "github.com/whyrusleeping/cbor-gen" + + "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/types" ) @@ -23,8 +25,10 @@ var log = logging.Logger("statetree") // StateTree stores actors state by their ID. type StateTree struct { - root *adt.Map - Store cbor.IpldStore + root adt.Map + version builtin.Version // TODO + info cid.Cid + Store cbor.IpldStore snaps *stateSnaps } @@ -116,26 +120,57 @@ func (ss *stateSnaps) deleteActor(addr address.Address) { ss.layers[len(ss.layers)-1].actors[addr] = streeOp{Delete: true} } -func NewStateTree(cst cbor.IpldStore) (*StateTree, error) { +func NewStateTree(cst cbor.IpldStore, version builtin.Version) (*StateTree, error) { + var info cid.Cid + switch version { + case builtin.Version0: + // info is undefined + default: + return nil, xerrors.Errorf("unsupported state tree version: %d", version) + } + root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), version) + if err != nil { + return nil, err + } return &StateTree{ - root: adt.MakeEmptyMap(adt.WrapStore(context.TODO(), cst)), - Store: cst, - snaps: newStateSnaps(), + root: root, + info: info, + version: version, + Store: cst, + snaps: newStateSnaps(), }, nil } func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) { - nd, err := adt.AsMap(adt.WrapStore(context.TODO(), cst), c) + var root types.StateRoot + // Try loading as a new-style state-tree (version/actors tuple). + if err := cst.Get(context.TODO(), c, &root); err != nil { + // We failed to decode as the new version, must be an old version. + root.Actors = c + root.Version = builtin.Version0 + } + + // If that fails, load as an old-style state-tree (direct hampt, version 0. + nd, err := adt.AsMap(adt.WrapStore(context.TODO(), cst), root.Actors, builtin.Version(root.Version)) if err != nil { log.Errorf("loading hamt node %s failed: %s", c, err) return nil, err } + switch root.Version { + case builtin.Version0: + // supported + default: + return nil, xerrors.Errorf("unsupported state tree version: %d", root.Version) + } + return &StateTree{ - root: nd, - Store: cst, - snaps: newStateSnaps(), + root: nd, + info: root.Info, + version: builtin.Version(root.Version), + Store: cst, + snaps: newStateSnaps(), }, nil } @@ -161,17 +196,17 @@ func (st *StateTree) LookupID(addr address.Address) (address.Address, error) { return resa, nil } - act, err := st.GetActor(builtin.InitActorAddr) + act, err := st.GetActor(init_.Address) if err != nil { return address.Undef, xerrors.Errorf("getting init actor: %w", err) } - var ias init_.State - if err := st.Store.Get(context.TODO(), act.Head, &ias); err != nil { + ias, err := init_.Load(&AdtStore{st.Store}, act) + if err != nil { return address.Undef, xerrors.Errorf("loading init actor state: %w", err) } - a, found, err := ias.ResolveAddress(&AdtStore{st.Store}, addr) + a, found, err := ias.ResolveAddress(addr) if err == nil && !found { err = types.ErrActorNotFound } @@ -265,7 +300,16 @@ func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) { } } - return st.root.Root() + root, err := st.root.Root() + if err != nil { + return cid.Undef, xerrors.Errorf("failed to flush state-tree hamt: %w", err) + } + // If we're version 0, return a raw tree. + if st.version == builtin.Version0 { + return root, nil + } + // Otherwise, return a versioned tree. + return st.Store.Put(ctx, &types.StateRoot{Version: uint64(st.version), Actors: root, Info: st.info}) } func (st *StateTree) Snapshot(ctx context.Context) error { @@ -283,19 +327,19 @@ func (st *StateTree) ClearSnapshot() { func (st *StateTree) RegisterNewAddress(addr address.Address) (address.Address, error) { var out address.Address - err := st.MutateActor(builtin.InitActorAddr, func(initact *types.Actor) error { - var ias init_.State - if err := st.Store.Get(context.TODO(), initact.Head, &ias); err != nil { + err := st.MutateActor(init_.Address, func(initact *types.Actor) error { + ias, err := init_.Load(&AdtStore{st.Store}, initact) + if err != nil { return err } - oaddr, err := ias.MapAddressToNewID(&AdtStore{st.Store}, addr) + oaddr, err := ias.MapAddressToNewID(addr) if err != nil { return err } out = oaddr - ncid, err := st.Store.Put(context.TODO(), &ias) + ncid, err := st.Store.Put(context.TODO(), ias) if err != nil { return err } @@ -341,6 +385,7 @@ func (st *StateTree) MutateActor(addr address.Address, f func(*types.Actor) erro func (st *StateTree) ForEach(f func(address.Address, *types.Actor) error) error { var act types.Actor return st.root.ForEach(&act, func(k string) error { + act := act // copy addr, err := address.NewFromBytes([]byte(k)) if err != nil { return xerrors.Errorf("invalid address (%x) found in state tree key: %w", []byte(k), err) @@ -349,3 +394,44 @@ func (st *StateTree) ForEach(f func(address.Address, *types.Actor) error) error return f(addr, &act) }) } + +func Diff(oldTree, newTree *StateTree) (map[string]types.Actor, error) { + out := map[string]types.Actor{} + + var ( + ncval, ocval cbg.Deferred + buf = bytes.NewReader(nil) + ) + if err := newTree.root.ForEach(&ncval, func(k string) error { + var act types.Actor + + addr, err := address.NewFromBytes([]byte(k)) + if err != nil { + return xerrors.Errorf("address in state tree was not valid: %w", err) + } + + found, err := oldTree.root.Get(abi.AddrKey(addr), &ocval) + if err != nil { + return err + } + + if found && bytes.Equal(ocval.Raw, ncval.Raw) { + return nil // not changed + } + + buf.Reset(ncval.Raw) + err = act.UnmarshalCBOR(buf) + buf.Reset(nil) + + if err != nil { + return err + } + + out[addr.String()] = act + + return nil + }); err != nil { + return nil, err + } + return out, nil +} diff --git a/chain/state/statetree_test.go b/chain/state/statetree_test.go index e45090d1a..79ab20606 100644 --- a/chain/state/statetree_test.go +++ b/chain/state/statetree_test.go @@ -5,17 +5,20 @@ import ( "fmt" "testing" - "github.com/filecoin-project/specs-actors/actors/builtin" - - address "github.com/filecoin-project/go-address" - "github.com/filecoin-project/lotus/chain/types" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" + + address "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/builtin" + + "github.com/filecoin-project/lotus/build" + builtin2 "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/types" ) func BenchmarkStateTreeSet(b *testing.B) { cst := cbor.NewMemCborStore() - st, err := NewStateTree(cst) + st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion)) if err != nil { b.Fatal(err) } @@ -42,7 +45,7 @@ func BenchmarkStateTreeSet(b *testing.B) { func BenchmarkStateTreeSetFlush(b *testing.B) { cst := cbor.NewMemCborStore() - st, err := NewStateTree(cst) + st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion)) if err != nil { b.Fatal(err) } @@ -72,7 +75,7 @@ func BenchmarkStateTreeSetFlush(b *testing.B) { func BenchmarkStateTree10kGetActor(b *testing.B) { cst := cbor.NewMemCborStore() - st, err := NewStateTree(cst) + st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion)) if err != nil { b.Fatal(err) } @@ -114,7 +117,7 @@ func BenchmarkStateTree10kGetActor(b *testing.B) { func TestSetCache(t *testing.T) { cst := cbor.NewMemCborStore() - st, err := NewStateTree(cst) + st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion)) if err != nil { t.Fatal(err) } @@ -151,7 +154,7 @@ func TestSetCache(t *testing.T) { func TestSnapshots(t *testing.T) { ctx := context.Background() cst := cbor.NewMemCborStore() - st, err := NewStateTree(cst) + st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion)) if err != nil { t.Fatal(err) } @@ -234,7 +237,7 @@ func assertNotHas(t *testing.T, st *StateTree, addr address.Address) { func TestStateTreeConsistency(t *testing.T) { cst := cbor.NewMemCborStore() - st, err := NewStateTree(cst) + st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion)) if err != nil { t.Fatal(err) } diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index 4b83842b4..f4dfc7115 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -33,7 +33,7 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate BaseFee: types.NewInt(0), } - vmi, err := vm.NewVM(vmopt) + vmi, err := vm.NewVM(ctx, vmopt) if err != nil { return nil, xerrors.Errorf("failed to set up vm: %w", err) } @@ -134,7 +134,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri NtwkVersion: sm.GetNtwkVersion, BaseFee: ts.Blocks()[0].ParentBaseFee, } - vmi, err := vm.NewVM(vmopt) + vmi, err := vm.NewVM(ctx, vmopt) if err != nil { return nil, xerrors.Errorf("failed to set up vm: %w", err) } diff --git a/chain/stmgr/forks.go b/chain/stmgr/forks.go index addaba90f..f9418c4d8 100644 --- a/chain/stmgr/forks.go +++ b/chain/stmgr/forks.go @@ -6,13 +6,14 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" + adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/util/adt" cbor "github.com/ipfs/go-ipld-cbor" "golang.org/x/xerrors" ) @@ -96,11 +97,8 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types return xerrors.Errorf("failed to get tipset at lookback height: %w", err) } - var lbtree *state.StateTree - if err = sm.WithStateTree(lbts.ParentState(), func(state *state.StateTree) error { - lbtree = state - return nil - }); err != nil { + lbtree, err := sm.ParentState(lbts) + if err != nil { return xerrors.Errorf("loading state tree failed: %w", err) } @@ -125,7 +123,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types // Take all excess funds away, put them into the reserve account err = fetree.ForEach(func(addr address.Address, act *types.Actor) error { switch act.Code { - case builtin.AccountActorCodeID, builtin.MultisigActorCodeID, builtin.PaymentChannelActorCodeID: + case builtin0.AccountActorCodeID, builtin0.MultisigActorCodeID, builtin0.PaymentChannelActorCodeID: sysAcc, err := isSystemAccount(addr) if err != nil { return xerrors.Errorf("checking system account: %w", err) @@ -138,9 +136,9 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types Amt: act.Balance, }) } - case builtin.StorageMinerActorCodeID: - var st miner.State - if err := sm.WithActorState(ctx, &st)(act); err != nil { + case builtin0.StorageMinerActorCodeID: + var st miner0.State + if err := sm.ChainStore().Store(ctx).Get(ctx, act.Head, &st); err != nil { return xerrors.Errorf("failed to load miner state: %w", err) } @@ -176,8 +174,8 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types } // pull up power table to give miners back some funds proportional to their power - var ps power.State - powAct, err := tree.GetActor(builtin.StoragePowerActorAddr) + var ps power0.State + powAct, err := tree.GetActor(builtin0.StoragePowerActorAddr) if err != nil { return xerrors.Errorf("failed to load power actor: %w", err) } @@ -205,7 +203,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types } switch act.Code { - case builtin.AccountActorCodeID, builtin.MultisigActorCodeID, builtin.PaymentChannelActorCodeID: + case builtin0.AccountActorCodeID, builtin0.MultisigActorCodeID, builtin0.PaymentChannelActorCodeID: nbalance := big.Min(prevBalance, AccountCap) if nbalance.Sign() != 0 { transfersBack = append(transfersBack, transfer{ @@ -214,18 +212,18 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types Amt: nbalance, }) } - case builtin.StorageMinerActorCodeID: - var st miner.State - if err := sm.WithActorState(ctx, &st)(act); err != nil { + case builtin0.StorageMinerActorCodeID: + var st miner0.State + if err := sm.ChainStore().Store(ctx).Get(ctx, act.Head, &st); err != nil { return xerrors.Errorf("failed to load miner state: %w", err) } - var minfo miner.MinerInfo + var minfo miner0.MinerInfo if err := cst.Get(ctx, st.Info, &minfo); err != nil { return xerrors.Errorf("failed to get miner info: %w", err) } - sectorsArr, err := adt.AsArray(sm.ChainStore().Store(ctx), st.Sectors) + sectorsArr, err := adt0.AsArray(sm.ChainStore().Store(ctx), st.Sectors) if err != nil { return xerrors.Errorf("failed to load sectors array: %w", err) } @@ -244,12 +242,12 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types // Now make sure to give each miner who had power at the lookback some FIL lbact, err := lbtree.GetActor(addr) if err == nil { - var lbst miner.State - if err := sm.WithActorState(ctx, &lbst)(lbact); err != nil { + var lbst miner0.State + if err := sm.ChainStore().Store(ctx).Get(ctx, lbact.Head, &lbst); err != nil { return xerrors.Errorf("failed to load miner state: %w", err) } - lbsectors, err := adt.AsArray(sm.ChainStore().Store(ctx), lbst.Sectors) + lbsectors, err := adt0.AsArray(sm.ChainStore().Store(ctx), lbst.Sectors) if err != nil { return xerrors.Errorf("failed to load lb sectors array: %w", err) } @@ -279,11 +277,11 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types } // transfer all burnt funds back to the reserve account - burntAct, err := tree.GetActor(builtin.BurntFundsActorAddr) + burntAct, err := tree.GetActor(builtin0.BurntFundsActorAddr) if err != nil { return xerrors.Errorf("failed to load burnt funds actor: %w", err) } - if err := doTransfer(tree, builtin.BurntFundsActorAddr, ReserveAddress, burntAct.Balance); err != nil { + if err := doTransfer(tree, builtin0.BurntFundsActorAddr, ReserveAddress, burntAct.Balance); err != nil { return xerrors.Errorf("failed to unburn funds: %w", err) } diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index 2fc11b3d7..516058a81 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -8,17 +8,15 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" "github.com/filecoin-project/specs-actors/actors/runtime" "golang.org/x/xerrors" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/aerrors" + lotusinit "github.com/filecoin-project/lotus/chain/actors/builtin/init" + "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/stmgr" . "github.com/filecoin-project/lotus/chain/stmgr" @@ -33,11 +31,9 @@ import ( ) func init() { - miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ - abi.RegisteredSealProof_StackedDrg2KiBV1: {}, - } - power.ConsensusMinerMinPower = big.NewInt(2048) - verifreg.MinVerifiedDealSize = big.NewInt(256) + policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) + policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048)) + policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) } const testForkHeight = 40 @@ -148,8 +144,8 @@ func TestForkHeightTriggers(t *testing.T) { } inv.Register(builtin.PaymentChannelActorCodeID, &testActor{}, &testActorState{}) - sm.SetVMConstructor(func(vmopt *vm.VMOpts) (*vm.VM, error) { - nvm, err := vm.NewVM(vmopt) + sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) { + nvm, err := vm.NewVM(ctx, vmopt) if err != nil { return nil, err } @@ -168,7 +164,7 @@ func TestForkHeightTriggers(t *testing.T) { m := &types.Message{ From: cg.Banker(), - To: builtin.InitActorAddr, + To: lotusinit.Address, Method: builtin.MethodsInit.Exec, Params: enc, GasLimit: types.TestGasLimit, diff --git a/chain/stmgr/read.go b/chain/stmgr/read.go index c707b5195..9a9b80265 100644 --- a/chain/stmgr/read.go +++ b/chain/stmgr/read.go @@ -2,7 +2,6 @@ package stmgr import ( "context" - "reflect" "golang.org/x/xerrors" @@ -12,144 +11,56 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/util/adt" ) -type StateTreeCB func(state *state.StateTree) error - -func (sm *StateManager) WithParentStateTsk(tsk types.TipSetKey, cb StateTreeCB) error { +func (sm *StateManager) ParentStateTsk(tsk types.TipSetKey) (*state.StateTree, error) { ts, err := sm.cs.GetTipSetFromKey(tsk) if err != nil { - return xerrors.Errorf("loading tipset %s: %w", tsk, err) + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } + return sm.ParentState(ts) +} +func (sm *StateManager) ParentState(ts *types.TipSet) (*state.StateTree, error) { cst := cbor.NewCborStore(sm.cs.Blockstore()) state, err := state.LoadStateTree(cst, sm.parentState(ts)) if err != nil { - return xerrors.Errorf("load state tree: %w", err) + return nil, xerrors.Errorf("load state tree: %w", err) } - return cb(state) + return state, nil } -func (sm *StateManager) WithParentState(ts *types.TipSet, cb StateTreeCB) error { - cst := cbor.NewCborStore(sm.cs.Blockstore()) - state, err := state.LoadStateTree(cst, sm.parentState(ts)) - if err != nil { - return xerrors.Errorf("load state tree: %w", err) - } - - return cb(state) -} - -func (sm *StateManager) WithStateTree(st cid.Cid, cb StateTreeCB) error { +func (sm *StateManager) StateTree(st cid.Cid) (*state.StateTree, error) { cst := cbor.NewCborStore(sm.cs.Blockstore()) state, err := state.LoadStateTree(cst, st) if err != nil { - return xerrors.Errorf("load state tree: %w", err) + return nil, xerrors.Errorf("load state tree: %w", err) } - return cb(state) + return state, nil } -type ActorCB func(act *types.Actor) error - -func GetActor(out *types.Actor) ActorCB { - return func(act *types.Actor) error { - *out = *act - return nil +func (sm *StateManager) LoadActor(_ context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, error) { + state, err := sm.ParentState(ts) + if err != nil { + return nil, err } + return state.GetActor(addr) } -func (sm *StateManager) WithActor(addr address.Address, cb ActorCB) StateTreeCB { - return func(state *state.StateTree) error { - act, err := state.GetActor(addr) - if err != nil { - return xerrors.Errorf("get actor: %w", err) - } - - return cb(act) +func (sm *StateManager) LoadActorTsk(_ context.Context, addr address.Address, tsk types.TipSetKey) (*types.Actor, error) { + state, err := sm.ParentStateTsk(tsk) + if err != nil { + return nil, err } + return state.GetActor(addr) } -// WithActorState usage: -// Option 1: WithActorState(ctx, idAddr, func(store adt.Store, st *ActorStateType) error {...}) -// Option 2: WithActorState(ctx, idAddr, actorStatePtr) -func (sm *StateManager) WithActorState(ctx context.Context, out interface{}) ActorCB { - return func(act *types.Actor) error { - store := sm.cs.Store(ctx) - - outCallback := reflect.TypeOf(out).Kind() == reflect.Func - - var st reflect.Value - if outCallback { - st = reflect.New(reflect.TypeOf(out).In(1).Elem()) - } else { - st = reflect.ValueOf(out) - } - if err := store.Get(ctx, act.Head, st.Interface()); err != nil { - return xerrors.Errorf("read actor head: %w", err) - } - - if outCallback { - out := reflect.ValueOf(out).Call([]reflect.Value{reflect.ValueOf(store), st}) - if !out[0].IsNil() && out[0].Interface().(error) != nil { - return out[0].Interface().(error) - } - } - - return nil - } -} - -type DeadlinesCB func(store adt.Store, deadlines *miner.Deadlines) error - -func (sm *StateManager) WithDeadlines(cb DeadlinesCB) func(store adt.Store, mas *miner.State) error { - return func(store adt.Store, mas *miner.State) error { - deadlines, err := mas.LoadDeadlines(store) - if err != nil { - return err - } - - return cb(store, deadlines) - } -} - -type DeadlineCB func(store adt.Store, idx uint64, deadline *miner.Deadline) error - -func (sm *StateManager) WithDeadline(idx uint64, cb DeadlineCB) DeadlinesCB { - return func(store adt.Store, deadlines *miner.Deadlines) error { - d, err := deadlines.LoadDeadline(store, idx) - if err != nil { - return err - } - - return cb(store, idx, d) - } -} - -func (sm *StateManager) WithEachDeadline(cb DeadlineCB) DeadlinesCB { - return func(store adt.Store, deadlines *miner.Deadlines) error { - return deadlines.ForEach(store, func(dlIdx uint64, dl *miner.Deadline) error { - return cb(store, dlIdx, dl) - }) - } -} - -type PartitionCB func(store adt.Store, idx uint64, partition *miner.Partition) error - -func (sm *StateManager) WithEachPartition(cb PartitionCB) DeadlineCB { - return func(store adt.Store, idx uint64, deadline *miner.Deadline) error { - parts, err := deadline.PartitionsArray(store) - if err != nil { - return err - } - - var partition miner.Partition - return parts.ForEach(&partition, func(i int64) error { - p := partition - return cb(store, uint64(i), &p) - }) +func (sm *StateManager) LoadActorRaw(_ context.Context, addr address.Address, st cid.Cid) (*types.Actor, error) { + state, err := sm.StateTree(st) + if err != nil { + return nil, err } + return state.GetActor(addr) } diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index a7f94e6ee..eaf9215db 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -5,35 +5,35 @@ import ( "fmt" "sync" - "github.com/filecoin-project/go-state-types/network" - - "github.com/filecoin-project/specs-actors/actors/builtin/power" - - "github.com/filecoin-project/specs-actors/actors/builtin/multisig" - - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/actors" - "github.com/filecoin-project/lotus/chain/state" - "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/go-state-types/abi" - "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/builtin/reward" - "github.com/filecoin-project/specs-actors/actors/util/adt" - - "golang.org/x/xerrors" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" logging "github.com/ipfs/go-log/v2" cbg "github.com/whyrusleeping/cbor-gen" "go.opencensus.io/trace" + "golang.org/x/xerrors" + + "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/go-state-types/network" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors/builtin/market" + "github.com/filecoin-project/lotus/chain/actors/builtin/multisig" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" + "github.com/filecoin-project/lotus/chain/actors/builtin/power" + "github.com/filecoin-project/lotus/chain/actors/builtin/reward" + "github.com/filecoin-project/lotus/chain/state" + "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("statemgr") @@ -45,7 +45,7 @@ type StateManager struct { compWait map[string]chan struct{} stlk sync.Mutex genesisMsigLk sync.Mutex - newVM func(*vm.VMOpts) (*vm.VM, error) + newVM func(context.Context, *vm.VMOpts) (*vm.VM, error) genInfo *genesisInfo } @@ -160,27 +160,27 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp BaseFee: baseFee, } - vmi, err := sm.newVM(vmopt) + vmi, err := sm.newVM(ctx, vmopt) if err != nil { return cid.Undef, cid.Undef, xerrors.Errorf("instantiating VM failed: %w", err) } runCron := func() error { // TODO: this nonce-getting is a tiny bit ugly - ca, err := vmi.StateTree().GetActor(builtin.SystemActorAddr) + ca, err := vmi.StateTree().GetActor(builtin0.SystemActorAddr) if err != nil { return err } cronMsg := &types.Message{ - To: builtin.CronActorAddr, - From: builtin.SystemActorAddr, + To: builtin0.CronActorAddr, + From: builtin0.SystemActorAddr, Nonce: ca.Nonce, Value: types.NewInt(0), GasFeeCap: types.NewInt(0), GasPremium: types.NewInt(0), GasLimit: build.BlockGasLimit * 10000, // Make super sure this is never too little - Method: builtin.MethodsCron.EpochTick, + Method: builtin0.MethodsCron.EpochTick, Params: nil, } ret, err := vmi.ApplyImplicitMessage(ctx, cronMsg) @@ -201,6 +201,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp for i := parentEpoch; i < epoch; i++ { // handle state forks + // XXX: The state tree err = sm.handleStateForks(ctx, vmi.StateTree(), i, ts) if err != nil { return cid.Undef, cid.Undef, xerrors.Errorf("error handling state forks: %w", err) @@ -244,7 +245,6 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp processedMsgs[m.Cid()] = true } - var err error params, err := actors.SerializeParams(&reward.AwardBlockRewardParams{ Miner: b.Miner, Penalty: penalty, @@ -255,24 +255,24 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp return cid.Undef, cid.Undef, xerrors.Errorf("failed to serialize award params: %w", err) } - sysAct, err := vmi.StateTree().GetActor(builtin.SystemActorAddr) - if err != nil { + sysAct, actErr := vmi.StateTree().GetActor(builtin0.SystemActorAddr) + if actErr != nil { return cid.Undef, cid.Undef, xerrors.Errorf("failed to get system actor: %w", err) } rwMsg := &types.Message{ - From: builtin.SystemActorAddr, - To: builtin.RewardActorAddr, + From: builtin0.SystemActorAddr, + To: reward.Address, Nonce: sysAct.Nonce, Value: types.NewInt(0), GasFeeCap: types.NewInt(0), GasPremium: types.NewInt(0), GasLimit: 1 << 30, - Method: builtin.MethodsReward.AwardBlockReward, + Method: builtin0.MethodsReward.AwardBlockReward, Params: params, } - ret, err := vmi.ApplyImplicitMessage(ctx, rwMsg) - if err != nil { + ret, actErr := vmi.ApplyImplicitMessage(ctx, rwMsg) + if actErr != nil { return cid.Undef, cid.Undef, xerrors.Errorf("failed to apply reward message for miner %s: %w", b.Miner, err) } if cb != nil { @@ -290,7 +290,11 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp return cid.Cid{}, cid.Cid{}, err } - rectarr := adt.MakeEmptyArray(sm.cs.Store(ctx)) + // XXX: Is the height correct? Or should it be epoch-1? + rectarr, err := adt.NewArray(sm.cs.Store(ctx), builtin.VersionForNetwork(sm.GetNtwkVersion(ctx, epoch))) + if err != nil { + return cid.Undef, cid.Undef, xerrors.Errorf("failed to create receipts amt: %w", err) + } for i, receipt := range receipts { if err := rectarr.Set(uint64(i), receipt); err != nil { return cid.Undef, cid.Undef, xerrors.Errorf("failed to build receipts amt: %w", err) @@ -601,10 +605,9 @@ func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet default: } - var act types.Actor - err := sm.WithParentState(cur, sm.WithActor(m.VMMessage().From, GetActor(&act))) + act, err := sm.LoadActor(ctx, m.VMMessage().From, cur) if err != nil { - return nil, nil, cid.Undef, err + return nil, nil, cid.Cid{}, err } // we either have no messages from the sender, or the latest message we found has a lower nonce than the one being searched for, @@ -689,17 +692,13 @@ func (sm *StateManager) ListAllActors(ctx context.Context, ts *types.TipSet) ([] return nil, err } - r, err := adt.AsMap(sm.cs.Store(ctx), st) + stateTree, err := sm.StateTree(st) if err != nil { return nil, err } var out []address.Address - err = r.ForEach(nil, func(k string) error { - addr, err := address.NewFromBytes([]byte(k)) - if err != nil { - return xerrors.Errorf("address in state tree was not valid: %w", err) - } + err = stateTree.ForEach(func(addr address.Address, act *types.Actor) error { out = append(out, addr) return nil }) @@ -711,8 +710,17 @@ func (sm *StateManager) ListAllActors(ctx context.Context, ts *types.TipSet) ([] } func (sm *StateManager) MarketBalance(ctx context.Context, addr address.Address, ts *types.TipSet) (api.MarketBalance, error) { - var state market.State - _, err := sm.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts) + st, err := sm.ParentState(ts) + if err != nil { + return api.MarketBalance{}, err + } + + act, err := st.GetActor(market.Address) + if err != nil { + return api.MarketBalance{}, err + } + + mstate, err := market.Load(sm.cs.Store(ctx), act) if err != nil { return api.MarketBalance{}, err } @@ -724,7 +732,7 @@ func (sm *StateManager) MarketBalance(ctx context.Context, addr address.Address, var out api.MarketBalance - et, err := adt.AsBalanceTable(sm.cs.Store(ctx), state.EscrowTable) + et, err := mstate.EscrowTable() if err != nil { return api.MarketBalance{}, err } @@ -733,7 +741,7 @@ func (sm *StateManager) MarketBalance(ctx context.Context, addr address.Address, return api.MarketBalance{}, xerrors.Errorf("getting escrow balance: %w", err) } - lt, err := adt.AsBalanceTable(sm.cs.Store(ctx), state.LockedTable) + lt, err := mstate.LockedTable() if err != nil { return api.MarketBalance{}, err } @@ -774,12 +782,12 @@ func (sm *StateManager) ValidateChain(ctx context.Context, ts *types.TipSet) err return nil } -func (sm *StateManager) SetVMConstructor(nvm func(*vm.VMOpts) (*vm.VM, error)) { +func (sm *StateManager) SetVMConstructor(nvm func(context.Context, *vm.VMOpts) (*vm.VM, error)) { sm.newVM = nvm } type genesisInfo struct { - genesisMsigs []multisig.State + genesisMsigs []msig0.State // info about the Accounts in the genesis state genesisActors []genesisActor genesisPledge abi.TokenAmount @@ -827,51 +835,56 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error { return xerrors.Errorf("setting up genesis pledge: %w", err) } - r, err := adt.AsMap(sm.cs.Store(ctx), st) - if err != nil { - return xerrors.Errorf("getting genesis actors: %w", err) - } - totalsByEpoch := make(map[abi.ChainEpoch]abi.TokenAmount) - var act types.Actor - err = r.ForEach(&act, func(k string) error { - if act.Code == builtin.MultisigActorCodeID { - var s multisig.State - err := sm.cs.Store(ctx).Get(ctx, act.Head, &s) + err = sTree.ForEach(func(kaddr address.Address, act *types.Actor) error { + if act.IsMultisigActor() { + s, err := multisig.Load(sm.cs.Store(ctx), act) if err != nil { return err } - if s.StartEpoch != 0 { + se, err := s.StartEpoch() + if err != nil { + return err + } + + if se != 0 { return xerrors.New("genesis multisig doesn't start vesting at epoch 0!") } - ot, f := totalsByEpoch[s.UnlockDuration] - if f { - totalsByEpoch[s.UnlockDuration] = big.Add(ot, s.InitialBalance) - } else { - totalsByEpoch[s.UnlockDuration] = s.InitialBalance + ud, err := s.UnlockDuration() + if err != nil { + return err } - } else if act.Code == builtin.AccountActorCodeID { + ib, err := s.InitialBalance() + if err != nil { + return err + } + + ot, f := totalsByEpoch[ud] + if f { + totalsByEpoch[ud] = big.Add(ot, ib) + } else { + totalsByEpoch[ud] = ib + } + + } else if act.IsAccountActor() { // should exclude burnt funds actor and "remainder account actor" // should only ever be "faucet" accounts in testnets - kaddr, err := address.NewFromBytes([]byte(k)) + if kaddr == builtin0.BurntFundsActorAddr { + return nil + } + + kid, err := sTree.LookupID(kaddr) if err != nil { - return xerrors.Errorf("decoding address: %w", err) + return xerrors.Errorf("resolving address: %w", err) } - if kaddr != builtin.BurntFundsActorAddr { - kid, err := sTree.LookupID(kaddr) - if err != nil { - return xerrors.Errorf("resolving address: %w", err) - } - - gi.genesisActors = append(gi.genesisActors, genesisActor{ - addr: kid, - initBal: act.Balance, - }) - } + gi.genesisActors = append(gi.genesisActors, genesisActor{ + addr: kid, + initBal: act.Balance, + }) } return nil }) @@ -880,9 +893,10 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error { return xerrors.Errorf("error setting up genesis infos: %w", err) } - gi.genesisMsigs = make([]multisig.State, 0, len(totalsByEpoch)) + // TODO: use network upgrade abstractions or always start at actors v0? + gi.genesisMsigs = make([]msig0.State, 0, len(totalsByEpoch)) for k, v := range totalsByEpoch { - ns := multisig.State{ + ns := msig0.State{ InitialBalance: v, UnlockDuration: k, PendingTxns: cid.Undef, @@ -936,30 +950,30 @@ func (sm *StateManager) setupGenesisActorsTestnet(ctx context.Context) error { totalsByEpoch := make(map[abi.ChainEpoch]abi.TokenAmount) // 6 months - sixMonths := abi.ChainEpoch(183 * builtin.EpochsInDay) + sixMonths := abi.ChainEpoch(183 * builtin0.EpochsInDay) totalsByEpoch[sixMonths] = big.NewInt(49_929_341) totalsByEpoch[sixMonths] = big.Add(totalsByEpoch[sixMonths], big.NewInt(32_787_700)) // 1 year - oneYear := abi.ChainEpoch(365 * builtin.EpochsInDay) + oneYear := abi.ChainEpoch(365 * builtin0.EpochsInDay) totalsByEpoch[oneYear] = big.NewInt(22_421_712) // 2 years - twoYears := abi.ChainEpoch(2 * 365 * builtin.EpochsInDay) + twoYears := abi.ChainEpoch(2 * 365 * builtin0.EpochsInDay) totalsByEpoch[twoYears] = big.NewInt(7_223_364) // 3 years - threeYears := abi.ChainEpoch(3 * 365 * builtin.EpochsInDay) + threeYears := abi.ChainEpoch(3 * 365 * builtin0.EpochsInDay) totalsByEpoch[threeYears] = big.NewInt(87_637_883) // 6 years - sixYears := abi.ChainEpoch(6 * 365 * builtin.EpochsInDay) + sixYears := abi.ChainEpoch(6 * 365 * builtin0.EpochsInDay) totalsByEpoch[sixYears] = big.NewInt(100_000_000) totalsByEpoch[sixYears] = big.Add(totalsByEpoch[sixYears], big.NewInt(300_000_000)) - gi.genesisMsigs = make([]multisig.State, 0, len(totalsByEpoch)) + gi.genesisMsigs = make([]msig0.State, 0, len(totalsByEpoch)) for k, v := range totalsByEpoch { - ns := multisig.State{ + ns := msig0.State{ InitialBalance: v, UnlockDuration: k, PendingTxns: cid.Undef, @@ -1002,46 +1016,45 @@ func (sm *StateManager) GetFilVested(ctx context.Context, height abi.ChainEpoch, } func GetFilMined(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) { - ractor, err := st.GetActor(builtin.RewardActorAddr) + ractor, err := st.GetActor(reward.Address) if err != nil { return big.Zero(), xerrors.Errorf("failed to load reward actor state: %w", err) } - var rst reward.State - if err := st.Store.Get(ctx, ractor.Head, &rst); err != nil { - return big.Zero(), xerrors.Errorf("failed to load reward state: %w", err) + rst, err := reward.Load(adt.WrapStore(ctx, st.Store), ractor) + if err != nil { + return big.Zero(), err } - return rst.TotalMined, nil + return rst.TotalStoragePowerReward() } func getFilMarketLocked(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) { - mactor, err := st.GetActor(builtin.StorageMarketActorAddr) + act, err := st.GetActor(market.Address) if err != nil { return big.Zero(), xerrors.Errorf("failed to load market actor: %w", err) } - var mst market.State - if err := st.Store.Get(ctx, mactor.Head, &mst); err != nil { + mst, err := market.Load(adt.WrapStore(ctx, st.Store), act) + if err != nil { return big.Zero(), xerrors.Errorf("failed to load market state: %w", err) } - fml := types.BigAdd(mst.TotalClientLockedCollateral, mst.TotalProviderLockedCollateral) - fml = types.BigAdd(fml, mst.TotalClientStorageFee) - return fml, nil + return mst.TotalLocked() } func getFilPowerLocked(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) { - pactor, err := st.GetActor(builtin.StoragePowerActorAddr) + pactor, err := st.GetActor(power.Address) if err != nil { return big.Zero(), xerrors.Errorf("failed to load power actor: %w", err) } - var pst power.State - if err := st.Store.Get(ctx, pactor.Head, &pst); err != nil { + pst, err := power.Load(adt.WrapStore(ctx, st.Store), pactor) + if err != nil { return big.Zero(), xerrors.Errorf("failed to load power state: %w", err) } - return pst.TotalPledgeCollateral, nil + + return pst.TotalLocked() } func (sm *StateManager) GetFilLocked(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) { @@ -1060,7 +1073,7 @@ func (sm *StateManager) GetFilLocked(ctx context.Context, st *state.StateTree) ( } func GetFilBurnt(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) { - burnt, err := st.GetActor(builtin.BurntFundsActorAddr) + burnt, err := st.GetActor(builtin0.BurntFundsActorAddr) if err != nil { return big.Zero(), xerrors.Errorf("failed to load burnt actor: %w", err) } @@ -1125,6 +1138,8 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha } func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) network.Version { + // TODO: move hard fork epoch checks to a schedule defined in build/ + if build.UseNewestNetwork() { return build.NewestNetworkVersion } @@ -1139,3 +1154,39 @@ func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoc return build.NewestNetworkVersion } + +func (sm *StateManager) GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) { + st, err := sm.ParentState(ts) + if err != nil { + return nil, nil, err + } + + act, err := st.GetActor(addr) + if err != nil { + return nil, nil, err + } + + actState, err := paych.Load(sm.cs.Store(ctx), act) + if err != nil { + return nil, nil, err + } + return act, actState, nil +} + +func (sm *StateManager) GetMarketState(ctx context.Context, ts *types.TipSet) (market.State, error) { + st, err := sm.ParentState(ts) + if err != nil { + return nil, err + } + + act, err := st.GetActor(market.Address) + if err != nil { + return nil, err + } + + actState, err := market.Load(sm.cs.Store(ctx), act) + if err != nil { + return nil, err + } + return actState, nil +} diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index 27b71f358..3493afca3 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -9,11 +9,7 @@ import ( "runtime" "strings" - saruntime "github.com/filecoin-project/specs-actors/actors/runtime" - "github.com/filecoin-project/specs-actors/actors/runtime/proof" - cid "github.com/ipfs/go-cid" - cbor "github.com/ipfs/go-ipld-cbor" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" @@ -21,210 +17,176 @@ import ( "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/crypto" - "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/account" - "github.com/filecoin-project/specs-actors/actors/builtin/cron" - init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" - "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/multisig" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/builtin/reward" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" - "github.com/filecoin-project/specs-actors/actors/util/adt" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + account0 "github.com/filecoin-project/specs-actors/actors/builtin/account" + cron0 "github.com/filecoin-project/specs-actors/actors/builtin/cron" + init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" + paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" + power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" + reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward" + verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" + "github.com/filecoin-project/lotus/chain/actors/builtin/market" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/builtin/power" "github.com/filecoin-project/lotus/chain/beacon" "github.com/filecoin-project/lotus/chain/state" "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/lib/blockstore" + "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" "github.com/filecoin-project/lotus/node/modules/dtypes" ) func GetNetworkName(ctx context.Context, sm *StateManager, st cid.Cid) (dtypes.NetworkName, error) { - var state init_.State - err := sm.WithStateTree(st, sm.WithActor(builtin.InitActorAddr, sm.WithActorState(ctx, &state))) + act, err := sm.LoadActorRaw(ctx, init_.Address, st) + if err != nil { + return "", err + } + ias, err := init_.Load(sm.cs.Store(ctx), act) if err != nil { return "", err } - return dtypes.NetworkName(state.NetworkName), nil -} - -func (sm *StateManager) LoadActorState(ctx context.Context, addr address.Address, out interface{}, ts *types.TipSet) (*types.Actor, error) { - var a *types.Actor - if err := sm.WithParentState(ts, sm.WithActor(addr, func(act *types.Actor) error { - a = act - return sm.WithActorState(ctx, out)(act) - })); err != nil { - return nil, err - } - - return a, nil -} - -func (sm *StateManager) LoadActorStateRaw(ctx context.Context, addr address.Address, out interface{}, st cid.Cid) (*types.Actor, error) { - var a *types.Actor - if err := sm.WithStateTree(st, sm.WithActor(addr, func(act *types.Actor) error { - a = act - return sm.WithActorState(ctx, out)(act) - })); err != nil { - return nil, err - } - - return a, nil + return ias.NetworkName() } func GetMinerWorkerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) { - var mas miner.State - _, err := sm.LoadActorStateRaw(ctx, maddr, &mas, st) + state, err := sm.StateTree(st) + if err != nil { + return address.Undef, xerrors.Errorf("(get sset) failed to load state tree: %w", err) + } + act, err := state.GetActor(maddr) + if err != nil { + return address.Undef, xerrors.Errorf("(get sset) failed to load miner actor: %w", err) + } + mas, err := miner.Load(sm.cs.Store(ctx), act) if err != nil { return address.Undef, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err) } - cst := cbor.NewCborStore(sm.cs.Blockstore()) - state, err := state.LoadStateTree(cst, st) + info, err := mas.Info() if err != nil { - return address.Undef, xerrors.Errorf("load state tree: %w", err) + return address.Undef, xerrors.Errorf("failed to load actor info: %w", err) } - info, err := mas.GetInfo(sm.cs.Store(ctx)) - if err != nil { - return address.Address{}, err - } - - return vm.ResolveToKeyAddr(state, cst, info.Worker) + return vm.ResolveToKeyAddr(state, sm.cs.Store(ctx), info.Worker) } -func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (power.Claim, power.Claim, error) { +func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (power.Claim, power.Claim, bool, error) { return GetPowerRaw(ctx, sm, ts.ParentState(), maddr) } -func GetPowerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (power.Claim, power.Claim, error) { - var ps power.State - _, err := sm.LoadActorStateRaw(ctx, builtin.StoragePowerActorAddr, &ps, st) +func GetPowerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (power.Claim, power.Claim, bool, error) { + act, err := sm.LoadActorRaw(ctx, power.Address, st) if err != nil { - return power.Claim{}, power.Claim{}, xerrors.Errorf("(get sset) failed to load power actor state: %w", err) + return power.Claim{}, power.Claim{}, false, xerrors.Errorf("(get sset) failed to load power actor state: %w", err) + } + + pas, err := power.Load(sm.cs.Store(ctx), act) + if err != nil { + return power.Claim{}, power.Claim{}, false, err + } + + tpow, err := pas.TotalPower() + if err != nil { + return power.Claim{}, power.Claim{}, false, err } var mpow power.Claim if maddr != address.Undef { - cm, err := adt.AsMap(sm.cs.Store(ctx), ps.Claims) - if err != nil { - return power.Claim{}, power.Claim{}, err + var found bool + mpow, found, err = pas.MinerPower(maddr) + if err != nil || !found { + // TODO: return an error when not found? + return power.Claim{}, power.Claim{}, false, err } - - var claim power.Claim - if _, err := cm.Get(abi.AddrKey(maddr), &claim); err != nil { - return power.Claim{}, power.Claim{}, err - } - - mpow = claim } - return mpow, power.Claim{ - RawBytePower: ps.TotalRawBytePower, - QualityAdjPower: ps.TotalQualityAdjPower, - }, nil + minpow, err := pas.MinerNominalPowerMeetsConsensusMinimum(maddr) + if err != nil { + return power.Claim{}, power.Claim{}, false, err + } + + return mpow, tpow, minpow, nil } -func PreCommitInfo(ctx context.Context, sm *StateManager, maddr address.Address, sid abi.SectorNumber, ts *types.TipSet) (miner.SectorPreCommitOnChainInfo, error) { - var mas miner.State - _, err := sm.LoadActorState(ctx, maddr, &mas, ts) +func PreCommitInfo(ctx context.Context, sm *StateManager, maddr address.Address, sid abi.SectorNumber, ts *types.TipSet) (*miner.SectorPreCommitOnChainInfo, error) { + act, err := sm.LoadActor(ctx, maddr, ts) if err != nil { - return miner.SectorPreCommitOnChainInfo{}, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err) + return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err) } - i, ok, err := mas.GetPrecommittedSector(sm.cs.Store(ctx), sid) + mas, err := miner.Load(sm.cs.Store(ctx), act) if err != nil { - return miner.SectorPreCommitOnChainInfo{}, err - } - if !ok { - return miner.SectorPreCommitOnChainInfo{}, xerrors.New("precommit not found") + return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err) } - return *i, nil + return mas.GetPrecommittedSector(sid) } func MinerSectorInfo(ctx context.Context, sm *StateManager, maddr address.Address, sid abi.SectorNumber, ts *types.TipSet) (*miner.SectorOnChainInfo, error) { - var mas miner.State - _, err := sm.LoadActorState(ctx, maddr, &mas, ts) + act, err := sm.LoadActor(ctx, maddr, ts) + if err != nil { + return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err) + } + + mas, err := miner.Load(sm.cs.Store(ctx), act) if err != nil { return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err) } - sectorInfo, ok, err := mas.GetSector(sm.cs.Store(ctx), sid) - if err != nil { - return nil, err - } - if !ok { - return nil, nil - } - - return sectorInfo, nil + return mas.GetSector(sid) } -func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address, filter *bitfield.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) { - var mas miner.State - _, err := sm.LoadActorState(ctx, maddr, &mas, ts) +func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address, snos *bitfield.BitField) ([]*miner.SectorOnChainInfo, error) { + act, err := sm.LoadActor(ctx, maddr, ts) + if err != nil { + return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err) + } + + mas, err := miner.Load(sm.cs.Store(ctx), act) if err != nil { return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err) } - return LoadSectorsFromSet(ctx, sm.ChainStore().Blockstore(), mas.Sectors, filter, filterOut) + return mas.LoadSectors(snos) } -func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]proof.SectorInfo, error) { - var partsProving []bitfield.BitField - var mas *miner.State - var info *miner.MinerInfo - - err := sm.WithStateTree(st, sm.WithActor(maddr, sm.WithActorState(ctx, func(store adt.Store, mst *miner.State) error { - var err error - - mas = mst - - info, err = mas.GetInfo(store) - if err != nil { - return xerrors.Errorf("getting miner info: %w", err) - } - - deadlines, err := mas.LoadDeadlines(store) - if err != nil { - return xerrors.Errorf("loading deadlines: %w", err) - } - - return deadlines.ForEach(store, func(dlIdx uint64, deadline *miner.Deadline) error { - partitions, err := deadline.PartitionsArray(store) - if err != nil { - return xerrors.Errorf("getting partition array: %w", err) - } - - var partition miner.Partition - return partitions.ForEach(&partition, func(partIdx int64) error { - p, err := bitfield.SubtractBitField(partition.Sectors, partition.Faults) - if err != nil { - return xerrors.Errorf("subtract faults from partition sectors: %w", err) - } - - partsProving = append(partsProving, p) - - return nil - }) - }) - }))) +func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]proof0.SectorInfo, error) { + act, err := sm.LoadActorRaw(ctx, maddr, st) if err != nil { - return nil, err + return nil, xerrors.Errorf("failed to load miner actor: %w", err) } - provingSectors, err := bitfield.MultiMerge(partsProving...) + mas, err := miner.Load(sm.cs.Store(ctx), act) if err != nil { - return nil, xerrors.Errorf("merge partition proving sets: %w", err) + return nil, xerrors.Errorf("failed to load miner actor state: %w", err) + } + + // TODO (!!): Actor Update: Make this active sectors + + allSectors, err := miner.AllPartSectors(mas, miner.Partition.AllSectors) + if err != nil { + return nil, xerrors.Errorf("get all sectors: %w", err) + } + + faultySectors, err := miner.AllPartSectors(mas, miner.Partition.FaultySectors) + if err != nil { + return nil, xerrors.Errorf("get faulty sectors: %w", err) + } + + provingSectors, err := bitfield.SubtractBitField(allSectors, faultySectors) // TODO: This is wrong, as it can contain faaults, change to just ActiveSectors in an upgrade + if err != nil { + return nil, xerrors.Errorf("calc proving sectors: %w", err) } numProvSect, err := provingSectors.Count() @@ -237,6 +199,11 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S return nil, nil } + info, err := mas.Info() + if err != nil { + return nil, xerrors.Errorf("getting miner info: %w", err) + } + spt, err := ffiwrapper.SealProofTypeFromSectorSize(info.SectorSize) if err != nil { return nil, xerrors.Errorf("getting seal proof type: %w", err) @@ -257,28 +224,31 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S return nil, xerrors.Errorf("generating winning post challenges: %w", err) } - sectors, err := provingSectors.All(miner.SectorsMax) + iter, err := provingSectors.BitIterator() if err != nil { - return nil, xerrors.Errorf("failed to enumerate all sector IDs: %w", err) + return nil, xerrors.Errorf("iterating over proving sectors: %w", err) } - sectorAmt, err := adt.AsArray(sm.cs.Store(ctx), mas.Sectors) - if err != nil { - return nil, xerrors.Errorf("failed to load sectors amt: %w", err) - } - - out := make([]proof.SectorInfo, len(ids)) - for i, n := range ids { - sid := sectors[n] - - var sinfo miner.SectorOnChainInfo - if found, err := sectorAmt.Get(sid, &sinfo); err != nil { - return nil, xerrors.Errorf("failed to get sector %d: %w", sid, err) - } else if !found { - return nil, xerrors.Errorf("failed to find sector %d", sid) + // Select winning sectors by _index_ in the all-sectors bitfield. + selectedSectors := bitfield.New() + prev := uint64(0) + for _, n := range ids { + sno, err := iter.Nth(n - prev) + if err != nil { + return nil, xerrors.Errorf("iterating over proving sectors: %w", err) } + selectedSectors.Set(sno) + prev = n + } - out[i] = proof.SectorInfo{ + sectors, err := mas.LoadSectors(&selectedSectors) + if err != nil { + return nil, xerrors.Errorf("loading proving sectors: %w", err) + } + + out := make([]proof0.SectorInfo, len(sectors)) + for i, sinfo := range sectors { + out[i] = proof0.SectorInfo{ SealProof: spt, SectorNumber: sinfo.SectorNumber, SealedCID: sinfo.SealedCID, @@ -289,33 +259,40 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S } func StateMinerInfo(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (*miner.MinerInfo, error) { - var mas miner.State - _, err := sm.LoadActorStateRaw(ctx, maddr, &mas, ts.ParentState()) + act, err := sm.LoadActor(ctx, maddr, ts) if err != nil { - return nil, xerrors.Errorf("(get ssize) failed to load miner actor state: %w", err) + return nil, xerrors.Errorf("failed to load miner actor: %w", err) } - return mas.GetInfo(sm.cs.Store(ctx)) + mas, err := miner.Load(sm.cs.Store(ctx), act) + if err != nil { + return nil, xerrors.Errorf("failed to load miner actor state: %w", err) + } + + mi, err := mas.Info() + if err != nil { + return nil, err + } + + return &mi, err } func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (bool, error) { - var spas power.State - _, err := sm.LoadActorState(ctx, builtin.StoragePowerActorAddr, &spas, ts) + act, err := sm.LoadActor(ctx, power.Address, ts) if err != nil { - return false, xerrors.Errorf("(get miner slashed) failed to load power actor state") + return false, xerrors.Errorf("failed to load power actor: %w", err) } - store := sm.cs.Store(ctx) - - claims, err := adt.AsMap(store, spas.Claims) + spas, err := power.Load(sm.cs.Store(ctx), act) if err != nil { - return false, err + return false, xerrors.Errorf("failed to load power actor state: %w", err) } - ok, err := claims.Get(abi.AddrKey(maddr), nil) + _, ok, err := spas.MinerPower(maddr) if err != nil { - return false, err + return false, xerrors.Errorf("getting miner power: %w", err) } + if !ok { return true, nil } @@ -324,108 +301,61 @@ func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, ma } func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts *types.TipSet) (*api.MarketDeal, error) { - var state market.State - if _, err := sm.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil { - return nil, err + act, err := sm.LoadActor(ctx, market.Address, ts) + if err != nil { + return nil, xerrors.Errorf("failed to load market actor: %w", err) } - store := sm.ChainStore().Store(ctx) - da, err := adt.AsArray(store, state.Proposals) + state, err := market.Load(sm.cs.Store(ctx), act) + if err != nil { + return nil, xerrors.Errorf("failed to load market actor state: %w", err) + } + + proposals, err := state.Proposals() if err != nil { return nil, err } - var dp market.DealProposal - if found, err := da.Get(uint64(dealID), &dp); err != nil { + proposal, found, err := proposals.Get(dealID) + + if err != nil { return nil, err } else if !found { return nil, xerrors.Errorf("deal %d not found", dealID) } - sa, err := market.AsDealStateArray(store, state.States) + states, err := state.States() if err != nil { return nil, err } - st, found, err := sa.Get(dealID) + st, found, err := states.Get(dealID) if err != nil { return nil, err } if !found { - st = &market.DealState{ - SectorStartEpoch: -1, - LastUpdatedEpoch: -1, - SlashEpoch: -1, - } + st = market.EmptyDealState() } return &api.MarketDeal{ - Proposal: dp, + Proposal: *proposal, State: *st, }, nil } func ListMinerActors(ctx context.Context, sm *StateManager, ts *types.TipSet) ([]address.Address, error) { - var state power.State - if _, err := sm.LoadActorState(ctx, builtin.StoragePowerActorAddr, &state, ts); err != nil { - return nil, err - } - - m, err := adt.AsMap(sm.cs.Store(ctx), state.Claims) + act, err := sm.LoadActor(ctx, power.Address, ts) if err != nil { - return nil, err + return nil, xerrors.Errorf("failed to load power actor: %w", err) } - var miners []address.Address - err = m.ForEach(nil, func(k string) error { - a, err := address.NewFromBytes([]byte(k)) - if err != nil { - return err - } - miners = append(miners, a) - return nil - }) + powState, err := power.Load(sm.cs.Store(ctx), act) if err != nil { - return nil, err + return nil, xerrors.Errorf("failed to load power actor state: %w", err) } - return miners, nil -} - -func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.Cid, filter *bitfield.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) { - a, err := adt.AsArray(store.ActorStore(ctx, bs), ssc) - if err != nil { - return nil, err - } - - var sset []*api.ChainSectorInfo - var v cbg.Deferred - if err := a.ForEach(&v, func(i int64) error { - if filter != nil { - set, err := filter.IsSet(uint64(i)) - if err != nil { - return xerrors.Errorf("filter check error: %w", err) - } - if set == filterOut { - return nil - } - } - - var oci miner.SectorOnChainInfo - if err := cbor.DecodeInto(v.Raw, &oci); err != nil { - return err - } - sset = append(sset, &api.ChainSectorInfo{ - Info: oci, - ID: abi.SectorNumber(i), - }) - return nil - }); err != nil { - return nil, err - } - - return sset, nil + return powState.ListAllMiners() } func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, msgs []*types.Message, ts *types.TipSet) (cid.Cid, []*api.InvocResult, error) { @@ -449,7 +379,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, NtwkVersion: sm.GetNtwkVersion, BaseFee: ts.Blocks()[0].ParentBaseFee, } - vmi, err := vm.NewVM(vmopt) + vmi, err := vm.NewVM(ctx, vmopt) if err != nil { return cid.Undef, nil, err } @@ -537,9 +467,14 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule return nil, err } - var mas miner.State - if _, err := sm.LoadActorStateRaw(ctx, maddr, &mas, lbst); err != nil { - return nil, err + act, err := sm.LoadActorRaw(ctx, maddr, lbst) + if err != nil { + return nil, xerrors.Errorf("failed to load miner actor: %w", err) + } + + mas, err := miner.Load(sm.cs.Store(ctx), act) + if err != nil { + return nil, xerrors.Errorf("failed to load miner actor state: %w", err) } buf := new(bytes.Buffer) @@ -554,19 +489,19 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule sectors, err := GetSectorsForWinningPoSt(ctx, pv, sm, lbst, maddr, prand) if err != nil { - return nil, xerrors.Errorf("getting wpost proving set: %w", err) + return nil, xerrors.Errorf("getting winning post proving set: %w", err) } if len(sectors) == 0 { return nil, nil } - mpow, tpow, err := GetPowerRaw(ctx, sm, lbst, maddr) + mpow, tpow, hmp, err := GetPowerRaw(ctx, sm, lbst, maddr) if err != nil { return nil, xerrors.Errorf("failed to get power: %w", err) } - info, err := mas.GetInfo(sm.cs.Store(ctx)) + info, err := mas.Info() if err != nil { return nil, err } @@ -576,11 +511,6 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule return nil, xerrors.Errorf("resolving worker address: %w", err) } - hmp, err := MinerHasMinPower(ctx, sm, maddr, lbts) - if err != nil { - return nil, xerrors.Errorf("determining if miner has min power failed: %w", err) - } - return &api.MiningBaseInfo{ MinerPower: mpow.QualityAdjPower, NetworkPower: tpow.QualityAdjPower, @@ -605,24 +535,24 @@ var MethodsMap = map[cid.Cid]map[abi.MethodNum]MethodMeta{} func init() { cidToMethods := map[cid.Cid][2]interface{}{ // builtin.SystemActorCodeID: {builtin.MethodsSystem, system.Actor{} }- apparently it doesn't have methods - builtin.InitActorCodeID: {builtin.MethodsInit, init_.Actor{}}, - builtin.CronActorCodeID: {builtin.MethodsCron, cron.Actor{}}, - builtin.AccountActorCodeID: {builtin.MethodsAccount, account.Actor{}}, - builtin.StoragePowerActorCodeID: {builtin.MethodsPower, power.Actor{}}, - builtin.StorageMinerActorCodeID: {builtin.MethodsMiner, miner.Actor{}}, - builtin.StorageMarketActorCodeID: {builtin.MethodsMarket, market.Actor{}}, - builtin.PaymentChannelActorCodeID: {builtin.MethodsPaych, paych.Actor{}}, - builtin.MultisigActorCodeID: {builtin.MethodsMultisig, multisig.Actor{}}, - builtin.RewardActorCodeID: {builtin.MethodsReward, reward.Actor{}}, - builtin.VerifiedRegistryActorCodeID: {builtin.MethodsVerifiedRegistry, verifreg.Actor{}}, + builtin0.InitActorCodeID: {builtin0.MethodsInit, init0.Actor{}}, + builtin0.CronActorCodeID: {builtin0.MethodsCron, cron0.Actor{}}, + builtin0.AccountActorCodeID: {builtin0.MethodsAccount, account0.Actor{}}, + builtin0.StoragePowerActorCodeID: {builtin0.MethodsPower, power0.Actor{}}, + builtin0.StorageMinerActorCodeID: {builtin0.MethodsMiner, miner0.Actor{}}, + builtin0.StorageMarketActorCodeID: {builtin0.MethodsMarket, market0.Actor{}}, + builtin0.PaymentChannelActorCodeID: {builtin0.MethodsPaych, paych0.Actor{}}, + builtin0.MultisigActorCodeID: {builtin0.MethodsMultisig, msig0.Actor{}}, + builtin0.RewardActorCodeID: {builtin0.MethodsReward, reward0.Actor{}}, + builtin0.VerifiedRegistryActorCodeID: {builtin0.MethodsVerifiedRegistry, verifreg0.Actor{}}, } for c, m := range cidToMethods { - exports := m[1].(saruntime.Invokee).Exports() + exports := m[1].(vm.Invokee).Exports() methods := make(map[abi.MethodNum]MethodMeta, len(exports)) // Explicitly add send, it's special. - methods[builtin.MethodSend] = MethodMeta{ + methods[builtin0.MethodSend] = MethodMeta{ Name: "Send", Params: reflect.TypeOf(new(abi.EmptyValue)), Ret: reflect.TypeOf(new(abi.EmptyValue)), @@ -662,9 +592,9 @@ func init() { } switch abi.MethodNum(number) { - case builtin.MethodSend: + case builtin0.MethodSend: panic("method 0 is reserved for Send") - case builtin.MethodConstructor: + case builtin0.MethodConstructor: if fnName != "Constructor" { panic("method 1 is reserved for Constructor") } @@ -681,9 +611,9 @@ func init() { } func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, method abi.MethodNum, ts *types.TipSet) (cbg.CBORUnmarshaler, error) { - var act types.Actor - if err := sm.WithParentState(ts, sm.WithActor(to, GetActor(&act))); err != nil { - return nil, xerrors.Errorf("getting actor: %w", err) + act, err := sm.LoadActor(ctx, to, ts) + if err != nil { + return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err) } m, found := MethodsMap[act.Code][method] @@ -694,13 +624,17 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me } func MinerHasMinPower(ctx context.Context, sm *StateManager, addr address.Address, ts *types.TipSet) (bool, error) { - var ps power.State - _, err := sm.LoadActorState(ctx, builtin.StoragePowerActorAddr, &ps, ts) + pact, err := sm.LoadActor(ctx, power.Address, ts) if err != nil { return false, xerrors.Errorf("loading power actor state: %w", err) } - return ps.MinerNominalPowerMeetsConsensusMinimum(sm.ChainStore().Store(ctx), addr) + ps, err := power.Load(sm.cs.Store(ctx), pact) + if err != nil { + return false, err + } + + return ps.MinerNominalPowerMeetsConsensusMinimum(addr) } func CheckTotalFIL(ctx context.Context, sm *StateManager, ts *types.TipSet) (abi.TokenAmount, error) { diff --git a/chain/store/store.go b/chain/store/store.go index 20a7e3031..fce8a650f 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -18,7 +18,6 @@ import ( "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/journal" bstore "github.com/filecoin-project/lotus/lib/blockstore" @@ -767,32 +766,16 @@ type BlockMessages struct { func (cs *ChainStore) BlockMsgsForTipset(ts *types.TipSet) ([]BlockMessages, error) { applied := make(map[address.Address]uint64) - cst := cbor.NewCborStore(cs.bs) - st, err := state.LoadStateTree(cst, ts.Blocks()[0].ParentStateRoot) - if err != nil { - return nil, xerrors.Errorf("failed to load state tree") - } - - preloadAddr := func(a address.Address) error { - if _, ok := applied[a]; !ok { - act, err := st.GetActor(a) - if err != nil { - return err - } - - applied[a] = act.Nonce - } - return nil - } - selectMsg := func(m *types.Message) (bool, error) { - if err := preloadAddr(m.From); err != nil { - return false, err + // The first match for a sender is guaranteed to have correct nonce -- the block isn't valid otherwise + if _, ok := applied[m.From]; !ok { + applied[m.From] = m.Nonce } if applied[m.From] != m.Nonce { return false, nil } + applied[m.From]++ return true, nil @@ -1318,7 +1301,7 @@ func (cs *ChainStore) GetLatestBeaconEntry(ts *types.TipSet) (*types.BeaconEntry }, nil } - return nil, xerrors.Errorf("found NO beacon entries in the 20 blocks prior to given tipset") + return nil, xerrors.Errorf("found NO beacon entries in the 20 latest tipsets") } type chainRand struct { diff --git a/chain/store/store_test.go b/chain/store/store_test.go index e56bab4c9..b7adfb595 100644 --- a/chain/store/store_test.go +++ b/chain/store/store_test.go @@ -8,12 +8,9 @@ import ( datastore "github.com/ipfs/go-datastore" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" @@ -22,11 +19,9 @@ import ( ) func init() { - miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ - abi.RegisteredSealProof_StackedDrg2KiBV1: {}, - } - power.ConsensusMinerMinPower = big.NewInt(2048) - verifreg.MinVerifiedDealSize = big.NewInt(256) + policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) + policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048)) + policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) } func BenchmarkGetRandomness(b *testing.B) { diff --git a/chain/store/weight.go b/chain/store/weight.go index 5249df011..9100df315 100644 --- a/chain/store/weight.go +++ b/chain/store/weight.go @@ -4,12 +4,12 @@ import ( "context" "math/big" + "github.com/filecoin-project/lotus/chain/actors/builtin/power" + big2 "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/power" cbor "github.com/ipfs/go-ipld-cbor" "golang.org/x/xerrors" ) @@ -34,16 +34,22 @@ func (cs *ChainStore) Weight(ctx context.Context, ts *types.TipSet) (types.BigIn return types.NewInt(0), xerrors.Errorf("load state tree: %w", err) } - act, err := state.GetActor(builtin.StoragePowerActorAddr) + act, err := state.GetActor(power.Address) if err != nil { return types.NewInt(0), xerrors.Errorf("get power actor: %w", err) } - var st power.State - if err := cst.Get(ctx, act.Head, &st); err != nil { - return types.NewInt(0), xerrors.Errorf("get power actor head (%s, height=%d): %w", act.Head, ts.Height(), err) + powState, err := power.Load(cs.Store(ctx), act) + if err != nil { + return types.NewInt(0), xerrors.Errorf("failed to load power actor state: %w", err) } - tpow = st.TotalQualityAdjPower // TODO: REVIEW: Is this correct? + + claim, err := powState.TotalPower() + if err != nil { + return types.NewInt(0), xerrors.Errorf("failed to get total power: %w", err) + } + + tpow = claim.QualityAdjPower // TODO: REVIEW: Is this correct? } log2P := int64(0) diff --git a/chain/sub/incoming.go b/chain/sub/incoming.go index 34dde227f..c6e0c8b80 100644 --- a/chain/sub/incoming.go +++ b/chain/sub/incoming.go @@ -1,7 +1,6 @@ package sub import ( - "bytes" "context" "errors" "fmt" @@ -11,7 +10,6 @@ import ( "golang.org/x/xerrors" address "github.com/filecoin-project/go-address" - miner "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/util/adt" lru "github.com/hashicorp/golang-lru" blocks "github.com/ipfs/go-block-format" @@ -28,6 +26,7 @@ import ( "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/stmgr" @@ -432,6 +431,7 @@ func (bv *BlockValidator) checkPowerAndGetWorkerKey(ctx context.Context, bh *typ if err != nil { return address.Undef, err } + buf := bufbstore.NewBufferedBstore(bv.chain.Blockstore()) cst := cbor.NewCborStore(buf) state, err := state.LoadStateTree(cst, st) @@ -443,19 +443,12 @@ func (bv *BlockValidator) checkPowerAndGetWorkerKey(ctx context.Context, bh *typ return address.Undef, err } - blk, err := bv.chain.Blockstore().Get(act.Head) - if err != nil { - return address.Undef, err - } - aso := blk.RawData() - - var mst miner.State - err = mst.UnmarshalCBOR(bytes.NewReader(aso)) + mst, err := miner.Load(bv.chain.Store(ctx), act) if err != nil { return address.Undef, err } - info, err := mst.GetInfo(adt.WrapStore(ctx, cst)) + info, err := mst.Info() if err != nil { return address.Undef, err } diff --git a/chain/sync.go b/chain/sync.go index f7530f556..9e098a57e 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -7,7 +7,6 @@ import ( "fmt" "os" "sort" - "strconv" "strings" "sync" "time" @@ -18,6 +17,7 @@ import ( "github.com/Gurpartap/async" "github.com/hashicorp/go-multierror" + blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" logging "github.com/ipfs/go-log/v2" @@ -33,13 +33,12 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/specs-actors/actors/util/adt" blst "github.com/supranational/blst/bindings/go" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin/power" "github.com/filecoin-project/lotus/chain/beacon" "github.com/filecoin-project/lotus/chain/exchange" "github.com/filecoin-project/lotus/chain/gen" @@ -63,20 +62,12 @@ var ( // where the Syncer publishes candidate chain heads to be synced. LocalIncoming = "incoming" - log = logging.Logger("chain") - defaultMessageFetchWindowSize = 200 -) + log = logging.Logger("chain") -func init() { - if s := os.Getenv("LOTUS_BSYNC_MSG_WINDOW"); s != "" { - val, err := strconv.Atoi(s) - if err != nil { - log.Errorf("failed to parse LOTUS_BSYNC_MSG_WINDOW: %s", err) - return - } - defaultMessageFetchWindowSize = val - } -} + concurrentSyncRequests = exchange.ShufflePeersPrefix + syncRequestBatchSize = 8 + syncRequestRetries = 5 +) // Syncer is in charge of running the chain synchronization logic. As such, it // is tasked with these functions, amongst others: @@ -132,8 +123,6 @@ type Syncer struct { verifier ffiwrapper.Verifier - windowSize int - tickerCtxCancel context.CancelFunc checkptLk sync.Mutex @@ -175,7 +164,6 @@ func NewSyncer(ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.C receiptTracker: newBlockReceiptTracker(), connmgr: connmgr, verifier: verifier, - windowSize: defaultMessageFetchWindowSize, incoming: pubsub.New(50), } @@ -387,21 +375,28 @@ func (syncer *Syncer) InformNewBlock(from peer.ID, blk *types.FullBlock) bool { return syncer.InformNewHead(from, fts) } -func copyBlockstore(from, to bstore.Blockstore) error { - cids, err := from.AllKeysChan(context.TODO()) +func copyBlockstore(ctx context.Context, from, to bstore.Blockstore) error { + ctx, span := trace.StartSpan(ctx, "copyBlockstore") + defer span.End() + + cids, err := from.AllKeysChan(ctx) if err != nil { return err } + // TODO: should probably expose better methods on the blockstore for this operation + var blks []blocks.Block for c := range cids { b, err := from.Get(c) if err != nil { return err } - if err := to.Put(b); err != nil { - return err - } + blks = append(blks, b) + } + + if err := to.PutMany(blks); err != nil { + return err } return nil @@ -640,26 +635,25 @@ func (syncer *Syncer) ValidateTipSet(ctx context.Context, fts *store.FullTipSet) } func (syncer *Syncer) minerIsValid(ctx context.Context, maddr address.Address, baseTs *types.TipSet) error { - var spast power.State - - _, err := syncer.sm.LoadActorState(ctx, builtin.StoragePowerActorAddr, &spast, baseTs) + act, err := syncer.sm.LoadActor(ctx, power.Address, baseTs) if err != nil { - return err + return xerrors.Errorf("failed to load power actor: %w", err) } - cm, err := adt.AsMap(syncer.store.Store(ctx), spast.Claims) + powState, err := power.Load(syncer.store.Store(ctx), act) if err != nil { - return err + return xerrors.Errorf("failed to load power actor state: %w", err) } - var claim power.Claim - exist, err := cm.Get(abi.AddrKey(maddr), &claim) + _, exist, err := powState.MinerPower(maddr) if err != nil { - return err + return xerrors.Errorf("failed to look up miner's claim: %w", err) } + if !exist { return xerrors.New("miner isn't valid") } + return nil } @@ -859,7 +853,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er return xerrors.Errorf("received block was from slashed or invalid miner") } - mpow, tpow, err := stmgr.GetPowerRaw(ctx, syncer.sm, lbst, h.Miner) + mpow, tpow, _, err := stmgr.GetPowerRaw(ctx, syncer.sm, lbst, h.Miner) if err != nil { return xerrors.Errorf("failed getting power: %w", err) } @@ -991,7 +985,7 @@ func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.Block rand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, h.Height, buf.Bytes()) if err != nil { - return xerrors.Errorf("failed to get randomness for verifying winningPost proof: %w", err) + return xerrors.Errorf("failed to get randomness for verifying winning post proof: %w", err) } mid, err := address.IDFromAddress(h.Miner) @@ -1483,8 +1477,6 @@ func (syncer *Syncer) iterFullTipsets(ctx context.Context, headers []*types.TipS span.AddAttributes(trace.Int64Attribute("num_headers", int64(len(headers)))) - windowSize := syncer.windowSize -mainLoop: for i := len(headers) - 1; i >= 0; { fts, err := syncer.store.TryFillTipSet(headers[i]) if err != nil { @@ -1498,35 +1490,20 @@ mainLoop: continue } - batchSize := windowSize + batchSize := concurrentSyncRequests * syncRequestBatchSize if i < batchSize { - batchSize = i + batchSize = i + 1 } - nextI := (i + 1) - batchSize // want to fetch batchSize values, 'i' points to last one we want to fetch, so its 'inclusive' of our request, thus we need to add one to our request start index - ss.SetStage(api.StageFetchingMessages) - var bstout []*exchange.CompactedMessages - for len(bstout) < batchSize { - next := headers[nextI] - - nreq := batchSize - len(bstout) - bstips, err := syncer.Exchange.GetChainMessages(ctx, next, uint64(nreq)) - if err != nil { - // TODO check errors for temporary nature - if windowSize > 1 { - windowSize /= 2 - log.Infof("error fetching messages: %s; reducing window size to %d and trying again", err, windowSize) - continue mainLoop - } - return xerrors.Errorf("message processing failed: %w", err) - } - - bstout = append(bstout, bstips...) - nextI += len(bstips) - } + startOffset := i + 1 - batchSize + bstout, batchErr := syncer.fetchMessages(ctx, headers[startOffset:startOffset+batchSize], startOffset) ss.SetStage(api.StageMessages) + if batchErr != nil { + return xerrors.Errorf("failed to fetch messages: %w", err) + } + for bsi := 0; bsi < len(bstout); bsi++ { // temp storage so we don't persist data we dont want to bs := bstore.NewTemporary() @@ -1546,36 +1523,91 @@ mainLoop: return err } - if err := persistMessages(bs, bstip); err != nil { + if err := persistMessages(ctx, bs, bstip); err != nil { return err } - if err := copyBlockstore(bs, syncer.store.Blockstore()); err != nil { + if err := copyBlockstore(ctx, bs, syncer.store.Blockstore()); err != nil { return xerrors.Errorf("message processing failed: %w", err) } } - if i >= windowSize { - newWindowSize := windowSize + 10 - if newWindowSize > int(exchange.MaxRequestLength) { - newWindowSize = int(exchange.MaxRequestLength) - } - if newWindowSize > windowSize { - windowSize = newWindowSize - log.Infof("successfully fetched %d messages; increasing window size to %d", len(bstout), windowSize) - } - } - i -= batchSize } - // remember our window size - syncer.windowSize = windowSize - return nil } -func persistMessages(bs bstore.Blockstore, bst *exchange.CompactedMessages) error { +func (syncer *Syncer) fetchMessages(ctx context.Context, headers []*types.TipSet, startOffset int) ([]*exchange.CompactedMessages, error) { + batchSize := len(headers) + batch := make([]*exchange.CompactedMessages, batchSize) + + var wg sync.WaitGroup + var mx sync.Mutex + var batchErr error + + start := build.Clock.Now() + + for j := 0; j < batchSize; j += syncRequestBatchSize { + wg.Add(1) + go func(j int) { + defer wg.Done() + + nreq := syncRequestBatchSize + if j+nreq > batchSize { + nreq = batchSize - j + } + + failed := false + for offset := 0; !failed && offset < nreq; { + nextI := j + offset + lastI := j + nreq + + var requestErr error + var requestResult []*exchange.CompactedMessages + for retry := 0; requestResult == nil && retry < syncRequestRetries; retry++ { + if retry > 0 { + log.Infof("fetching messages at %d (retry %d)", startOffset+nextI, retry) + } else { + log.Infof("fetching messages at %d", startOffset+nextI) + } + + result, err := syncer.Exchange.GetChainMessages(ctx, headers[nextI:lastI]) + if err != nil { + requestErr = multierror.Append(requestErr, err) + } else { + requestResult = result + } + } + + mx.Lock() + if requestResult != nil { + copy(batch[j+offset:], requestResult) + offset += len(requestResult) + } else { + log.Errorf("error fetching messages at %d: %s", nextI, requestErr) + batchErr = multierror.Append(batchErr, requestErr) + failed = true + } + mx.Unlock() + } + }(j) + } + wg.Wait() + + if batchErr != nil { + return nil, batchErr + } + + log.Infof("fetching messages for %d tipsets at %d done; took %s", batchSize, startOffset, build.Clock.Since(start)) + + return batch, nil +} + +func persistMessages(ctx context.Context, bs bstore.Blockstore, bst *exchange.CompactedMessages) error { + _, span := trace.StartSpan(ctx, "persistMessages") + defer span.End() + for _, m := range bst.Bls { //log.Infof("putting BLS message: %s", m.Cid()) if _, err := store.PutMessage(bs, m); err != nil { @@ -1707,7 +1739,7 @@ func (syncer *Syncer) getLatestBeaconEntry(_ context.Context, ts *types.TipSet) cur = next } - return nil, xerrors.Errorf("found NO beacon entries in the 20 blocks prior to given tipset") + return nil, xerrors.Errorf("found NO beacon entries in the 20 latest tipsets") } func (syncer *Syncer) IsEpochBeyondCurrMax(epoch abi.ChainEpoch) bool { diff --git a/chain/sync_test.go b/chain/sync_test.go index 0b0d1ed00..7a839be2b 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -19,13 +19,10 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/gen/slashfilter" "github.com/filecoin-project/lotus/chain/store" @@ -43,11 +40,9 @@ func init() { if err != nil { panic(err) } - miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ - abi.RegisteredSealProof_StackedDrg2KiBV1: {}, - } - power.ConsensusMinerMinPower = big.NewInt(2048) - verifreg.MinVerifiedDealSize = big.NewInt(256) + policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) + policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048)) + policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) } const source = 0 @@ -662,6 +657,49 @@ func TestDuplicateNonce(t *testing.T) { require.Equal(t, includedMsg, mft[0].VMMessage().Cid(), "messages for tipset didn't contain expected message") } +// This test asserts that a block that includes a message with bad nonce can't be synced. A nonce is "bad" if it can't +// be applied on the parent state. +func TestBadNonce(t *testing.T) { + H := 10 + tu := prepSyncTest(t, H) + + base := tu.g.CurTipset + + // Produce a message from the banker with a bad nonce + makeBadMsg := func() *types.SignedMessage { + + ba, err := tu.nds[0].StateGetActor(context.TODO(), tu.g.Banker(), base.TipSet().Key()) + require.NoError(t, err) + msg := types.Message{ + To: tu.g.Banker(), + From: tu.g.Banker(), + + Nonce: ba.Nonce + 5, + + Value: types.NewInt(1), + + Method: 0, + + GasLimit: 100_000_000, + GasFeeCap: types.NewInt(0), + GasPremium: types.NewInt(0), + } + + sig, err := tu.g.Wallet().Sign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes()) + require.NoError(t, err) + + return &types.SignedMessage{ + Message: msg, + Signature: *sig, + } + } + + msgs := make([][]*types.SignedMessage, 1) + msgs[0] = []*types.SignedMessage{makeBadMsg()} + + tu.mineOnBlock(base, 0, []int{0}, true, true, msgs) +} + func BenchmarkSyncBasic(b *testing.B) { for i := 0; i < b.N; i++ { runSyncBenchLength(b, 100) diff --git a/chain/types/actor.go b/chain/types/actor.go index bb5635995..eb8e05c49 100644 --- a/chain/types/actor.go +++ b/chain/types/actor.go @@ -5,7 +5,7 @@ import ( "github.com/ipfs/go-cid" - "github.com/filecoin-project/specs-actors/actors/builtin" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" ) var ErrActorNotFound = errors.New("actor not found") @@ -19,5 +19,17 @@ type Actor struct { } func (a *Actor) IsAccountActor() bool { - return a.Code == builtin.AccountActorCodeID + return a.Code == builtin0.AccountActorCodeID +} + +func (a *Actor) IsStorageMinerActor() bool { + return a.Code == builtin0.StorageMinerActorCodeID +} + +func (a *Actor) IsMultisigActor() bool { + return a.Code == builtin0.MultisigActorCodeID +} + +func (a *Actor) IsPaymentChannelActor() bool { + return a.Code == builtin0.PaymentChannelActorCodeID } diff --git a/chain/types/cbor_gen.go b/chain/types/cbor_gen.go index 676ae7054..f95df33bc 100644 --- a/chain/types/cbor_gen.go +++ b/chain/types/cbor_gen.go @@ -1634,3 +1634,131 @@ func (t *BeaconEntry) UnmarshalCBOR(r io.Reader) error { } return nil } + +var lengthBufStateRoot = []byte{131} + +func (t *StateRoot) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufStateRoot); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Version (uint64) (uint64) + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Version)); err != nil { + return err + } + + // t.Actors (cid.Cid) (struct) + + if err := cbg.WriteCidBuf(scratch, w, t.Actors); err != nil { + return xerrors.Errorf("failed to write cid field t.Actors: %w", err) + } + + // t.Info (cid.Cid) (struct) + + if err := cbg.WriteCidBuf(scratch, w, t.Info); err != nil { + return xerrors.Errorf("failed to write cid field t.Info: %w", err) + } + + return nil +} + +func (t *StateRoot) UnmarshalCBOR(r io.Reader) error { + *t = StateRoot{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Version (uint64) (uint64) + + { + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.Version = uint64(extra) + + } + // t.Actors (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.Actors: %w", err) + } + + t.Actors = c + + } + // t.Info (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.Info: %w", err) + } + + t.Info = c + + } + return nil +} + +var lengthBufStateInfo = []byte{128} + +func (t *StateInfo) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufStateInfo); err != nil { + return err + } + + return nil +} + +func (t *StateInfo) UnmarshalCBOR(r io.Reader) error { + *t = StateInfo{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 0 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + return nil +} diff --git a/chain/types/state.go b/chain/types/state.go new file mode 100644 index 000000000..b99eb19c2 --- /dev/null +++ b/chain/types/state.go @@ -0,0 +1,15 @@ +package types + +import "github.com/ipfs/go-cid" + +type StateRoot struct { + // State root version. Versioned along with actors (for now). + Version uint64 + // Actors tree. The structure depends on the state root version. + Actors cid.Cid + // Info. The structure depends on the state root version. + Info cid.Cid +} + +// TODO: version this. +type StateInfo struct{} diff --git a/chain/vectors/gen/main.go b/chain/vectors/gen/main.go index ecc2498b9..2b1c6f340 100644 --- a/chain/vectors/gen/main.go +++ b/chain/vectors/gen/main.go @@ -6,7 +6,7 @@ import ( "math/rand" "os" - "github.com/filecoin-project/specs-actors/actors/builtin/power" + power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/go-address" "golang.org/x/xerrors" @@ -19,15 +19,15 @@ import ( "github.com/filecoin-project/lotus/chain/types/mock" "github.com/filecoin-project/lotus/chain/vectors" "github.com/filecoin-project/lotus/chain/wallet" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" _ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/secp" ) func init() { - verifreg.MinVerifiedDealSize = big.NewInt(2048) - power.ConsensusMinerMinPower = big.NewInt(2048) + verifreg0.MinVerifiedDealSize = big.NewInt(2048) + power0.ConsensusMinerMinPower = big.NewInt(2048) } func MakeHeaderVectors() []vectors.HeaderVector { diff --git a/chain/vm/burn.go b/chain/vm/burn.go index eb0611349..9f9b95755 100644 --- a/chain/vm/burn.go +++ b/chain/vm/burn.go @@ -22,6 +22,17 @@ type GasOutputs struct { GasBurned int64 } +// ZeroGasOutputs returns a logically zeroed GasOutputs. +func ZeroGasOutputs() GasOutputs { + return GasOutputs{ + BaseFeeBurn: big.Zero(), + OverEstimationBurn: big.Zero(), + MinerPenalty: big.Zero(), + MinerTip: big.Zero(), + Refund: big.Zero(), + } +} + // ComputeGasOverestimationBurn computes amount of gas to be refunded and amount of gas to be burned // Result is (refund, burn) func ComputeGasOverestimationBurn(gasUsed, gasLimit int64) (int64, int64) { @@ -58,13 +69,7 @@ func ComputeGasOverestimationBurn(gasUsed, gasLimit int64) (int64, int64) { func ComputeGasOutputs(gasUsed, gasLimit int64, baseFee, feeCap, gasPremium abi.TokenAmount) GasOutputs { gasUsedBig := big.NewInt(gasUsed) - out := GasOutputs{ - BaseFeeBurn: big.Zero(), - OverEstimationBurn: big.Zero(), - MinerPenalty: big.Zero(), - MinerTip: big.Zero(), - Refund: big.Zero(), - } + out := ZeroGasOutputs() baseFeeToPay := baseFee if baseFee.Cmp(feeCap.Int) > 0 { diff --git a/chain/vm/invoker.go b/chain/vm/invoker.go index 1a9a2090a..0a83e273d 100644 --- a/chain/vm/invoker.go +++ b/chain/vm/invoker.go @@ -6,28 +6,28 @@ import ( "fmt" "reflect" - "github.com/filecoin-project/go-state-types/exitcode" - "github.com/filecoin-project/specs-actors/actors/builtin/account" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" - "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/chain/actors/aerrors" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/cron" - init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" - "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/multisig" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/builtin/reward" - "github.com/filecoin-project/specs-actors/actors/builtin/system" - "github.com/filecoin-project/specs-actors/actors/runtime" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + account0 "github.com/filecoin-project/specs-actors/actors/builtin/account" + cron0 "github.com/filecoin-project/specs-actors/actors/builtin/cron" + init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" + paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" + power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" + reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward" + system0 "github.com/filecoin-project/specs-actors/actors/builtin/system" + verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" vmr "github.com/filecoin-project/specs-actors/actors/runtime" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/exitcode" + + "github.com/filecoin-project/lotus/chain/actors/aerrors" ) type Invoker struct { @@ -35,7 +35,7 @@ type Invoker struct { builtInState map[cid.Cid]reflect.Type } -type invokeFunc func(rt runtime.Runtime, params []byte) ([]byte, aerrors.ActorError) +type invokeFunc func(rt vmr.Runtime, params []byte) ([]byte, aerrors.ActorError) type nativeCode []invokeFunc func NewInvoker() *Invoker { @@ -45,22 +45,23 @@ func NewInvoker() *Invoker { } // add builtInCode using: register(cid, singleton) - inv.Register(builtin.SystemActorCodeID, system.Actor{}, abi.EmptyValue{}) - inv.Register(builtin.InitActorCodeID, init_.Actor{}, init_.State{}) - inv.Register(builtin.RewardActorCodeID, reward.Actor{}, reward.State{}) - inv.Register(builtin.CronActorCodeID, cron.Actor{}, cron.State{}) - inv.Register(builtin.StoragePowerActorCodeID, power.Actor{}, power.State{}) - inv.Register(builtin.StorageMarketActorCodeID, market.Actor{}, market.State{}) - inv.Register(builtin.StorageMinerActorCodeID, miner.Actor{}, miner.State{}) - inv.Register(builtin.MultisigActorCodeID, multisig.Actor{}, multisig.State{}) - inv.Register(builtin.PaymentChannelActorCodeID, paych.Actor{}, paych.State{}) - inv.Register(builtin.VerifiedRegistryActorCodeID, verifreg.Actor{}, verifreg.State{}) - inv.Register(builtin.AccountActorCodeID, account.Actor{}, account.State{}) + // NETUPGRADE: register code IDs for v2, etc. + inv.Register(builtin0.SystemActorCodeID, system0.Actor{}, abi.EmptyValue{}) + inv.Register(builtin0.InitActorCodeID, init0.Actor{}, init0.State{}) + inv.Register(builtin0.RewardActorCodeID, reward0.Actor{}, reward0.State{}) + inv.Register(builtin0.CronActorCodeID, cron0.Actor{}, cron0.State{}) + inv.Register(builtin0.StoragePowerActorCodeID, power0.Actor{}, power0.State{}) + inv.Register(builtin0.StorageMarketActorCodeID, market0.Actor{}, market0.State{}) + inv.Register(builtin0.StorageMinerActorCodeID, miner0.Actor{}, miner0.State{}) + inv.Register(builtin0.MultisigActorCodeID, msig0.Actor{}, msig0.State{}) + inv.Register(builtin0.PaymentChannelActorCodeID, paych0.Actor{}, paych0.State{}) + inv.Register(builtin0.VerifiedRegistryActorCodeID, verifreg0.Actor{}, verifreg0.State{}) + inv.Register(builtin0.AccountActorCodeID, account0.Actor{}, account0.State{}) return inv } -func (inv *Invoker) Invoke(codeCid cid.Cid, rt runtime.Runtime, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) { +func (inv *Invoker) Invoke(codeCid cid.Cid, rt vmr.Runtime, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) { code, ok := inv.builtInCode[codeCid] if !ok { @@ -176,7 +177,7 @@ func DecodeParams(b []byte, out interface{}) error { } func DumpActorState(code cid.Cid, b []byte) (interface{}, error) { - if code == builtin.AccountActorCodeID { // Account code special case + if code == builtin0.AccountActorCodeID { // Account code special case return nil, nil } diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index d3757f458..156d57282 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -8,15 +8,14 @@ import ( gruntime "runtime" "time" - "github.com/filecoin-project/go-state-types/cbor" - "github.com/filecoin-project/go-state-types/network" - rtt "github.com/filecoin-project/go-state-types/rt" - "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/go-state-types/cbor" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/exitcode" + "github.com/filecoin-project/go-state-types/network" + rtt "github.com/filecoin-project/go-state-types/rt" "github.com/filecoin-project/specs-actors/actors/builtin" rt0 "github.com/filecoin-project/specs-actors/actors/runtime" "github.com/ipfs/go-cid" @@ -318,14 +317,6 @@ func (rt *Runtime) CurrEpoch() abi.ChainEpoch { return rt.height } -type dumbWrapperType struct { - val []byte -} - -func (dwt *dumbWrapperType) Into(um cbor.Unmarshaler) error { - return um.UnmarshalCBOR(bytes.NewReader(dwt.val)) -} - func (rt *Runtime) Send(to address.Address, method abi.MethodNum, m cbor.Marshaler, value abi.TokenAmount, out cbor.Er) exitcode.ExitCode { if !rt.allowInternal { rt.Abortf(exitcode.SysErrorIllegalActor, "runtime.Send() is currently disallowed") @@ -391,8 +382,8 @@ func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum, if subrt != nil { rt.numActorsCreated = subrt.numActorsCreated + rt.executionTrace.Subcalls = append(rt.executionTrace.Subcalls, subrt.executionTrace) } - rt.executionTrace.Subcalls = append(rt.executionTrace.Subcalls, subrt.executionTrace) return ret, errSend } diff --git a/chain/vm/syscalls.go b/chain/vm/syscalls.go index 3e221f61f..a7f5dab0c 100644 --- a/chain/vm/syscalls.go +++ b/chain/vm/syscalls.go @@ -18,12 +18,12 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/sigs" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/runtime" - "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" ) @@ -192,12 +192,12 @@ func (ss *syscallShim) VerifyBlockSig(blk *types.BlockHeader) error { } // use that to get the miner state - var mas miner.State - if err = ss.cst.Get(ss.ctx, act.Head, &mas); err != nil { + mas, err := miner.Load(adt.WrapStore(ss.ctx, ss.cst), act) + if err != nil { return err } - info, err := mas.GetInfo(adt.WrapStore(ss.ctx, ss.cst)) + info, err := mas.Info() if err != nil { return err } diff --git a/chain/vm/vm.go b/chain/vm/vm.go index f245bb2b0..54ea47698 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -5,15 +5,9 @@ import ( "context" "fmt" "reflect" + "sync/atomic" "time" - "github.com/filecoin-project/go-state-types/network" - - bstore "github.com/filecoin-project/lotus/lib/blockstore" - - "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/builtin" - block "github.com/ipfs/go-block-format" cid "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" @@ -25,15 +19,21 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/exitcode" - "github.com/filecoin-project/specs-actors/actors/builtin/account" + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/aerrors" + "github.com/filecoin-project/lotus/chain/actors/builtin/account" + "github.com/filecoin-project/lotus/chain/actors/builtin/reward" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/blockstore" + bstore "github.com/filecoin-project/lotus/lib/blockstore" "github.com/filecoin-project/lotus/lib/bufbstore" ) @@ -41,6 +41,12 @@ var log = logging.Logger("vm") var actorLog = logging.Logger("actors") var gasOnActorExec = newGasCharge("OnActorExec", 0, 0) +// stat counters +var ( + StatSends uint64 + StatApplied uint64 +) + // ResolveToKeyAddr returns the public key type of address (`BLS`/`SECP256K1`) of an account actor identified by `addr`. func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Address) (address.Address, error) { if addr.Protocol() == address.BLS || addr.Protocol() == address.SECP256K1 { @@ -52,16 +58,12 @@ func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Ad return address.Undef, xerrors.Errorf("failed to find actor: %s", addr) } - if act.Code != builtin.AccountActorCodeID { - return address.Undef, xerrors.Errorf("address %s was not for an account actor", addr) - } - - var aast account.State - if err := cst.Get(context.TODO(), act.Head, &aast); err != nil { + aast, err := account.Load(adt.WrapStore(context.TODO(), cst), act) + if err != nil { return address.Undef, xerrors.Errorf("failed to get account actor state for %s: %w", addr, err) } - return aast.Address, nil + return aast.PubkeyAddress() } var _ cbor.IpldBlockstore = (*gasChargingBlocks)(nil) @@ -166,11 +168,11 @@ type VMOpts struct { Bstore bstore.Blockstore Syscalls SyscallBuilder CircSupplyCalc CircSupplyCalculator - NtwkVersion NtwkVersionGetter + NtwkVersion NtwkVersionGetter // TODO: stebalien: In what cases do we actually need this? It seems like even when creating new networks we want to use the 'global'/build-default version getter BaseFee abi.TokenAmount } -func NewVM(opts *VMOpts) (*VM, error) { +func NewVM(ctx context.Context, opts *VMOpts) (*VM, error) { buf := bufbstore.NewBufferedBstore(opts.Bstore) cst := cbor.NewCborStore(buf) state, err := state.LoadStateTree(cst, opts.StateBase) @@ -209,6 +211,8 @@ type ApplyRet struct { func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime, gasCharge *GasCharge, start time.Time) ([]byte, aerrors.ActorError, *Runtime) { + defer atomic.AddUint64(&StatSends, 1) + st := vm.cstate origin := msg.From @@ -317,6 +321,7 @@ func checkMessage(msg *types.Message) error { func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*ApplyRet, error) { start := build.Clock.Now() + defer atomic.AddUint64(&StatApplied, 1) ret, actorErr, rt := vm.send(ctx, msg, nil, nil, start) rt.finilizeGasTracing() return &ApplyRet{ @@ -336,6 +341,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, start := build.Clock.Now() ctx, span := trace.StartSpan(ctx, "vm.ApplyMessage") defer span.End() + defer atomic.AddUint64(&StatApplied, 1) msg := cmsg.VMMessage() if span.IsRecordingEvents() { span.AddAttributes( @@ -355,14 +361,14 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, msgGasCost := msgGas.Total() // this should never happen, but is currently still exercised by some tests if msgGasCost > msg.GasLimit { + gasOutputs := ZeroGasOutputs() + gasOutputs.MinerPenalty = types.BigMul(vm.baseFee, abi.NewTokenAmount(msgGasCost)) return &ApplyRet{ MessageReceipt: types.MessageReceipt{ ExitCode: exitcode.SysErrOutOfGas, GasUsed: 0, }, - GasCosts: GasOutputs{ - MinerPenalty: types.BigMul(vm.baseFee, abi.NewTokenAmount(msgGasCost)), - }, + GasCosts: gasOutputs, Duration: time.Since(start), }, nil } @@ -374,15 +380,15 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, // this should never happen, but is currently still exercised by some tests if err != nil { if xerrors.Is(err, types.ErrActorNotFound) { + gasOutputs := ZeroGasOutputs() + gasOutputs.MinerPenalty = minerPenaltyAmount return &ApplyRet{ MessageReceipt: types.MessageReceipt{ ExitCode: exitcode.SysErrSenderInvalid, GasUsed: 0, }, ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "actor not found: %s", msg.From), - GasCosts: GasOutputs{ - MinerPenalty: minerPenaltyAmount, - }, + GasCosts: gasOutputs, Duration: time.Since(start), }, nil } @@ -390,21 +396,23 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, } // this should never happen, but is currently still exercised by some tests - if !fromActor.Code.Equals(builtin.AccountActorCodeID) { + if !fromActor.IsAccountActor() { + gasOutputs := ZeroGasOutputs() + gasOutputs.MinerPenalty = minerPenaltyAmount return &ApplyRet{ MessageReceipt: types.MessageReceipt{ ExitCode: exitcode.SysErrSenderInvalid, GasUsed: 0, }, ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "send from not account actor: %s", fromActor.Code), - GasCosts: GasOutputs{ - MinerPenalty: minerPenaltyAmount, - }, + GasCosts: gasOutputs, Duration: time.Since(start), }, nil } if msg.Nonce != fromActor.Nonce { + gasOutputs := ZeroGasOutputs() + gasOutputs.MinerPenalty = minerPenaltyAmount return &ApplyRet{ MessageReceipt: types.MessageReceipt{ ExitCode: exitcode.SysErrSenderStateInvalid, @@ -413,15 +421,15 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid, "actor nonce invalid: msg:%d != state:%d", msg.Nonce, fromActor.Nonce), - GasCosts: GasOutputs{ - MinerPenalty: minerPenaltyAmount, - }, + GasCosts: gasOutputs, Duration: time.Since(start), }, nil } gascost := types.BigMul(types.NewInt(uint64(msg.GasLimit)), msg.GasFeeCap) if fromActor.Balance.LessThan(gascost) { + gasOutputs := ZeroGasOutputs() + gasOutputs.MinerPenalty = minerPenaltyAmount return &ApplyRet{ MessageReceipt: types.MessageReceipt{ ExitCode: exitcode.SysErrSenderStateInvalid, @@ -429,9 +437,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, }, ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid, "actor balance less than needed: %s < %s", types.FIL(fromActor.Balance), types.FIL(gascost)), - GasCosts: GasOutputs{ - MinerPenalty: minerPenaltyAmount, - }, + GasCosts: gasOutputs, Duration: time.Since(start), }, nil } @@ -499,7 +505,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, return nil, xerrors.Errorf("failed to burn base fee: %w", err) } - if err := vm.transferFromGasHolder(builtin.RewardActorAddr, gasHolder, gasOutputs.MinerTip); err != nil { + if err := vm.transferFromGasHolder(reward.Address, gasHolder, gasOutputs.MinerTip); err != nil { return nil, xerrors.Errorf("failed to give miner gas reward: %w", err) } @@ -551,7 +557,7 @@ func (vm *VM) Flush(ctx context.Context) (cid.Cid, error) { return cid.Undef, xerrors.Errorf("flushing vm: %w", err) } - if err := Copy(from, to, root); err != nil { + if err := Copy(ctx, from, to, root); err != nil { return cid.Undef, xerrors.Errorf("copying tree: %w", err) } @@ -605,9 +611,18 @@ func linksForObj(blk block.Block, cb func(cid.Cid)) error { } } -func Copy(from, to blockstore.Blockstore, root cid.Cid) error { +func Copy(ctx context.Context, from, to blockstore.Blockstore, root cid.Cid) error { + ctx, span := trace.StartSpan(ctx, "vm.Copy") // nolint + defer span.End() + + var numBlocks int + var totalCopySize int + var batch []block.Block batchCp := func(blk block.Block) error { + numBlocks++ + totalCopySize += len(blk.RawData()) + batch = append(batch, blk) if len(batch) > 100 { if err := to.PutMany(batch); err != nil { @@ -628,6 +643,11 @@ func Copy(from, to blockstore.Blockstore, root cid.Cid) error { } } + span.AddAttributes( + trace.Int64Attribute("numBlocks", int64(numBlocks)), + trace.Int64Attribute("copySize", int64(totalCopySize)), + ) + return nil } diff --git a/cli/chain.go b/cli/chain.go index 278a8e29b..73b25324b 100644 --- a/cli/chain.go +++ b/cli/chain.go @@ -40,6 +40,7 @@ var chainCmd = &cli.Command{ chainHeadCmd, chainGetBlock, chainReadObjCmd, + chainDeleteObjCmd, chainStatObjCmd, chainGetMsgCmd, chainSetHeadCmd, @@ -193,6 +194,43 @@ var chainReadObjCmd = &cli.Command{ }, } +var chainDeleteObjCmd = &cli.Command{ + Name: "delete-obj", + Usage: "Delete an object from the chain blockstore", + Description: "WARNING: Removing wrong objects from the chain blockstore may lead to sync issues", + ArgsUsage: "[objectCid]", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "really-do-it", + }, + }, + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + c, err := cid.Decode(cctx.Args().First()) + if err != nil { + return fmt.Errorf("failed to parse cid input: %s", err) + } + + if !cctx.Bool("really-do-it") { + return xerrors.Errorf("pass the --really-do-it flag to proceed") + } + + err = api.ChainDeleteObj(ctx, c) + if err != nil { + return err + } + + fmt.Printf("Obj %s deleted\n", c.String()) + return nil + }, +} + var chainStatObjCmd = &cli.Command{ Name: "stat-obj", Usage: "Collect size and ipld link counts for objs", diff --git a/cli/client.go b/cli/client.go index e68f98791..5d40dce0d 100644 --- a/cli/client.go +++ b/cli/client.go @@ -12,6 +12,8 @@ import ( "text/tabwriter" "time" + "github.com/filecoin-project/specs-actors/actors/builtin" + tm "github.com/buger/goterm" "github.com/docker/go-units" "github.com/fatih/color" @@ -29,11 +31,11 @@ import ( "github.com/filecoin-project/go-multistore" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/lotus/api" lapi "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin/market" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/tablewriter" ) @@ -527,6 +529,11 @@ func interactiveDeal(cctx *cli.Context) error { continue } + if days < int(build.MinDealDuration/builtin.EpochsInDay) { + printErr(xerrors.Errorf("minimum duration is %d days", int(build.MinDealDuration/builtin.EpochsInDay))) + continue + } + state = "miner" case "miner": fmt.Print("Miner Address (t0..): ") @@ -1044,12 +1051,8 @@ var clientListDeals = &cli.Command{ func dealFromDealInfo(ctx context.Context, full api.FullNode, head *types.TipSet, v api.DealInfo) deal { if v.DealID == 0 { return deal{ - LocalDeal: v, - OnChainDealState: market.DealState{ - SectorStartEpoch: -1, - LastUpdatedEpoch: -1, - SlashEpoch: -1, - }, + LocalDeal: v, + OnChainDealState: *market.EmptyDealState(), } } diff --git a/cli/multisig.go b/cli/multisig.go index 1f626ae7f..944f67b2e 100644 --- a/cli/multisig.go +++ b/cli/multisig.go @@ -2,8 +2,6 @@ package cli import ( "bytes" - "context" - "encoding/binary" "encoding/hex" "fmt" "os" @@ -16,21 +14,20 @@ import ( "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/go-address" - init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" - samsig "github.com/filecoin-project/specs-actors/actors/builtin/multisig" - cid "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" "github.com/urfave/cli/v2" "golang.org/x/xerrors" - "github.com/filecoin-project/lotus/api" + init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" + msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" + "github.com/filecoin-project/lotus/api/apibstore" "github.com/filecoin-project/lotus/build" - types "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin/multisig" + "github.com/filecoin-project/lotus/chain/types" ) var multisigCmd = &cli.Command{ @@ -153,7 +150,7 @@ var msigCreateCmd = &cli.Command{ // get address of newly created miner - var execreturn init_.ExecReturn + var execreturn init0.ExecReturn if err := execreturn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil { return err } @@ -186,50 +183,73 @@ var msigInspectCmd = &cli.Command{ defer closer() ctx := ReqContext(cctx) + store := adt.WrapStore(ctx, cbor.NewCborStore(apibstore.NewAPIBlockstore(api))) + maddr, err := address.NewFromString(cctx.Args().First()) if err != nil { return err } - act, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - obj, err := api.ChainReadObj(ctx, act.Head) - if err != nil { - return err - } - head, err := api.ChainHead(ctx) if err != nil { return err } - var mstate samsig.State - if err := mstate.UnmarshalCBOR(bytes.NewReader(obj)); err != nil { + act, err := api.StateGetActor(ctx, maddr, head.Key()) + if err != nil { + return err + } + + mstate, err := multisig.Load(store, act) + if err != nil { + return err + } + locked, err := mstate.LockedBalance(head.Height()) + if err != nil { return err } - locked := mstate.AmountLocked(head.Height() - mstate.StartEpoch) fmt.Printf("Balance: %s\n", types.FIL(act.Balance)) fmt.Printf("Spendable: %s\n", types.FIL(types.BigSub(act.Balance, locked))) if cctx.Bool("vesting") { - fmt.Printf("InitialBalance: %s\n", types.FIL(mstate.InitialBalance)) - fmt.Printf("StartEpoch: %d\n", mstate.StartEpoch) - fmt.Printf("UnlockDuration: %d\n", mstate.UnlockDuration) + ib, err := mstate.InitialBalance() + if err != nil { + return err + } + fmt.Printf("InitialBalance: %s\n", types.FIL(ib)) + se, err := mstate.StartEpoch() + if err != nil { + return err + } + fmt.Printf("StartEpoch: %d\n", se) + ud, err := mstate.UnlockDuration() + if err != nil { + return err + } + fmt.Printf("UnlockDuration: %d\n", ud) } - fmt.Printf("Threshold: %d / %d\n", mstate.NumApprovalsThreshold, len(mstate.Signers)) + signers, err := mstate.Signers() + if err != nil { + return err + } + threshold, err := mstate.Threshold() + if err != nil { + return err + } + fmt.Printf("Threshold: %d / %d\n", threshold, len(signers)) fmt.Println("Signers:") - for _, s := range mstate.Signers { + for _, s := range signers { fmt.Printf("\t%s\n", s) } - pending, err := GetMultisigPending(ctx, api, mstate.PendingTxns) - if err != nil { - return fmt.Errorf("reading pending transactions: %w", err) + pending := make(map[int64]multisig.Transaction) + if err := mstate.ForEachPendingTxn(func(id int64, txn multisig.Transaction) error { + pending[id] = txn + return nil + }); err != nil { + return xerrors.Errorf("reading pending transactions: %w", err) } fmt.Println("Transactions: ", len(pending)) @@ -246,7 +266,7 @@ var msigInspectCmd = &cli.Command{ fmt.Fprintf(w, "ID\tState\tApprovals\tTo\tValue\tMethod\tParams\n") for _, txid := range txids { tx := pending[txid] - fmt.Fprintf(w, "%d\t%s\t%d\t%s\t%s\t%d\t%x\n", txid, state(tx), len(tx.Approved), tx.To, types.FIL(tx.Value), tx.Method, tx.Params) + fmt.Fprintf(w, "%d\t%s\t%d\t%s\t%s\t%d\t%x\n", txid, "pending", len(tx.Approved), tx.To, types.FIL(tx.Value), tx.Method, tx.Params) } if err := w.Flush(); err != nil { return xerrors.Errorf("flushing output: %+v", err) @@ -258,43 +278,6 @@ var msigInspectCmd = &cli.Command{ }, } -func GetMultisigPending(ctx context.Context, lapi api.FullNode, hroot cid.Cid) (map[int64]*samsig.Transaction, error) { - bs := apibstore.NewAPIBlockstore(lapi) - store := adt.WrapStore(ctx, cbor.NewCborStore(bs)) - - nd, err := adt.AsMap(store, hroot) - if err != nil { - return nil, err - } - - txs := make(map[int64]*samsig.Transaction) - var tx samsig.Transaction - err = nd.ForEach(&tx, func(k string) error { - txid, _ := binary.Varint([]byte(k)) - - cpy := tx // copy so we don't clobber on future iterations. - txs[txid] = &cpy - return nil - }) - if err != nil { - return nil, xerrors.Errorf("failed to iterate transactions hamt: %w", err) - } - - return txs, nil -} - -func state(tx *samsig.Transaction) string { - /* // TODO(why): I strongly disagree with not having these... but i need to move forward - if tx.Complete { - return "done" - } - if tx.Canceled { - return "canceled" - } - */ - return "pending" -} - var msigProposeCmd = &cli.Command{ Name: "propose", Usage: "Propose a multisig transaction", @@ -372,7 +355,7 @@ var msigProposeCmd = &cli.Command{ return fmt.Errorf("failed to look up multisig %s: %w", msig, err) } - if act.Code != builtin.MultisigActorCodeID { + if !act.IsMultisigActor() { return fmt.Errorf("actor %s is not a multisig actor", msig) } @@ -392,7 +375,7 @@ var msigProposeCmd = &cli.Command{ return fmt.Errorf("proposal returned exit %d", wait.Receipt.ExitCode) } - var retval samsig.ProposeReturn + var retval msig0.ProposeReturn if err := retval.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil { return fmt.Errorf("failed to unmarshal propose return value: %w", err) } diff --git a/cli/paych_test.go b/cli/paych_test.go index cccc80ff4..35f56d90e 100644 --- a/cli/paych_test.go +++ b/cli/paych_test.go @@ -12,38 +12,31 @@ import ( "testing" "time" - "github.com/filecoin-project/lotus/build" - - "github.com/filecoin-project/go-state-types/big" - saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" - - "github.com/multiformats/go-multiaddr" - - "github.com/filecoin-project/lotus/chain/events" - - "github.com/filecoin-project/lotus/api/apibstore" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" - cbor "github.com/ipfs/go-ipld-cbor" - - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/lotus/chain/types" - - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/api/test" - "github.com/filecoin-project/lotus/chain/wallet" - builder "github.com/filecoin-project/lotus/node/test" "github.com/stretchr/testify/require" "github.com/urfave/cli/v2" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + cbor "github.com/ipfs/go-ipld-cbor" + "github.com/multiformats/go-multiaddr" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" + "github.com/filecoin-project/lotus/chain/actors/policy" + + "github.com/filecoin-project/lotus/api/apibstore" + "github.com/filecoin-project/lotus/api/test" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/events" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/wallet" + builder "github.com/filecoin-project/lotus/node/test" ) func init() { - power.ConsensusMinerMinPower = big.NewInt(2048) - saminer.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ - abi.RegisteredSealProof_StackedDrg2KiBV1: {}, - } - verifreg.MinVerifiedDealSize = big.NewInt(256) + policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) + policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048)) + policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) } // TestPaymentChannels does a basic test to exercise the payment channel CLI @@ -88,7 +81,9 @@ func TestPaymentChannels(t *testing.T) { // Wait for the chain to reach the settle height chState := getPaychState(ctx, t, paymentReceiver, chAddr) - waitForHeight(ctx, t, paymentReceiver, chState.SettlingAt) + sa, err := chState.SettlingAt() + require.NoError(t, err) + waitForHeight(ctx, t, paymentReceiver, sa) // receiver: paych collect cmd = []string{chAddr.String()} @@ -540,8 +535,7 @@ func getPaychState(ctx context.Context, t *testing.T, node test.TestNode, chAddr require.NoError(t, err) store := cbor.NewCborStore(apibstore.NewAPIBlockstore(node)) - var chState paych.State - err = store.Get(ctx, act.Head, &chState) + chState, err := paych.Load(adt.WrapStore(ctx, store), act) require.NoError(t, err) return chState diff --git a/cli/state.go b/cli/state.go index 2476d7c59..d96c93c54 100644 --- a/cli/state.go +++ b/cli/state.go @@ -259,13 +259,13 @@ var stateSectorsCmd = &cli.Command{ return err } - sectors, err := api.StateMinerSectors(ctx, maddr, nil, true, ts.Key()) + sectors, err := api.StateMinerSectors(ctx, maddr, nil, ts.Key()) if err != nil { return err } for _, s := range sectors { - fmt.Printf("%d: %x\n", s.Info.SectorNumber, s.Info.SealedCID) + fmt.Printf("%d: %x\n", s.SectorNumber, s.SealedCID) } return nil @@ -305,7 +305,7 @@ var stateActiveSectorsCmd = &cli.Command{ } for _, s := range sectors { - fmt.Printf("%d: %x\n", s.Info.SectorNumber, s.Info.SealedCID) + fmt.Printf("%d: %x\n", s.SectorNumber, s.SealedCID) } return nil diff --git a/cli/sync.go b/cli/sync.go index bff34960e..bee87cf70 100644 --- a/cli/sync.go +++ b/cli/sync.go @@ -225,6 +225,16 @@ var syncCheckpointCmd = &cli.Command{ } func SyncWait(ctx context.Context, napi api.FullNode) error { + tick := time.Second / 4 + + lastLines := 0 + ticker := time.NewTicker(tick) + defer ticker.Stop() + + samples := 8 + i := 0 + var app, lastApp uint64 + for { state, err := napi.SyncState(ctx) if err != nil { @@ -249,14 +259,41 @@ func SyncWait(ctx context.Context, napi api.FullNode) error { ss := state.ActiveSyncs[working] + var baseHeight abi.ChainEpoch var target []cid.Cid var theight abi.ChainEpoch + var heightDiff int64 + + if ss.Base != nil { + baseHeight = ss.Base.Height() + heightDiff = int64(ss.Base.Height()) + } if ss.Target != nil { target = ss.Target.Cids() theight = ss.Target.Height() + heightDiff = int64(ss.Target.Height()) - heightDiff + } else { + heightDiff = 0 } - fmt.Printf("\r\x1b[2KWorker %d: Target Height: %d\tTarget: %s\tState: %s\tHeight: %d", working, theight, target, ss.Stage, ss.Height) + for i := 0; i < lastLines; i++ { + fmt.Print("\r\x1b[2K\x1b[A") + } + + fmt.Printf("Worker: %d; Base: %d; Target: %d (diff: %d)\n", working, baseHeight, theight, heightDiff) + fmt.Printf("State: %s; Current Epoch: %d; Todo: %d\n", ss.Stage, ss.Height, theight-ss.Height) + lastLines = 2 + + if i%samples == 0 { + lastApp = app + app = state.VMApplied + } + if i > 0 { + fmt.Printf("Validated %d messages (%d per second)\n", state.VMApplied, (app-lastApp)*uint64(time.Second/tick)/uint64(samples)) + lastLines++ + } + + _ = target // todo: maybe print? (creates a bunch of line wrapping issues with most tipsets) if time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs) { fmt.Println("\nDone!") @@ -267,7 +304,9 @@ func SyncWait(ctx context.Context, napi api.FullNode) error { case <-ctx.Done(): fmt.Println("\nExit by user") return nil - case <-build.Clock.After(1 * time.Second): + case <-ticker.C: } + + i++ } } diff --git a/cli/wallet.go b/cli/wallet.go index 4339a1fb6..27993a1ba 100644 --- a/cli/wallet.go +++ b/cli/wallet.go @@ -382,7 +382,11 @@ var walletVerify = &cli.Command{ return err } - if api.WalletVerify(ctx, addr, msg, &sig) { + ok, err := api.WalletVerify(ctx, addr, msg, &sig) + if err != nil { + return err + } + if ok { fmt.Println("valid") return nil } diff --git a/cmd/lotus-bench/main.go b/cmd/lotus-bench/main.go index 431bfdd44..2516bfd26 100644 --- a/cmd/lotus-bench/main.go +++ b/cmd/lotus-bench/main.go @@ -27,11 +27,11 @@ import ( "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper/basicfs" "github.com/filecoin-project/lotus/extern/sector-storage/stores" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-storage/storage" lapi "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/genesis" ) @@ -76,7 +76,7 @@ func main() { log.Info("Starting lotus-bench") - miner.SupportedProofTypes[abi.RegisteredSealProof_StackedDrg2KiBV1] = struct{}{} + policy.AddSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) app := &cli.App{ Name: "lotus-bench", @@ -387,7 +387,7 @@ var sealBenchCmd = &cli.Command{ return err } if !ok { - log.Error("post verification failed") + log.Error("window post verification failed") } verifyWindowpost1 := time.Now() @@ -403,7 +403,7 @@ var sealBenchCmd = &cli.Command{ return err } if !ok { - log.Error("post verification failed") + log.Error("window post verification failed") } verifyWindowpost2 := time.Now() diff --git a/cmd/lotus-chainwatch/processor/common_actors.go b/cmd/lotus-chainwatch/processor/common_actors.go index d6aec7f90..56520880c 100644 --- a/cmd/lotus-chainwatch/processor/common_actors.go +++ b/cmd/lotus-chainwatch/processor/common_actors.go @@ -1,7 +1,6 @@ package processor import ( - "bytes" "context" "time" @@ -9,14 +8,13 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + _init "github.com/filecoin-project/lotus/chain/actors/builtin/init" "github.com/filecoin-project/lotus/chain/events/state" "github.com/filecoin-project/lotus/chain/types" cw_util "github.com/filecoin-project/lotus/cmd/lotus-chainwatch/util" "github.com/filecoin-project/specs-actors/actors/builtin" - _init "github.com/filecoin-project/specs-actors/actors/builtin/init" - "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/ipfs/go-cid" - typegen "github.com/whyrusleeping/cbor-gen" ) func (p *Processor) setupCommonActors() error { @@ -150,32 +148,17 @@ func (p Processor) storeActorAddresses(ctx context.Context, actors map[cid.Cid]A return err } - initActorRaw, err := p.node.ChainReadObj(ctx, initActor.Head) - if err != nil { - return err - } - - var initActorState _init.State - if err := initActorState.UnmarshalCBOR(bytes.NewReader(initActorRaw)); err != nil { - return err - } - ctxStore := cw_util.NewAPIIpldStore(ctx, p.node) - addrMap, err := adt.AsMap(ctxStore, initActorState.AddressMap) + initActorState, err := _init.Load(cw_util.NewAPIIpldStore(ctx, p.node), initActor) if err != nil { return err } // gross.. - var actorID typegen.CborInt - if err := addrMap.ForEach(&actorID, func(key string) error { - longAddr, err := address.NewFromBytes([]byte(key)) + if err := initActorState.ForEachActor(func(id abi.ActorID, addr address.Address) error { + idAddr, err := address.NewIDAddress(uint64(id)) if err != nil { return err } - shortAddr, err := address.NewIDAddress(uint64(actorID)) - if err != nil { - return err - } - addressToID[longAddr] = shortAddr + addressToID[addr] = idAddr return nil }); err != nil { return err diff --git a/cmd/lotus-chainwatch/processor/market.go b/cmd/lotus-chainwatch/processor/market.go index e50ec3076..17aa1c37b 100644 --- a/cmd/lotus-chainwatch/processor/market.go +++ b/cmd/lotus-chainwatch/processor/market.go @@ -8,6 +8,7 @@ import ( "golang.org/x/sync/errgroup" "golang.org/x/xerrors" + "github.com/filecoin-project/lotus/chain/actors/builtin/market" "github.com/filecoin-project/lotus/chain/events/state" ) @@ -293,7 +294,7 @@ func (p *Processor) updateMarketActorDealProposals(ctx context.Context, marketTi if !changed { continue } - changes, ok := val.(*state.MarketDealStateChanges) + changes, ok := val.(*market.DealStateChanges) if !ok { return xerrors.Errorf("Unknown type returned by Deal State AMT predicate: %T", val) } diff --git a/cmd/lotus-chainwatch/processor/miner.go b/cmd/lotus-chainwatch/processor/miner.go index 71d881927..3a37a82f8 100644 --- a/cmd/lotus-chainwatch/processor/miner.go +++ b/cmd/lotus-chainwatch/processor/miner.go @@ -1,9 +1,7 @@ package processor import ( - "bytes" "context" - "fmt" "strings" "time" @@ -15,13 +13,13 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/apibstore" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/builtin/power" "github.com/filecoin-project/lotus/chain/events/state" + "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" cw_util "github.com/filecoin-project/lotus/cmd/lotus-chainwatch/util" ) @@ -204,11 +202,13 @@ func (p *Processor) processMiners(ctx context.Context, minerTips map[types.TipSe log.Debugw("Processed Miners", "duration", time.Since(start).String()) }() + stor := store.ActorStore(ctx, apibstore.NewAPIBlockstore(p.node)) + var out []minerActorInfo // TODO add parallel calls if this becomes slow for tipset, miners := range minerTips { // get the power actors claims map - minersClaims, err := getPowerActorClaimsMap(ctx, p.node, tipset) + powerState, err := getPowerActorState(ctx, p.node, tipset) if err != nil { return nil, err } @@ -218,10 +218,9 @@ func (p *Processor) processMiners(ctx context.Context, minerTips map[types.TipSe var mi minerActorInfo mi.common = act - var claim power.Claim // get miner claim from power actors claim map and store if found, else the miner had no claim at // this tipset - found, err := minersClaims.Get(abi.AddrKey(act.addr), &claim) + claim, found, err := powerState.MinerPower(act.addr) if err != nil { return nil, err } @@ -230,15 +229,13 @@ func (p *Processor) processMiners(ctx context.Context, minerTips map[types.TipSe mi.rawPower = claim.RawBytePower } - // Get the miner state info - astb, err := p.node.ChainReadObj(ctx, act.act.Head) + // Get the miner state + mas, err := miner.Load(stor, &act.act) if err != nil { log.Warnw("failed to find miner actor state", "address", act.addr, "error", err) continue } - if err := mi.state.UnmarshalCBOR(bytes.NewReader(astb)); err != nil { - return nil, err - } + mi.state = mas out = append(out, mi) } } @@ -322,11 +319,6 @@ func (p *Processor) storeMinerPreCommitInfo(ctx context.Context, miners []minerA for _, m := range miners { m := m grp.Go(func() error { - minerSectors, err := adt.AsArray(p.ctxStore, m.state.Sectors) - if err != nil { - return err - } - changes, err := p.getMinerPreCommitChanges(ctx, m) if err != nil { if strings.Contains(err.Error(), types.ErrActorNotFound.Error()) { @@ -399,10 +391,12 @@ func (p *Processor) storeMinerPreCommitInfo(ctx context.Context, miners []minerA } var preCommitExpired []uint64 for _, removed := range changes.Removed { - var sector miner.SectorOnChainInfo - if found, err := minerSectors.Get(uint64(removed.Info.SectorNumber), §or); err != nil { + // TODO: we can optimize this to not load the AMT every time, if necessary. + si, err := m.state.GetSector(removed.Info.SectorNumber) + if err != nil { return err - } else if !found { + } + if si == nil { preCommitExpired = append(preCommitExpired, uint64(removed.Info.SectorNumber)) } } @@ -653,21 +647,12 @@ func (p *Processor) storeMinerSectorEvents(ctx context.Context, sectorEvents, pr func (p *Processor) getMinerStateAt(ctx context.Context, maddr address.Address, tskey types.TipSetKey) (miner.State, error) { prevActor, err := p.node.StateGetActor(ctx, maddr, tskey) if err != nil { - return miner.State{}, err + return nil, err } - var out miner.State - // Get the miner state info - astb, err := p.node.ChainReadObj(ctx, prevActor.Head) - if err != nil { - return miner.State{}, err - } - if err := out.UnmarshalCBOR(bytes.NewReader(astb)); err != nil { - return miner.State{}, err - } - return out, nil + return miner.Load(store.ActorStore(ctx, apibstore.NewAPIBlockstore(p.node)), prevActor) } -func (p *Processor) getMinerPreCommitChanges(ctx context.Context, m minerActorInfo) (*state.MinerPreCommitChanges, error) { +func (p *Processor) getMinerPreCommitChanges(ctx context.Context, m minerActorInfo) (*miner.PreCommitChanges, error) { pred := state.NewStatePredicates(p.node) changed, val, err := pred.OnMinerActorChange(m.common.addr, pred.OnMinerPreCommitChange())(ctx, m.common.parentTsKey, m.common.tsKey) if err != nil { @@ -676,11 +661,11 @@ func (p *Processor) getMinerPreCommitChanges(ctx context.Context, m minerActorIn if !changed { return nil, nil } - out := val.(*state.MinerPreCommitChanges) + out := val.(*miner.PreCommitChanges) return out, nil } -func (p *Processor) getMinerSectorChanges(ctx context.Context, m minerActorInfo) (*state.MinerSectorChanges, error) { +func (p *Processor) getMinerSectorChanges(ctx context.Context, m minerActorInfo) (*miner.SectorChanges, error) { pred := state.NewStatePredicates(p.node) changed, val, err := pred.OnMinerActorChange(m.common.addr, pred.OnMinerSectorChange())(ctx, m.common.parentTsKey, m.common.tsKey) if err != nil { @@ -689,7 +674,7 @@ func (p *Processor) getMinerSectorChanges(ctx context.Context, m minerActorInfo) if !changed { return nil, nil } - out := val.(*state.MinerSectorChanges) + out := val.(*miner.SectorChanges) return out, nil } @@ -698,179 +683,200 @@ func (p *Processor) diffMinerPartitions(ctx context.Context, m minerActorInfo, e if err != nil { return err } - dlIdx := prevMiner.CurrentDeadline curMiner := m.state - - // load the old deadline - prevDls, err := prevMiner.LoadDeadlines(p.ctxStore) + dc, err := prevMiner.DeadlinesChanged(curMiner) if err != nil { return err } - var prevDl miner.Deadline - if err := p.ctxStore.Get(ctx, prevDls.Due[dlIdx], &prevDl); err != nil { - return err + if !dc { + return nil } + panic("TODO") - prevPartitions, err := prevDl.PartitionsArray(p.ctxStore) - if err != nil { - return err - } + // FIXME: This code doesn't work. + // 1. We need to diff all deadlines, not just the "current" deadline. + // 2. We need to handle the case where we _add_ a partition. (i.e., + // where len(newPartitions) != len(oldPartitions). + /* - // load the new deadline - curDls, err := curMiner.LoadDeadlines(p.ctxStore) - if err != nil { - return err - } + // NOTE: If we change the number of deadlines in an upgrade, this will + // break. - var curDl miner.Deadline - if err := p.ctxStore.Get(ctx, curDls.Due[dlIdx], &curDl); err != nil { - return err - } + // load the old deadline + prevDls, err := prevMiner.LoadDeadlines(p.ctxStore) + if err != nil { + return err + } + var prevDl miner.Deadline + if err := p.ctxStore.Get(ctx, prevDls.Due[dlIdx], &prevDl); err != nil { + return err + } - curPartitions, err := curDl.PartitionsArray(p.ctxStore) - if err != nil { - return err - } + prevPartitions, err := prevDl.PartitionsArray(p.ctxStore) + if err != nil { + return err + } - // TODO this can be optimized by inspecting the miner state for partitions that have changed and only inspecting those. - var prevPart miner.Partition - if err := prevPartitions.ForEach(&prevPart, func(i int64) error { - var curPart miner.Partition - if found, err := curPartitions.Get(uint64(i), &curPart); err != nil { - return err - } else if !found { - log.Fatal("I don't know what this means, are partitions ever removed?") - } - partitionDiff, err := p.diffPartition(prevPart, curPart) - if err != nil { - return err - } + // load the new deadline + curDls, err := curMiner.LoadDeadlines(p.ctxStore) + if err != nil { + return err + } - recovered, err := partitionDiff.Recovered.All(miner.SectorsMax) - if err != nil { - return err - } - events <- &MinerSectorsEvent{ - MinerID: m.common.addr, - StateRoot: m.common.stateroot, - SectorIDs: recovered, - Event: SectorRecovered, - } - inRecovery, err := partitionDiff.InRecovery.All(miner.SectorsMax) - if err != nil { - return err - } - events <- &MinerSectorsEvent{ - MinerID: m.common.addr, - StateRoot: m.common.stateroot, - SectorIDs: inRecovery, - Event: SectorRecovering, - } - faulted, err := partitionDiff.Faulted.All(miner.SectorsMax) - if err != nil { - return err - } - events <- &MinerSectorsEvent{ - MinerID: m.common.addr, - StateRoot: m.common.stateroot, - SectorIDs: faulted, - Event: SectorFaulted, - } - terminated, err := partitionDiff.Terminated.All(miner.SectorsMax) - if err != nil { - return err - } - events <- &MinerSectorsEvent{ - MinerID: m.common.addr, - StateRoot: m.common.stateroot, - SectorIDs: terminated, - Event: SectorTerminated, - } - expired, err := partitionDiff.Expired.All(miner.SectorsMax) - if err != nil { - return err - } - events <- &MinerSectorsEvent{ - MinerID: m.common.addr, - StateRoot: m.common.stateroot, - SectorIDs: expired, - Event: SectorExpired, - } + var curDl miner.Deadline + if err := p.ctxStore.Get(ctx, curDls.Due[dlIdx], &curDl); err != nil { + return err + } + + curPartitions, err := curDl.PartitionsArray(p.ctxStore) + if err != nil { + return err + } + + // TODO this can be optimized by inspecting the miner state for partitions that have changed and only inspecting those. + var prevPart miner.Partition + if err := prevPartitions.ForEach(&prevPart, func(i int64) error { + var curPart miner.Partition + if found, err := curPartitions.Get(uint64(i), &curPart); err != nil { + return err + } else if !found { + log.Fatal("I don't know what this means, are partitions ever removed?") + } + partitionDiff, err := p.diffPartition(prevPart, curPart) + if err != nil { + return err + } + + recovered, err := partitionDiff.Recovered.All(miner.SectorsMax) + if err != nil { + return err + } + events <- &MinerSectorsEvent{ + MinerID: m.common.addr, + StateRoot: m.common.stateroot, + SectorIDs: recovered, + Event: SectorRecovered, + } + inRecovery, err := partitionDiff.InRecovery.All(miner.SectorsMax) + if err != nil { + return err + } + events <- &MinerSectorsEvent{ + MinerID: m.common.addr, + StateRoot: m.common.stateroot, + SectorIDs: inRecovery, + Event: SectorRecovering, + } + faulted, err := partitionDiff.Faulted.All(miner.SectorsMax) + if err != nil { + return err + } + events <- &MinerSectorsEvent{ + MinerID: m.common.addr, + StateRoot: m.common.stateroot, + SectorIDs: faulted, + Event: SectorFaulted, + } + terminated, err := partitionDiff.Terminated.All(miner.SectorsMax) + if err != nil { + return err + } + events <- &MinerSectorsEvent{ + MinerID: m.common.addr, + StateRoot: m.common.stateroot, + SectorIDs: terminated, + Event: SectorTerminated, + } + expired, err := partitionDiff.Expired.All(miner.SectorsMax) + if err != nil { + return err + } + events <- &MinerSectorsEvent{ + MinerID: m.common.addr, + StateRoot: m.common.stateroot, + SectorIDs: expired, + Event: SectorExpired, + } + + return nil + }); err != nil { + return err + } return nil - }); err != nil { - return err - } - - return nil + */ } func (p *Processor) diffPartition(prevPart, curPart miner.Partition) (*PartitionStatus, error) { - // all the sectors that were in previous but not in current - allRemovedSectors, err := bitfield.SubtractBitField(prevPart.Sectors, curPart.Sectors) + prevLiveSectors, err := prevPart.LiveSectors() + if err != nil { + return nil, err + } + curLiveSectors, err := curPart.LiveSectors() if err != nil { return nil, err } - // list of sectors that were terminated before their expiration. - terminatedEarlyArr, err := adt.AsArray(p.ctxStore, curPart.EarlyTerminated) + removedSectors, err := bitfield.SubtractBitField(prevLiveSectors, curLiveSectors) if err != nil { return nil, err } - expired := bitfield.New() - var bf bitfield.BitField - if err := terminatedEarlyArr.ForEach(&bf, func(i int64) error { - // expired = all removals - termination - expirations, err := bitfield.SubtractBitField(allRemovedSectors, bf) - if err != nil { - return err - } - // merge with expired sectors from other epochs - expired, err = bitfield.MergeBitFields(expirations, expired) - if err != nil { - return nil - } - return nil - }); err != nil { - return nil, err - } - - // terminated = all removals - expired - terminated, err := bitfield.SubtractBitField(allRemovedSectors, expired) + prevRecoveries, err := prevPart.RecoveringSectors() if err != nil { return nil, err } - // faults in current but not previous - faults, err := bitfield.SubtractBitField(curPart.Recoveries, prevPart.Recoveries) + curRecoveries, err := curPart.RecoveringSectors() if err != nil { return nil, err } - // recoveries in current but not previous - inRecovery, err := bitfield.SubtractBitField(curPart.Recoveries, prevPart.Recoveries) + newRecoveries, err := bitfield.SubtractBitField(curRecoveries, prevRecoveries) + if err != nil { + return nil, err + } + + prevFaults, err := prevPart.FaultySectors() + if err != nil { + return nil, err + } + + curFaults, err := curPart.FaultySectors() + if err != nil { + return nil, err + } + + newFaults, err := bitfield.SubtractBitField(curFaults, prevFaults) if err != nil { return nil, err } // all current good sectors - newActiveSectors, err := curPart.ActiveSectors() + curActiveSectors, err := curPart.ActiveSectors() if err != nil { return nil, err } // sectors that were previously fault and are now currently active are considered recovered. - recovered, err := bitfield.IntersectBitField(prevPart.Faults, newActiveSectors) + recovered, err := bitfield.IntersectBitField(prevFaults, curActiveSectors) if err != nil { return nil, err } + // TODO: distinguish between "terminated" and "expired" sectors. The + // previous code here never had a chance of working in the first place, + // so I'm not going to try to replicate it right now. + // + // How? If the sector expires before it should (according to sector + // info) and it wasn't replaced by a pre-commit deleted in this change + // set, it was "early terminated". + return &PartitionStatus{ - Terminated: terminated, - Expired: expired, - Faulted: faults, - InRecovery: inRecovery, + Terminated: bitfield.New(), + Expired: removedSectors, + Faulted: newFaults, + InRecovery: newRecoveries, Recovered: recovered, }, nil } @@ -1020,22 +1026,10 @@ func (p *Processor) storeMinersPower(miners []minerActorInfo) error { } // load the power actor state clam as an adt.Map at the tipset `ts`. -func getPowerActorClaimsMap(ctx context.Context, api api.FullNode, ts types.TipSetKey) (*adt.Map, error) { - powerActor, err := api.StateGetActor(ctx, builtin.StoragePowerActorAddr, ts) +func getPowerActorState(ctx context.Context, api api.FullNode, ts types.TipSetKey) (power.State, error) { + powerActor, err := api.StateGetActor(ctx, power.Address, ts) if err != nil { return nil, err } - - powerRaw, err := api.ChainReadObj(ctx, powerActor.Head) - if err != nil { - return nil, err - } - - var powerActorState power.State - if err := powerActorState.UnmarshalCBOR(bytes.NewReader(powerRaw)); err != nil { - return nil, fmt.Errorf("failed to unmarshal power actor state: %w", err) - } - - s := cw_util.NewAPIIpldStore(ctx, api) - return adt.AsMap(s, powerActorState.Claims) + return power.Load(cw_util.NewAPIIpldStore(ctx, api), powerActor) } diff --git a/cmd/lotus-chainwatch/processor/power.go b/cmd/lotus-chainwatch/processor/power.go index dfd7eddd7..726a46706 100644 --- a/cmd/lotus-chainwatch/processor/power.go +++ b/cmd/lotus-chainwatch/processor/power.go @@ -1,16 +1,14 @@ package processor import ( - "bytes" "context" "time" "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/util/smoothing" + + "github.com/filecoin-project/lotus/chain/actors/builtin" ) type powerActorInfo struct { @@ -22,10 +20,7 @@ type powerActorInfo struct { totalQualityAdjustedBytesCommitted big.Int totalPledgeCollateral big.Int - newRawBytes big.Int - newQualityAdjustedBytes big.Int - newPledgeCollateral big.Int - newQAPowerSmoothed *smoothing.FilterEstimate + qaPowerSmoothed builtin.FilterEstimate minerCount int64 minerCountAboveMinimumPower int64 @@ -44,10 +39,6 @@ create table if not exists chain_power constraint power_smoothing_estimates_pk primary key, - new_raw_bytes_power text not null, - new_qa_bytes_power text not null, - new_pledge_collateral text not null, - total_raw_bytes_power text not null, total_raw_bytes_committed text not null, total_qa_bytes_power text not null, @@ -92,35 +83,50 @@ func (p *Processor) processPowerActors(ctx context.Context, powerTips ActorTips) var pw powerActorInfo pw.common = act - powerActor, err := p.node.StateGetActor(ctx, builtin.StoragePowerActorAddr, tipset) + powerActorState, err := getPowerActorState(ctx, p.node, tipset) if err != nil { return nil, xerrors.Errorf("get power state (@ %s): %w", pw.common.stateroot.String(), err) } - powerStateRaw, err := p.node.ChainReadObj(ctx, powerActor.Head) + totalPower, err := powerActorState.TotalPower() if err != nil { - return nil, xerrors.Errorf("read state obj (@ %s): %w", pw.common.stateroot.String(), err) + return nil, xerrors.Errorf("failed to compute total power: %w", err) } - var powerActorState power.State - if err := powerActorState.UnmarshalCBOR(bytes.NewReader(powerStateRaw)); err != nil { - return nil, xerrors.Errorf("unmarshal state (@ %s): %w", pw.common.stateroot.String(), err) + totalCommitted, err := powerActorState.TotalCommitted() + if err != nil { + return nil, xerrors.Errorf("failed to compute total committed: %w", err) } - pw.totalRawBytes = powerActorState.TotalRawBytePower - pw.totalRawBytesCommitted = powerActorState.TotalBytesCommitted - pw.totalQualityAdjustedBytes = powerActorState.TotalQualityAdjPower - pw.totalQualityAdjustedBytesCommitted = powerActorState.TotalQABytesCommitted - pw.totalPledgeCollateral = powerActorState.TotalPledgeCollateral + totalLocked, err := powerActorState.TotalLocked() + if err != nil { + return nil, xerrors.Errorf("failed to compute total locked: %w", err) + } - pw.newRawBytes = powerActorState.ThisEpochRawBytePower - pw.newQualityAdjustedBytes = powerActorState.ThisEpochQualityAdjPower - pw.newPledgeCollateral = powerActorState.ThisEpochPledgeCollateral - pw.newQAPowerSmoothed = powerActorState.ThisEpochQAPowerSmoothed + powerSmoothed, err := powerActorState.TotalPowerSmoothed() + if err != nil { + return nil, xerrors.Errorf("failed to determine smoothed power: %w", err) + } - pw.minerCount = powerActorState.MinerCount - pw.minerCountAboveMinimumPower = powerActorState.MinerAboveMinPowerCount - out = append(out, pw) + // NOTE: this doesn't set new* fields. Previously, we + // filled these using ThisEpoch* fields from the actor + // state, but these fields are effectively internal + // state and don't represent "new" power, as was + // assumed. + + participatingMiners, totalMiners, err := powerActorState.MinerCounts() + if err != nil { + return nil, xerrors.Errorf("failed to count miners: %w", err) + } + + pw.totalRawBytes = totalPower.RawBytePower + pw.totalQualityAdjustedBytes = totalPower.QualityAdjPower + pw.totalRawBytesCommitted = totalCommitted.RawBytePower + pw.totalQualityAdjustedBytesCommitted = totalCommitted.QualityAdjPower + pw.totalPledgeCollateral = totalLocked + pw.qaPowerSmoothed = powerSmoothed + pw.minerCountAboveMinimumPower = int64(participatingMiners) + pw.minerCount = int64(totalMiners) } } @@ -142,7 +148,7 @@ func (p *Processor) storePowerSmoothingEstimates(powerStates []powerActorInfo) e return xerrors.Errorf("prep chain_power: %w", err) } - stmt, err := tx.Prepare(`copy cp (state_root, new_raw_bytes_power, new_qa_bytes_power, new_pledge_collateral, total_raw_bytes_power, total_raw_bytes_committed, total_qa_bytes_power, total_qa_bytes_committed, total_pledge_collateral, qa_smoothed_position_estimate, qa_smoothed_velocity_estimate, miner_count, minimum_consensus_miner_count) from stdin;`) + stmt, err := tx.Prepare(`copy cp (state_root, total_raw_bytes_power, total_raw_bytes_committed, total_qa_bytes_power, total_qa_bytes_committed, total_pledge_collateral, qa_smoothed_position_estimate, qa_smoothed_velocity_estimate, miner_count, minimum_consensus_miner_count) from stdin;`) if err != nil { return xerrors.Errorf("prepare tmp chain_power: %w", err) } @@ -150,9 +156,6 @@ func (p *Processor) storePowerSmoothingEstimates(powerStates []powerActorInfo) e for _, ps := range powerStates { if _, err := stmt.Exec( ps.common.stateroot.String(), - ps.newRawBytes.String(), - ps.newQualityAdjustedBytes.String(), - ps.newPledgeCollateral.String(), ps.totalRawBytes.String(), ps.totalRawBytesCommitted.String(), @@ -160,8 +163,8 @@ func (p *Processor) storePowerSmoothingEstimates(powerStates []powerActorInfo) e ps.totalQualityAdjustedBytesCommitted.String(), ps.totalPledgeCollateral.String(), - ps.newQAPowerSmoothed.PositionEstimate.String(), - ps.newQAPowerSmoothed.VelocityEstimate.String(), + ps.qaPowerSmoothed.PositionEstimate.String(), + ps.qaPowerSmoothed.VelocityEstimate.String(), ps.minerCount, ps.minerCountAboveMinimumPower, diff --git a/cmd/lotus-chainwatch/processor/reward.go b/cmd/lotus-chainwatch/processor/reward.go index 5bdb478df..72a329c87 100644 --- a/cmd/lotus-chainwatch/processor/reward.go +++ b/cmd/lotus-chainwatch/processor/reward.go @@ -1,18 +1,19 @@ package processor import ( - "bytes" "context" "time" "golang.org/x/xerrors" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/reward" - "github.com/filecoin-project/specs-actors/actors/util/smoothing" + "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/actors/builtin/reward" "github.com/filecoin-project/lotus/chain/types" + + cw_util "github.com/filecoin-project/lotus/cmd/lotus-chainwatch/util" ) type rewardActorInfo struct { @@ -21,16 +22,61 @@ type rewardActorInfo struct { cumSumBaselinePower big.Int cumSumRealizedPower big.Int - effectiveNetworkTime int64 + effectiveNetworkTime abi.ChainEpoch effectiveBaselinePower big.Int + // NOTE: These variables are wrong. Talk to @ZX about fixing. These _do + // not_ represent "new" anything. newBaselinePower big.Int newBaseReward big.Int - newSmoothingEstimate *smoothing.FilterEstimate + newSmoothingEstimate builtin.FilterEstimate totalMinedReward big.Int } +func (rw *rewardActorInfo) set(s reward.State) (err error) { + rw.cumSumBaselinePower, err = s.CumsumBaseline() + if err != nil { + return xerrors.Errorf("getting cumsum baseline power (@ %s): %w", rw.common.stateroot.String(), err) + } + + rw.cumSumRealizedPower, err = s.CumsumRealized() + if err != nil { + return xerrors.Errorf("getting cumsum realized power (@ %s): %w", rw.common.stateroot.String(), err) + } + + rw.effectiveNetworkTime, err = s.EffectiveNetworkTime() + if err != nil { + return xerrors.Errorf("getting effective network time (@ %s): %w", rw.common.stateroot.String(), err) + } + + rw.effectiveBaselinePower, err = s.EffectiveBaselinePower() + if err != nil { + return xerrors.Errorf("getting effective baseline power (@ %s): %w", rw.common.stateroot.String(), err) + } + + rw.totalMinedReward, err = s.TotalStoragePowerReward() + if err != nil { + return xerrors.Errorf("getting total mined (@ %s): %w", rw.common.stateroot.String(), err) + } + + rw.newBaselinePower, err = s.ThisEpochBaselinePower() + if err != nil { + return xerrors.Errorf("getting this epoch baseline power (@ %s): %w", rw.common.stateroot.String(), err) + } + + rw.newBaseReward, err = s.ThisEpochReward() + if err != nil { + return xerrors.Errorf("getting this epoch baseline power (@ %s): %w", rw.common.stateroot.String(), err) + } + + rw.newSmoothingEstimate, err = s.ThisEpochRewardSmoothed() + if err != nil { + return xerrors.Errorf("getting this epoch baseline power (@ %s): %w", rw.common.stateroot.String(), err) + } + return nil +} + func (p *Processor) setupRewards() error { tx, err := p.db.Begin() if err != nil { @@ -89,29 +135,19 @@ func (p *Processor) processRewardActors(ctx context.Context, rewardTips ActorTip rw.common = act // get reward actor states at each tipset once for all updates - rewardActor, err := p.node.StateGetActor(ctx, builtin.RewardActorAddr, tipset) + rewardActor, err := p.node.StateGetActor(ctx, reward.Address, tipset) if err != nil { return nil, xerrors.Errorf("get reward state (@ %s): %w", rw.common.stateroot.String(), err) } - rewardStateRaw, err := p.node.ChainReadObj(ctx, rewardActor.Head) + rewardActorState, err := reward.Load(cw_util.NewAPIIpldStore(ctx, p.node), rewardActor) if err != nil { return nil, xerrors.Errorf("read state obj (@ %s): %w", rw.common.stateroot.String(), err) } - - var rewardActorState reward.State - if err := rewardActorState.UnmarshalCBOR(bytes.NewReader(rewardStateRaw)); err != nil { - return nil, xerrors.Errorf("unmarshal state (@ %s): %w", rw.common.stateroot.String(), err) + if err := rw.set(rewardActorState); err != nil { + return nil, err } - rw.cumSumBaselinePower = rewardActorState.CumsumBaseline - rw.cumSumRealizedPower = rewardActorState.CumsumRealized - rw.effectiveNetworkTime = int64(rewardActorState.EffectiveNetworkTime) - rw.effectiveBaselinePower = rewardActorState.EffectiveBaselinePower - rw.newBaselinePower = rewardActorState.ThisEpochBaselinePower - rw.newBaseReward = rewardActorState.ThisEpochReward - rw.newSmoothingEstimate = rewardActorState.ThisEpochRewardSmoothed - rw.totalMinedReward = rewardActorState.TotalMined out = append(out, rw) } } @@ -126,29 +162,19 @@ func (p *Processor) processRewardActors(ctx context.Context, rewardTips ActorTip rw.common.stateroot = tipset.ParentState() rw.common.parentTsKey = tipset.Parents() // get reward actor states at each tipset once for all updates - rewardActor, err := p.node.StateGetActor(ctx, builtin.RewardActorAddr, tsKey) + rewardActor, err := p.node.StateGetActor(ctx, reward.Address, tsKey) if err != nil { return nil, err } - rewardStateRaw, err := p.node.ChainReadObj(ctx, rewardActor.Head) + rewardActorState, err := reward.Load(cw_util.NewAPIIpldStore(ctx, p.node), rewardActor) if err != nil { - return nil, err + return nil, xerrors.Errorf("read state obj (@ %s): %w", rw.common.stateroot.String(), err) } - var rewardActorState reward.State - if err := rewardActorState.UnmarshalCBOR(bytes.NewReader(rewardStateRaw)); err != nil { + if err := rw.set(rewardActorState); err != nil { return nil, err } - - rw.cumSumBaselinePower = rewardActorState.CumsumBaseline - rw.cumSumRealizedPower = rewardActorState.CumsumRealized - rw.effectiveNetworkTime = int64(rewardActorState.EffectiveNetworkTime) - rw.effectiveBaselinePower = rewardActorState.EffectiveBaselinePower - rw.newBaselinePower = rewardActorState.ThisEpochBaselinePower - rw.newBaseReward = rewardActorState.ThisEpochReward - rw.newSmoothingEstimate = rewardActorState.ThisEpochRewardSmoothed - rw.totalMinedReward = rewardActorState.TotalMined out = append(out, rw) } @@ -180,7 +206,7 @@ func (p *Processor) persistRewardActors(ctx context.Context, rewards []rewardAct rewardState.common.stateroot.String(), rewardState.cumSumBaselinePower.String(), rewardState.cumSumRealizedPower.String(), - rewardState.effectiveNetworkTime, + uint64(rewardState.effectiveNetworkTime), rewardState.effectiveBaselinePower.String(), rewardState.newBaselinePower.String(), rewardState.newBaseReward.String(), diff --git a/cmd/lotus-pcr/main.go b/cmd/lotus-pcr/main.go index dc12693ca..36961a663 100644 --- a/cmd/lotus-pcr/main.go +++ b/cmd/lotus-pcr/main.go @@ -12,6 +12,11 @@ import ( "strconv" "time" + "github.com/filecoin-project/specs-actors/actors/builtin" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + + "github.com/filecoin-project/go-state-types/network" + "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" @@ -23,12 +28,11 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/exitcode" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/tools/stats" ) @@ -321,6 +325,7 @@ type refunderNodeApi interface { StateMinerInitialPledgeCollateral(ctx context.Context, addr address.Address, precommitInfo miner.SectorPreCommitInfo, tsk types.TipSetKey) (types.BigInt, error) StateSectorPreCommitInfo(ctx context.Context, addr address.Address, sector abi.SectorNumber, tsk types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) + StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (network.Version, error) MpoolPushMessage(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec) (*types.SignedMessage, error) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) WalletBalance(ctx context.Context, addr address.Address) (types.BigInt, error) @@ -370,7 +375,7 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refu continue } - if a.Code != builtin.StorageMinerActorCodeID { + if !a.IsStorageMinerActor() { continue } @@ -389,33 +394,37 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refu continue } - var proveCommitSector miner.ProveCommitSectorParams + var sn abi.SectorNumber + + var proveCommitSector miner0.ProveCommitSectorParams if err := proveCommitSector.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil { log.Warnw("failed to decode provecommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To) continue } + sn = proveCommitSector.SectorNumber + // We use the parent tipset key because precommit information is removed when ProveCommitSector is executed - precommitChainInfo, err := r.api.StateSectorPreCommitInfo(ctx, m.To, proveCommitSector.SectorNumber, tipset.Parents()) + precommitChainInfo, err := r.api.StateSectorPreCommitInfo(ctx, m.To, sn, tipset.Parents()) if err != nil { - log.Warnw("failed to get precommit info for sector", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", proveCommitSector.SectorNumber) + log.Warnw("failed to get precommit info for sector", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn) continue } precommitTipset, err := r.api.ChainGetTipSetByHeight(ctx, precommitChainInfo.PreCommitEpoch, tipset.Key()) if err != nil { - log.Warnf("failed to lookup precommit epoch", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", proveCommitSector.SectorNumber) + log.Warnf("failed to lookup precommit epoch", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn) continue } collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitChainInfo.Info, precommitTipset.Key()) if err != nil { - log.Warnw("failed to get initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", proveCommitSector.SectorNumber) + log.Warnw("failed to get initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn) } collateral = big.Sub(collateral, precommitChainInfo.PreCommitDeposit) if collateral.LessThan(big.Zero()) { - log.Debugw("skipping zero pledge collateral difference", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", proveCommitSector.SectorNumber) + log.Debugw("skipping zero pledge collateral difference", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn) continue } diff --git a/cmd/lotus-shed/balances.go b/cmd/lotus-shed/balances.go index aad321783..c156de931 100644 --- a/cmd/lotus-shed/balances.go +++ b/cmd/lotus-shed/balances.go @@ -12,6 +12,8 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/store" @@ -21,9 +23,6 @@ import ( "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" "github.com/filecoin-project/lotus/lib/blockstore" "github.com/filecoin-project/lotus/node/repo" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/util/adt" ) type accountInfo struct { @@ -90,7 +89,7 @@ var chainBalanceCmd = &cli.Command{ Type: string(act.Code.Hash()[2:]), } - if act.Code == builtin.StorageMinerActorCodeID { + if act.IsStorageMinerActor() { pow, err := api.StateMinerPower(ctx, addr, tsk) if err != nil { return xerrors.Errorf("failed to get power: %w", err) @@ -167,6 +166,7 @@ var chainBalanceStateCmd = &cli.Command{ cs := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier)) cst := cbor.NewCborStore(bs) + store := adt.WrapStore(ctx, cst) sm := stmgr.NewStateManager(cs) @@ -190,32 +190,37 @@ var chainBalanceStateCmd = &cli.Command{ PreCommits: types.FIL(big.NewInt(0)), } - if act.Code == builtin.StorageMinerActorCodeID && minerInfo { - pow, _, err := stmgr.GetPowerRaw(ctx, sm, sroot, addr) + if minerInfo && act.IsStorageMinerActor() { + pow, _, _, err := stmgr.GetPowerRaw(ctx, sm, sroot, addr) if err != nil { return xerrors.Errorf("failed to get power: %w", err) } ai.Power = pow.RawBytePower - var st miner.State - if err := cst.Get(ctx, act.Head, &st); err != nil { + st, err := miner.Load(store, act) + if err != nil { return xerrors.Errorf("failed to read miner state: %w", err) } - sectors, err := adt.AsArray(cs.Store(ctx), st.Sectors) + liveSectorCount, err := st.NumLiveSectors() if err != nil { - return xerrors.Errorf("failed to load sector set: %w", err) + return xerrors.Errorf("failed to compute live sector count: %w", err) } - ai.InitialPledge = types.FIL(st.InitialPledgeRequirement) - ai.LockedFunds = types.FIL(st.LockedFunds) - ai.PreCommits = types.FIL(st.PreCommitDeposits) - ai.Sectors = sectors.Length() + lockedFunds, err := st.LockedFunds() + if err != nil { + return xerrors.Errorf("failed to compute locked funds: %w", err) + } - var minfo miner.MinerInfo - if err := cst.Get(ctx, st.Info, &minfo); err != nil { - return xerrors.Errorf("failed to read miner info: %w", err) + ai.InitialPledge = types.FIL(lockedFunds.InitialPledgeRequirement) + ai.LockedFunds = types.FIL(lockedFunds.VestingFunds) + ai.PreCommits = types.FIL(lockedFunds.PreCommitDeposits) + ai.Sectors = liveSectorCount + + minfo, err := st.Info() + if err != nil { + return xerrors.Errorf("failed to get miner info: %w", err) } ai.Worker = minfo.Worker diff --git a/cmd/lotus-shed/bitfield.go b/cmd/lotus-shed/bitfield.go index 79ce214ee..442cbef48 100644 --- a/cmd/lotus-shed/bitfield.go +++ b/cmd/lotus-shed/bitfield.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "encoding/hex" "fmt" + "io" "io/ioutil" "os" @@ -28,6 +29,9 @@ var bitFieldCmd = &cli.Command{ bitFieldRunsCmd, bitFieldStatCmd, bitFieldDecodeCmd, + bitFieldIntersectCmd, + bitFieldEncodeCmd, + bitFieldSubCmd, }, } @@ -200,38 +204,9 @@ var bitFieldDecodeCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { - var val string - if cctx.Args().Present() { - val = cctx.Args().Get(0) - } else { - b, err := ioutil.ReadAll(os.Stdin) - if err != nil { - return err - } - val = string(b) - } - - var dec []byte - switch cctx.String("enc") { - case "base64": - d, err := base64.StdEncoding.DecodeString(val) - if err != nil { - return fmt.Errorf("decoding base64 value: %w", err) - } - dec = d - case "hex": - d, err := hex.DecodeString(val) - if err != nil { - return fmt.Errorf("decoding hex value: %w", err) - } - dec = d - default: - return fmt.Errorf("unrecognized encoding: %s", cctx.String("enc")) - } - - rle, err := bitfield.NewFromBytes(dec) + rle, err := decode(cctx, 0) if err != nil { - return xerrors.Errorf("failed to parse bitfield: %w", err) + return err } vals, err := rle.All(100000000000) @@ -243,3 +218,170 @@ var bitFieldDecodeCmd = &cli.Command{ return nil }, } + +var bitFieldIntersectCmd = &cli.Command{ + Name: "intersect", + Description: "intersect 2 bitfields and print the resulting bitfield as base64", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "enc", + Value: "base64", + Usage: "specify input encoding to parse", + }, + }, + Action: func(cctx *cli.Context) error { + b, err := decode(cctx, 1) + if err != nil { + return err + } + + a, err := decode(cctx, 0) + if err != nil { + return err + } + + o, err := bitfield.IntersectBitField(a, b) + if err != nil { + return xerrors.Errorf("intersect: %w", err) + } + + s, err := o.RunIterator() + if err != nil { + return err + } + + bytes, err := rlepluslazy.EncodeRuns(s, []byte{}) + if err != nil { + return err + } + + fmt.Println(base64.StdEncoding.EncodeToString(bytes)) + + return nil + }, +} + +var bitFieldSubCmd = &cli.Command{ + Name: "sub", + Description: "subtract 2 bitfields and print the resulting bitfield as base64", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "enc", + Value: "base64", + Usage: "specify input encoding to parse", + }, + }, + Action: func(cctx *cli.Context) error { + b, err := decode(cctx, 1) + if err != nil { + return err + } + + a, err := decode(cctx, 0) + if err != nil { + return err + } + + o, err := bitfield.SubtractBitField(a, b) + if err != nil { + return xerrors.Errorf("intersect: %w", err) + } + + s, err := o.RunIterator() + if err != nil { + return err + } + + bytes, err := rlepluslazy.EncodeRuns(s, []byte{}) + if err != nil { + return err + } + + fmt.Println(base64.StdEncoding.EncodeToString(bytes)) + + return nil + }, +} + +var bitFieldEncodeCmd = &cli.Command{ + Name: "encode", + Description: "encode a series of decimal numbers into a bitfield", + ArgsUsage: "[infile]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "enc", + Value: "base64", + Usage: "specify input encoding to parse", + }, + }, + Action: func(cctx *cli.Context) error { + f, err := os.Open(cctx.Args().First()) + if err != nil { + return err + } + defer f.Close() // nolint + + out := bitfield.New() + for { + var i uint64 + _, err := fmt.Fscan(f, &i) + if err == io.EOF { + break + } + out.Set(i) + } + + s, err := out.RunIterator() + if err != nil { + return err + } + + bytes, err := rlepluslazy.EncodeRuns(s, []byte{}) + if err != nil { + return err + } + + fmt.Println(base64.StdEncoding.EncodeToString(bytes)) + + return nil + }, +} + +func decode(cctx *cli.Context, a int) (bitfield.BitField, error) { + var val string + if cctx.Args().Present() { + if a >= cctx.NArg() { + return bitfield.BitField{}, xerrors.Errorf("need more than %d args", a) + } + val = cctx.Args().Get(a) + } else { + if a > 0 { + return bitfield.BitField{}, xerrors.Errorf("need more than %d args", a) + } + b, err := ioutil.ReadAll(os.Stdin) + if err != nil { + return bitfield.BitField{}, err + } + val = string(b) + } + + var dec []byte + switch cctx.String("enc") { + case "base64": + d, err := base64.StdEncoding.DecodeString(val) + if err != nil { + return bitfield.BitField{}, fmt.Errorf("decoding base64 value: %w", err) + } + dec = d + case "hex": + d, err := hex.DecodeString(val) + if err != nil { + return bitfield.BitField{}, fmt.Errorf("decoding hex value: %w", err) + } + dec = d + default: + return bitfield.BitField{}, fmt.Errorf("unrecognized encoding: %s", cctx.String("enc")) + } + + return bitfield.NewFromBytes(dec) +} diff --git a/cmd/lotus-shed/consensus.go b/cmd/lotus-shed/consensus.go new file mode 100644 index 000000000..59d9555df --- /dev/null +++ b/cmd/lotus-shed/consensus.go @@ -0,0 +1,286 @@ +package main + +import ( + "bufio" + "fmt" + "io" + "os" + "strconv" + "strings" + "time" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/client" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/multiformats/go-multiaddr" + "github.com/urfave/cli/v2" +) + +var consensusCmd = &cli.Command{ + Name: "consensus", + Usage: "tools for gathering information about consensus between nodes", + Flags: []cli.Flag{}, + Subcommands: []*cli.Command{ + consensusCheckCmd, + }, +} + +type consensusItem struct { + multiaddr multiaddr.Multiaddr + genesisTipset *types.TipSet + targetTipset *types.TipSet + headTipset *types.TipSet + peerID peer.ID + version api.Version + api api.FullNode +} + +var consensusCheckCmd = &cli.Command{ + Name: "check", + Usage: "verify if all nodes agree upon a common tipset for a given tipset height", + Description: `Consensus check verifies that all nodes share a common tipset for a given + height. + + The height flag specifies a chain height to start a comparison from. There are two special + arguments for this flag. All other expected values should be chain tipset heights. + + @common - Use the maximum common chain height between all nodes + @expected - Use the current time and the genesis timestamp to determine a height + + Examples + + Find the highest common tipset and look back 10 tipsets + lotus-shed consensus check --height @common --lookback 10 + + Calculate the expected tipset height and look back 10 tipsets + lotus-shed consensus check --height @expected --lookback 10 + + Check if nodes all share a common genesis + lotus-shed consensus check --height 0 + + Check that all nodes agree upon the tipset for 1day post genesis + lotus-shed consensus check --height 2880 --lookback 0 + `, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "height", + Value: "@common", + Usage: "height of tipset to start check from", + }, + &cli.IntFlag{ + Name: "lookback", + Value: int(build.MessageConfidence * 2), + Usage: "number of tipsets behind to look back when comparing nodes", + }, + }, + Action: func(cctx *cli.Context) error { + filePath := cctx.Args().First() + + var input *bufio.Reader + if cctx.Args().Len() == 0 { + input = bufio.NewReader(os.Stdin) + } else { + var err error + inputFile, err := os.Open(filePath) + if err != nil { + return err + } + defer inputFile.Close() //nolint:errcheck + input = bufio.NewReader(inputFile) + } + + var nodes []*consensusItem + ctx := lcli.ReqContext(cctx) + + for { + strma, errR := input.ReadString('\n') + strma = strings.TrimSpace(strma) + + if len(strma) == 0 { + if errR == io.EOF { + break + } + continue + } + + apima, err := multiaddr.NewMultiaddr(strma) + if err != nil { + return err + } + ainfo := lcli.APIInfo{Addr: apima} + addr, err := ainfo.DialArgs() + if err != nil { + return err + } + + api, closer, err := client.NewFullNodeRPC(cctx.Context, addr, nil) + if err != nil { + return err + } + defer closer() + + peerID, err := api.ID(ctx) + if err != nil { + return err + } + + version, err := api.Version(ctx) + if err != nil { + return err + } + + genesisTipset, err := api.ChainGetGenesis(ctx) + if err != nil { + return err + } + + headTipset, err := api.ChainHead(ctx) + if err != nil { + return err + } + + nodes = append(nodes, &consensusItem{ + genesisTipset: genesisTipset, + headTipset: headTipset, + multiaddr: apima, + api: api, + peerID: peerID, + version: version, + }) + + if errR != nil && errR != io.EOF { + return err + } + + if errR == io.EOF { + break + } + } + + if len(nodes) == 0 { + return fmt.Errorf("no nodes") + } + + genesisBuckets := make(map[types.TipSetKey][]*consensusItem) + for _, node := range nodes { + genesisBuckets[node.genesisTipset.Key()] = append(genesisBuckets[node.genesisTipset.Key()], node) + + } + + if len(genesisBuckets) != 1 { + for _, nodes := range genesisBuckets { + for _, node := range nodes { + log.Errorw( + "genesis do not match", + "genesis_tipset", node.genesisTipset.Key(), + "peer_id", node.peerID, + "version", node.version, + ) + } + } + + return fmt.Errorf("genesis does not match between all nodes") + } + + target := abi.ChainEpoch(0) + + switch cctx.String("height") { + case "@common": + minTipset := nodes[0].headTipset + for _, node := range nodes { + if node.headTipset.Height() < minTipset.Height() { + minTipset = node.headTipset + } + } + + target = minTipset.Height() + case "@expected": + tnow := uint64(time.Now().Unix()) + tgen := nodes[0].genesisTipset.MinTimestamp() + + target = abi.ChainEpoch((tnow - tgen) / build.BlockDelaySecs) + default: + h, err := strconv.Atoi(strings.TrimSpace(cctx.String("height"))) + if err != nil { + return fmt.Errorf("failed to parse string: %s", cctx.String("height")) + } + + target = abi.ChainEpoch(h) + } + + lookback := abi.ChainEpoch(cctx.Int("lookback")) + if lookback > target { + target = abi.ChainEpoch(0) + } else { + target = target - lookback + } + + for _, node := range nodes { + targetTipset, err := node.api.ChainGetTipSetByHeight(ctx, target, types.EmptyTSK) + if err != nil { + log.Errorw("error checking target", "err", err) + node.targetTipset = nil + } else { + node.targetTipset = targetTipset + } + + } + for _, node := range nodes { + log.Debugw( + "node info", + "peer_id", node.peerID, + "version", node.version, + "genesis_tipset", node.genesisTipset.Key(), + "head_tipset", node.headTipset.Key(), + "target_tipset", node.targetTipset.Key(), + ) + } + + targetBuckets := make(map[types.TipSetKey][]*consensusItem) + for _, node := range nodes { + if node.targetTipset == nil { + targetBuckets[types.EmptyTSK] = append(targetBuckets[types.EmptyTSK], node) + continue + } + + targetBuckets[node.targetTipset.Key()] = append(targetBuckets[node.targetTipset.Key()], node) + } + + if nodes, ok := targetBuckets[types.EmptyTSK]; ok { + for _, node := range nodes { + log.Errorw( + "targeted tipset not found", + "peer_id", node.peerID, + "version", node.version, + "genesis_tipset", node.genesisTipset.Key(), + "head_tipset", node.headTipset.Key(), + "target_tipset", node.targetTipset.Key(), + ) + } + + return fmt.Errorf("targeted tipset not found") + } + + if len(targetBuckets) != 1 { + for _, nodes := range targetBuckets { + for _, node := range nodes { + log.Errorw( + "targeted tipset not found", + "peer_id", node.peerID, + "version", node.version, + "genesis_tipset", node.genesisTipset.Key(), + "head_tipset", node.headTipset.Key(), + "target_tipset", node.targetTipset.Key(), + ) + } + } + return fmt.Errorf("nodes not in consensus at tipset height %d", target) + } + + return nil + }, +} diff --git a/cmd/lotus-shed/dealtracker.go b/cmd/lotus-shed/dealtracker.go new file mode 100644 index 000000000..d39f51bd1 --- /dev/null +++ b/cmd/lotus-shed/dealtracker.go @@ -0,0 +1,265 @@ +package main + +import ( + "context" + "encoding/json" + "net" + "net/http" + "os" + "strings" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/ipfs/go-cid" + "github.com/urfave/cli/v2" +) + +type dealStatsServer struct { + api api.FullNode +} + +var filteredClients map[address.Address]bool + +func init() { + fc := []string{"t0112", "t0113", "t0114", "t010089"} + + filtered, set := os.LookupEnv("FILTERED_CLIENTS") + if set { + fc = strings.Split(filtered, ":") + } + + filteredClients = make(map[address.Address]bool) + for _, a := range fc { + addr, err := address.NewFromString(a) + if err != nil { + panic(err) + } + filteredClients[addr] = true + } +} + +type dealCountResp struct { + Total int64 `json:"total"` + Epoch int64 `json:"epoch"` +} + +func (dss *dealStatsServer) handleStorageDealCount(w http.ResponseWriter, r *http.Request) { + ctx := context.Background() + + head, err := dss.api.ChainHead(ctx) + if err != nil { + log.Warnf("failed to get chain head: %s", err) + w.WriteHeader(500) + return + } + + deals, err := dss.api.StateMarketDeals(ctx, head.Key()) + if err != nil { + log.Warnf("failed to get market deals: %s", err) + w.WriteHeader(500) + return + } + + var count int64 + for _, d := range deals { + if !filteredClients[d.Proposal.Client] { + count++ + } + } + + if err := json.NewEncoder(w).Encode(&dealCountResp{ + Total: count, + Epoch: int64(head.Height()), + }); err != nil { + log.Warnf("failed to write back deal count response: %s", err) + return + } +} + +type dealAverageResp struct { + AverageSize int64 `json:"average_size"` + Epoch int64 `json:"epoch"` +} + +func (dss *dealStatsServer) handleStorageDealAverageSize(w http.ResponseWriter, r *http.Request) { + ctx := context.Background() + + head, err := dss.api.ChainHead(ctx) + if err != nil { + log.Warnf("failed to get chain head: %s", err) + w.WriteHeader(500) + return + } + + deals, err := dss.api.StateMarketDeals(ctx, head.Key()) + if err != nil { + log.Warnf("failed to get market deals: %s", err) + w.WriteHeader(500) + return + } + + var count int64 + var totalBytes int64 + for _, d := range deals { + if !filteredClients[d.Proposal.Client] { + count++ + totalBytes += int64(d.Proposal.PieceSize.Unpadded()) + } + } + + if err := json.NewEncoder(w).Encode(&dealAverageResp{ + AverageSize: totalBytes / count, + Epoch: int64(head.Height()), + }); err != nil { + log.Warnf("failed to write back deal average response: %s", err) + return + } +} + +type dealTotalResp struct { + TotalBytes int64 `json:"total_size"` + Epoch int64 `json:"epoch"` +} + +func (dss *dealStatsServer) handleStorageDealTotalReal(w http.ResponseWriter, r *http.Request) { + ctx := context.Background() + + head, err := dss.api.ChainHead(ctx) + if err != nil { + log.Warnf("failed to get chain head: %s", err) + w.WriteHeader(500) + return + } + + deals, err := dss.api.StateMarketDeals(ctx, head.Key()) + if err != nil { + log.Warnf("failed to get market deals: %s", err) + w.WriteHeader(500) + return + } + + var totalBytes int64 + for _, d := range deals { + if !filteredClients[d.Proposal.Client] { + totalBytes += int64(d.Proposal.PieceSize.Unpadded()) + } + } + + if err := json.NewEncoder(w).Encode(&dealTotalResp{ + TotalBytes: totalBytes, + Epoch: int64(head.Height()), + }); err != nil { + log.Warnf("failed to write back deal average response: %s", err) + return + } + +} + +type clientStatsOutput struct { + Client address.Address `json:"client"` + DataSize int64 `json:"data_size"` + NumCids int `json:"num_cids"` + NumDeals int `json:"num_deals"` + NumMiners int `json:"num_miners"` + + cids map[cid.Cid]bool + providers map[address.Address]bool +} + +func (dss *dealStatsServer) handleStorageClientStats(w http.ResponseWriter, r *http.Request) { + ctx := context.Background() + + head, err := dss.api.ChainHead(ctx) + if err != nil { + log.Warnf("failed to get chain head: %s", err) + w.WriteHeader(500) + return + } + + deals, err := dss.api.StateMarketDeals(ctx, head.Key()) + if err != nil { + log.Warnf("failed to get market deals: %s", err) + w.WriteHeader(500) + return + } + + stats := make(map[address.Address]*clientStatsOutput) + + for _, d := range deals { + if filteredClients[d.Proposal.Client] { + continue + } + + st, ok := stats[d.Proposal.Client] + if !ok { + st = &clientStatsOutput{ + Client: d.Proposal.Client, + cids: make(map[cid.Cid]bool), + providers: make(map[address.Address]bool), + } + stats[d.Proposal.Client] = st + } + + st.DataSize += int64(d.Proposal.PieceSize.Unpadded()) + st.cids[d.Proposal.PieceCID] = true + st.providers[d.Proposal.Provider] = true + st.NumDeals++ + } + + out := make([]*clientStatsOutput, 0, len(stats)) + for _, cso := range stats { + cso.NumCids = len(cso.cids) + cso.NumMiners = len(cso.providers) + + out = append(out, cso) + } + + if err := json.NewEncoder(w).Encode(out); err != nil { + log.Warnf("failed to write back client stats response: %s", err) + return + } +} + +var serveDealStatsCmd = &cli.Command{ + Name: "serve-deal-stats", + Flags: []cli.Flag{}, + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + + defer closer() + ctx := lcli.ReqContext(cctx) + + _ = ctx + + dss := &dealStatsServer{api} + + mux := &http.ServeMux{} + mux.HandleFunc("/api/storagedeal/count", dss.handleStorageDealCount) + mux.HandleFunc("/api/storagedeal/averagesize", dss.handleStorageDealAverageSize) + mux.HandleFunc("/api/storagedeal/totalreal", dss.handleStorageDealTotalReal) + mux.HandleFunc("/api/storagedeal/clientstats", dss.handleStorageClientStats) + + s := &http.Server{ + Addr: ":7272", + Handler: mux, + } + + go func() { + <-ctx.Done() + if err := s.Shutdown(context.TODO()); err != nil { + log.Error(err) + } + }() + + list, err := net.Listen("tcp", ":7272") // nolint + if err != nil { + panic(err) + } + + return s.Serve(list) + }, +} diff --git a/cmd/lotus-shed/genesis-verify.go b/cmd/lotus-shed/genesis-verify.go index 043cb72bb..da2c82359 100644 --- a/cmd/lotus-shed/genesis-verify.go +++ b/cmd/lotus-shed/genesis-verify.go @@ -14,16 +14,17 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin/account" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/builtin/multisig" "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/lib/blockstore" - "github.com/filecoin-project/specs-actors/actors/builtin" - saacc "github.com/filecoin-project/specs-actors/actors/builtin/account" - saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner" - samsig "github.com/filecoin-project/specs-actors/actors/builtin/multisig" ) type addrInfo struct { @@ -90,36 +91,50 @@ var genesisVerifyCmd = &cli.Command{ kminers := make(map[address.Address]minerInfo) ctx := context.TODO() + store := adt.WrapStore(ctx, cst) if err := stree.ForEach(func(addr address.Address, act *types.Actor) error { - switch act.Code { - case builtin.StorageMinerActorCodeID: - var st saminer.State - if err := cst.Get(ctx, act.Head, &st); err != nil { - return err + switch { + case act.IsStorageMinerActor(): + _, err := miner.Load(store, act) + if err != nil { + return xerrors.Errorf("miner actor: %w", err) + } + // TODO: actually verify something here? + kminers[addr] = minerInfo{} + case act.IsMultisigActor(): + st, err := multisig.Load(store, act) + if err != nil { + return xerrors.Errorf("multisig actor: %w", err) } - kminers[addr] = minerInfo{} - case builtin.MultisigActorCodeID: - var st samsig.State - if err := cst.Get(ctx, act.Head, &st); err != nil { + signers, err := st.Signers() + if err != nil { + return xerrors.Errorf("multisig actor: %w", err) + } + threshold, err := st.Threshold() + if err != nil { return xerrors.Errorf("multisig actor: %w", err) } kmultisigs[addr] = msigInfo{ Balance: types.FIL(act.Balance), - Signers: st.Signers, - Threshold: st.NumApprovalsThreshold, + Signers: signers, + Threshold: threshold, } msigAddrs = append(msigAddrs, addr) - case builtin.AccountActorCodeID: - var st saacc.State - if err := cst.Get(ctx, act.Head, &st); err != nil { - log.Warn(xerrors.Errorf("account actor %s: %w", addr, err)) + case act.IsAccountActor(): + st, err := account.Load(store, act) + if err != nil { + // TODO: magik6k: this _used_ to log instead of failing, why? + return xerrors.Errorf("account actor %s: %w", addr, err) + } + pkaddr, err := st.PubkeyAddress() + if err != nil { + return xerrors.Errorf("failed to get actor pk address %s: %w", addr, err) } - kaccounts[addr] = addrInfo{ - Key: st.Address, + Key: pkaddr, Balance: types.FIL(act.Balance.Copy()), } accAddrs = append(accAddrs, addr) diff --git a/cmd/lotus-shed/jwt.go b/cmd/lotus-shed/jwt.go index d37359f71..7fa1a18dd 100644 --- a/cmd/lotus-shed/jwt.go +++ b/cmd/lotus-shed/jwt.go @@ -1,6 +1,7 @@ package main import ( + "bufio" "crypto/rand" "encoding/hex" "encoding/json" @@ -8,10 +9,12 @@ import ( "io" "io/ioutil" "os" + "strings" "github.com/gbrlsnchs/jwt/v3" "github.com/urfave/cli/v2" + "github.com/filecoin-project/go-jsonrpc/auth" "github.com/filecoin-project/lotus/api/apistruct" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/modules" @@ -24,6 +27,102 @@ var jwtCmd = &cli.Command{ having to run the lotus daemon.`, Subcommands: []*cli.Command{ jwtNewCmd, + jwtTokenCmd, + }, +} + +var jwtTokenCmd = &cli.Command{ + Name: "token", + Usage: "create a token for a given jwt secret", + ArgsUsage: "", + Description: `The jwt tokens have four different levels of permissions that provide some ability + to control access to what methods can be invoked by the holder of the token. + + This command only works on jwt secrets that are base16 encoded files, such as those produced by the + sibling 'new' command. + `, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "output", + Value: "token", + Usage: "specify a name", + }, + &cli.BoolFlag{ + Name: "read", + Value: false, + Usage: "add read permissions to the token", + }, + &cli.BoolFlag{ + Name: "write", + Value: false, + Usage: "add write permissions to the token", + }, + &cli.BoolFlag{ + Name: "sign", + Value: false, + Usage: "add sign permissions to the token", + }, + &cli.BoolFlag{ + Name: "admin", + Value: false, + Usage: "add admin permissions to the token", + }, + }, + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return fmt.Errorf("please specify a name") + } + + inputFile, err := os.Open(cctx.Args().First()) + if err != nil { + return err + } + defer inputFile.Close() //nolint:errcheck + input := bufio.NewReader(inputFile) + + encoded, err := ioutil.ReadAll(input) + if err != nil { + return err + } + + decoded, err := hex.DecodeString(strings.TrimSpace(string(encoded))) + if err != nil { + return err + } + + var keyInfo types.KeyInfo + if err := json.Unmarshal(decoded, &keyInfo); err != nil { + return err + } + + perms := []auth.Permission{} + + if cctx.Bool("read") { + perms = append(perms, apistruct.PermRead) + } + + if cctx.Bool("write") { + perms = append(perms, apistruct.PermWrite) + } + + if cctx.Bool("sign") { + perms = append(perms, apistruct.PermSign) + } + + if cctx.Bool("admin") { + perms = append(perms, apistruct.PermAdmin) + } + + p := modules.JwtPayload{ + Allow: perms, + } + + token, err := jwt.Sign(&p, jwt.NewHS256(keyInfo.PrivateKey)) + if err != nil { + return err + } + + return ioutil.WriteFile(cctx.String("output"), token, 0600) }, } diff --git a/cmd/lotus-shed/keyinfo.go b/cmd/lotus-shed/keyinfo.go index f397bd4c7..6090b7a0f 100644 --- a/cmd/lotus-shed/keyinfo.go +++ b/cmd/lotus-shed/keyinfo.go @@ -9,16 +9,22 @@ import ( "io" "io/ioutil" "os" + "path" "strings" "text/template" "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/multiformats/go-base32" + "github.com/libp2p/go-libp2p-core/crypto" "github.com/libp2p/go-libp2p-core/peer" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" + "github.com/filecoin-project/lotus/node/modules" "github.com/filecoin-project/lotus/node/modules/lp2p" "github.com/filecoin-project/lotus/node/repo" @@ -43,6 +49,90 @@ var keyinfoCmd = &cli.Command{ keyinfoNewCmd, keyinfoInfoCmd, keyinfoImportCmd, + keyinfoVerifyCmd, + }, +} + +var keyinfoVerifyCmd = &cli.Command{ + Name: "verify", + Usage: "verify the filename of a keystore object on disk with it's contents", + Description: `Keystore objects are base32 enocded strings, with wallets being dynamically named via + the wallet address. This command can ensure that the naming of these keystore objects are correct`, + Action: func(cctx *cli.Context) error { + filePath := cctx.Args().First() + fileName := path.Base(filePath) + + inputFile, err := os.Open(filePath) + if err != nil { + return err + } + defer inputFile.Close() //nolint:errcheck + input := bufio.NewReader(inputFile) + + keyContent, err := ioutil.ReadAll(input) + if err != nil { + return err + } + + var keyInfo types.KeyInfo + if err := json.Unmarshal(keyContent, &keyInfo); err != nil { + return err + } + + switch keyInfo.Type { + case lp2p.KTLibp2pHost: + name, err := base32.RawStdEncoding.DecodeString(fileName) + if err != nil { + return xerrors.Errorf("decoding key: '%s': %w", fileName, err) + } + + if string(name) != keyInfo.Type { + return fmt.Errorf("%s of type %s is incorrect", fileName, keyInfo.Type) + } + case modules.KTJwtHmacSecret: + name, err := base32.RawStdEncoding.DecodeString(fileName) + if err != nil { + return xerrors.Errorf("decoding key: '%s': %w", fileName, err) + } + + if string(name) != modules.JWTSecretName { + return fmt.Errorf("%s of type %s is incorrect", fileName, keyInfo.Type) + } + case wallet.KTSecp256k1, wallet.KTBLS: + keystore := wallet.NewMemKeyStore() + w, err := wallet.NewWallet(keystore) + if err != nil { + return err + } + + if _, err := w.Import(&keyInfo); err != nil { + return err + } + + list, err := keystore.List() + if err != nil { + return err + } + + if len(list) != 1 { + return fmt.Errorf("Unexpected number of keys, expected 1, found %d", len(list)) + } + + name, err := base32.RawStdEncoding.DecodeString(fileName) + if err != nil { + return xerrors.Errorf("decoding key: '%s': %w", fileName, err) + } + + if string(name) != list[0] { + return fmt.Errorf("%s of type %s; file is named for %s, but key is actually %s", fileName, keyInfo.Type, string(name), list[0]) + } + + break + default: + return fmt.Errorf("Unknown keytype %s", keyInfo.Type) + } + + return nil }, } diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index cff3059b6..118b4ea72 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -35,6 +35,8 @@ func main() { mathCmd, mpoolStatsCmd, exportChainCmd, + consensusCmd, + serveDealStatsCmd, } app := &cli.App{ @@ -49,6 +51,13 @@ func main() { Hidden: true, Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME }, + &cli.StringFlag{ + Name: "log-level", + Value: "info", + }, + }, + Before: func(cctx *cli.Context) error { + return logging.SetLogLevel("lotus-shed", cctx.String("log-level")) }, } diff --git a/cmd/lotus-shed/mempool-stats.go b/cmd/lotus-shed/mempool-stats.go index b81cf2704..165c01432 100644 --- a/cmd/lotus-shed/mempool-stats.go +++ b/cmd/lotus-shed/mempool-stats.go @@ -14,11 +14,12 @@ import ( "go.opencensus.io/stats/view" "go.opencensus.io/tag" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/go-address" lapi "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" - "github.com/filecoin-project/specs-actors/actors/builtin" ) var ( @@ -121,7 +122,7 @@ var mpoolStatsCmd = &cli.Command{ return false, err } - ism := act.Code == builtin.StorageMinerActorCodeID + ism := act.IsStorageMinerActor() mcache[addr] = ism return ism, nil } @@ -143,7 +144,7 @@ var mpoolStatsCmd = &cli.Command{ seen: time.Now(), } - if u.Message.Message.Method == builtin.MethodsMiner.SubmitWindowedPoSt { + if u.Message.Message.Method == builtin0.MethodsMiner.SubmitWindowedPoSt { miner, err := isMiner(u.Message.Message.To) if err != nil { diff --git a/cmd/lotus-shed/verifreg.go b/cmd/lotus-shed/verifreg.go index 9f475261d..3e2f34f4b 100644 --- a/cmd/lotus-shed/verifreg.go +++ b/cmd/lotus-shed/verifreg.go @@ -8,13 +8,15 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" - "github.com/filecoin-project/specs-actors/actors/util/adt" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" "github.com/filecoin-project/lotus/api/apibstore" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin/verifreg" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" cbor "github.com/ipfs/go-ipld-cbor" @@ -57,7 +59,7 @@ var verifRegAddVerifierCmd = &cli.Command{ return err } - params, err := actors.SerializeParams(&verifreg.AddVerifierParams{Address: target, Allowance: allowance}) + params, err := actors.SerializeParams(&verifreg0.AddVerifierParams{Address: target, Allowance: allowance}) if err != nil { return err } @@ -70,9 +72,9 @@ var verifRegAddVerifierCmd = &cli.Command{ ctx := lcli.ReqContext(cctx) msg := &types.Message{ - To: builtin.VerifiedRegistryActorAddr, + To: verifreg.Address, From: fromk, - Method: builtin.MethodsVerifiedRegistry.AddVerifier, + Method: builtin0.MethodsVerifiedRegistry.AddVerifier, Params: params, } @@ -131,7 +133,7 @@ var verifRegVerifyClientCmd = &cli.Command{ return err } - params, err := actors.SerializeParams(&verifreg.AddVerifiedClientParams{Address: target, Allowance: allowance}) + params, err := actors.SerializeParams(&verifreg0.AddVerifiedClientParams{Address: target, Allowance: allowance}) if err != nil { return err } @@ -144,9 +146,9 @@ var verifRegVerifyClientCmd = &cli.Command{ ctx := lcli.ReqContext(cctx) msg := &types.Message{ - To: builtin.VerifiedRegistryActorAddr, + To: verifreg.Address, From: fromk, - Method: builtin.MethodsVerifiedRegistry.AddVerifiedClient, + Method: builtin0.MethodsVerifiedRegistry.AddVerifiedClient, Params: params, } @@ -181,7 +183,7 @@ var verifRegListVerifiersCmd = &cli.Command{ defer closer() ctx := lcli.ReqContext(cctx) - act, err := api.StateGetActor(ctx, builtin.VerifiedRegistryActorAddr, types.EmptyTSK) + act, err := api.StateGetActor(ctx, verifreg.Address, types.EmptyTSK) if err != nil { return err } @@ -189,31 +191,14 @@ var verifRegListVerifiersCmd = &cli.Command{ apibs := apibstore.NewAPIBlockstore(api) store := adt.WrapStore(ctx, cbor.NewCborStore(apibs)) - var st verifreg.State - if err := store.Get(ctx, act.Head, &st); err != nil { - return err - } - - vh, err := adt.AsMap(store, st.Verifiers) + st, err := verifreg.Load(store, act) if err != nil { return err } - - var dcap verifreg.DataCap - if err := vh.ForEach(&dcap, func(k string) error { - addr, err := address.NewFromBytes([]byte(k)) - if err != nil { - return err - } - - fmt.Printf("%s: %s\n", addr, dcap) - - return nil - }); err != nil { + return st.ForEachVerifier(func(addr address.Address, dcap abi.StoragePower) error { + _, err := fmt.Printf("%s: %s\n", addr, dcap) return err - } - - return nil + }) }, } @@ -228,7 +213,7 @@ var verifRegListClientsCmd = &cli.Command{ defer closer() ctx := lcli.ReqContext(cctx) - act, err := api.StateGetActor(ctx, builtin.VerifiedRegistryActorAddr, types.EmptyTSK) + act, err := api.StateGetActor(ctx, verifreg.Address, types.EmptyTSK) if err != nil { return err } @@ -236,31 +221,14 @@ var verifRegListClientsCmd = &cli.Command{ apibs := apibstore.NewAPIBlockstore(api) store := adt.WrapStore(ctx, cbor.NewCborStore(apibs)) - var st verifreg.State - if err := store.Get(ctx, act.Head, &st); err != nil { - return err - } - - vh, err := adt.AsMap(store, st.VerifiedClients) + st, err := verifreg.Load(store, act) if err != nil { return err } - - var dcap verifreg.DataCap - if err := vh.ForEach(&dcap, func(k string) error { - addr, err := address.NewFromBytes([]byte(k)) - if err != nil { - return err - } - - fmt.Printf("%s: %s\n", addr, dcap) - - return nil - }); err != nil { + return st.ForEachClient(func(addr address.Address, dcap abi.StoragePower) error { + _, err := fmt.Printf("%s: %s\n", addr, dcap) return err - } - - return nil + }) }, } @@ -318,7 +286,17 @@ var verifRegCheckVerifierCmd = &cli.Command{ defer closer() ctx := lcli.ReqContext(cctx) - act, err := api.StateGetActor(ctx, builtin.VerifiedRegistryActorAddr, types.EmptyTSK) + head, err := api.ChainHead(ctx) + if err != nil { + return err + } + + vid, err := api.StateLookupID(ctx, vaddr, head.Key()) + if err != nil { + return err + } + + act, err := api.StateGetActor(ctx, verifreg.Address, head.Key()) if err != nil { return err } @@ -326,20 +304,16 @@ var verifRegCheckVerifierCmd = &cli.Command{ apibs := apibstore.NewAPIBlockstore(api) store := adt.WrapStore(ctx, cbor.NewCborStore(apibs)) - var st verifreg.State - if err := store.Get(ctx, act.Head, &st); err != nil { - return err - } - - vh, err := adt.AsMap(store, st.Verifiers) + st, err := verifreg.Load(store, act) if err != nil { return err } - var dcap verifreg.DataCap - if found, err := vh.Get(abi.AddrKey(vaddr), &dcap); err != nil { + found, dcap, err := st.VerifierDataCap(vid) + if err != nil { return err - } else if !found { + } + if !found { return fmt.Errorf("not found") } diff --git a/cmd/lotus-storage-miner/actor.go b/cmd/lotus-storage-miner/actor.go index c84e006d7..ea21aa90d 100644 --- a/cmd/lotus-storage-miner/actor.go +++ b/cmd/lotus-storage-miner/actor.go @@ -14,8 +14,9 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/types" @@ -87,7 +88,7 @@ var actorSetAddrsCmd = &cli.Command{ return err } - params, err := actors.SerializeParams(&miner.ChangeMultiaddrsParams{NewMultiaddrs: addrs}) + params, err := actors.SerializeParams(&miner0.ChangeMultiaddrsParams{NewMultiaddrs: addrs}) if err != nil { return err } @@ -152,7 +153,7 @@ var actorSetPeeridCmd = &cli.Command{ return err } - params, err := actors.SerializeParams(&miner.ChangePeerIDParams{NewID: abi.PeerID(pid)}) + params, err := actors.SerializeParams(&miner0.ChangePeerIDParams{NewID: abi.PeerID(pid)}) if err != nil { return err } @@ -225,7 +226,7 @@ var actorWithdrawCmd = &cli.Command{ } } - params, err := actors.SerializeParams(&miner.WithdrawBalanceParams{ + params, err := actors.SerializeParams(&miner0.WithdrawBalanceParams{ AmountRequested: amount, // Default to attempting to withdraw all the extra funds in the miner actor }) if err != nil { @@ -450,7 +451,7 @@ var actorControlSet = &cli.Command{ return nil } - cwp := &miner.ChangeWorkerAddressParams{ + cwp := &miner0.ChangeWorkerAddressParams{ NewWorker: mi.Worker, NewControlAddrs: toSet, } diff --git a/cmd/lotus-storage-miner/info.go b/cmd/lotus-storage-miner/info.go index 55ef024f3..3ccfd67da 100644 --- a/cmd/lotus-storage-miner/info.go +++ b/cmd/lotus-storage-miner/info.go @@ -1,7 +1,6 @@ package main import ( - "bytes" "context" "fmt" "sort" @@ -16,13 +15,12 @@ import ( "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-state-types/abi" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/apibstore" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" "github.com/filecoin-project/lotus/lib/blockstore" @@ -55,11 +53,6 @@ func infoCmdAct(cctx *cli.Context) error { ctx := lcli.ReqContext(cctx) - head, err := api.ChainHead(ctx) - if err != nil { - return xerrors.Errorf("getting chain head: %w", err) - } - maddr, err := getActorAddress(ctx, nodeApi, cctx.String("actor")) if err != nil { return err @@ -69,15 +62,11 @@ func infoCmdAct(cctx *cli.Context) error { if err != nil { return err } - var mas miner.State - { - rmas, err := api.ChainReadObj(ctx, mact.Head) - if err != nil { - return err - } - if err := mas.UnmarshalCBOR(bytes.NewReader(rmas)); err != nil { - return err - } + + tbs := bufbstore.NewTieredBstore(apibstore.NewAPIBlockstore(api), blockstore.NewTemporary()) + mas, err := miner.Load(adt.WrapStore(ctx, cbor.NewCborStore(tbs)), mact) + if err != nil { + return err } fmt.Printf("Miner: %s\n", color.BlueString("%s", maddr)) @@ -112,31 +101,24 @@ func infoCmdAct(cctx *cli.Context) error { if err != nil { return err } - faults, err := api.StateMinerFaults(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - nfaults, err := faults.Count() - if err != nil { - return xerrors.Errorf("counting faults: %w", err) - } - - fmt.Printf("\tCommitted: %s\n", types.SizeStr(types.BigMul(types.NewInt(secCounts.Sectors), types.NewInt(uint64(mi.SectorSize))))) + proving := secCounts.Active + secCounts.Faulty + nfaults := secCounts.Faulty + fmt.Printf("\tCommitted: %s\n", types.SizeStr(types.BigMul(types.NewInt(secCounts.Live), types.NewInt(uint64(mi.SectorSize))))) if nfaults == 0 { - fmt.Printf("\tProving: %s\n", types.SizeStr(types.BigMul(types.NewInt(secCounts.Active), types.NewInt(uint64(mi.SectorSize))))) + fmt.Printf("\tProving: %s\n", types.SizeStr(types.BigMul(types.NewInt(proving), types.NewInt(uint64(mi.SectorSize))))) } else { var faultyPercentage float64 - if secCounts.Sectors != 0 { - faultyPercentage = float64(10000*nfaults/secCounts.Sectors) / 100. + if secCounts.Live != 0 { + faultyPercentage = float64(10000*nfaults/secCounts.Live) / 100. } fmt.Printf("\tProving: %s (%s Faulty, %.2f%%)\n", - types.SizeStr(types.BigMul(types.NewInt(secCounts.Sectors), types.NewInt(uint64(mi.SectorSize)))), + types.SizeStr(types.BigMul(types.NewInt(proving), types.NewInt(uint64(mi.SectorSize)))), types.SizeStr(types.BigMul(types.NewInt(nfaults), types.NewInt(uint64(mi.SectorSize)))), faultyPercentage) } - if pow.MinerPower.RawBytePower.LessThan(power.ConsensusMinerMinPower) { + if !pow.HasMinPower { fmt.Print("Below minimum power threshold, no blocks will be won") } else { expWinChance := float64(types.BigMul(qpercI, types.NewInt(build.BlocksPerEpoch)).Int64()) / 1000000 @@ -180,17 +162,21 @@ func infoCmdAct(cctx *cli.Context) error { fmt.Printf("\tActive: %d, %s (Verified: %d, %s)\n", nactiveDeals, types.SizeStr(types.NewInt(uint64(activeDealBytes))), nVerifDeals, types.SizeStr(types.NewInt(uint64(activeVerifDealBytes)))) fmt.Println() - tbs := bufbstore.NewTieredBstore(apibstore.NewAPIBlockstore(api), blockstore.NewTemporary()) - _, err = mas.UnlockVestedFunds(adt.WrapStore(ctx, cbor.NewCborStore(tbs)), head.Height()) + // NOTE: there's no need to unlock anything here. Funds only + // vest on deadline boundaries, and they're unlocked by cron. + lockedFunds, err := mas.LockedFunds() if err != nil { - return xerrors.Errorf("calculating vested funds: %w", err) + return xerrors.Errorf("getting locked funds: %w", err) + } + availBalance, err := mas.AvailableBalance(mact.Balance) + if err != nil { + return xerrors.Errorf("getting available balance: %w", err) } - fmt.Printf("Miner Balance: %s\n", color.YellowString("%s", types.FIL(mact.Balance))) - fmt.Printf("\tPreCommit: %s\n", types.FIL(mas.PreCommitDeposits)) - fmt.Printf("\tPledge: %s\n", types.FIL(mas.InitialPledgeRequirement)) - fmt.Printf("\tLocked: %s\n", types.FIL(mas.LockedFunds)) - color.Green("\tAvailable: %s", types.FIL(mas.GetAvailableBalance(mact.Balance))) + fmt.Printf("\tPreCommit: %s\n", types.FIL(lockedFunds.PreCommitDeposits)) + fmt.Printf("\tPledge: %s\n", types.FIL(lockedFunds.InitialPledgeRequirement)) + fmt.Printf("\tVesting: %s\n", types.FIL(lockedFunds.VestingFunds)) + color.Green("\tAvailable: %s", types.FIL(availBalance)) wb, err := api.WalletBalance(ctx, mi.Worker) if err != nil { return xerrors.Errorf("getting worker balance: %w", err) diff --git a/cmd/lotus-storage-miner/init.go b/cmd/lotus-storage-miner/init.go index e2a2419f3..4faf6a25b 100644 --- a/cmd/lotus-storage-miner/init.go +++ b/cmd/lotus-storage-miner/init.go @@ -31,10 +31,11 @@ import ( sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" "github.com/filecoin-project/lotus/extern/sector-storage/stores" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/market" - miner2 "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/power" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" lapi "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" @@ -372,7 +373,7 @@ func migratePreSealMeta(ctx context.Context, api lapi.FullNode, metadata string, return mds.Put(datastore.NewKey(modules.StorageCounterDSPrefix), buf[:size]) } -func findMarketDealID(ctx context.Context, api lapi.FullNode, deal market.DealProposal) (abi.DealID, error) { +func findMarketDealID(ctx context.Context, api lapi.FullNode, deal market0.DealProposal) (abi.DealID, error) { // TODO: find a better way // (this is only used by genesis miners) @@ -566,7 +567,7 @@ func configureStorageMiner(ctx context.Context, api lapi.FullNode, addr address. return xerrors.Errorf("getWorkerAddr returned bad address: %w", err) } - enc, err := actors.SerializeParams(&miner2.ChangePeerIDParams{NewID: abi.PeerID(peerid)}) + enc, err := actors.SerializeParams(&miner0.ChangePeerIDParams{NewID: abi.PeerID(peerid)}) if err != nil { return err } @@ -574,7 +575,7 @@ func configureStorageMiner(ctx context.Context, api lapi.FullNode, addr address. msg := &types.Message{ To: addr, From: mi.Worker, - Method: builtin.MethodsMiner.ChangePeerID, + Method: builtin0.MethodsMiner.ChangePeerID, Params: enc, Value: types.NewInt(0), GasPremium: gasPrice, @@ -633,7 +634,7 @@ func createStorageMiner(ctx context.Context, api lapi.FullNode, peerid peer.ID, return address.Undef, err } - params, err := actors.SerializeParams(&power.CreateMinerParams{ + params, err := actors.SerializeParams(&power0.CreateMinerParams{ Owner: owner, Worker: worker, SealProofType: spt, @@ -653,11 +654,11 @@ func createStorageMiner(ctx context.Context, api lapi.FullNode, peerid peer.ID, } createStorageMinerMsg := &types.Message{ - To: builtin.StoragePowerActorAddr, + To: builtin0.StoragePowerActorAddr, From: sender, Value: big.Zero(), - Method: builtin.MethodsPower.CreateMiner, + Method: builtin0.MethodsPower.CreateMiner, Params: params, GasLimit: 0, @@ -681,7 +682,7 @@ func createStorageMiner(ctx context.Context, api lapi.FullNode, peerid peer.ID, return address.Undef, xerrors.Errorf("create miner failed: exit code %d", mw.Receipt.ExitCode) } - var retval power.CreateMinerReturn + var retval power0.CreateMinerReturn if err := retval.UnmarshalCBOR(bytes.NewReader(mw.Receipt.Return)); err != nil { return address.Undef, err } diff --git a/cmd/lotus-storage-miner/proving.go b/cmd/lotus-storage-miner/proving.go index c828f7ef8..377b81d32 100644 --- a/cmd/lotus-storage-miner/proving.go +++ b/cmd/lotus-storage-miner/proving.go @@ -1,17 +1,18 @@ package main import ( - "bytes" "fmt" "os" + "strconv" "text/tabwriter" "github.com/fatih/color" "github.com/urfave/cli/v2" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - + "github.com/filecoin-project/lotus/api/apibstore" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" ) @@ -22,6 +23,7 @@ var provingCmd = &cli.Command{ Subcommands: []*cli.Command{ provingInfoCmd, provingDeadlinesCmd, + provingDeadlineInfoCmd, provingFaultsCmd, }, } @@ -46,54 +48,41 @@ var provingFaultsCmd = &cli.Command{ ctx := lcli.ReqContext(cctx) + stor := store.ActorStore(ctx, apibstore.NewAPIBlockstore(api)) + maddr, err := getActorAddress(ctx, nodeApi, cctx.String("actor")) if err != nil { return err } - var mas miner.State - { - mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - rmas, err := api.ChainReadObj(ctx, mact.Head) - if err != nil { - return err - } - if err := mas.UnmarshalCBOR(bytes.NewReader(rmas)); err != nil { - return err - } + mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + mas, err := miner.Load(stor, mact) + if err != nil { + return err } fmt.Printf("Miner: %s\n", color.BlueString("%s", maddr)) - head, err := api.ChainHead(ctx) - if err != nil { - return xerrors.Errorf("getting chain head: %w", err) - } - deadlines, err := api.StateMinerDeadlines(ctx, maddr, head.Key()) - if err != nil { - return xerrors.Errorf("getting miner deadlines: %w", err) - } tw := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0) _, _ = fmt.Fprintln(tw, "deadline\tpartition\tsectors") - for dlIdx := range deadlines { - partitions, err := api.StateMinerPartitions(ctx, maddr, uint64(dlIdx), types.EmptyTSK) - if err != nil { - return xerrors.Errorf("loading partitions for deadline %d: %w", dlIdx, err) - } - - for partIdx, partition := range partitions { - faulty, err := partition.Faults.All(10000000) + err = mas.ForEachDeadline(func(dlIdx uint64, dl miner.Deadline) error { + return dl.ForEachPartition(func(partIdx uint64, part miner.Partition) error { + faults, err := part.FaultySectors() if err != nil { return err } - - for _, num := range faulty { + return faults.ForEach(func(num uint64) error { _, _ = fmt.Fprintf(tw, "%d\t%d\t%d\n", dlIdx, partIdx, num) - } - } + return nil + }) + }) + }) + if err != nil { + return err } return tw.Flush() }, @@ -129,67 +118,63 @@ var provingInfoCmd = &cli.Command{ return xerrors.Errorf("getting chain head: %w", err) } + mact, err := api.StateGetActor(ctx, maddr, head.Key()) + if err != nil { + return err + } + + stor := store.ActorStore(ctx, apibstore.NewAPIBlockstore(api)) + + mas, err := miner.Load(stor, mact) + if err != nil { + return err + } + cd, err := api.StateMinerProvingDeadline(ctx, maddr, head.Key()) if err != nil { return xerrors.Errorf("getting miner info: %w", err) } - deadlines, err := api.StateMinerDeadlines(ctx, maddr, head.Key()) - if err != nil { - return xerrors.Errorf("getting miner deadlines: %w", err) - } - fmt.Printf("Miner: %s\n", color.BlueString("%s", maddr)) - var mas miner.State - { - mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - rmas, err := api.ChainReadObj(ctx, mact.Head) - if err != nil { - return err - } - if err := mas.UnmarshalCBOR(bytes.NewReader(rmas)); err != nil { - return err - } - } - - parts := map[uint64][]*miner.Partition{} - for dlIdx := range deadlines { - part, err := api.StateMinerPartitions(ctx, maddr, uint64(dlIdx), types.EmptyTSK) - if err != nil { - return xerrors.Errorf("getting miner partition: %w", err) - } - - parts[uint64(dlIdx)] = part - } - proving := uint64(0) faults := uint64(0) recovering := uint64(0) + curDeadlineSectors := uint64(0) - for _, partitions := range parts { - for _, partition := range partitions { - sc, err := partition.Sectors.Count() - if err != nil { - return xerrors.Errorf("count partition sectors: %w", err) + if err := mas.ForEachDeadline(func(dlIdx uint64, dl miner.Deadline) error { + return dl.ForEachPartition(func(partIdx uint64, part miner.Partition) error { + if bf, err := part.LiveSectors(); err != nil { + return err + } else if count, err := bf.Count(); err != nil { + return err + } else { + proving += count + if dlIdx == cd.Index { + curDeadlineSectors += count + } } - proving += sc - fc, err := partition.Faults.Count() - if err != nil { - return xerrors.Errorf("count partition faults: %w", err) + if bf, err := part.FaultySectors(); err != nil { + return err + } else if count, err := bf.Count(); err != nil { + return err + } else { + faults += count } - faults += fc - rc, err := partition.Recoveries.Count() - if err != nil { - return xerrors.Errorf("count partition recoveries: %w", err) + if bf, err := part.RecoveringSectors(); err != nil { + return err + } else if count, err := bf.Count(); err != nil { + return err + } else { + recovering += count } - recovering += rc - } + + return nil + }) + }); err != nil { + return xerrors.Errorf("walking miner deadlines and partitions: %w", err) } var faultPerc float64 @@ -199,28 +184,15 @@ var provingInfoCmd = &cli.Command{ fmt.Printf("Current Epoch: %d\n", cd.CurrentEpoch) - fmt.Printf("Proving Period Boundary: %d\n", cd.PeriodStart%miner.WPoStProvingPeriod) + fmt.Printf("Proving Period Boundary: %d\n", cd.PeriodStart%cd.WPoStProvingPeriod) fmt.Printf("Proving Period Start: %s\n", lcli.EpochTime(cd.CurrentEpoch, cd.PeriodStart)) - fmt.Printf("Next Period Start: %s\n\n", lcli.EpochTime(cd.CurrentEpoch, cd.PeriodStart+miner.WPoStProvingPeriod)) + fmt.Printf("Next Period Start: %s\n\n", lcli.EpochTime(cd.CurrentEpoch, cd.PeriodStart+cd.WPoStProvingPeriod)) fmt.Printf("Faults: %d (%.2f%%)\n", faults, faultPerc) fmt.Printf("Recovering: %d\n", recovering) fmt.Printf("Deadline Index: %d\n", cd.Index) - - if cd.Index < miner.WPoStPeriodDeadlines { - curDeadlineSectors := uint64(0) - for _, partition := range parts[cd.Index] { - sc, err := partition.Sectors.Count() - if err != nil { - return xerrors.Errorf("counting current deadline sectors: %w", err) - } - curDeadlineSectors += sc - } - - fmt.Printf("Deadline Sectors: %d\n", curDeadlineSectors) - } - + fmt.Printf("Deadline Sectors: %d\n", curDeadlineSectors) fmt.Printf("Deadline Open: %s\n", lcli.EpochTime(cd.CurrentEpoch, cd.Open)) fmt.Printf("Deadline Close: %s\n", lcli.EpochTime(cd.CurrentEpoch, cd.Close)) fmt.Printf("Deadline Challenge: %s\n", lcli.EpochTime(cd.CurrentEpoch, cd.Challenge)) @@ -264,21 +236,6 @@ var provingDeadlinesCmd = &cli.Command{ return xerrors.Errorf("getting deadlines: %w", err) } - var mas miner.State - { - mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - rmas, err := api.ChainReadObj(ctx, mact.Head) - if err != nil { - return err - } - if err := mas.UnmarshalCBOR(bytes.NewReader(rmas)); err != nil { - return err - } - } - fmt.Printf("Miner: %s\n", color.BlueString("%s", maddr)) tw := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0) @@ -299,14 +256,14 @@ var provingDeadlinesCmd = &cli.Command{ faults := uint64(0) for _, partition := range partitions { - sc, err := partition.Sectors.Count() + sc, err := partition.AllSectors.Count() if err != nil { return err } sectors += sc - fc, err := partition.Faults.Count() + fc, err := partition.FaultySectors.Count() if err != nil { return err } @@ -324,3 +281,93 @@ var provingDeadlinesCmd = &cli.Command{ return tw.Flush() }, } + +var provingDeadlineInfoCmd = &cli.Command{ + Name: "deadline", + Usage: "View the current proving period deadline information by its index ", + ArgsUsage: "", + Action: func(cctx *cli.Context) error { + + if cctx.Args().Len() != 1 { + return xerrors.Errorf("must pass deadline index") + } + + dlIdx, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64) + if err != nil { + return xerrors.Errorf("could not parse deadline index: %w", err) + } + + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := getActorAddress(ctx, nodeApi, cctx.String("actor")) + if err != nil { + return err + } + + deadlines, err := api.StateMinerDeadlines(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting deadlines: %w", err) + } + + di, err := api.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting deadlines: %w", err) + } + + partitions, err := api.StateMinerPartitions(ctx, maddr, dlIdx, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting partitions for deadline %d: %w", dlIdx, err) + } + + provenPartitions, err := deadlines[dlIdx].PostSubmissions.Count() + if err != nil { + return err + } + + fmt.Printf("Deadline Index: %d\n", dlIdx) + fmt.Printf("Partitions: %d\n", len(partitions)) + fmt.Printf("Proven Partitions: %d\n", provenPartitions) + fmt.Printf("Current: %t\n\n", di.Index == dlIdx) + + for pIdx, partition := range partitions { + sectorCount, err := partition.AllSectors.Count() + if err != nil { + return err + } + + sectorNumbers, err := partition.AllSectors.All(sectorCount) + if err != nil { + return err + } + + faultsCount, err := partition.FaultySectors.Count() + if err != nil { + return err + } + + fn, err := partition.FaultySectors.All(faultsCount) + if err != nil { + return err + } + + fmt.Printf("Partition Index: %d\n", pIdx) + fmt.Printf("Sectors: %d\n", sectorCount) + fmt.Printf("Sector Numbers: %v\n", sectorNumbers) + fmt.Printf("Faults: %d\n", faultsCount) + fmt.Printf("Faulty Sectors: %d\n", fn) + } + return nil + }, +} diff --git a/cmd/lotus-storage-miner/retrieval-deals.go b/cmd/lotus-storage-miner/retrieval-deals.go index df194978d..03d397852 100644 --- a/cmd/lotus-storage-miner/retrieval-deals.go +++ b/cmd/lotus-storage-miner/retrieval-deals.go @@ -5,9 +5,12 @@ import ( "os" "text/tabwriter" + "github.com/docker/go-units" "github.com/filecoin-project/go-fil-markets/retrievalmarket" + "github.com/filecoin-project/go-state-types/abi" "github.com/urfave/cli/v2" + "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" ) @@ -17,6 +20,8 @@ var retrievalDealsCmd = &cli.Command{ Subcommands: []*cli.Command{ retrievalDealSelectionCmd, retrievalDealsListCmd, + retrievalSetAskCmd, + retrievalGetAskCmd, }, } @@ -154,3 +159,112 @@ var retrievalDealsListCmd = &cli.Command{ return w.Flush() }, } + +var retrievalSetAskCmd = &cli.Command{ + Name: "set-ask", + Usage: "Configure the provider's retrieval ask", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "price", + Usage: "Set the price of the ask for retrievals (FIL/GiB)", + }, + &cli.StringFlag{ + Name: "unseal-price", + Usage: "Set the price to unseal", + }, + &cli.StringFlag{ + Name: "payment-interval", + Usage: "Set the payment interval (in bytes) for retrieval", + DefaultText: "1MiB", + }, + &cli.StringFlag{ + Name: "payment-interval-increase", + Usage: "Set the payment interval increase (in bytes) for retrieval", + DefaultText: "1MiB", + }, + }, + Action: func(cctx *cli.Context) error { + ctx := lcli.DaemonContext(cctx) + + api, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + ask, err := api.MarketGetRetrievalAsk(ctx) + if err != nil { + return err + } + + if cctx.IsSet("price") { + v, err := types.ParseFIL(cctx.String("price")) + if err != nil { + return err + } + ask.PricePerByte = types.BigDiv(types.BigInt(v), types.NewInt(1<<30)) + } + + if cctx.IsSet("unseal-price") { + v, err := types.ParseFIL(cctx.String("unseal-price")) + if err != nil { + return err + } + ask.UnsealPrice = abi.TokenAmount(v) + } + + if cctx.IsSet("payment-interval") { + v, err := units.RAMInBytes(cctx.String("payment-interval")) + if err != nil { + return err + } + ask.PaymentInterval = uint64(v) + } + + if cctx.IsSet("payment-interval-increase") { + v, err := units.RAMInBytes(cctx.String("payment-interval-increase")) + if err != nil { + return err + } + ask.PaymentIntervalIncrease = uint64(v) + } + + return api.MarketSetRetrievalAsk(ctx, ask) + }, +} + +var retrievalGetAskCmd = &cli.Command{ + Name: "get-ask", + Usage: "Get the provider's current retrieval ask", + Flags: []cli.Flag{}, + Action: func(cctx *cli.Context) error { + ctx := lcli.DaemonContext(cctx) + + api, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + ask, err := api.MarketGetRetrievalAsk(ctx) + if err != nil { + return err + } + + w := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0) + fmt.Fprintf(w, "Price per Byte\tUnseal Price\tPayment Interval\tPayment Interval Increase\n") + if ask == nil { + fmt.Fprintf(w, "\n") + return w.Flush() + } + + fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", + types.FIL(ask.PricePerByte), + types.FIL(ask.UnsealPrice), + units.BytesSize(float64(ask.PaymentInterval)), + units.BytesSize(float64(ask.PaymentIntervalIncrease)), + ) + return w.Flush() + + }, +} diff --git a/cmd/lotus-storage-miner/run.go b/cmd/lotus-storage-miner/run.go index 83d78172e..a5d996f78 100644 --- a/cmd/lotus-storage-miner/run.go +++ b/cmd/lotus-storage-miner/run.go @@ -163,8 +163,10 @@ var runCmd = &cli.Command{ sigChan := make(chan os.Signal, 2) go func() { select { - case <-sigChan: + case sig := <-sigChan: + log.Warnw("received shutdown", "signal", sig) case <-shutdownChan: + log.Warn("received shutdown") } log.Warn("Shutting down...") diff --git a/cmd/lotus-storage-miner/sectors.go b/cmd/lotus-storage-miner/sectors.go index 06f09fe20..370962bdc 100644 --- a/cmd/lotus-storage-miner/sectors.go +++ b/cmd/lotus-storage-miner/sectors.go @@ -8,16 +8,19 @@ import ( "text/tabwriter" "time" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/urfave/cli/v2" "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/abi" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + sealing "github.com/filecoin-project/lotus/extern/storage-sealing" ) var sectorsCmd = &cli.Command{ @@ -136,6 +139,12 @@ var sectorsStatusCmd = &cli.Command{ var sectorsListCmd = &cli.Command{ Name: "list", Usage: "List sectors", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "show-removed", + Usage: "show removed sectors", + }, + }, Action: func(cctx *cli.Context) error { nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) if err != nil { @@ -167,16 +176,16 @@ var sectorsListCmd = &cli.Command{ } activeIDs := make(map[abi.SectorNumber]struct{}, len(activeSet)) for _, info := range activeSet { - activeIDs[info.ID] = struct{}{} + activeIDs[info.SectorNumber] = struct{}{} } - sset, err := fullApi.StateMinerSectors(ctx, maddr, nil, true, types.EmptyTSK) + sset, err := fullApi.StateMinerSectors(ctx, maddr, nil, types.EmptyTSK) if err != nil { return err } commitedIDs := make(map[abi.SectorNumber]struct{}, len(activeSet)) for _, info := range sset { - commitedIDs[info.ID] = struct{}{} + commitedIDs[info.SectorNumber] = struct{}{} } sort.Slice(list, func(i, j int) bool { @@ -192,19 +201,21 @@ var sectorsListCmd = &cli.Command{ continue } - _, inSSet := commitedIDs[s] - _, inASet := activeIDs[s] + if cctx.Bool("show-removed") || st.State != api.SectorState(sealing.Removed) { + _, inSSet := commitedIDs[s] + _, inASet := activeIDs[s] - fmt.Fprintf(w, "%d: %s\tsSet: %s\tactive: %s\ttktH: %d\tseedH: %d\tdeals: %v\t toUpgrade:%t\n", - s, - st.State, - yesno(inSSet), - yesno(inASet), - st.Ticket.Epoch, - st.Seed.Epoch, - st.Deals, - st.ToUpgrade, - ) + _, _ = fmt.Fprintf(w, "%d: %s\tsSet: %s\tactive: %s\ttktH: %d\tseedH: %d\tdeals: %v\t toUpgrade:%t\n", + s, + st.State, + yesno(inSSet), + yesno(inASet), + st.Ticket.Epoch, + st.Seed.Epoch, + st.Deals, + st.ToUpgrade, + ) + } } return w.Flush() @@ -379,7 +390,7 @@ var sectorsCapacityCollateralCmd = &cli.Command{ Expiration: abi.ChainEpoch(cctx.Uint64("expiration")), } if pci.Expiration == 0 { - pci.Expiration = miner.MaxSectorExpirationExtension + pci.Expiration = miner0.MaxSectorExpirationExtension } pc, err := nApi.StateMinerInitialPledgeCollateral(ctx, maddr, pci, types.EmptyTSK) if err != nil { @@ -393,8 +404,9 @@ var sectorsCapacityCollateralCmd = &cli.Command{ } var sectorsUpdateCmd = &cli.Command{ - Name: "update-state", - Usage: "ADVANCED: manually update the state of a sector, this may aid in error recovery", + Name: "update-state", + Usage: "ADVANCED: manually update the state of a sector, this may aid in error recovery", + ArgsUsage: " ", Flags: []cli.Flag{ &cli.BoolFlag{ Name: "really-do-it", @@ -420,6 +432,15 @@ var sectorsUpdateCmd = &cli.Command{ return xerrors.Errorf("could not parse sector number: %w", err) } + newState := cctx.Args().Get(1) + if _, ok := sealing.ExistSectorStateList[sealing.SectorState(newState)]; !ok { + fmt.Printf(" \"%s\" is not a valid state. Possible states for sectors are: \n", newState) + for state := range sealing.ExistSectorStateList { + fmt.Printf("%s\n", string(state)) + } + return nil + } + return nodeApi.SectorsUpdate(ctx, abi.SectorNumber(id), api.SectorState(cctx.Args().Get(1))) }, } diff --git a/cmd/lotus-storage-miner/storage.go b/cmd/lotus-storage-miner/storage.go index 71d88de6d..8a3687877 100644 --- a/cmd/lotus-storage-miner/storage.go +++ b/cmd/lotus-storage-miner/storage.go @@ -370,7 +370,7 @@ var storageFindCmd = &cli.Command{ } fmt.Printf("In %s (%s)\n", info.id, types[:len(types)-2]) - fmt.Printf("\tSealing: %t; Storage: %t\n", info.store.CanSeal, info.store.CanSeal) + fmt.Printf("\tSealing: %t; Storage: %t\n", info.store.CanSeal, info.store.CanStore) if localPath, ok := local[info.id]; ok { fmt.Printf("\tLocal (%s)\n", localPath) } else { diff --git a/cmd/lotus/rpc.go b/cmd/lotus/rpc.go index fbe05e938..9718deb3a 100644 --- a/cmd/lotus/rpc.go +++ b/cmd/lotus/rpc.go @@ -66,8 +66,10 @@ func serveRPC(a api.FullNode, stop node.StopFunc, addr multiaddr.Multiaddr, shut shutdownDone := make(chan struct{}) go func() { select { - case <-sigCh: + case sig := <-sigCh: + log.Warnw("received shutdown", "signal", sig) case <-shutdownCh: + log.Warn("received shutdown") } log.Warn("Shutting down...") diff --git a/conformance/chaos/actor.go b/conformance/chaos/actor.go index daff26694..477204374 100644 --- a/conformance/chaos/actor.go +++ b/conformance/chaos/actor.go @@ -7,8 +7,6 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/runtime" "github.com/ipfs/go-cid" - - typegen "github.com/whyrusleeping/cbor-gen" ) //go:generate go run ./gen @@ -31,10 +29,14 @@ type Actor struct{} type CallerValidationBranch int64 const ( + // CallerValidationBranchNone causes no caller validation to take place. CallerValidationBranchNone CallerValidationBranch = iota + // CallerValidationBranchTwice causes Runtime.ValidateImmediateCallerAcceptAny to be called twice. CallerValidationBranchTwice - CallerValidationBranchAddrNilSet - CallerValidationBranchTypeNilSet + // CallerValidationBranchIsAddress causes caller validation against CallerValidationArgs.Addrs. + CallerValidationBranchIsAddress + // CallerValidationBranchIsType causes caller validation against CallerValidationArgs.Types. + CallerValidationBranchIsType ) // MutateStateBranch is an enum used to select the type of state mutation to attempt. @@ -64,6 +66,9 @@ const ( // MethodAbortWith is the identifier for the method that panics optionally with // a passed exit code. MethodAbortWith + // MethodInspectRuntime is the identifier for the method that returns the + // current runtime values. + MethodInspectRuntime ) // Exports defines the methods this actor exposes publicly. @@ -77,6 +82,7 @@ func (a Actor) Exports() []interface{} { MethodSend: a.Send, MethodMutateState: a.MutateState, MethodAbortWith: a.AbortWith, + MethodInspectRuntime: a.InspectRuntime, } } @@ -119,23 +125,29 @@ func (a Actor) Constructor(_ runtime.Runtime, _ *abi.EmptyValue) *abi.EmptyValue panic("constructor should not be called; the Chaos actor is a singleton actor") } +// CallerValidationArgs are the arguments to Actor.CallerValidation. +type CallerValidationArgs struct { + Branch CallerValidationBranch + Addrs []address.Address + Types []cid.Cid +} + // CallerValidation violates VM call validation constraints. // // CallerValidationBranchNone performs no validation. // CallerValidationBranchTwice validates twice. -// CallerValidationBranchAddrNilSet validates against an empty caller -// address set. -// CallerValidationBranchTypeNilSet validates against an empty caller type set. -func (a Actor) CallerValidation(rt runtime.Runtime, branch *typegen.CborInt) *abi.EmptyValue { - switch CallerValidationBranch(*branch) { +// CallerValidationBranchIsAddress validates caller against CallerValidationArgs.Addrs. +// CallerValidationBranchIsType validates caller against CallerValidationArgs.Types. +func (a Actor) CallerValidation(rt runtime.Runtime, args *CallerValidationArgs) *abi.EmptyValue { + switch args.Branch { case CallerValidationBranchNone: case CallerValidationBranchTwice: rt.ValidateImmediateCallerAcceptAny() rt.ValidateImmediateCallerAcceptAny() - case CallerValidationBranchAddrNilSet: - rt.ValidateImmediateCallerIs() - case CallerValidationBranchTypeNilSet: - rt.ValidateImmediateCallerType() + case CallerValidationBranchIsAddress: + rt.ValidateImmediateCallerIs(args.Addrs...) + case CallerValidationBranchIsType: + rt.ValidateImmediateCallerType(args.Types...) default: panic("invalid branch passed to CallerValidation") } @@ -247,3 +259,28 @@ func (a Actor) AbortWith(rt runtime.Runtime, args *AbortWithArgs) *abi.EmptyValu } return nil } + +// InspectRuntimeReturn is the return value for the Actor.InspectRuntime method. +type InspectRuntimeReturn struct { + Caller address.Address + Receiver address.Address + ValueReceived abi.TokenAmount + CurrEpoch abi.ChainEpoch + CurrentBalance abi.TokenAmount + State State +} + +// InspectRuntime returns a copy of the serializable values available in the Runtime. +func (a Actor) InspectRuntime(rt runtime.Runtime, _ *abi.EmptyValue) *InspectRuntimeReturn { + rt.ValidateImmediateCallerAcceptAny() + var st State + rt.StateReadonly(&st) + return &InspectRuntimeReturn{ + Caller: rt.Caller(), + Receiver: rt.Receiver(), + ValueReceived: rt.ValueReceived(), + CurrEpoch: rt.CurrEpoch(), + CurrentBalance: rt.CurrentBalance(), + State: st, + } +} diff --git a/conformance/chaos/actor_test.go b/conformance/chaos/actor_test.go index 67ced2899..2061efb82 100644 --- a/conformance/chaos/actor_test.go +++ b/conformance/chaos/actor_test.go @@ -4,10 +4,13 @@ import ( "context" "testing" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/exitcode" + "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/support/mock" atesting "github.com/filecoin-project/specs-actors/support/testing" + "github.com/ipfs/go-cid" ) func TestSingleton(t *testing.T) { @@ -24,6 +27,86 @@ func TestSingleton(t *testing.T) { rt.Verify() } +func TestCallerValidationNone(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + rt.Call(a.CallerValidation, &CallerValidationArgs{Branch: CallerValidationBranchNone}) + rt.Verify() +} + +func TestCallerValidationIs(t *testing.T) { + caller := atesting.NewIDAddr(t, 100) + receiver := atesting.NewIDAddr(t, 101) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + rt.SetCaller(caller, builtin.AccountActorCodeID) + var a Actor + + caddrs := []address.Address{atesting.NewIDAddr(t, 101)} + + rt.ExpectValidateCallerAddr(caddrs...) + // FIXME: https://github.com/filecoin-project/specs-actors/pull/1155 + rt.ExpectAbort(exitcode.ErrForbidden, func() { + rt.Call(a.CallerValidation, &CallerValidationArgs{ + Branch: CallerValidationBranchIsAddress, + Addrs: caddrs, + }) + }) + rt.Verify() + + rt.ExpectValidateCallerAddr(caller) + rt.Call(a.CallerValidation, &CallerValidationArgs{ + Branch: CallerValidationBranchIsAddress, + Addrs: []address.Address{caller}, + }) + rt.Verify() +} + +func TestCallerValidationType(t *testing.T) { + caller := atesting.NewIDAddr(t, 100) + receiver := atesting.NewIDAddr(t, 101) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + rt.SetCaller(caller, builtin.AccountActorCodeID) + var a Actor + + rt.ExpectValidateCallerType(builtin.CronActorCodeID) + // FIXME: https://github.com/filecoin-project/specs-actors/pull/1155 + rt.ExpectAbort(exitcode.ErrForbidden, func() { + rt.Call(a.CallerValidation, &CallerValidationArgs{ + Branch: CallerValidationBranchIsType, + Types: []cid.Cid{builtin.CronActorCodeID}, + }) + }) + rt.Verify() + + rt.ExpectValidateCallerType(builtin.AccountActorCodeID) + rt.Call(a.CallerValidation, &CallerValidationArgs{ + Branch: CallerValidationBranchIsType, + Types: []cid.Cid{builtin.AccountActorCodeID}, + }) + rt.Verify() +} + +func TestCallerValidationInvalidBranch(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + rt.ExpectAssertionFailure("invalid branch passed to CallerValidation", func() { + rt.Call(a.CallerValidation, &CallerValidationArgs{Branch: -1}) + }) + rt.Verify() +} + func TestDeleteActor(t *testing.T) { receiver := atesting.NewIDAddr(t, 100) beneficiary := atesting.NewIDAddr(t, 101) @@ -117,6 +200,20 @@ func TestMutateStateReadonly(t *testing.T) { rt.Verify() } +func TestMutateStateInvalidBranch(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + rt.ExpectValidateCallerAny() + rt.ExpectAssertionFailure("unknown mutation type", func() { + rt.Call(a.MutateState, &MutateStateArgs{Branch: -1}) + }) + rt.Verify() +} + func TestAbortWith(t *testing.T) { receiver := atesting.NewIDAddr(t, 100) builder := mock.NewBuilder(context.Background(), receiver) @@ -151,3 +248,28 @@ func TestAbortWithUncontrolled(t *testing.T) { }) rt.Verify() } + +func TestInspectRuntime(t *testing.T) { + caller := atesting.NewIDAddr(t, 100) + receiver := atesting.NewIDAddr(t, 101) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + rt.SetCaller(caller, builtin.AccountActorCodeID) + rt.StateCreate(&State{}) + var a Actor + + rt.ExpectValidateCallerAny() + ret := rt.Call(a.InspectRuntime, abi.Empty) + rtr, ok := ret.(*InspectRuntimeReturn) + if !ok { + t.Fatal("invalid return value") + } + if rtr.Caller != caller { + t.Fatal("unexpected runtime caller") + } + if rtr.Receiver != receiver { + t.Fatal("unexpected runtime receiver") + } + rt.Verify() +} diff --git a/conformance/chaos/cbor_gen.go b/conformance/chaos/cbor_gen.go index 710b84b93..882af7026 100644 --- a/conformance/chaos/cbor_gen.go +++ b/conformance/chaos/cbor_gen.go @@ -6,8 +6,10 @@ import ( "fmt" "io" + address "github.com/filecoin-project/go-address" abi "github.com/filecoin-project/go-state-types/abi" exitcode "github.com/filecoin-project/go-state-types/exitcode" + cid "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" ) @@ -115,6 +117,163 @@ func (t *State) UnmarshalCBOR(r io.Reader) error { return nil } +var lengthBufCallerValidationArgs = []byte{131} + +func (t *CallerValidationArgs) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufCallerValidationArgs); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Branch (chaos.CallerValidationBranch) (int64) + if t.Branch >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Branch)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.Branch-1)); err != nil { + return err + } + } + + // t.Addrs ([]address.Address) (slice) + if len(t.Addrs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Addrs was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Addrs))); err != nil { + return err + } + for _, v := range t.Addrs { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + + // t.Types ([]cid.Cid) (slice) + if len(t.Types) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Types was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Types))); err != nil { + return err + } + for _, v := range t.Types { + if err := cbg.WriteCidBuf(scratch, w, v); err != nil { + return xerrors.Errorf("failed writing cid field t.Types: %w", err) + } + } + return nil +} + +func (t *CallerValidationArgs) UnmarshalCBOR(r io.Reader) error { + *t = CallerValidationArgs{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Branch (chaos.CallerValidationBranch) (int64) + { + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.Branch = CallerValidationBranch(extraI) + } + // t.Addrs ([]address.Address) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Addrs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Addrs = make([]address.Address, extra) + } + + for i := 0; i < int(extra); i++ { + + var v address.Address + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Addrs[i] = v + } + + // t.Types ([]cid.Cid) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Types: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Types = make([]cid.Cid, extra) + } + + for i := 0; i < int(extra); i++ { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("reading cid field t.Types failed: %w", err) + } + t.Types[i] = c + } + + return nil +} + var lengthBufCreateActorArgs = []byte{132} func (t *CreateActorArgs) MarshalCBOR(w io.Writer) error { @@ -730,3 +889,145 @@ func (t *AbortWithArgs) UnmarshalCBOR(r io.Reader) error { } return nil } + +var lengthBufInspectRuntimeReturn = []byte{134} + +func (t *InspectRuntimeReturn) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufInspectRuntimeReturn); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Caller (address.Address) (struct) + if err := t.Caller.MarshalCBOR(w); err != nil { + return err + } + + // t.Receiver (address.Address) (struct) + if err := t.Receiver.MarshalCBOR(w); err != nil { + return err + } + + // t.ValueReceived (big.Int) (struct) + if err := t.ValueReceived.MarshalCBOR(w); err != nil { + return err + } + + // t.CurrEpoch (abi.ChainEpoch) (int64) + if t.CurrEpoch >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.CurrEpoch)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.CurrEpoch-1)); err != nil { + return err + } + } + + // t.CurrentBalance (big.Int) (struct) + if err := t.CurrentBalance.MarshalCBOR(w); err != nil { + return err + } + + // t.State (chaos.State) (struct) + if err := t.State.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *InspectRuntimeReturn) UnmarshalCBOR(r io.Reader) error { + *t = InspectRuntimeReturn{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 6 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Caller (address.Address) (struct) + + { + + if err := t.Caller.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Caller: %w", err) + } + + } + // t.Receiver (address.Address) (struct) + + { + + if err := t.Receiver.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Receiver: %w", err) + } + + } + // t.ValueReceived (big.Int) (struct) + + { + + if err := t.ValueReceived.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.ValueReceived: %w", err) + } + + } + // t.CurrEpoch (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.CurrEpoch = abi.ChainEpoch(extraI) + } + // t.CurrentBalance (big.Int) (struct) + + { + + if err := t.CurrentBalance.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.CurrentBalance: %w", err) + } + + } + // t.State (chaos.State) (struct) + + { + + if err := t.State.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.State: %w", err) + } + + } + return nil +} diff --git a/conformance/chaos/gen/gen.go b/conformance/chaos/gen/gen.go index 97ea98dc8..ac97da99e 100644 --- a/conformance/chaos/gen/gen.go +++ b/conformance/chaos/gen/gen.go @@ -7,14 +7,16 @@ import ( ) func main() { - if err := gen.WriteTupleEncodersToFile("../cbor_gen.go", "chaos", + if err := gen.WriteTupleEncodersToFile("./cbor_gen.go", "chaos", chaos.State{}, + chaos.CallerValidationArgs{}, chaos.CreateActorArgs{}, chaos.ResolveAddressResponse{}, chaos.SendArgs{}, chaos.SendReturn{}, chaos.MutateStateArgs{}, chaos.AbortWithArgs{}, + chaos.InspectRuntimeReturn{}, ); err != nil { panic(err) } diff --git a/conformance/driver.go b/conformance/driver.go index a33637837..66b6d0f8a 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -132,7 +132,7 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, preroot cid.Cid, epoch BaseFee: BaseFee, } - lvm, err := vm.NewVM(vmOpts) + lvm, err := vm.NewVM(context.TODO(), vmOpts) if err != nil { return nil, cid.Undef, err } diff --git a/documentation/en/api-methods.md b/documentation/en/api-methods.md index 2f3164bb7..e489fcb0f 100644 --- a/documentation/en/api-methods.md +++ b/documentation/en/api-methods.md @@ -9,6 +9,7 @@ * [Beacon](#Beacon) * [BeaconGetEntry](#BeaconGetEntry) * [Chain](#Chain) + * [ChainDeleteObj](#ChainDeleteObj) * [ChainExport](#ChainExport) * [ChainGetBlock](#ChainGetBlock) * [ChainGetBlockMessages](#ChainGetBlockMessages) @@ -150,6 +151,7 @@ * [StateMinerSectors](#StateMinerSectors) * [StateMsgGasCost](#StateMsgGasCost) * [StateNetworkName](#StateNetworkName) + * [StateNetworkVersion](#StateNetworkVersion) * [StateReadState](#StateReadState) * [StateReplay](#StateReplay) * [StateSearchMsg](#StateSearchMsg) @@ -212,7 +214,7 @@ Response: ```json { "Version": "string value", - "APIVersion": 3584, + "APIVersion": 4096, "BlockDelay": 42 } ``` @@ -280,6 +282,23 @@ The Chain method group contains methods for interacting with the blockchain, but that do not require any form of state computation. +### ChainDeleteObj +ChainDeleteObj deletes node referenced by the given CID + + +Perms: admin + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: `{}` + ### ChainExport ChainExport returns a stream of bytes with CAR dump of chain data. The exported chain data includes the header chain from the given tipset @@ -3516,7 +3535,7 @@ Inputs: Response: `"0"` ### StateMinerPartitions -StateMinerPartitions loads miner partitions for the specified miner/deadline +StateMinerPartitions returns all partitions in the specified deadline Perms: read @@ -3570,7 +3589,8 @@ Response: "TotalPower": { "RawBytePower": "0", "QualityAdjPower": "0" - } + }, + "HasMinPower": true } ``` @@ -3704,15 +3724,14 @@ Inputs: Response: ```json { - "Sectors": 42, - "Active": 42 + "Live": 42, + "Active": 42, + "Faulty": 42 } ``` ### StateMinerSectors StateMinerSectors returns info about the given miner's sectors. If the filter bitfield is nil, all sectors are included. -If the filterOut boolean is set to true, any sectors in the filter are excluded. -If false, only those sectors in the filter are included. Perms: read @@ -3724,7 +3743,6 @@ Inputs: [ 0 ], - true, [ { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" @@ -3787,6 +3805,28 @@ Inputs: `null` Response: `"lotus"` +### StateNetworkVersion +StateNetworkVersion returns the network version at the given tipset + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `2` + ### StateReadState StateReadState returns the indicated actor's state. @@ -4263,7 +4303,8 @@ Inputs: `null` Response: ```json { - "ActiveSyncs": null + "ActiveSyncs": null, + "VMApplied": 42 } ``` diff --git a/extern/oni b/extern/oni new file mode 160000 index 000000000..9a0d5cd73 --- /dev/null +++ b/extern/oni @@ -0,0 +1 @@ +Subproject commit 9a0d5cd739de77b357589ac1fc8b756ed27299be diff --git a/extern/sector-storage/ffiwrapper/sealer_test.go b/extern/sector-storage/ffiwrapper/sealer_test.go index d59de2cab..bb26adb77 100644 --- a/extern/sector-storage/ffiwrapper/sealer_test.go +++ b/extern/sector-storage/ffiwrapper/sealer_test.go @@ -245,6 +245,10 @@ func TestDownloadParams(t *testing.T) { } func TestSealAndVerify(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode") + } + defer requireFDsClosed(t, openFDs(t)) if runtime.NumCPU() < 10 && os.Getenv("CI") == "" { // don't bother on slow hardware @@ -314,6 +318,10 @@ func TestSealAndVerify(t *testing.T) { } func TestSealPoStNoCommit(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode") + } + defer requireFDsClosed(t, openFDs(t)) if runtime.NumCPU() < 10 && os.Getenv("CI") == "" { // don't bother on slow hardware @@ -375,6 +383,10 @@ func TestSealPoStNoCommit(t *testing.T) { } func TestSealAndVerify3(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode") + } + defer requireFDsClosed(t, openFDs(t)) if runtime.NumCPU() < 10 && os.Getenv("CI") == "" { // don't bother on slow hardware diff --git a/extern/storage-sealing/checks.go b/extern/storage-sealing/checks.go index 906c9c106..49994024f 100644 --- a/extern/storage-sealing/checks.go +++ b/extern/storage-sealing/checks.go @@ -4,7 +4,12 @@ import ( "bytes" "context" - saproof "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/filecoin-project/lotus/chain/actors/policy" + + "github.com/filecoin-project/lotus/build" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + + proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof" "golang.org/x/xerrors" @@ -13,7 +18,6 @@ import ( "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" "github.com/filecoin-project/lotus/extern/sector-storage/zerocomm" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) // TODO: For now we handle this by halting state execution, when we get jsonrpc reconnecting @@ -93,7 +97,20 @@ func checkPrecommit(ctx context.Context, maddr address.Address, si SectorInfo, t return &ErrBadCommD{xerrors.Errorf("on chain CommD differs from sector: %s != %s", commD, si.CommD)} } - if height-(si.TicketEpoch+SealRandomnessLookback) > SealRandomnessLookbackLimit(si.SectorType) { + nv, err := api.StateNetworkVersion(ctx, tok) + if err != nil { + return &ErrApi{xerrors.Errorf("calling StateNetworkVersion: %w", err)} + } + + var msd abi.ChainEpoch + if nv < build.ActorUpgradeNetworkVersion { + msd = miner0.MaxSealDuration[si.SectorType] + } else { + // TODO: ActorUpgrade(use MaxProveCommitDuration) + msd = 0 + } + + if height-(si.TicketEpoch+SealRandomnessLookback) > msd { return &ErrExpiredTicket{xerrors.Errorf("ticket expired: seal height: %d, head: %d", si.TicketEpoch+SealRandomnessLookback, height)} } @@ -139,8 +156,8 @@ func (m *Sealing) checkCommit(ctx context.Context, si SectorInfo, proof []byte, return &ErrNoPrecommit{xerrors.Errorf("precommit info not found on-chain")} } - if pci.PreCommitEpoch+miner.PreCommitChallengeDelay != si.SeedEpoch { - return &ErrBadSeed{xerrors.Errorf("seed epoch doesn't match on chain info: %d != %d", pci.PreCommitEpoch+miner.PreCommitChallengeDelay, si.SeedEpoch)} + if pci.PreCommitEpoch+policy.GetPreCommitChallengeDelay() != si.SeedEpoch { + return &ErrBadSeed{xerrors.Errorf("seed epoch doesn't match on chain info: %d != %d", pci.PreCommitEpoch+policy.GetPreCommitChallengeDelay(), si.SeedEpoch)} } buf := new(bytes.Buffer) @@ -170,7 +187,7 @@ func (m *Sealing) checkCommit(ctx context.Context, si SectorInfo, proof []byte, log.Warn("on-chain sealed CID doesn't match!") } - ok, err := m.verif.VerifySeal(saproof.SealVerifyInfo{ + ok, err := m.verif.VerifySeal(proof0.SealVerifyInfo{ SectorID: m.minerSector(si.SectorNumber), SealedCID: pci.Info.SealedCID, SealProof: spt, diff --git a/extern/storage-sealing/constants.go b/extern/storage-sealing/constants.go index ebb3d3347..8c7fa5abc 100644 --- a/extern/storage-sealing/constants.go +++ b/extern/storage-sealing/constants.go @@ -1,17 +1,11 @@ package sealing import ( - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) // Epochs -const SealRandomnessLookback = miner.ChainFinality - -// Epochs -func SealRandomnessLookbackLimit(spt abi.RegisteredSealProof) abi.ChainEpoch { - return miner.MaxSealDuration[spt] -} +const SealRandomnessLookback = miner0.ChainFinality // Epochs const InteractivePoRepConfidence = 6 diff --git a/extern/storage-sealing/fsm_events.go b/extern/storage-sealing/fsm_events.go index ee95ab1c7..3e597d761 100644 --- a/extern/storage-sealing/fsm_events.go +++ b/extern/storage-sealing/fsm_events.go @@ -1,12 +1,12 @@ package sealing import ( + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-storage/storage" ) diff --git a/extern/storage-sealing/precommit_policy.go b/extern/storage-sealing/precommit_policy.go index 93a963535..0b774b56f 100644 --- a/extern/storage-sealing/precommit_policy.go +++ b/extern/storage-sealing/precommit_policy.go @@ -3,8 +3,11 @@ package sealing import ( "context" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) type PreCommitPolicy interface { @@ -13,6 +16,7 @@ type PreCommitPolicy interface { type Chain interface { ChainHead(ctx context.Context) (TipSetToken, abi.ChainEpoch, error) + StateNetworkVersion(ctx context.Context, tok TipSetToken) (network.Version, error) } // BasicPreCommitPolicy satisfies PreCommitPolicy. It has two modes: @@ -50,7 +54,7 @@ func NewBasicPreCommitPolicy(api Chain, duration abi.ChainEpoch, provingBoundary func (p *BasicPreCommitPolicy) Expiration(ctx context.Context, ps ...Piece) (abi.ChainEpoch, error) { _, epoch, err := p.api.ChainHead(ctx) if err != nil { - return 0, nil + return 0, err } var end *abi.ChainEpoch diff --git a/extern/storage-sealing/precommit_policy_test.go b/extern/storage-sealing/precommit_policy_test.go index b9c3ec49b..52814167a 100644 --- a/extern/storage-sealing/precommit_policy_test.go +++ b/extern/storage-sealing/precommit_policy_test.go @@ -4,6 +4,9 @@ import ( "context" "testing" + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/lotus/build" + "github.com/ipfs/go-cid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -18,6 +21,10 @@ type fakeChain struct { h abi.ChainEpoch } +func (f *fakeChain) StateNetworkVersion(ctx context.Context, tok sealing.TipSetToken) (network.Version, error) { + return build.NewestNetworkVersion, nil +} + func (f *fakeChain) ChainHead(ctx context.Context) (sealing.TipSetToken, abi.ChainEpoch, error) { return []byte{1, 2, 3}, f.h, nil } diff --git a/extern/storage-sealing/sealing.go b/extern/storage-sealing/sealing.go index cb73182d3..1ba53661a 100644 --- a/extern/storage-sealing/sealing.go +++ b/extern/storage-sealing/sealing.go @@ -8,6 +8,7 @@ import ( "sync" "time" + "github.com/filecoin-project/go-state-types/network" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/namespace" @@ -20,10 +21,10 @@ import ( "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" statemachine "github.com/filecoin-project/go-statemachine" + "github.com/filecoin-project/lotus/chain/actors/builtin/market" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) const SectorStorePrefix = "/sectors" @@ -50,10 +51,10 @@ type SealingAPI interface { StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok TipSetToken) (*SectorLocation, error) StateMinerSectorSize(context.Context, address.Address, TipSetToken) (abi.SectorSize, error) StateMinerWorkerAddress(ctx context.Context, maddr address.Address, tok TipSetToken) (address.Address, error) - StateMinerDeadlines(ctx context.Context, maddr address.Address, tok TipSetToken) ([]*miner.Deadline, error) StateMinerPreCommitDepositForPower(context.Context, address.Address, miner.SectorPreCommitInfo, TipSetToken) (big.Int, error) StateMinerInitialPledgeCollateral(context.Context, address.Address, miner.SectorPreCommitInfo, TipSetToken) (big.Int, error) StateMarketStorageDeal(context.Context, abi.DealID, TipSetToken) (market.DealProposal, error) + StateNetworkVersion(ctx context.Context, tok TipSetToken) (network.Version, error) SendMsg(ctx context.Context, from, to address.Address, method abi.MethodNum, value, maxFee abi.TokenAmount, params []byte) (cid.Cid, error) ChainHead(ctx context.Context) (TipSetToken, abi.ChainEpoch, error) ChainGetRandomnessFromBeacon(ctx context.Context, tok TipSetToken, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) diff --git a/extern/storage-sealing/sector_state.go b/extern/storage-sealing/sector_state.go index 4e674603d..10b96e504 100644 --- a/extern/storage-sealing/sector_state.go +++ b/extern/storage-sealing/sector_state.go @@ -2,6 +2,38 @@ package sealing type SectorState string +var ExistSectorStateList = map[SectorState]struct{}{ + Empty: {}, + WaitDeals: {}, + Packing: {}, + PreCommit1: {}, + PreCommit2: {}, + PreCommitting: {}, + PreCommitWait: {}, + WaitSeed: {}, + Committing: {}, + SubmitCommit: {}, + CommitWait: {}, + FinalizeSector: {}, + Proving: {}, + FailedUnrecoverable: {}, + SealPreCommit1Failed: {}, + SealPreCommit2Failed: {}, + PreCommitFailed: {}, + ComputeProofFailed: {}, + CommitFailed: {}, + PackingFailed: {}, + FinalizeFailed: {}, + DealsExpired: {}, + RecoverDealIDs: {}, + Faulty: {}, + FaultReported: {}, + FaultedFinal: {}, + Removing: {}, + RemoveFailed: {}, + Removed: {}, +} + const ( UndefinedSectorState SectorState = "" diff --git a/extern/storage-sealing/states_failed.go b/extern/storage-sealing/states_failed.go index 4dd945a81..b026e70f9 100644 --- a/extern/storage-sealing/states_failed.go +++ b/extern/storage-sealing/states_failed.go @@ -4,13 +4,14 @@ import ( "bytes" "time" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/go-statemachine" "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/extern/sector-storage/zerocomm" ) diff --git a/extern/storage-sealing/states_sealing.go b/extern/storage-sealing/states_sealing.go index 5e2b72ee1..a4e852454 100644 --- a/extern/storage-sealing/states_sealing.go +++ b/extern/storage-sealing/states_sealing.go @@ -4,6 +4,11 @@ import ( "bytes" "context" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/policy" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/abi" @@ -12,7 +17,6 @@ import ( "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/go-statemachine" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-storage/storage" ) @@ -180,7 +184,20 @@ func (m *Sealing) handlePreCommitting(ctx statemachine.Context, sector SectorInf // Sectors must last _at least_ MinSectorExpiration + MaxSealDuration. // TODO: The "+10" allows the pre-commit to take 10 blocks to be accepted. - if minExpiration := height + miner.MaxSealDuration[sector.SectorType] + miner.MinSectorExpiration + 10; expiration < minExpiration { + nv, err := m.api.StateNetworkVersion(ctx.Context(), tok) + if err != nil { + return ctx.Send(SectorSealPreCommit1Failed{xerrors.Errorf("failed to get network version: %w", err)}) + } + + var msd abi.ChainEpoch + if nv < build.ActorUpgradeNetworkVersion { + msd = miner0.MaxSealDuration[sector.SectorType] + } else { + // TODO: ActorUpgrade(use MaxProveCommitDuration) + msd = 0 + } + + if minExpiration := height + msd + miner.MinSectorExpiration + 10; expiration < minExpiration { expiration = minExpiration } // TODO: enforce a reasonable _maximum_ sector lifetime? @@ -253,7 +270,7 @@ func (m *Sealing) handlePreCommitWait(ctx statemachine.Context, sector SectorInf func (m *Sealing) handleWaitSeed(ctx statemachine.Context, sector SectorInfo) error { tok, _, err := m.api.ChainHead(ctx.Context()) if err != nil { - log.Errorf("handleCommitting: api error, not proceeding: %+v", err) + log.Errorf("handleWaitSeed: api error, not proceeding: %+v", err) return nil } @@ -265,7 +282,7 @@ func (m *Sealing) handleWaitSeed(ctx statemachine.Context, sector SectorInfo) er return ctx.Send(SectorChainPreCommitFailed{error: xerrors.Errorf("precommit info not found on chain")}) } - randHeight := pci.PreCommitEpoch + miner.PreCommitChallengeDelay + randHeight := pci.PreCommitEpoch + policy.GetPreCommitChallengeDelay() err = m.events.ChainAt(func(ectx context.Context, _ TipSetToken, curH abi.ChainEpoch) error { // in case of null blocks the randomness can land after the tipset we @@ -356,12 +373,12 @@ func (m *Sealing) handleSubmitCommit(ctx statemachine.Context, sector SectorInfo return ctx.Send(SectorCommitFailed{xerrors.Errorf("commit check error: %w", err)}) } + enc := new(bytes.Buffer) params := &miner.ProveCommitSectorParams{ SectorNumber: sector.SectorNumber, Proof: sector.Proof, } - enc := new(bytes.Buffer) if err := params.MarshalCBOR(enc); err != nil { return ctx.Send(SectorCommitFailed{xerrors.Errorf("could not serialize commit sector parameters: %w", err)}) } diff --git a/extern/storage-sealing/upgrade_queue.go b/extern/storage-sealing/upgrade_queue.go index af2d1827d..78a78fc45 100644 --- a/extern/storage-sealing/upgrade_queue.go +++ b/extern/storage-sealing/upgrade_queue.go @@ -3,11 +3,12 @@ package sealing import ( "context" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) func (m *Sealing) IsMarkedForUpgrade(id abi.SectorNumber) bool { diff --git a/extern/test-vectors b/extern/test-vectors index 7d3becbeb..6bea015ed 160000 --- a/extern/test-vectors +++ b/extern/test-vectors @@ -1 +1 @@ -Subproject commit 7d3becbeb5b932baed419c43390595b5e5cece12 +Subproject commit 6bea015edddde116001a4251dce3c4a9966c25d9 diff --git a/gen/main.go b/gen/main.go index e7586a92a..bcb43a8f0 100644 --- a/gen/main.go +++ b/gen/main.go @@ -26,6 +26,8 @@ func main() { types.BlockMsg{}, types.ExpTipSet{}, types.BeaconEntry{}, + types.StateRoot{}, + types.StateInfo{}, ) if err != nil { fmt.Println(err) @@ -73,5 +75,4 @@ func main() { fmt.Println(err) os.Exit(1) } - } diff --git a/go.mod b/go.mod index 65c2addb8..cfdf4cb1d 100644 --- a/go.mod +++ b/go.mod @@ -25,9 +25,9 @@ require ( github.com/filecoin-project/go-bitfield v0.2.0 github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 - github.com/filecoin-project/go-data-transfer v0.6.3 + github.com/filecoin-project/go-data-transfer v0.6.5 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f - github.com/filecoin-project/go-fil-markets v0.6.1-0.20200911011457-2959ccca6a3c + github.com/filecoin-project/go-fil-markets v0.6.2 github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 @@ -60,7 +60,7 @@ require ( github.com/ipfs/go-ds-measure v0.1.0 github.com/ipfs/go-filestore v1.0.0 github.com/ipfs/go-fs-lock v0.0.6 - github.com/ipfs/go-graphsync v0.1.2 + github.com/ipfs/go-graphsync v0.2.0 github.com/ipfs/go-ipfs-blockstore v1.0.1 github.com/ipfs/go-ipfs-chunker v0.0.5 github.com/ipfs/go-ipfs-ds-help v1.0.0 @@ -77,8 +77,8 @@ require ( github.com/ipfs/go-path v0.0.7 github.com/ipfs/go-unixfs v0.2.4 github.com/ipfs/interface-go-ipfs-core v0.2.3 - github.com/ipld/go-car v0.1.1-0.20200526133713-1c7508d55aae - github.com/ipld/go-ipld-prime v0.0.4-0.20200828224805-5ff8c8b0b6ef + github.com/ipld/go-car v0.1.1-0.20200923150018-8cdef32e2da4 + github.com/ipld/go-ipld-prime v0.5.1-0.20200828233916-988837377a7f github.com/kelseyhightower/envconfig v1.4.0 github.com/lib/pq v1.7.0 github.com/libp2p/go-eventbus v0.2.1 diff --git a/go.sum b/go.sum index 77b556fb2..3b31e6c3b 100644 --- a/go.sum +++ b/go.sum @@ -222,13 +222,15 @@ github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 h1:a github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2/go.mod h1:pqTiPHobNkOVM5thSRsHYjyQfq7O5QSCMhvuu9JoDlg= 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 v0.6.3 h1:7TLwm8nuodHYD/uiwJjKc/PGRR+LwqM8jmlZqgWuUfY= -github.com/filecoin-project/go-data-transfer v0.6.3/go.mod h1:PmBKVXkhh67/tnEdJXQwDHl5mT+7Tbcwe1NPninqhnM= +github.com/filecoin-project/go-data-transfer v0.6.5 h1:oP20la8Z0CLrw0uqvt6xVgw6rOevZeGJ9GNQeC0OCSU= +github.com/filecoin-project/go-data-transfer v0.6.5/go.mod h1:I9Ylb/UiZyqnI41wUoCXq/le0nDLhlwpFQCtNPxEPOA= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= -github.com/filecoin-project/go-fil-markets v0.6.1-0.20200911011457-2959ccca6a3c h1:YGoyYmELQ0LHwDj/WcOvY3oYt+3iM0wdrAhqJQUAIy4= -github.com/filecoin-project/go-fil-markets v0.6.1-0.20200911011457-2959ccca6a3c/go.mod h1:PLr9svZxsnHkae1Ky7+66g7fP9AlneVxIVu+oSMq56A= +github.com/filecoin-project/go-fil-markets v0.6.2 h1:9Z57KeaQSa1liCmT1pH6SIjrn9mGTDFJXmR2WQVuaiY= +github.com/filecoin-project/go-fil-markets v0.6.2/go.mod h1:wtN4Hc/1hoVCpWhSWYxwUxH3PQtjSkWWuC1nQjiIWog= github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM= +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 v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= @@ -393,9 +395,8 @@ github.com/gxed/go-shellwords v1.0.3/go.mod h1:N7paucT91ByIjmVJHhvoarjoQnmsi3Jd3 github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/gxed/pubsub v0.0.0-20180201040156-26ebdf44f824/go.mod h1:OiEWyHgK+CWrmOlVquHaIK1vhpUJydC9m0Je6mhaiNE= -github.com/hannahhoward/cbor-gen-for v0.0.0-20191218204337-9ab7b1bcc099/go.mod h1:WVPCl0HO/0RAL5+vBH2GMxBomlxBF70MAS78+Lu1//k= -github.com/hannahhoward/cbor-gen-for v0.0.0-20200723175505-5892b522820a h1:wfqh5oiHXvn3Rk54xy8Cwqh+HnYihGnjMNzdNb3/ld0= -github.com/hannahhoward/cbor-gen-for v0.0.0-20200723175505-5892b522820a/go.mod h1:jvfsLIxk0fY/2BKSQ1xf2406AKA5dwMmKKv0ADcOfN8= +github.com/hannahhoward/cbor-gen-for v0.0.0-20200817222906-ea96cece81f1 h1:F9k+7wv5OIk1zcq23QpdiL0hfDuXPjuOmMNaC6fgQ0Q= +github.com/hannahhoward/cbor-gen-for v0.0.0-20200817222906-ea96cece81f1/go.mod h1:jvfsLIxk0fY/2BKSQ1xf2406AKA5dwMmKKv0ADcOfN8= github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e h1:3YKHER4nmd7b5qy5t0GWDTwSn4OyRgfAXSmo6VnryBY= github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e/go.mod h1:I8h3MITA53gN9OnWGCgaMa0JWVRdXthWw4M3CPM54OY= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= @@ -501,8 +502,8 @@ github.com/ipfs/go-filestore v1.0.0/go.mod h1:/XOCuNtIe2f1YPbiXdYvD0BKLA0JR1MgPi github.com/ipfs/go-fs-lock v0.0.6 h1:sn3TWwNVQqSeNjlWy6zQ1uUGAZrV3hPOyEA6y1/N2a0= github.com/ipfs/go-fs-lock v0.0.6/go.mod h1:OTR+Rj9sHiRubJh3dRhD15Juhd/+w6VPOY28L7zESmM= github.com/ipfs/go-graphsync v0.1.0/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= -github.com/ipfs/go-graphsync v0.1.2 h1:25Ll9kIXCE+DY0dicvfS3KMw+U5sd01b/FJbA7KAbhg= -github.com/ipfs/go-graphsync v0.1.2/go.mod h1:sLXVXm1OxtE2XYPw62MuXCdAuNwkAdsbnfrmos5odbA= +github.com/ipfs/go-graphsync v0.2.0 h1:x94MvHLNuRwBlZzVal7tR1RYK7T7H6bqQLPopxDbIF0= +github.com/ipfs/go-graphsync v0.2.0/go.mod h1:gEBvJUNelzMkaRPJTpg/jaKN4AQW/7wDWu0K92D8o10= 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= @@ -606,14 +607,14 @@ github.com/ipfs/iptb v1.4.0 h1:YFYTrCkLMRwk/35IMyC6+yjoQSHTEcNcefBStLJzgvo= github.com/ipfs/iptb v1.4.0/go.mod h1:1rzHpCYtNp87/+hTxG5TfCVn/yMY3dKnLn8tBiMfdmg= github.com/ipfs/iptb-plugins v0.2.1 h1:au4HWn9/pRPbkxA08pDx2oRAs4cnbgQWgV0teYXuuGA= github.com/ipfs/iptb-plugins v0.2.1/go.mod h1:QXMbtIWZ+jRsW8a4h13qAKU7jcM7qaittO8wOsTP0Rs= -github.com/ipld/go-car v0.1.1-0.20200526133713-1c7508d55aae h1:OV9dxl8iPMCOD8Vi/hvFwRh3JWPXqmkYSVxWr9JnEzM= -github.com/ipld/go-car v0.1.1-0.20200526133713-1c7508d55aae/go.mod h1:2mvxpu4dKRnuH3mj5u6KW/tmRSCcXvy/KYiJ4nC6h4c= +github.com/ipld/go-car v0.1.1-0.20200923150018-8cdef32e2da4 h1:6phjU3kXvCEWOZpu+Ob0w6DzgPFZmDLgLPxJhD8RxEY= +github.com/ipld/go-car v0.1.1-0.20200923150018-8cdef32e2da4/go.mod h1:xrMEcuSq+D1vEwl+YAXsg/JfA98XGpXDwnkIL4Aimqw= github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e/go.mod h1:uVIwe/u0H4VdKv3kaN1ck7uCb6yD9cFLS9/ELyXbsw8= -github.com/ipld/go-ipld-prime v0.0.4-0.20200828224805-5ff8c8b0b6ef h1:/yPelt/0CuzZsmRkYzBBnJ499JnAOGaIaAXHujx96ic= -github.com/ipld/go-ipld-prime v0.0.4-0.20200828224805-5ff8c8b0b6ef/go.mod h1:uVIwe/u0H4VdKv3kaN1ck7uCb6yD9cFLS9/ELyXbsw8= +github.com/ipld/go-ipld-prime v0.5.1-0.20200828233916-988837377a7f h1:XpOuNQ5GbXxUcSukbQcW9jkE7REpaFGJU2/T00fo9kA= +github.com/ipld/go-ipld-prime v0.5.1-0.20200828233916-988837377a7f/go.mod h1:0xEgdD6MKbZ1vF0GC+YcR/C4SQCAlRuOjIJ2i0HxqzM= github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1/go.mod h1:OAV6xBmuTLsPZ+epzKkPB1e25FHk/vCtyatkdHcArLs= -github.com/ipld/go-ipld-prime-proto v0.0.0-20200828231332-ae0aea07222b h1:ZtlW6pubN17TDaStlxgrwEXXwwUfJaXu9RobwczXato= -github.com/ipld/go-ipld-prime-proto v0.0.0-20200828231332-ae0aea07222b/go.mod h1:OAV6xBmuTLsPZ+epzKkPB1e25FHk/vCtyatkdHcArLs= +github.com/ipld/go-ipld-prime-proto v0.0.0-20200922192210-9a2bfd4440a6 h1:6Mq+tZGSEMEoJJ1NbJRhddeelkXZcU8yfH/ZRYUo/Es= +github.com/ipld/go-ipld-prime-proto v0.0.0-20200922192210-9a2bfd4440a6/go.mod h1:3pHYooM9Ea65jewRwrb2u5uHZCNkNTe9ABsVB+SrkH0= github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 h1:QG4CGBqCeuBo6aZlGAamSkxWdgWfZGeE49eUOWJPA4c= github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52/go.mod h1:fdg+/X9Gg4AsAIzWpEHwnqd+QY3b7lajxyjE1m4hkq4= github.com/jackpal/gateway v1.0.4/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= @@ -1359,7 +1360,6 @@ github.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMU github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM= github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba h1:X4n8JG2e2biEZZXdBKt9HX7DN3bYGFUqljqqy0DqgnY= github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba/go.mod h1:CHQnYnQUEPydYCwuy8lmTHfGmdw9TKrhWV0xLx8l0oM= -github.com/whyrusleeping/cbor-gen v0.0.0-20191212224538-d370462a7e8a/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY= github.com/whyrusleeping/cbor-gen v0.0.0-20191216205031-b047b6acb3c0/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY= github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= github.com/whyrusleeping/cbor-gen v0.0.0-20200402171437-3d27c146c105/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= diff --git a/lotuspond/front/src/chain/methods.json b/lotuspond/front/src/chain/methods.json index ad1076c84..ce4919cc4 100644 --- a/lotuspond/front/src/chain/methods.json +++ b/lotuspond/front/src/chain/methods.json @@ -23,7 +23,8 @@ "AddSigner", "RemoveSigner", "SwapSigner", - "ChangeNumApprovalsThreshold" + "ChangeNumApprovalsThreshold", + "LockBalance" ], "fil/1/paymentchannel": [ "Send", diff --git a/lotuspond/spawn.go b/lotuspond/spawn.go index 5fa82a865..8b2e8661d 100644 --- a/lotuspond/spawn.go +++ b/lotuspond/spawn.go @@ -11,6 +11,7 @@ import ( "sync/atomic" "time" + "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/types" "golang.org/x/xerrors" @@ -18,7 +19,6 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/cmd/lotus-seed/seed" @@ -26,9 +26,7 @@ import ( ) func init() { - miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ - abi.RegisteredSealProof_StackedDrg2KiBV1: {}, - } + policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) } func (api *api) Spawn() (nodeInfo, error) { diff --git a/markets/storageadapter/client.go b/markets/storageadapter/client.go index 4168792da..fabc5b197 100644 --- a/markets/storageadapter/client.go +++ b/markets/storageadapter/client.go @@ -7,6 +7,8 @@ import ( "context" "github.com/filecoin-project/go-state-types/big" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin" + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" "golang.org/x/xerrors" @@ -18,6 +20,7 @@ import ( "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/events/state" "github.com/filecoin-project/lotus/chain/market" @@ -27,9 +30,6 @@ import ( "github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/lotus/markets/utils" "github.com/filecoin-project/lotus/node/impl/full" - "github.com/filecoin-project/specs-actors/actors/builtin" - samarket "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/ipfs/go-cid" ) @@ -97,37 +97,14 @@ func (c *ClientNodeAdapter) VerifySignature(ctx context.Context, sig crypto.Sign return err == nil, err } -func (c *ClientNodeAdapter) ListClientDeals(ctx context.Context, addr address.Address, encodedTs shared.TipSetToken) ([]storagemarket.StorageDeal, error) { - tsk, err := types.TipSetKeyFromBytes(encodedTs) - if err != nil { - return nil, err - } - - allDeals, err := c.StateMarketDeals(ctx, tsk) - if err != nil { - return nil, err - } - - var out []storagemarket.StorageDeal - - for _, deal := range allDeals { - storageDeal := utils.FromOnChainDeal(deal.Proposal, deal.State) - if storageDeal.Client == addr { - out = append(out, storageDeal) - } - } - - return out, nil -} - // Adds funds with the StorageMinerActor for a storage participant. Used by both providers and clients. 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: builtin.StorageMarketActorAddr, + To: miner0.StorageMarketActorAddr, From: addr, Value: amount, - Method: builtin.MethodsMarket.AddBalance, + Method: miner0.MethodsMarket.AddBalance, }, nil) if err != nil { return cid.Undef, err @@ -178,15 +155,15 @@ func (c *ClientNodeAdapter) ValidatePublishedDeal(ctx context.Context, deal stor return 0, xerrors.Errorf("deal wasn't published by storage provider: from=%s, provider=%s", pubmsg.From, deal.Proposal.Provider) } - if pubmsg.To != builtin.StorageMarketActorAddr { + if pubmsg.To != miner0.StorageMarketActorAddr { return 0, xerrors.Errorf("deal publish message wasn't set to StorageMarket actor (to=%s)", pubmsg.To) } - if pubmsg.Method != builtin.MethodsMarket.PublishStorageDeals { + if pubmsg.Method != miner0.MethodsMarket.PublishStorageDeals { return 0, xerrors.Errorf("deal publish message called incorrect method (method=%s)", pubmsg.Method) } - var params samarket.PublishStorageDealsParams + var params market0.PublishStorageDealsParams if err := params.UnmarshalCBOR(bytes.NewReader(pubmsg.Params)); err != nil { return 0, err } @@ -218,7 +195,7 @@ func (c *ClientNodeAdapter) ValidatePublishedDeal(ctx context.Context, deal stor return 0, xerrors.Errorf("deal publish failed: exit=%d", ret.ExitCode) } - var res samarket.PublishStorageDealsReturn + var res market0.PublishStorageDealsReturn if err := res.UnmarshalCBOR(bytes.NewReader(ret.Return)); err != nil { return 0, err } @@ -296,7 +273,7 @@ func (c *ClientNodeAdapter) OnDealSectorCommitted(ctx context.Context, provider } switch msg.Method { - case builtin.MethodsMiner.PreCommitSector: + case miner0.MethodsMiner.PreCommitSector: var params miner.SectorPreCommitInfo if err := params.UnmarshalCBOR(bytes.NewReader(msg.Params)); err != nil { return true, false, xerrors.Errorf("unmarshal pre commit: %w", err) @@ -311,7 +288,7 @@ func (c *ClientNodeAdapter) OnDealSectorCommitted(ctx context.Context, provider } return true, false, nil - case builtin.MethodsMiner.ProveCommitSector: + case miner0.MethodsMiner.ProveCommitSector: var params miner.ProveCommitSectorParams if err := params.UnmarshalCBOR(bytes.NewReader(msg.Params)); err != nil { return true, false, xerrors.Errorf("failed to unmarshal prove commit sector params: %w", err) @@ -433,7 +410,7 @@ func (c *ClientNodeAdapter) OnDealExpiredOrSlashed(ctx context.Context, dealID a return nil } -func (c *ClientNodeAdapter) SignProposal(ctx context.Context, signer address.Address, proposal samarket.DealProposal) (*samarket.ClientDealProposal, error) { +func (c *ClientNodeAdapter) SignProposal(ctx context.Context, signer address.Address, proposal market0.DealProposal) (*market0.ClientDealProposal, error) { // TODO: output spec signed proposal buf, err := cborutil.Dump(&proposal) if err != nil { @@ -450,7 +427,7 @@ func (c *ClientNodeAdapter) SignProposal(ctx context.Context, signer address.Add return nil, err } - return &samarket.ClientDealProposal{ + return &market0.ClientDealProposal{ Proposal: proposal, ClientSignature: *sig, }, nil diff --git a/markets/storageadapter/provider.go b/markets/storageadapter/provider.go index 7af1808c1..9f610d76a 100644 --- a/markets/storageadapter/provider.go +++ b/markets/storageadapter/provider.go @@ -12,21 +12,23 @@ import ( logging "github.com/ipfs/go-log/v2" "golang.org/x/xerrors" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-fil-markets/shared" "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/exitcode" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/events" + + "github.com/filecoin-project/lotus/chain/actors/builtin/market" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/events/state" "github.com/filecoin-project/lotus/chain/types" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" @@ -67,8 +69,8 @@ func (n *ProviderNodeAdapter) PublishDeals(ctx context.Context, deal storagemark return cid.Undef, err } - params, err := actors.SerializeParams(&market.PublishStorageDealsParams{ - Deals: []market.ClientDealProposal{deal.ClientDealProposal}, + params, err := actors.SerializeParams(&market0.PublishStorageDealsParams{ + Deals: []market0.ClientDealProposal{deal.ClientDealProposal}, }) if err != nil { @@ -77,10 +79,10 @@ func (n *ProviderNodeAdapter) PublishDeals(ctx context.Context, deal storagemark // TODO: We may want this to happen after fetching data smsg, err := n.MpoolPushMessage(ctx, &types.Message{ - To: builtin.StorageMarketActorAddr, + To: market.Address, From: mi.Worker, Value: types.NewInt(0), - Method: builtin.MethodsMarket.PublishStorageDeals, + Method: builtin0.MethodsMarket.PublishStorageDeals, Params: params, }, nil) if err != nil { @@ -108,7 +110,9 @@ func (n *ProviderNodeAdapter) OnDealComplete(ctx context.Context, deal storagema curTime := time.Now() for time.Since(curTime) < addPieceRetryTimeout { if !xerrors.Is(err, sealing.ErrTooManySectorsSealing) { - log.Errorf("failed to addPiece for deal %d, err: %w", deal.DealID, err) + if err != nil { + log.Errorf("failed to addPiece for deal %d, err: %w", deal.DealID, err) + } break } select { @@ -141,28 +145,6 @@ func (n *ProviderNodeAdapter) VerifySignature(ctx context.Context, sig crypto.Si return err == nil, err } -func (n *ProviderNodeAdapter) ListProviderDeals(ctx context.Context, addr address.Address, encodedTs shared.TipSetToken) ([]storagemarket.StorageDeal, error) { - tsk, err := types.TipSetKeyFromBytes(encodedTs) - if err != nil { - return nil, err - } - allDeals, err := n.StateMarketDeals(ctx, tsk) - if err != nil { - return nil, err - } - - var out []storagemarket.StorageDeal - - for _, deal := range allDeals { - sharedDeal := utils.FromOnChainDeal(deal.Proposal, deal.State) - if sharedDeal.Provider == addr { - out = append(out, sharedDeal) - } - } - - return out, nil -} - func (n *ProviderNodeAdapter) GetMinerWorkerAddress(ctx context.Context, miner address.Address, tok shared.TipSetToken) (address.Address, error) { tsk, err := types.TipSetKeyFromBytes(tok) if err != nil { @@ -197,10 +179,10 @@ func (n *ProviderNodeAdapter) EnsureFunds(ctx context.Context, addr, wallet addr func (n *ProviderNodeAdapter) AddFunds(ctx context.Context, addr address.Address, amount abi.TokenAmount) (cid.Cid, error) { // (Provider Node API) smsg, err := n.MpoolPushMessage(ctx, &types.Message{ - To: builtin.StorageMarketActorAddr, + To: market.Address, From: addr, Value: amount, - Method: builtin.MethodsMarket.AddBalance, + Method: builtin0.MethodsMarket.AddBalance, }, nil) if err != nil { return cid.Undef, err @@ -322,7 +304,7 @@ func (n *ProviderNodeAdapter) OnDealSectorCommitted(ctx context.Context, provide } switch msg.Method { - case builtin.MethodsMiner.PreCommitSector: + case builtin0.MethodsMiner.PreCommitSector: var params miner.SectorPreCommitInfo if err := params.UnmarshalCBOR(bytes.NewReader(msg.Params)); err != nil { return true, false, xerrors.Errorf("unmarshal pre commit: %w", err) @@ -337,7 +319,7 @@ func (n *ProviderNodeAdapter) OnDealSectorCommitted(ctx context.Context, provide } return true, false, nil - case builtin.MethodsMiner.ProveCommitSector: + case builtin0.MethodsMiner.ProveCommitSector: var params miner.ProveCommitSectorParams if err := params.UnmarshalCBOR(bytes.NewReader(msg.Params)); err != nil { return true, false, xerrors.Errorf("failed to unmarshal prove commit sector params: %w", err) @@ -382,12 +364,14 @@ func (n *ProviderNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, receipt.Message, nil) } -func (n *ProviderNodeAdapter) GetDataCap(ctx context.Context, addr address.Address, encodedTs shared.TipSetToken) (*verifreg.DataCap, error) { +func (n *ProviderNodeAdapter) GetDataCap(ctx context.Context, addr address.Address, encodedTs shared.TipSetToken) (*abi.StoragePower, error) { tsk, err := types.TipSetKeyFromBytes(encodedTs) if err != nil { return nil, err } - return n.StateVerifiedClientStatus(ctx, addr, tsk) + + sp, err := n.StateVerifiedClientStatus(ctx, addr, tsk) + return sp, err } func (n *ProviderNodeAdapter) OnDealExpiredOrSlashed(ctx context.Context, dealID abi.DealID, onDealExpired storagemarket.DealExpiredCallback, onDealSlashed storagemarket.DealSlashedCallback) error { diff --git a/markets/utils/converters.go b/markets/utils/converters.go index 05472801d..4a3d21140 100644 --- a/markets/utils/converters.go +++ b/markets/utils/converters.go @@ -4,7 +4,6 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/specs-actors/actors/builtin/market" peer "github.com/libp2p/go-libp2p-core/peer" "github.com/multiformats/go-multiaddr" @@ -31,13 +30,6 @@ func NewStorageProviderInfo(address address.Address, miner address.Address, sect } } -func FromOnChainDeal(prop market.DealProposal, state market.DealState) storagemarket.StorageDeal { - return storagemarket.StorageDeal{ - DealProposal: prop, - DealState: state, - } -} - func ToSharedBalance(bal api.MarketBalance) storagemarket.Balance { return storagemarket.Balance{ Locked: bal.Locked, diff --git a/miner/miner.go b/miner/miner.go index bcfdb46c1..1b79f5245 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -9,7 +9,7 @@ import ( "sync" "time" - "github.com/filecoin-project/specs-actors/actors/runtime/proof" + proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof" "github.com/filecoin-project/lotus/chain/gen/slashfilter" @@ -139,6 +139,7 @@ func (m *Miner) niceSleep(d time.Duration) bool { case <-build.Clock.After(d): return true case <-m.stop: + log.Infow("received interrupt while trying to sleep in mining cycle") return false } } @@ -148,7 +149,7 @@ func (m *Miner) mine(ctx context.Context) { defer span.End() var lastBase MiningBase - +minerLoop: for { select { case <-m.stop: @@ -169,7 +170,9 @@ func (m *Miner) mine(ctx context.Context) { prebase, err := m.GetBestMiningCandidate(ctx) if err != nil { log.Errorf("failed to get best mining candidate: %s", err) - m.niceSleep(time.Second * 5) + if !m.niceSleep(time.Second * 5) { + continue minerLoop + } continue } @@ -199,7 +202,9 @@ func (m *Miner) mine(ctx context.Context) { _, err = m.api.BeaconGetEntry(ctx, prebase.TipSet.Height()+prebase.NullRounds+1) if err != nil { log.Errorf("failed getting beacon entry: %s", err) - m.niceSleep(time.Second) + if !m.niceSleep(time.Second) { + continue minerLoop + } continue } @@ -208,7 +213,9 @@ func (m *Miner) mine(ctx context.Context) { if base.TipSet.Equals(lastBase.TipSet) && lastBase.NullRounds == base.NullRounds { log.Warnf("BestMiningCandidate from the previous round: %s (nulls:%d)", lastBase.TipSet.Cids(), lastBase.NullRounds) - m.niceSleep(time.Duration(build.BlockDelaySecs) * time.Second) + if !m.niceSleep(time.Duration(build.BlockDelaySecs) * time.Second) { + continue minerLoop + } continue } @@ -217,7 +224,9 @@ func (m *Miner) mine(ctx context.Context) { b, err := m.mineOne(ctx, base) if err != nil { log.Errorf("mining block failed: %+v", err) - m.niceSleep(time.Second) + if !m.niceSleep(time.Second) { + continue minerLoop + } onDone(false, 0, err) continue } @@ -480,7 +489,7 @@ func (m *Miner) computeTicket(ctx context.Context, brand *types.BeaconEntry, bas } func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket, - eproof *types.ElectionProof, bvals []types.BeaconEntry, wpostProof []proof.PoStProof, msgs []*types.SignedMessage) (*types.BlockMsg, error) { + eproof *types.ElectionProof, bvals []types.BeaconEntry, wpostProof []proof0.PoStProof, msgs []*types.SignedMessage) (*types.BlockMsg, error) { uts := base.TipSet.MinTimestamp() + build.BlockDelaySecs*(uint64(base.NullRounds)+1) nheight := base.TipSet.Height() + base.NullRounds + 1 diff --git a/node/builder.go b/node/builder.go index 8c7674ffd..c37a5db58 100644 --- a/node/builder.go +++ b/node/builder.go @@ -382,7 +382,7 @@ func StorageMiner(out *api.StorageMiner) Option { func(s *Settings) error { resAPI := &impl.StorageMinerAPI{} - s.invokes[ExtractApiKey] = fx.Extract(resAPI) + s.invokes[ExtractApiKey] = fx.Populate(resAPI) *out = resAPI return nil }, @@ -509,7 +509,7 @@ func FullAPI(out *api.FullNode) Option { }, func(s *Settings) error { resAPI := &impl.FullNodeAPI{} - s.invokes[ExtractApiKey] = fx.Extract(resAPI) + s.invokes[ExtractApiKey] = fx.Populate(resAPI) *out = resAPI return nil }, diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 7a107c2fd..81978af16 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -41,7 +41,7 @@ import ( "github.com/filecoin-project/go-multistore" "github.com/filecoin-project/go-padreader" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" marketevents "github.com/filecoin-project/lotus/markets/loggers" @@ -87,7 +87,7 @@ func calcDealExpiration(minDuration uint64, md *dline.Info, startEpoch abi.Chain minExp := startEpoch + abi.ChainEpoch(minDuration) // Align on miners ProvingPeriodBoundary - return minExp + miner.WPoStProvingPeriod - (minExp % miner.WPoStProvingPeriod) + (md.PeriodStart % miner.WPoStProvingPeriod) - 1 + return minExp + miner0.WPoStProvingPeriod - (minExp % miner0.WPoStProvingPeriod) + (md.PeriodStart % miner0.WPoStProvingPeriod) - 1 } func (a *API) imgr() *importmgr.Mgr { @@ -711,7 +711,7 @@ func (a *API) ClientGenCar(ctx context.Context, ref api.FileRef, outputPath stri // TODO: does that defer mean to remove the whole blockstore? defer bufferedDS.Remove(ctx, c) //nolint:errcheck - ssb := builder.NewSelectorSpecBuilder(basicnode.Style.Any) + ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any) // entire DAG selector allSelector := ssb.ExploreRecursive(selector.RecursionLimitNone(), diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 0d6f923d8..9606a023a 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -197,6 +197,10 @@ func (a *ChainAPI) ChainReadObj(ctx context.Context, obj cid.Cid) ([]byte, error return blk.RawData(), nil } +func (a *ChainAPI) ChainDeleteObj(ctx context.Context, obj cid.Cid) error { + return a.Chain.Blockstore().DeleteBlock(obj) +} + func (a *ChainAPI) ChainHasObj(ctx context.Context, obj cid.Cid) (bool, error) { return a.Chain.Blockstore().Has(obj) } diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index 536bef360..f03807c80 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -13,7 +13,8 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/exitcode" - "github.com/filecoin-project/specs-actors/actors/builtin" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" @@ -166,8 +167,14 @@ func (a *GasAPI) GasEstimateGasLimit(ctx context.Context, msgIn *types.Message, } // Special case for PaymentChannel collect, which is deleting actor - var act types.Actor - err = a.Stmgr.WithParentState(ts, a.Stmgr.WithActor(msg.To, stmgr.GetActor(&act))) + st, err := a.Stmgr.ParentState(ts) + if err != nil { + _ = err + // somewhat ignore it as it can happen and we just want to detect + // an existing PaymentChannel actor + return res.MsgRct.GasUsed, nil + } + act, err := st.GetActor(msg.To) if err != nil { _ = err // somewhat ignore it as it can happen and we just want to detect @@ -175,10 +182,10 @@ func (a *GasAPI) GasEstimateGasLimit(ctx context.Context, msgIn *types.Message, return res.MsgRct.GasUsed, nil } - if !act.Code.Equals(builtin.PaymentChannelActorCodeID) { + if !act.IsPaymentChannelActor() { return res.MsgRct.GasUsed, nil } - if msgIn.Method != builtin.MethodsPaych.Collect { + if msgIn.Method != builtin0.MethodsPaych.Collect { return res.MsgRct.GasUsed, nil } diff --git a/node/impl/full/multisig.go b/node/impl/full/multisig.go index 2322d5a1e..8c15a27be 100644 --- a/node/impl/full/multisig.go +++ b/node/impl/full/multisig.go @@ -9,10 +9,12 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors" + init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/builtin" - init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" - samsig "github.com/filecoin-project/specs-actors/actors/builtin/multisig" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" + multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig" "github.com/ipfs/go-cid" "github.com/minio/blake2b-simd" @@ -46,7 +48,7 @@ func (a *MsigAPI) MsigCreate(ctx context.Context, req uint64, addrs []address.Ad } // Set up constructor parameters for multisig - msigParams := &samsig.ConstructorParams{ + msigParams := &multisig0.ConstructorParams{ Signers: addrs, NumApprovalsThreshold: req, UnlockDuration: duration, @@ -58,8 +60,9 @@ func (a *MsigAPI) MsigCreate(ctx context.Context, req uint64, addrs []address.Ad } // new actors are created by invoking 'exec' on the init actor with the constructor params - execParams := &init_.ExecParams{ - CodeCID: builtin.MultisigActorCodeID, + // TODO: network upgrade? + execParams := &init0.ExecParams{ + CodeCID: builtin0.MultisigActorCodeID, ConstructorParams: enc, } @@ -70,9 +73,9 @@ func (a *MsigAPI) MsigCreate(ctx context.Context, req uint64, addrs []address.Ad // now we create the message to send this with msg := types.Message{ - To: builtin.InitActorAddr, + To: init_.Address, From: src, - Method: builtin.MethodsInit.Exec, + Method: builtin0.MethodsInit.Exec, Params: enc, Value: val, } @@ -104,7 +107,7 @@ func (a *MsigAPI) MsigPropose(ctx context.Context, msig address.Address, to addr return cid.Undef, xerrors.Errorf("must provide source address") } - enc, actErr := actors.SerializeParams(&samsig.ProposeParams{ + enc, actErr := actors.SerializeParams(&multisig0.ProposeParams{ To: to, Value: amt, Method: abi.MethodNum(method), @@ -118,7 +121,7 @@ func (a *MsigAPI) MsigPropose(ctx context.Context, msig address.Address, to addr To: msig, From: src, Value: types.NewInt(0), - Method: builtin.MethodsMultisig.Propose, + Method: builtin0.MethodsMultisig.Propose, Params: enc, } @@ -136,7 +139,7 @@ func (a *MsigAPI) MsigAddPropose(ctx context.Context, msig address.Address, src return cid.Undef, actErr } - return a.MsigPropose(ctx, msig, msig, big.Zero(), src, uint64(builtin.MethodsMultisig.AddSigner), enc) + return a.MsigPropose(ctx, msig, msig, big.Zero(), src, uint64(builtin0.MethodsMultisig.AddSigner), enc) } func (a *MsigAPI) MsigAddApprove(ctx context.Context, msig address.Address, src address.Address, txID uint64, proposer address.Address, newAdd address.Address, inc bool) (cid.Cid, error) { @@ -145,7 +148,7 @@ func (a *MsigAPI) MsigAddApprove(ctx context.Context, msig address.Address, src return cid.Undef, actErr } - return a.MsigApprove(ctx, msig, txID, proposer, msig, big.Zero(), src, uint64(builtin.MethodsMultisig.AddSigner), enc) + return a.MsigApprove(ctx, msig, txID, proposer, msig, big.Zero(), src, uint64(builtin0.MethodsMultisig.AddSigner), enc) } func (a *MsigAPI) MsigAddCancel(ctx context.Context, msig address.Address, src address.Address, txID uint64, newAdd address.Address, inc bool) (cid.Cid, error) { @@ -154,7 +157,7 @@ func (a *MsigAPI) MsigAddCancel(ctx context.Context, msig address.Address, src a return cid.Undef, actErr } - return a.MsigCancel(ctx, msig, txID, msig, big.Zero(), src, uint64(builtin.MethodsMultisig.AddSigner), enc) + return a.MsigCancel(ctx, msig, txID, msig, big.Zero(), src, uint64(builtin0.MethodsMultisig.AddSigner), enc) } func (a *MsigAPI) MsigSwapPropose(ctx context.Context, msig address.Address, src address.Address, oldAdd address.Address, newAdd address.Address) (cid.Cid, error) { @@ -163,7 +166,7 @@ func (a *MsigAPI) MsigSwapPropose(ctx context.Context, msig address.Address, src return cid.Undef, actErr } - return a.MsigPropose(ctx, msig, msig, big.Zero(), src, uint64(builtin.MethodsMultisig.SwapSigner), enc) + return a.MsigPropose(ctx, msig, msig, big.Zero(), src, uint64(builtin0.MethodsMultisig.SwapSigner), enc) } func (a *MsigAPI) MsigSwapApprove(ctx context.Context, msig address.Address, src address.Address, txID uint64, proposer address.Address, oldAdd address.Address, newAdd address.Address) (cid.Cid, error) { @@ -172,7 +175,7 @@ func (a *MsigAPI) MsigSwapApprove(ctx context.Context, msig address.Address, src return cid.Undef, actErr } - return a.MsigApprove(ctx, msig, txID, proposer, msig, big.Zero(), src, uint64(builtin.MethodsMultisig.SwapSigner), enc) + return a.MsigApprove(ctx, msig, txID, proposer, msig, big.Zero(), src, uint64(builtin0.MethodsMultisig.SwapSigner), enc) } func (a *MsigAPI) MsigSwapCancel(ctx context.Context, msig address.Address, src address.Address, txID uint64, oldAdd address.Address, newAdd address.Address) (cid.Cid, error) { @@ -181,7 +184,7 @@ func (a *MsigAPI) MsigSwapCancel(ctx context.Context, msig address.Address, src return cid.Undef, actErr } - return a.MsigCancel(ctx, msig, txID, msig, big.Zero(), src, uint64(builtin.MethodsMultisig.SwapSigner), enc) + return a.MsigCancel(ctx, msig, txID, msig, big.Zero(), src, uint64(builtin0.MethodsMultisig.SwapSigner), enc) } func (a *MsigAPI) MsigApprove(ctx context.Context, msig address.Address, txID uint64, proposer address.Address, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) { @@ -217,7 +220,7 @@ func (a *MsigAPI) msigApproveOrCancel(ctx context.Context, operation api.MsigPro proposer = proposerID } - p := samsig.ProposalHashData{ + p := multisig0.ProposalHashData{ Requester: proposer, To: to, Value: amt, @@ -231,8 +234,8 @@ func (a *MsigAPI) msigApproveOrCancel(ctx context.Context, operation api.MsigPro } phash := blake2b.Sum256(pser) - enc, err := actors.SerializeParams(&samsig.TxnIDParams{ - ID: samsig.TxnID(txID), + enc, err := actors.SerializeParams(&multisig0.TxnIDParams{ + ID: multisig0.TxnID(txID), ProposalHash: phash[:], }) @@ -248,9 +251,9 @@ func (a *MsigAPI) msigApproveOrCancel(ctx context.Context, operation api.MsigPro */ switch operation { case api.MsigApprove: - msigResponseMethod = builtin.MethodsMultisig.Approve + msigResponseMethod = builtin0.MethodsMultisig.Approve case api.MsigCancel: - msigResponseMethod = builtin.MethodsMultisig.Cancel + msigResponseMethod = builtin0.MethodsMultisig.Cancel default: return cid.Undef, xerrors.Errorf("Invalid operation for msigApproveOrCancel") } @@ -272,7 +275,7 @@ func (a *MsigAPI) msigApproveOrCancel(ctx context.Context, operation api.MsigPro } func serializeAddParams(new address.Address, inc bool) ([]byte, error) { - enc, actErr := actors.SerializeParams(&samsig.AddSignerParams{ + enc, actErr := actors.SerializeParams(&multisig0.AddSignerParams{ Signer: new, Increase: inc, }) @@ -284,7 +287,7 @@ func serializeAddParams(new address.Address, inc bool) ([]byte, error) { } func serializeSwapParams(old address.Address, new address.Address) ([]byte, error) { - enc, actErr := actors.SerializeParams(&samsig.SwapSignerParams{ + enc, actErr := actors.SerializeParams(&multisig0.SwapSignerParams{ From: old, To: new, }) diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 0bd776a60..f8bf92a92 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -3,15 +3,20 @@ package full import ( "bytes" "context" - "errors" - "fmt" "strconv" + lotusbuiltin "github.com/filecoin-project/lotus/chain/actors/builtin" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" + + "github.com/filecoin-project/lotus/chain/actors/builtin/verifreg" + "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/network" cid "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" - cbg "github.com/whyrusleeping/cbor-gen" "go.uber.org/fx" "golang.org/x/xerrors" @@ -20,17 +25,13 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - samsig "github.com/filecoin-project/specs-actors/actors/builtin/multisig" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/builtin/reward" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" - "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/builtin/market" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/builtin/multisig" + "github.com/filecoin-project/lotus/chain/actors/builtin/power" + "github.com/filecoin-project/lotus/chain/actors/builtin/reward" "github.com/filecoin-project/lotus/chain/beacon" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/state" @@ -43,8 +44,6 @@ import ( "github.com/filecoin-project/lotus/node/modules/dtypes" ) -var errBreakForeach = errors.New("break") - type StateAPI struct { fx.In @@ -62,123 +61,177 @@ func (a *StateAPI) StateNetworkName(ctx context.Context) (dtypes.NetworkName, er return stmgr.GetNetworkName(ctx, a.StateManager, a.Chain.GetHeaviestTipSet().ParentState()) } -func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address, filter *bitfield.BitField, filterOut bool, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) { +func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address, sectorNos *bitfield.BitField, tsk types.TipSetKey) ([]*miner.SectorOnChainInfo, error) { ts, err := a.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - return stmgr.GetMinerSectorSet(ctx, a.StateManager, ts, addr, filter, filterOut) + return stmgr.GetMinerSectorSet(ctx, a.StateManager, ts, addr, sectorNos) } -func (a *StateAPI) StateMinerActiveSectors(ctx context.Context, maddr address.Address, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) { - var out []*api.ChainSectorInfo - - err := a.StateManager.WithParentStateTsk(tsk, - a.StateManager.WithActor(maddr, - a.StateManager.WithActorState(ctx, func(store adt.Store, mas *miner.State) error { - var allActive []bitfield.BitField - - err := a.StateManager.WithDeadlines( - a.StateManager.WithEachDeadline( - a.StateManager.WithEachPartition(func(store adt.Store, partIdx uint64, partition *miner.Partition) error { - active, err := partition.ActiveSectors() - if err != nil { - return xerrors.Errorf("partition.ActiveSectors: %w", err) - } - - allActive = append(allActive, active) - return nil - })))(store, mas) - if err != nil { - return xerrors.Errorf("with deadlines: %w", err) - } - - active, err := bitfield.MultiMerge(allActive...) - if err != nil { - return xerrors.Errorf("merging active sector bitfields: %w", err) - } - - out, err = stmgr.LoadSectorsFromSet(ctx, a.Chain.Blockstore(), mas.Sectors, &active, false) - return err - }))) +func (a *StateAPI) StateMinerActiveSectors(ctx context.Context, maddr address.Address, tsk types.TipSetKey) ([]*miner.SectorOnChainInfo, error) { // TODO: only used in cli + ts, err := a.Chain.GetTipSetFromKey(tsk) if err != nil { - return nil, xerrors.Errorf("getting active sectors from partitions: %w", err) + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } + act, err := a.StateManager.LoadActorTsk(ctx, maddr, tsk) + if err != nil { + return nil, xerrors.Errorf("failed to load miner actor: %w", err) + } + + mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act) + if err != nil { + return nil, xerrors.Errorf("failed to load miner actor state: %w", err) + } + + activeSectors, err := miner.AllPartSectors(mas, miner.Partition.ActiveSectors) + if err != nil { + return nil, xerrors.Errorf("merge partition active sets: %w", err) + } + + return stmgr.GetMinerSectorSet(ctx, a.StateManager, ts, maddr, &activeSectors) +} + +func (a *StateAPI) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) { + act, err := a.StateManager.LoadActorTsk(ctx, actor, tsk) + if err != nil { + return miner.MinerInfo{}, xerrors.Errorf("failed to load miner actor: %w", err) + } + + mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act) + if err != nil { + return miner.MinerInfo{}, xerrors.Errorf("failed to load miner actor state: %w", err) + } + + return mas.Info() +} + +func (a *StateAPI) StateMinerDeadlines(ctx context.Context, m address.Address, tsk types.TipSetKey) ([]api.Deadline, error) { + act, err := a.StateManager.LoadActorTsk(ctx, m, tsk) + if err != nil { + return nil, xerrors.Errorf("failed to load miner actor: %w", err) + } + + mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act) + if err != nil { + return nil, xerrors.Errorf("failed to load miner actor state: %w", err) + } + + deadlines, err := mas.NumDeadlines() + if err != nil { + return nil, xerrors.Errorf("getting deadline count: %w", err) + } + + out := make([]api.Deadline, deadlines) + if err := mas.ForEachDeadline(func(i uint64, dl miner.Deadline) error { + ps, err := dl.PostSubmissions() + if err != nil { + return err + } + + out[i] = api.Deadline{ + PostSubmissions: ps, + } + return nil + }); err != nil { + return nil, err + } return out, nil } -func (a *StateAPI) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (api.MinerInfo, error) { - ts, err := a.Chain.GetTipSetFromKey(tsk) +func (a *StateAPI) StateMinerPartitions(ctx context.Context, m address.Address, dlIdx uint64, tsk types.TipSetKey) ([]api.Partition, error) { + act, err := a.StateManager.LoadActorTsk(ctx, m, tsk) if err != nil { - return api.MinerInfo{}, xerrors.Errorf("loading tipset %s: %w", tsk, err) + return nil, xerrors.Errorf("failed to load miner actor: %w", err) } - mi, err := stmgr.StateMinerInfo(ctx, a.StateManager, ts, actor) + mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act) if err != nil { - return api.MinerInfo{}, err + return nil, xerrors.Errorf("failed to load miner actor state: %w", err) } - return api.NewApiMinerInfo(mi), nil -} -func (a *StateAPI) StateMinerDeadlines(ctx context.Context, m address.Address, tsk types.TipSetKey) ([]*miner.Deadline, error) { - var out []*miner.Deadline - return out, a.StateManager.WithParentStateTsk(tsk, - a.StateManager.WithActor(m, - a.StateManager.WithActorState(ctx, - a.StateManager.WithDeadlines( - a.StateManager.WithEachDeadline( - func(store adt.Store, idx uint64, deadline *miner.Deadline) error { - out = append(out, deadline) - return nil - }))))) -} + dl, err := mas.LoadDeadline(dlIdx) + if err != nil { + return nil, xerrors.Errorf("failed to load the deadline: %w", err) + } -func (a *StateAPI) StateMinerPartitions(ctx context.Context, m address.Address, dlIdx uint64, tsk types.TipSetKey) ([]*miner.Partition, error) { - var out []*miner.Partition - return out, a.StateManager.WithParentStateTsk(tsk, - a.StateManager.WithActor(m, - a.StateManager.WithActorState(ctx, - a.StateManager.WithDeadlines( - a.StateManager.WithDeadline(dlIdx, - a.StateManager.WithEachPartition(func(store adt.Store, partIdx uint64, partition *miner.Partition) error { - out = append(out, partition) - return nil - })))))) + var out []api.Partition + err = dl.ForEachPartition(func(_ uint64, part miner.Partition) error { + allSectors, err := part.AllSectors() + if err != nil { + return xerrors.Errorf("getting AllSectors: %w", err) + } + + faultySectors, err := part.FaultySectors() + if err != nil { + return xerrors.Errorf("getting FaultySectors: %w", err) + } + + recoveringSectors, err := part.RecoveringSectors() + if err != nil { + return xerrors.Errorf("getting RecoveringSectors: %w", err) + } + + liveSectors, err := part.LiveSectors() + if err != nil { + return xerrors.Errorf("getting LiveSectors: %w", err) + } + + activeSectors, err := part.ActiveSectors() + if err != nil { + return xerrors.Errorf("getting ActiveSectors: %w", err) + } + + out = append(out, api.Partition{ + AllSectors: allSectors, + FaultySectors: faultySectors, + RecoveringSectors: recoveringSectors, + LiveSectors: liveSectors, + ActiveSectors: activeSectors, + }) + return nil + }) + + return out, err } func (a *StateAPI) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) { - ts, err := a.Chain.GetTipSetFromKey(tsk) + ts, err := a.StateManager.ChainStore().GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - var mas miner.State - _, err = a.StateManager.LoadActorState(ctx, addr, &mas, ts) + act, err := a.StateManager.LoadActor(ctx, addr, ts) if err != nil { - return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err) + return nil, xerrors.Errorf("failed to load miner actor: %w", err) } - return mas.DeadlineInfo(ts.Height()).NextNotElapsed(), nil + mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act) + if err != nil { + return nil, xerrors.Errorf("failed to load miner actor state: %w", err) + } + + di, err := mas.DeadlineInfo(ts.Height()) + if err != nil { + return nil, xerrors.Errorf("failed to get deadline info: %w", err) + } + + return di.NextNotElapsed(), nil } func (a *StateAPI) StateMinerFaults(ctx context.Context, addr address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { - out := bitfield.New() - - err := a.StateManager.WithParentStateTsk(tsk, - a.StateManager.WithActor(addr, - a.StateManager.WithActorState(ctx, - a.StateManager.WithDeadlines( - a.StateManager.WithEachDeadline( - a.StateManager.WithEachPartition(func(store adt.Store, idx uint64, partition *miner.Partition) (err error) { - out, err = bitfield.MergeBitFields(out, partition.Faults) - return err - })))))) + act, err := a.StateManager.LoadActorTsk(ctx, addr, tsk) if err != nil { - return bitfield.BitField{}, err + return bitfield.BitField{}, xerrors.Errorf("failed to load miner actor: %w", err) } - return out, err + mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act) + if err != nil { + return bitfield.BitField{}, xerrors.Errorf("failed to load miner actor state: %w", err) + } + + return miner.AllPartSectors(mas, miner.Partition.FaultySectors) } func (a *StateAPI) StateAllMinerFaults(ctx context.Context, lookback abi.ChainEpoch, endTsk types.TipSetKey) ([]*api.Fault, error) { @@ -225,22 +278,17 @@ func (a *StateAPI) StateAllMinerFaults(ctx context.Context, lookback abi.ChainEp } func (a *StateAPI) StateMinerRecoveries(ctx context.Context, addr address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { - out := bitfield.New() - - err := a.StateManager.WithParentStateTsk(tsk, - a.StateManager.WithActor(addr, - a.StateManager.WithActorState(ctx, - a.StateManager.WithDeadlines( - a.StateManager.WithEachDeadline( - a.StateManager.WithEachPartition(func(store adt.Store, idx uint64, partition *miner.Partition) (err error) { - out, err = bitfield.MergeBitFields(out, partition.Recoveries) - return err - })))))) + act, err := a.StateManager.LoadActorTsk(ctx, addr, tsk) if err != nil { - return bitfield.BitField{}, err + return bitfield.BitField{}, xerrors.Errorf("failed to load miner actor: %w", err) } - return out, err + mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act) + if err != nil { + return bitfield.BitField{}, xerrors.Errorf("failed to load miner actor state: %w", err) + } + + return miner.AllPartSectors(mas, miner.Partition.RecoveringSectors) } func (a *StateAPI) StateMinerPower(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*api.MinerPower, error) { @@ -249,14 +297,15 @@ func (a *StateAPI) StateMinerPower(ctx context.Context, addr address.Address, ts return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - m, net, err := stmgr.GetPower(ctx, a.StateManager, ts, addr) + m, net, hmp, err := stmgr.GetPower(ctx, a.StateManager, ts, addr) if err != nil { return nil, err } return &api.MinerPower{ - MinerPower: m, - TotalPower: net, + MinerPower: m, + TotalPower: net, + HasMinPower: hmp, }, nil } @@ -484,37 +533,31 @@ func (a *StateAPI) StateMarketBalance(ctx context.Context, addr address.Address, func (a *StateAPI) StateMarketParticipants(ctx context.Context, tsk types.TipSetKey) (map[string]api.MarketBalance, error) { out := map[string]api.MarketBalance{} - var state market.State ts, err := a.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - if _, err := a.StateManager.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil { - return nil, err - } - store := a.StateManager.ChainStore().Store(ctx) - escrow, err := adt.AsMap(store, state.EscrowTable) + + state, err := a.StateManager.GetMarketState(ctx, ts) if err != nil { return nil, err } - locked, err := adt.AsMap(store, state.LockedTable) + escrow, err := state.EscrowTable() + if err != nil { + return nil, err + } + locked, err := state.LockedTable() if err != nil { return nil, err } - var es, lk abi.TokenAmount - err = escrow.ForEach(&es, func(k string) error { - a, err := address.NewFromBytes([]byte(k)) + err = escrow.ForEach(func(a address.Address, es abi.TokenAmount) error { + + lk, err := locked.Get(a) if err != nil { return err } - if found, err := locked.Get(abi.AddrKey(a), &lk); err != nil { - return err - } else if !found { - return fmt.Errorf("locked funds not found") - } - out[a.String()] = api.MarketBalance{ Escrow: es, Locked: lk, @@ -530,37 +573,36 @@ func (a *StateAPI) StateMarketParticipants(ctx context.Context, tsk types.TipSet func (a *StateAPI) StateMarketDeals(ctx context.Context, tsk types.TipSetKey) (map[string]api.MarketDeal, error) { out := map[string]api.MarketDeal{} - var state market.State ts, err := a.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - if _, err := a.StateManager.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil { - return nil, err - } - store := a.StateManager.ChainStore().Store(ctx) - da, err := adt.AsArray(store, state.Proposals) + state, err := a.StateManager.GetMarketState(ctx, ts) if err != nil { return nil, err } - sa, err := adt.AsArray(store, state.States) + da, err := state.Proposals() if err != nil { return nil, err } - var d market.DealProposal - if err := da.ForEach(&d, func(i int64) error { - var s market.DealState - if found, err := sa.Get(uint64(i), &s); err != nil { + sa, err := state.States() + if err != nil { + return nil, err + } + + if err := da.ForEach(func(dealID abi.DealID, d market.DealProposal) error { + s, found, err := sa.Get(dealID) + if err != nil { return xerrors.Errorf("failed to get state for deal in proposals array: %w", err) } else if !found { - s.SectorStartEpoch = -1 + s = market.EmptyDealState() } - out[strconv.FormatInt(i, 10)] = api.MarketDeal{ + out[strconv.FormatInt(int64(dealID), 10)] = api.MarketDeal{ Proposal: d, - State: s, + State: *s, } return nil }); err != nil { @@ -578,106 +620,60 @@ func (a *StateAPI) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID } func (a *StateAPI) StateChangedActors(ctx context.Context, old cid.Cid, new cid.Cid) (map[string]types.Actor, error) { - store := adt.WrapStore(ctx, cbor.NewCborStore(a.Chain.Blockstore())) + store := a.Chain.Store(ctx) - nh, err := adt.AsMap(store, new) + oldTree, err := state.LoadStateTree(store, old) if err != nil { - return nil, err + return nil, xerrors.Errorf("failed to load old state tree: %w", err) } - oh, err := adt.AsMap(store, old) + newTree, err := state.LoadStateTree(store, new) if err != nil { - return nil, err + return nil, xerrors.Errorf("failed to load new state tree: %w", err) } - out := map[string]types.Actor{} - - var ( - ncval, ocval cbg.Deferred - buf = bytes.NewReader(nil) - ) - err = nh.ForEach(&ncval, func(k string) error { - var act types.Actor - - addr, err := address.NewFromBytes([]byte(k)) - if err != nil { - return xerrors.Errorf("address in state tree was not valid: %w", err) - } - - found, err := oh.Get(abi.AddrKey(addr), &ocval) - if err != nil { - return err - } - - if found && bytes.Equal(ocval.Raw, ncval.Raw) { - return nil // not changed - } - - buf.Reset(ncval.Raw) - err = act.UnmarshalCBOR(buf) - buf.Reset(nil) - - if err != nil { - return err - } - - out[addr.String()] = act - - return nil - }) - if err != nil { - return nil, err - } - - return out, nil + return state.Diff(oldTree, newTree) } func (a *StateAPI) StateMinerSectorCount(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MinerSectors, error) { - var out api.MinerSectors - - err := a.StateManager.WithParentStateTsk(tsk, - a.StateManager.WithActor(addr, - a.StateManager.WithActorState(ctx, func(store adt.Store, mas *miner.State) error { - var allActive []bitfield.BitField - - err := a.StateManager.WithDeadlines( - a.StateManager.WithEachDeadline( - a.StateManager.WithEachPartition(func(store adt.Store, partIdx uint64, partition *miner.Partition) error { - active, err := partition.ActiveSectors() - if err != nil { - return xerrors.Errorf("partition.ActiveSectors: %w", err) - } - - allActive = append(allActive, active) - return nil - })))(store, mas) - if err != nil { - return xerrors.Errorf("with deadlines: %w", err) - } - - active, err := bitfield.MultiMerge(allActive...) - if err != nil { - return xerrors.Errorf("merging active sector bitfields: %w", err) - } - - out.Active, err = active.Count() - if err != nil { - return xerrors.Errorf("counting active sectors: %w", err) - } - - sarr, err := adt.AsArray(store, mas.Sectors) - if err != nil { - return err - } - - out.Sectors = sarr.Length() - return nil - }))) + act, err := a.StateManager.LoadActorTsk(ctx, addr, tsk) if err != nil { return api.MinerSectors{}, err } - - return out, nil + mas, err := miner.Load(a.Chain.Store(ctx), act) + if err != nil { + return api.MinerSectors{}, err + } + var activeCount, liveCount, faultyCount uint64 + if err := mas.ForEachDeadline(func(_ uint64, dl miner.Deadline) error { + return dl.ForEachPartition(func(_ uint64, part miner.Partition) error { + if active, err := part.ActiveSectors(); err != nil { + return err + } else if count, err := active.Count(); err != nil { + return err + } else { + activeCount += count + } + if live, err := part.LiveSectors(); err != nil { + return err + } else if count, err := live.Count(); err != nil { + return err + } else { + liveCount += count + } + if faulty, err := part.FaultySectors(); err != nil { + return err + } else if count, err := faulty.Count(); err != nil { + return err + } else { + faultyCount += count + } + return nil + }) + }); err != nil { + return api.MinerSectors{}, err + } + return api.MinerSectors{Live: liveCount, Active: activeCount, Faulty: faultyCount}, nil } func (a *StateAPI) StateSectorPreCommitInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) { @@ -685,7 +681,13 @@ func (a *StateAPI) StateSectorPreCommitInfo(ctx context.Context, maddr address.A if err != nil { return miner.SectorPreCommitOnChainInfo{}, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - return stmgr.PreCommitInfo(ctx, a.StateManager, maddr, n, ts) + + pci, err := stmgr.PreCommitInfo(ctx, a.StateManager, maddr, n, ts) + if err != nil { + return miner.SectorPreCommitOnChainInfo{}, err + } + + return *pci, err } func (a *StateAPI) StateSectorGetInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorOnChainInfo, error) { @@ -696,97 +698,28 @@ func (a *StateAPI) StateSectorGetInfo(ctx context.Context, maddr address.Address return stmgr.MinerSectorInfo(ctx, a.StateManager, maddr, n, ts) } -type sectorPartitionCb func(store adt.Store, mas *miner.State, di uint64, pi uint64, part *miner.Partition) error - -func (a *StateAPI) sectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tsk types.TipSetKey, cb sectorPartitionCb) error { - return a.StateManager.WithParentStateTsk(tsk, - a.StateManager.WithActor(maddr, - a.StateManager.WithActorState(ctx, func(store adt.Store, mas *miner.State) error { - return a.StateManager.WithDeadlines(func(store adt.Store, deadlines *miner.Deadlines) error { - err := a.StateManager.WithEachDeadline(func(store adt.Store, di uint64, deadline *miner.Deadline) error { - return a.StateManager.WithEachPartition(func(store adt.Store, pi uint64, partition *miner.Partition) error { - set, err := partition.Sectors.IsSet(uint64(sectorNumber)) - if err != nil { - return xerrors.Errorf("is set: %w", err) - } - if set { - if err := cb(store, mas, di, pi, partition); err != nil { - return err - } - - return errBreakForeach - } - return nil - })(store, di, deadline) - })(store, deadlines) - if err == errBreakForeach { - err = nil - } - return err - })(store, mas) - }))) -} - -func (a *StateAPI) StateSectorExpiration(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tsk types.TipSetKey) (*api.SectorExpiration, error) { - var onTimeEpoch, earlyEpoch abi.ChainEpoch - - err := a.sectorPartition(ctx, maddr, sectorNumber, tsk, func(store adt.Store, mas *miner.State, di uint64, pi uint64, part *miner.Partition) error { - quant := mas.QuantSpecForDeadline(di) - expirations, err := miner.LoadExpirationQueue(store, part.ExpirationsEpochs, quant) - if err != nil { - return xerrors.Errorf("loading expiration queue: %w", err) - } - - var eset miner.ExpirationSet - return expirations.Array.ForEach(&eset, func(epoch int64) error { - set, err := eset.OnTimeSectors.IsSet(uint64(sectorNumber)) - if err != nil { - return xerrors.Errorf("checking if sector is in onTime set: %w", err) - } - if set { - onTimeEpoch = abi.ChainEpoch(epoch) - } - - set, err = eset.EarlySectors.IsSet(uint64(sectorNumber)) - if err != nil { - return xerrors.Errorf("checking if sector is in early set: %w", err) - } - if set { - earlyEpoch = abi.ChainEpoch(epoch) - } - - return nil - }) - }) +func (a *StateAPI) StateSectorExpiration(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorExpiration, error) { + act, err := a.StateManager.LoadActorTsk(ctx, maddr, tsk) if err != nil { return nil, err } - - if onTimeEpoch == 0 { - return nil, xerrors.Errorf("expiration for sector %d not found", sectorNumber) - } - - return &api.SectorExpiration{ - OnTime: onTimeEpoch, - Early: earlyEpoch, - }, nil -} - -func (a *StateAPI) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tsk types.TipSetKey) (*api.SectorLocation, error) { - var found *api.SectorLocation - - err := a.sectorPartition(ctx, maddr, sectorNumber, tsk, func(store adt.Store, mas *miner.State, di, pi uint64, partition *miner.Partition) error { - found = &api.SectorLocation{ - Deadline: di, - Partition: pi, - } - return errBreakForeach - }) + mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act) if err != nil { return nil, err } + return mas.GetSectorExpiration(sectorNumber) +} - return found, nil +func (a *StateAPI) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorLocation, error) { + act, err := a.StateManager.LoadActorTsk(ctx, maddr, tsk) + if err != nil { + return nil, err + } + mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act) + if err != nil { + return nil, err + } + return mas.FindSector(sectorNumber) } func (a *StateAPI) StateListMessages(ctx context.Context, match *types.Message, tsk types.TipSetKey, toheight abi.ChainEpoch) ([]cid.Cid, error) { @@ -864,27 +797,19 @@ func (a *StateAPI) MsigGetAvailableBalance(ctx context.Context, addr address.Add return types.EmptyInt, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - var st samsig.State - act, err := a.StateManager.LoadActorState(ctx, addr, &st, ts) + act, err := a.StateManager.LoadActor(ctx, addr, ts) + if err != nil { + return types.EmptyInt, xerrors.Errorf("failed to load multisig actor: %w", err) + } + msas, err := multisig.Load(a.Chain.Store(ctx), act) if err != nil { return types.EmptyInt, xerrors.Errorf("failed to load multisig actor state: %w", err) } - - if act.Code != builtin.MultisigActorCodeID { - return types.EmptyInt, fmt.Errorf("given actor was not a multisig") + locked, err := msas.LockedBalance(ts.Height()) + if err != nil { + return types.EmptyInt, xerrors.Errorf("failed to compute locked multisig balance: %w", err) } - - if st.UnlockDuration == 0 { - return act.Balance, nil - } - - offset := ts.Height() - st.StartEpoch - if offset > st.UnlockDuration { - return act.Balance, nil - } - - al := st.AmountLocked(offset) - return types.BigSub(act.Balance, al), nil + return types.BigSub(act.Balance, locked), nil } func (a *StateAPI) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) { @@ -904,29 +829,27 @@ func (a *StateAPI) MsigGetVested(ctx context.Context, addr address.Address, star return big.Zero(), nil } - var mst samsig.State - act, err := a.StateManager.LoadActorState(ctx, addr, &mst, endTs) + act, err := a.StateManager.LoadActor(ctx, addr, endTs) if err != nil { - return types.EmptyInt, xerrors.Errorf("failed to load multisig actor state at end epoch: %w", err) + return types.EmptyInt, xerrors.Errorf("failed to load multisig actor at end epoch: %w", err) } - if act.Code != builtin.MultisigActorCodeID { - return types.EmptyInt, fmt.Errorf("given actor was not a multisig") + msas, err := multisig.Load(a.Chain.Store(ctx), act) + if err != nil { + return types.EmptyInt, xerrors.Errorf("failed to load multisig actor state: %w", err) } - if mst.UnlockDuration == 0 || - mst.InitialBalance.IsZero() || - mst.StartEpoch+mst.UnlockDuration <= startTs.Height() || - mst.StartEpoch >= endTs.Height() { - return big.Zero(), nil + startLk, err := msas.LockedBalance(startTs.Height()) + if err != nil { + return types.EmptyInt, xerrors.Errorf("failed to compute locked balance at start height: %w", err) } - startLk := mst.InitialBalance - if startTs.Height() > mst.StartEpoch { - startLk = mst.AmountLocked(startTs.Height() - mst.StartEpoch) + endLk, err := msas.LockedBalance(endTs.Height()) + if err != nil { + return types.EmptyInt, xerrors.Errorf("failed to compute locked balance at end height: %w", err) } - return big.Sub(startLk, mst.AmountLocked(endTs.Height()-mst.StartEpoch)), nil + return types.BigSub(startLk, endLk), nil } var initialPledgeNum = types.NewInt(110) @@ -938,160 +861,133 @@ func (a *StateAPI) StateMinerPreCommitDepositForPower(ctx context.Context, maddr return types.EmptyInt, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - var minerState miner.State - var powerState power.State - var rewardState reward.State - - err = a.StateManager.WithParentStateTsk(tsk, func(state *state.StateTree) error { - if err := a.StateManager.WithActor(maddr, a.StateManager.WithActorState(ctx, &minerState))(state); err != nil { - return xerrors.Errorf("getting miner state: %w", err) - } - - if err := a.StateManager.WithActor(builtin.StoragePowerActorAddr, a.StateManager.WithActorState(ctx, &powerState))(state); err != nil { - return xerrors.Errorf("getting power state: %w", err) - } - - if err := a.StateManager.WithActor(builtin.RewardActorAddr, a.StateManager.WithActorState(ctx, &rewardState))(state); err != nil { - return xerrors.Errorf("getting reward state: %w", err) - } - - return nil - }) + state, err := a.StateManager.ParentState(ts) if err != nil { - return types.EmptyInt, err + return types.EmptyInt, xerrors.Errorf("loading state %s: %w", tsk, err) } - dealWeights := market.VerifyDealsForActivationReturn{ - DealWeight: big.Zero(), - VerifiedDealWeight: big.Zero(), - } - - if len(pci.DealIDs) != 0 { - var err error - params, err := actors.SerializeParams(&market.VerifyDealsForActivationParams{ - DealIDs: pci.DealIDs, - SectorExpiry: pci.Expiration, - }) - if err != nil { - return types.EmptyInt, err - } - - ret, err := a.StateManager.Call(ctx, &types.Message{ - From: maddr, - To: builtin.StorageMarketActorAddr, - Method: builtin.MethodsMarket.VerifyDealsForActivation, - Params: params, - }, ts) - if err != nil { - return types.EmptyInt, err - } - - if err := dealWeights.UnmarshalCBOR(bytes.NewReader(ret.MsgRct.Return)); err != nil { - return types.BigInt{}, err - } - } - - mi, err := a.StateMinerInfo(ctx, maddr, tsk) + ssize, err := pci.SealProof.SectorSize() if err != nil { - return types.EmptyInt, err + return types.EmptyInt, xerrors.Errorf("failed to get resolve size: %w", err) } - ssize := mi.SectorSize + store := a.Chain.Store(ctx) - duration := pci.Expiration - ts.Height() // NB: not exactly accurate, but should always lead us to *over* estimate, not under + var sectorWeight abi.StoragePower + if act, err := state.GetActor(market.Address); err != nil { + return types.EmptyInt, xerrors.Errorf("loading market actor %s: %w", maddr, err) + } else if s, err := market.Load(store, act); err != nil { + return types.EmptyInt, xerrors.Errorf("loading market actor state %s: %w", maddr, err) + } else if w, vw, err := s.VerifyDealsForActivation(maddr, pci.DealIDs, ts.Height(), pci.Expiration); err != nil { + return types.EmptyInt, xerrors.Errorf("verifying deals for activation: %w", err) + } else { + // NB: not exactly accurate, but should always lead us to *over* estimate, not under + duration := pci.Expiration - ts.Height() + sectorWeight = lotusbuiltin.QAPowerForWeight(ssize, duration, w, vw) + } - sectorWeight := miner.QAPowerForWeight(ssize, duration, dealWeights.DealWeight, dealWeights.VerifiedDealWeight) - deposit := miner.PreCommitDepositForPower( - rewardState.ThisEpochRewardSmoothed, - powerState.ThisEpochQAPowerSmoothed, - sectorWeight, - ) + var powerSmoothed lotusbuiltin.FilterEstimate + if act, err := state.GetActor(power.Address); err != nil { + return types.EmptyInt, xerrors.Errorf("loading power actor: %w", err) + } else if s, err := power.Load(store, act); err != nil { + return types.EmptyInt, xerrors.Errorf("loading power actor state: %w", err) + } else if p, err := s.TotalPowerSmoothed(); err != nil { + return types.EmptyInt, xerrors.Errorf("failed to determine total power: %w", err) + } else { + powerSmoothed = p + } + + rewardActor, err := state.GetActor(reward.Address) + if err != nil { + return types.EmptyInt, xerrors.Errorf("loading miner actor: %w", err) + } + + rewardState, err := reward.Load(store, rewardActor) + if err != nil { + return types.EmptyInt, xerrors.Errorf("loading reward actor state: %w", err) + } + + deposit, err := rewardState.PreCommitDepositForPower(powerSmoothed, sectorWeight) + if err != nil { + return big.Zero(), xerrors.Errorf("calculating precommit deposit: %w", err) + } return types.BigDiv(types.BigMul(deposit, initialPledgeNum), initialPledgeDen), nil } func (a *StateAPI) StateMinerInitialPledgeCollateral(ctx context.Context, maddr address.Address, pci miner.SectorPreCommitInfo, tsk types.TipSetKey) (types.BigInt, error) { + // TODO: this repeats a lot of the previous function. Fix that. ts, err := a.Chain.GetTipSetFromKey(tsk) if err != nil { return types.EmptyInt, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - var minerState miner.State - var powerState power.State - var rewardState reward.State - - err = a.StateManager.WithParentStateTsk(tsk, func(state *state.StateTree) error { - if err := a.StateManager.WithActor(maddr, a.StateManager.WithActorState(ctx, &minerState))(state); err != nil { - return xerrors.Errorf("getting miner state: %w", err) - } - - if err := a.StateManager.WithActor(builtin.StoragePowerActorAddr, a.StateManager.WithActorState(ctx, &powerState))(state); err != nil { - return xerrors.Errorf("getting power state: %w", err) - } - - if err := a.StateManager.WithActor(builtin.RewardActorAddr, a.StateManager.WithActorState(ctx, &rewardState))(state); err != nil { - return xerrors.Errorf("getting reward state: %w", err) - } - - return nil - }) + state, err := a.StateManager.ParentState(ts) if err != nil { - return types.EmptyInt, err + return types.EmptyInt, xerrors.Errorf("loading state %s: %w", tsk, err) } - dealWeights := market.VerifyDealsForActivationReturn{ - DealWeight: big.Zero(), - VerifiedDealWeight: big.Zero(), - } - - if len(pci.DealIDs) != 0 { - var err error - params, err := actors.SerializeParams(&market.VerifyDealsForActivationParams{ - DealIDs: pci.DealIDs, - SectorExpiry: pci.Expiration, - }) - if err != nil { - return types.EmptyInt, err - } - - ret, err := a.StateManager.Call(ctx, &types.Message{ - From: maddr, - To: builtin.StorageMarketActorAddr, - Method: builtin.MethodsMarket.VerifyDealsForActivation, - Params: params, - }, ts) - if err != nil { - return types.EmptyInt, err - } - - if err := dealWeights.UnmarshalCBOR(bytes.NewReader(ret.MsgRct.Return)); err != nil { - return types.BigInt{}, err - } - } - - mi, err := a.StateMinerInfo(ctx, maddr, tsk) + ssize, err := pci.SealProof.SectorSize() if err != nil { - return types.EmptyInt, err + return types.EmptyInt, xerrors.Errorf("failed to get resolve size: %w", err) } - ssize := mi.SectorSize + store := a.Chain.Store(ctx) - duration := pci.Expiration - ts.Height() // NB: not exactly accurate, but should always lead us to *over* estimate, not under + var sectorWeight abi.StoragePower + if act, err := state.GetActor(market.Address); err != nil { + return types.EmptyInt, xerrors.Errorf("loading miner actor %s: %w", maddr, err) + } else if s, err := market.Load(store, act); err != nil { + return types.EmptyInt, xerrors.Errorf("loading market actor state %s: %w", maddr, err) + } else if w, vw, err := s.VerifyDealsForActivation(maddr, pci.DealIDs, ts.Height(), pci.Expiration); err != nil { + return types.EmptyInt, xerrors.Errorf("verifying deals for activation: %w", err) + } else { + // NB: not exactly accurate, but should always lead us to *over* estimate, not under + duration := pci.Expiration - ts.Height() + sectorWeight = lotusbuiltin.QAPowerForWeight(ssize, duration, w, vw) + } + + var ( + powerSmoothed lotusbuiltin.FilterEstimate + pledgeCollateral abi.TokenAmount + ) + if act, err := state.GetActor(power.Address); err != nil { + return types.EmptyInt, xerrors.Errorf("loading miner actor: %w", err) + } else if s, err := power.Load(store, act); err != nil { + return types.EmptyInt, xerrors.Errorf("loading power actor state: %w", err) + } else if p, err := s.TotalPowerSmoothed(); err != nil { + return types.EmptyInt, xerrors.Errorf("failed to determine total power: %w", err) + } else if c, err := s.TotalLocked(); err != nil { + return types.EmptyInt, xerrors.Errorf("failed to determine pledge collateral: %w", err) + } else { + powerSmoothed = p + pledgeCollateral = c + } + + rewardActor, err := state.GetActor(reward.Address) + if err != nil { + return types.EmptyInt, xerrors.Errorf("loading miner actor: %w", err) + } + + rewardState, err := reward.Load(store, rewardActor) + if err != nil { + return types.EmptyInt, xerrors.Errorf("loading reward actor state: %w", err) + } circSupply, err := a.StateCirculatingSupply(ctx, ts.Key()) if err != nil { return big.Zero(), xerrors.Errorf("getting circulating supply: %w", err) } - sectorWeight := miner.QAPowerForWeight(ssize, duration, dealWeights.DealWeight, dealWeights.VerifiedDealWeight) - initialPledge := miner.InitialPledgeForPower( + initialPledge, err := rewardState.InitialPledgeForPower( sectorWeight, - rewardState.ThisEpochBaselinePower, - powerState.ThisEpochPledgeCollateral, - rewardState.ThisEpochRewardSmoothed, - powerState.ThisEpochQAPowerSmoothed, + pledgeCollateral, + &powerSmoothed, circSupply.FilCirculating, ) + if err != nil { + return big.Zero(), xerrors.Errorf("calculating initial pledge: %w", err) + } return types.BigDiv(types.BigMul(initialPledge, initialPledgeNum), initialPledgeDen), nil } @@ -1102,30 +998,34 @@ func (a *StateAPI) StateMinerAvailableBalance(ctx context.Context, maddr address return types.EmptyInt, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - var act *types.Actor - var mas miner.State - - if err := a.StateManager.WithParentState(ts, a.StateManager.WithActor(maddr, func(actor *types.Actor) error { - act = actor - return a.StateManager.WithActorState(ctx, &mas)(actor) - })); err != nil { - return types.BigInt{}, xerrors.Errorf("getting miner state: %w", err) + act, err := a.StateManager.LoadActor(ctx, maddr, ts) + if err != nil { + return types.EmptyInt, xerrors.Errorf("failed to load miner actor: %w", err) } - as := store.ActorStore(ctx, a.Chain.Blockstore()) - vested, err := mas.CheckVestedFunds(as, ts.Height()) + mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act) + if err != nil { + return types.EmptyInt, xerrors.Errorf("failed to load miner actor state: %w", err) + } + + vested, err := mas.VestedFunds(ts.Height()) if err != nil { return types.EmptyInt, err } - return types.BigAdd(mas.GetAvailableBalance(act.Balance), vested), nil + abal, err := mas.AvailableBalance(act.Balance) + if err != nil { + return types.EmptyInt, err + } + + return types.BigAdd(abal, vested), nil } // StateVerifiedClientStatus returns the data cap for the given address. -// Returns nil if there is no entry in the data cap table for the +// Returns zero if there is no entry in the data cap table for the // address. -func (a *StateAPI) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*verifreg.DataCap, error) { - act, err := a.StateGetActor(ctx, builtin.VerifiedRegistryActorAddr, tsk) +func (a *StateAPI) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) { + act, err := a.StateGetActor(ctx, builtin0.VerifiedRegistryActorAddr, tsk) if err != nil { return nil, err } @@ -1136,22 +1036,16 @@ func (a *StateAPI) StateVerifiedClientStatus(ctx context.Context, addr address.A return nil, err } - store := a.StateManager.ChainStore().Store(ctx) - - var st verifreg.State - if err := store.Get(ctx, act.Head, &st); err != nil { - return nil, err - } - - vh, err := adt.AsMap(store, st.VerifiedClients) + vrs, err := verifreg.Load(a.StateManager.ChainStore().Store(ctx), act) if err != nil { - return nil, err + return nil, xerrors.Errorf("failed to load verified registry state: %w", err) } - var dcap verifreg.DataCap - if found, err := vh.Get(abi.AddrKey(aid), &dcap); err != nil { - return nil, err - } else if !found { + verified, dcap, err := vrs.VerifiedClientDataCap(aid) + if err != nil { + return nil, xerrors.Errorf("looking up verified client: %w", err) + } + if !verified { return nil, nil } @@ -1169,23 +1063,24 @@ func (a *StateAPI) StateDealProviderCollateralBounds(ctx context.Context, size a return api.DealCollateralBounds{}, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - var powerState power.State - var rewardState reward.State - - err = a.StateManager.WithParentStateTsk(ts.Key(), func(state *state.StateTree) error { - if err := a.StateManager.WithActor(builtin.StoragePowerActorAddr, a.StateManager.WithActorState(ctx, &powerState))(state); err != nil { - return xerrors.Errorf("getting power state: %w", err) - } - - if err := a.StateManager.WithActor(builtin.RewardActorAddr, a.StateManager.WithActorState(ctx, &rewardState))(state); err != nil { - return xerrors.Errorf("getting reward state: %w", err) - } - - return nil - }) - + pact, err := a.StateGetActor(ctx, builtin0.StoragePowerActorAddr, tsk) if err != nil { - return api.DealCollateralBounds{}, xerrors.Errorf("getting power and reward actor states: %w", err) + return api.DealCollateralBounds{}, xerrors.Errorf("failed to load power actor: %w", err) + } + + ract, err := a.StateGetActor(ctx, builtin0.RewardActorAddr, tsk) + if err != nil { + return api.DealCollateralBounds{}, xerrors.Errorf("failed to load reward actor: %w", err) + } + + pst, err := power.Load(a.StateManager.ChainStore().Store(ctx), pact) + if err != nil { + return api.DealCollateralBounds{}, xerrors.Errorf("failed to load power actor state: %w", err) + } + + rst, err := reward.Load(a.StateManager.ChainStore().Store(ctx), ract) + if err != nil { + return api.DealCollateralBounds{}, xerrors.Errorf("failed to load reward actor state: %w", err) } circ, err := a.StateCirculatingSupply(ctx, ts.Key()) @@ -1193,11 +1088,21 @@ func (a *StateAPI) StateDealProviderCollateralBounds(ctx context.Context, size a return api.DealCollateralBounds{}, xerrors.Errorf("getting total circulating supply: %w", err) } - min, max := market.DealProviderCollateralBounds(size, + powClaim, err := pst.TotalPower() + if err != nil { + return api.DealCollateralBounds{}, xerrors.Errorf("getting total power: %w", err) + } + + rewPow, err := rst.ThisEpochBaselinePower() + if err != nil { + return api.DealCollateralBounds{}, xerrors.Errorf("getting reward baseline power: %w", err) + } + + min, max := market0.DealProviderCollateralBounds(size, verified, - powerState.TotalRawBytePower, - powerState.ThisEpochQualityAdjPower, - rewardState.ThisEpochBaselinePower, + powClaim.RawBytePower, + powClaim.QualityAdjPower, + rewPow, circ.FilCirculating, a.StateManager.GetNtwkVersion(ctx, ts.Height())) return api.DealCollateralBounds{ @@ -1212,20 +1117,22 @@ func (a *StateAPI) StateCirculatingSupply(ctx context.Context, tsk types.TipSetK return api.CirculatingSupply{}, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - st, _, err := a.StateManager.TipSetState(ctx, ts) + sTree, err := a.stateForTs(ctx, ts) if err != nil { return api.CirculatingSupply{}, err } - - cst := cbor.NewCborStore(a.Chain.Blockstore()) - sTree, err := state.LoadStateTree(cst, st) - if err != nil { - return api.CirculatingSupply{}, err - } - return a.StateManager.GetCirculatingSupplyDetailed(ctx, ts.Height(), sTree) } +func (a *StateAPI) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (network.Version, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return network.VersionMax, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + + return a.StateManager.GetNtwkVersion(ctx, ts.Height()), nil +} + func (a *StateAPI) StateMsgGasCost(ctx context.Context, inputMsg cid.Cid, tsk types.TipSetKey) (*api.MsgGasCost, error) { var msg cid.Cid var ts *types.TipSet diff --git a/node/impl/full/sync.go b/node/impl/full/sync.go index 31a707b90..dc3bfe230 100644 --- a/node/impl/full/sync.go +++ b/node/impl/full/sync.go @@ -2,6 +2,7 @@ package full import ( "context" + "sync/atomic" cid "github.com/ipfs/go-cid" pubsub "github.com/libp2p/go-libp2p-pubsub" @@ -13,6 +14,7 @@ import ( "github.com/filecoin-project/lotus/chain" "github.com/filecoin-project/lotus/chain/gen/slashfilter" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/node/modules/dtypes" ) @@ -28,7 +30,9 @@ type SyncAPI struct { func (a *SyncAPI) SyncState(ctx context.Context) (*api.SyncState, error) { states := a.Syncer.State() - out := &api.SyncState{} + out := &api.SyncState{ + VMApplied: atomic.LoadUint64(&vm.StatApplied), + } for i := range states { ss := &states[i] diff --git a/node/impl/full/wallet.go b/node/impl/full/wallet.go index af786085b..64231b74e 100644 --- a/node/impl/full/wallet.go +++ b/node/impl/full/wallet.go @@ -36,16 +36,13 @@ func (a *WalletAPI) WalletList(ctx context.Context) ([]address.Address, error) { } func (a *WalletAPI) WalletBalance(ctx context.Context, addr address.Address) (types.BigInt, error) { - var bal types.BigInt - err := a.StateManager.WithParentStateTsk(types.EmptyTSK, a.StateManager.WithActor(addr, func(act *types.Actor) error { - bal = act.Balance - return nil - })) - + act, err := a.StateManager.LoadActorTsk(ctx, addr, types.EmptyTSK) if xerrors.Is(err, types.ErrActorNotFound) { return big.Zero(), nil + } else if err != nil { + return big.Zero(), err } - return bal, err + return act.Balance, nil } func (a *WalletAPI) WalletSign(ctx context.Context, k address.Address, msg []byte) (*crypto.Signature, error) { @@ -70,8 +67,8 @@ func (a *WalletAPI) WalletSignMessage(ctx context.Context, k address.Address, ms }, nil } -func (a *WalletAPI) WalletVerify(ctx context.Context, k address.Address, msg []byte, sig *crypto.Signature) bool { - return sigs.Verify(sig, k, msg) == nil +func (a *WalletAPI) WalletVerify(ctx context.Context, k address.Address, msg []byte, sig *crypto.Signature) (bool, error) { + return sigs.Verify(sig, k, msg) == nil, nil } func (a *WalletAPI) WalletDefaultAddress(ctx context.Context) (address.Address, error) { diff --git a/node/impl/paych/paych.go b/node/impl/paych/paych.go index 94fcc320d..af0a1db15 100644 --- a/node/impl/paych/paych.go +++ b/node/impl/paych/paych.go @@ -9,9 +9,9 @@ import ( "go.uber.org/fx" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/types" full "github.com/filecoin-project/lotus/node/impl/full" "github.com/filecoin-project/lotus/paychmgr" diff --git a/node/impl/storminer.go b/node/impl/storminer.go index 6eedc9f54..5634c140b 100644 --- a/node/impl/storminer.go +++ b/node/impl/storminer.go @@ -305,8 +305,30 @@ func (sm *StorageMinerAPI) MarketImportDealData(ctx context.Context, propCid cid return sm.StorageProvider.ImportDataForDeal(ctx, propCid, fi) } -func (sm *StorageMinerAPI) MarketListDeals(ctx context.Context) ([]storagemarket.StorageDeal, error) { - return sm.StorageProvider.ListDeals(ctx) +func (sm *StorageMinerAPI) listDeals(ctx context.Context) ([]api.MarketDeal, error) { + ts, err := sm.Full.ChainHead(ctx) + if err != nil { + return nil, err + } + tsk := ts.Key() + allDeals, err := sm.Full.StateMarketDeals(ctx, tsk) + if err != nil { + return nil, err + } + + var out []api.MarketDeal + + for _, deal := range allDeals { + if deal.Proposal.Provider == sm.Miner.Address() { + out = append(out, deal) + } + } + + return out, nil +} + +func (sm *StorageMinerAPI) MarketListDeals(ctx context.Context) ([]api.MarketDeal, error) { + return sm.listDeals(ctx) } func (sm *StorageMinerAPI) MarketListRetrievalDeals(ctx context.Context) ([]retrievalmarket.ProviderDealState, error) { @@ -395,8 +417,8 @@ func (sm *StorageMinerAPI) MarketDataTransferUpdates(ctx context.Context) (<-cha return channels, nil } -func (sm *StorageMinerAPI) DealsList(ctx context.Context) ([]storagemarket.StorageDeal, error) { - return sm.StorageProvider.ListDeals(ctx) +func (sm *StorageMinerAPI) DealsList(ctx context.Context) ([]api.MarketDeal, error) { + return sm.listDeals(ctx) } func (sm *StorageMinerAPI) RetrievalDealsList(ctx context.Context) (map[retrievalmarket.ProviderDealIdentifier]retrievalmarket.ProviderDealState, error) { diff --git a/node/node_test.go b/node/node_test.go index 8cc51f629..001b99c04 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -8,24 +8,19 @@ import ( builder "github.com/filecoin-project/lotus/node/test" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/lib/lotuslog" - saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" logging "github.com/ipfs/go-log/v2" "github.com/filecoin-project/lotus/api/test" + "github.com/filecoin-project/lotus/chain/actors/policy" ) func init() { _ = logging.SetLogLevel("*", "INFO") - power.ConsensusMinerMinPower = big.NewInt(2048) - saminer.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ - abi.RegisteredSealProof_StackedDrg2KiBV1: {}, - } - verifreg.MinVerifiedDealSize = big.NewInt(256) + policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048)) + policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1) + policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) } func TestAPI(t *testing.T) { @@ -68,7 +63,12 @@ func TestAPIDealFlowReal(t *testing.T) { logging.SetLogLevel("sub", "ERROR") logging.SetLogLevel("storageminer", "ERROR") - saminer.PreCommitChallengeDelay = 5 + // TODO: just set this globally? + oldDelay := policy.GetPreCommitChallengeDelay() + policy.SetPreCommitChallengeDelay(5) + t.Cleanup(func() { + policy.SetPreCommitChallengeDelay(oldDelay) + }) t.Run("basic", func(t *testing.T) { test.TestDealFlow(t, builder.Builder, time.Second, false, false) diff --git a/node/test/builder.go b/node/test/builder.go index de2071e7a..c496b1e4c 100644 --- a/node/test/builder.go +++ b/node/test/builder.go @@ -37,7 +37,7 @@ import ( "github.com/filecoin-project/lotus/node/repo" "github.com/filecoin-project/lotus/storage/mockstorage" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/ipfs/go-datastore" "github.com/libp2p/go-libp2p-core/crypto" "github.com/libp2p/go-libp2p-core/peer" @@ -83,7 +83,7 @@ func CreateTestStorageNode(ctx context.Context, t *testing.T, waddr address.Addr peerid, err := peer.IDFromPrivateKey(pk) require.NoError(t, err) - enc, err := actors.SerializeParams(&miner.ChangePeerIDParams{NewID: abi.PeerID(peerid)}) + enc, err := actors.SerializeParams(&miner0.ChangePeerIDParams{NewID: abi.PeerID(peerid)}) require.NoError(t, err) msg := &types.Message{ diff --git a/paychmgr/manager.go b/paychmgr/manager.go index 4b102f062..d9c568cbe 100644 --- a/paychmgr/manager.go +++ b/paychmgr/manager.go @@ -4,28 +4,23 @@ import ( "context" "sync" - "github.com/filecoin-project/go-state-types/crypto" - - "github.com/filecoin-project/lotus/node/modules/helpers" - - "github.com/ipfs/go-datastore" - - xerrors "golang.org/x/xerrors" - - "github.com/filecoin-project/lotus/api" - - "github.com/filecoin-project/specs-actors/actors/builtin/paych" - "github.com/filecoin-project/specs-actors/actors/util/adt" - "github.com/ipfs/go-cid" + "github.com/ipfs/go-datastore" logging "github.com/ipfs/go-log/v2" "go.uber.org/fx" + xerrors "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/crypto" + paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/impl/full" + "github.com/filecoin-project/lotus/node/modules/helpers" ) var log = logging.Logger("paych") @@ -40,9 +35,9 @@ type PaychAPI struct { // stateManagerAPI defines the methods needed from StateManager type stateManagerAPI interface { - LoadActorState(ctx context.Context, a address.Address, out interface{}, ts *types.TipSet) (*types.Actor, error) + ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) + GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) - AdtStore(ctx context.Context) adt.Store } // paychAPI defines the API methods needed by the payment channel manager @@ -226,7 +221,7 @@ func (pm *Manager) GetChannelInfo(addr address.Address) (*ChannelInfo, error) { return ca.getChannelInfo(addr) } -func (pm *Manager) CreateVoucher(ctx context.Context, ch address.Address, voucher paych.SignedVoucher) (*api.VoucherCreateResult, error) { +func (pm *Manager) CreateVoucher(ctx context.Context, ch address.Address, voucher paych0.SignedVoucher) (*api.VoucherCreateResult, error) { ca, err := pm.accessorByAddress(ch) if err != nil { return nil, err @@ -238,7 +233,7 @@ func (pm *Manager) CreateVoucher(ctx context.Context, ch address.Address, vouche // CheckVoucherValid checks if the given voucher is valid (is or could become spendable at some point). // If the channel is not in the store, fetches the channel from state (and checks that // the channel To address is owned by the wallet). -func (pm *Manager) CheckVoucherValid(ctx context.Context, ch address.Address, sv *paych.SignedVoucher) error { +func (pm *Manager) CheckVoucherValid(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher) error { // Get an accessor for the channel, creating it from state if necessary ca, err := pm.inboundChannelAccessor(ctx, ch) if err != nil { @@ -250,7 +245,7 @@ func (pm *Manager) CheckVoucherValid(ctx context.Context, ch address.Address, sv } // CheckVoucherSpendable checks if the given voucher is currently spendable -func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, secret []byte, proof []byte) (bool, error) { +func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, secret []byte, proof []byte) (bool, error) { ca, err := pm.accessorByAddress(ch) if err != nil { return false, err @@ -261,7 +256,7 @@ func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address // AddVoucherOutbound adds a voucher for an outbound channel. // Returns an error if the channel is not already in the store. -func (pm *Manager) AddVoucherOutbound(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { +func (pm *Manager) AddVoucherOutbound(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { ca, err := pm.accessorByAddress(ch) if err != nil { return types.NewInt(0), err @@ -272,7 +267,7 @@ func (pm *Manager) AddVoucherOutbound(ctx context.Context, ch address.Address, s // AddVoucherInbound adds a voucher for an inbound channel. // If the channel is not in the store, fetches the channel from state (and checks that // the channel To address is owned by the wallet). -func (pm *Manager) AddVoucherInbound(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { +func (pm *Manager) AddVoucherInbound(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { // Get an accessor for the channel, creating it from state if necessary ca, err := pm.inboundChannelAccessor(ctx, ch) if err != nil { @@ -341,7 +336,7 @@ func (pm *Manager) trackInboundChannel(ctx context.Context, ch address.Address) return pm.store.TrackChannel(stateCi) } -func (pm *Manager) SubmitVoucher(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, secret []byte, proof []byte) (cid.Cid, error) { +func (pm *Manager) SubmitVoucher(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, secret []byte, proof []byte) (cid.Cid, error) { ca, err := pm.accessorByAddress(ch) if err != nil { return cid.Undef, err diff --git a/paychmgr/mock_test.go b/paychmgr/mock_test.go index bc19de223..c761221d2 100644 --- a/paychmgr/mock_test.go +++ b/paychmgr/mock_test.go @@ -2,23 +2,18 @@ package paychmgr import ( "context" - "fmt" + "errors" "sync" - "github.com/filecoin-project/lotus/lib/sigs" - - "github.com/filecoin-project/go-state-types/crypto" - - cbornode "github.com/ipfs/go-ipld-cbor" - - "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/builtin/account" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" - "github.com/ipfs/go-cid" + "github.com/filecoin-project/lotus/lib/sigs" ) type mockManagerAPI struct { @@ -40,29 +35,23 @@ type mockPchState struct { type mockStateManager struct { lk sync.Mutex - accountState map[address.Address]account.State + accountState map[address.Address]address.Address paychState map[address.Address]mockPchState - store adt.Store response *api.InvocResult lastCall *types.Message } func newMockStateManager() *mockStateManager { return &mockStateManager{ - accountState: make(map[address.Address]account.State), + accountState: make(map[address.Address]address.Address), paychState: make(map[address.Address]mockPchState), - store: adt.WrapStore(context.Background(), cbornode.NewMemCborStore()), } } -func (sm *mockStateManager) AdtStore(ctx context.Context) adt.Store { - return sm.store -} - -func (sm *mockStateManager) setAccountState(a address.Address, state account.State) { +func (sm *mockStateManager) setAccountAddress(a address.Address, lookup address.Address) { sm.lk.Lock() defer sm.lk.Unlock() - sm.accountState[a] = state + sm.accountState[a] = lookup } func (sm *mockStateManager) setPaychState(a address.Address, actor *types.Actor, state paych.State) { @@ -71,31 +60,24 @@ func (sm *mockStateManager) setPaychState(a address.Address, actor *types.Actor, sm.paychState[a] = mockPchState{actor, state} } -func (sm *mockStateManager) storeLaneStates(laneStates map[uint64]paych.LaneState) (cid.Cid, error) { - arr := adt.MakeEmptyArray(sm.store) - for i, ls := range laneStates { - ls := ls - if err := arr.Set(i, &ls); err != nil { - return cid.Undef, err - } - } - return arr.Root() -} - -func (sm *mockStateManager) LoadActorState(ctx context.Context, a address.Address, out interface{}, ts *types.TipSet) (*types.Actor, error) { +func (sm *mockStateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { sm.lk.Lock() defer sm.lk.Unlock() + keyAddr, ok := sm.accountState[addr] + if !ok { + return address.Undef, errors.New("not found") + } + return keyAddr, nil +} - if outState, ok := out.(*account.State); ok { - *outState = sm.accountState[a] - return nil, nil +func (sm *mockStateManager) GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) { + sm.lk.Lock() + defer sm.lk.Unlock() + info, ok := sm.paychState[addr] + if !ok { + return nil, nil, errors.New("not found") } - if outState, ok := out.(*paych.State); ok { - info := sm.paychState[a] - *outState = info.state - return info.actor, nil - } - panic(fmt.Sprintf("unexpected state type %v", out)) + return info.actor, info.state, nil } func (sm *mockStateManager) setCallResponse(response *api.InvocResult) { diff --git a/paychmgr/msglistener_test.go b/paychmgr/msglistener_test.go index 2c3ae16e4..4b8ae6f30 100644 --- a/paychmgr/msglistener_test.go +++ b/paychmgr/msglistener_test.go @@ -4,9 +4,7 @@ import ( "testing" "github.com/ipfs/go-cid" - "github.com/stretchr/testify/require" - "golang.org/x/xerrors" ) diff --git a/paychmgr/paych.go b/paychmgr/paych.go index 20d76b7fd..f856b9890 100644 --- a/paychmgr/paych.go +++ b/paychmgr/paych.go @@ -5,22 +5,20 @@ import ( "context" "fmt" - "github.com/filecoin-project/lotus/api" - - "github.com/filecoin-project/specs-actors/actors/util/adt" - "github.com/ipfs/go-cid" + "golang.org/x/xerrors" "github.com/filecoin-project/go-address" cborutil "github.com/filecoin-project/go-cbor-util" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/specs-actors/actors/builtin" + paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" + + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/sigs" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/account" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" - "golang.org/x/xerrors" ) // insufficientFundsErr indicates that there are not enough funds in the @@ -45,6 +43,19 @@ func (e *ErrInsufficientFunds) Shortfall() types.BigInt { return e.shortfall } +type laneState struct { + redeemed big.Int + nonce uint64 +} + +func (ls laneState) Redeemed() (big.Int, error) { + return ls.redeemed, nil +} + +func (ls laneState) Nonce() (uint64, error) { + return ls.nonce, nil +} + // channelAccessor is used to simplify locking when accessing a channel type channelAccessor struct { from address.Address @@ -92,7 +103,7 @@ func (ca *channelAccessor) outboundActiveByFromTo(from, to address.Address) (*Ch // nonce, signing the voucher and storing it in the local datastore. // If there are not enough funds in the channel to create the voucher, returns // the shortfall in funds. -func (ca *channelAccessor) createVoucher(ctx context.Context, ch address.Address, voucher paych.SignedVoucher) (*api.VoucherCreateResult, error) { +func (ca *channelAccessor) createVoucher(ctx context.Context, ch address.Address, voucher paych0.SignedVoucher) (*api.VoucherCreateResult, error) { ca.lk.Lock() defer ca.lk.Unlock() @@ -151,14 +162,14 @@ func (ca *channelAccessor) nextNonceForLane(ci *ChannelInfo, lane uint64) uint64 return maxnonce + 1 } -func (ca *channelAccessor) checkVoucherValid(ctx context.Context, ch address.Address, sv *paych.SignedVoucher) (map[uint64]*paych.LaneState, error) { +func (ca *channelAccessor) checkVoucherValid(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher) (map[uint64]paych.LaneState, error) { ca.lk.Lock() defer ca.lk.Unlock() return ca.checkVoucherValidUnlocked(ctx, ch, sv) } -func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch address.Address, sv *paych.SignedVoucher) (map[uint64]*paych.LaneState, error) { +func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher) (map[uint64]paych.LaneState, error) { if sv.ChannelAddr != ch { return nil, xerrors.Errorf("voucher ChannelAddr doesn't match channel address, got %s, expected %s", sv.ChannelAddr, ch) } @@ -170,12 +181,15 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add } // Load channel "From" account actor state - var actState account.State - _, err = ca.api.LoadActorState(ctx, pchState.From, &actState, nil) + f, err := pchState.From() + if err != nil { + return nil, err + } + + from, err := ca.api.ResolveToKeyAddress(ctx, f, nil) if err != nil { return nil, err } - from := actState.Address // verify voucher signature vb, err := sv.SigningBytes() @@ -199,13 +213,24 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add // If the new voucher nonce value is less than the highest known // nonce for the lane ls, lsExists := laneStates[sv.Lane] - if lsExists && sv.Nonce <= ls.Nonce { - return nil, fmt.Errorf("nonce too low") - } + if lsExists { + n, err := ls.Nonce() + if err != nil { + return nil, err + } - // If the voucher amount is less than the highest known voucher amount - if lsExists && sv.Amount.LessThanEqual(ls.Redeemed) { - return nil, fmt.Errorf("voucher amount is lower than amount for voucher with lower nonce") + if sv.Nonce <= n { + return nil, fmt.Errorf("nonce too low") + } + + // If the voucher amount is less than the highest known voucher amount + r, err := ls.Redeemed() + if err != nil { + return nil, err + } + if sv.Amount.LessThanEqual(r) { + return nil, fmt.Errorf("voucher amount is lower than amount for voucher with lower nonce") + } } // Total redeemed is the total redeemed amount for all lanes, including @@ -230,7 +255,12 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add // Total required balance = total redeemed + toSend // Must not exceed actor balance - newTotal := types.BigAdd(totalRedeemed, pchState.ToSend) + ts, err := pchState.ToSend() + if err != nil { + return nil, err + } + + newTotal := types.BigAdd(totalRedeemed, ts) if act.Balance.LessThan(newTotal) { return nil, newErrInsufficientFunds(types.BigSub(newTotal, act.Balance)) } @@ -242,7 +272,7 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add return laneStates, nil } -func (ca *channelAccessor) checkVoucherSpendable(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, secret []byte, proof []byte) (bool, error) { +func (ca *channelAccessor) checkVoucherSpendable(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, secret []byte, proof []byte) (bool, error) { ca.lk.Lock() defer ca.lk.Unlock() @@ -281,7 +311,7 @@ func (ca *channelAccessor) checkVoucherSpendable(ctx context.Context, ch address } } - enc, err := actors.SerializeParams(&paych.UpdateChannelStateParams{ + enc, err := actors.SerializeParams(&paych0.UpdateChannelStateParams{ Sv: *sv, Secret: secret, Proof: proof, @@ -308,22 +338,22 @@ func (ca *channelAccessor) checkVoucherSpendable(ctx context.Context, ch address } func (ca *channelAccessor) getPaychRecipient(ctx context.Context, ch address.Address) (address.Address, error) { - var state paych.State - if _, err := ca.api.LoadActorState(ctx, ch, &state, nil); err != nil { + _, state, err := ca.api.GetPaychState(ctx, ch, nil) + if err != nil { return address.Address{}, err } - return state.To, nil + return state.To() } -func (ca *channelAccessor) addVoucher(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { +func (ca *channelAccessor) addVoucher(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { ca.lk.Lock() defer ca.lk.Unlock() return ca.addVoucherUnlocked(ctx, ch, sv, proof, minDelta) } -func (ca *channelAccessor) addVoucherUnlocked(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { +func (ca *channelAccessor) addVoucherUnlocked(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { ci, err := ca.store.ByAddress(ch) if err != nil { return types.BigInt{}, err @@ -367,7 +397,10 @@ func (ca *channelAccessor) addVoucherUnlocked(ctx context.Context, ch address.Ad laneState, exists := laneStates[sv.Lane] redeemed := big.NewInt(0) if exists { - redeemed = laneState.Redeemed + redeemed, err = laneState.Redeemed() + if err != nil { + return types.NewInt(0), err + } } delta := types.BigSub(sv.Amount, redeemed) @@ -387,7 +420,7 @@ func (ca *channelAccessor) addVoucherUnlocked(ctx context.Context, ch address.Ad return delta, ca.store.putChannelInfo(ci) } -func (ca *channelAccessor) submitVoucher(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, secret []byte, proof []byte) (cid.Cid, error) { +func (ca *channelAccessor) submitVoucher(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, secret []byte, proof []byte) (cid.Cid, error) { ca.lk.Lock() defer ca.lk.Unlock() @@ -428,7 +461,7 @@ func (ca *channelAccessor) submitVoucher(ctx context.Context, ch address.Address } } - enc, err := actors.SerializeParams(&paych.UpdateChannelStateParams{ + enc, err := actors.SerializeParams(&paych0.UpdateChannelStateParams{ Sv: *sv, Secret: secret, Proof: proof, @@ -487,13 +520,11 @@ func (ca *channelAccessor) listVouchers(ctx context.Context, ch address.Address) // laneState gets the LaneStates from chain, then applies all vouchers in // the data store over the chain state -func (ca *channelAccessor) laneState(ctx context.Context, state *paych.State, ch address.Address) (map[uint64]*paych.LaneState, error) { +func (ca *channelAccessor) laneState(ctx context.Context, state paych.State, ch address.Address) (map[uint64]paych.LaneState, error) { // TODO: we probably want to call UpdateChannelState with all vouchers to be fully correct // (but technically dont't need to) - // Get the lane state from the chain - store := ca.api.AdtStore(ctx) - lsamt, err := adt.AsArray(store, state.LaneStates) + laneCount, err := state.LaneCount() if err != nil { return nil, err } @@ -501,11 +532,9 @@ func (ca *channelAccessor) laneState(ctx context.Context, state *paych.State, ch // 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 paych.LaneState - laneStates := make(map[uint64]*paych.LaneState, lsamt.Length()) - err = lsamt.ForEach(&ls, func(i int64) error { - current := ls - laneStates[uint64(i)] = ¤t + laneStates := make(map[uint64]paych.LaneState, laneCount) + err = state.ForEachLaneState(func(idx uint64, ls paych.LaneState) error { + laneStates[idx] = ls return nil }) if err != nil { @@ -526,27 +555,24 @@ func (ca *channelAccessor) laneState(ctx context.Context, state *paych.State, ch // If there's a voucher for a lane that isn't in chain state just // create it ls, ok := laneStates[v.Voucher.Lane] - if !ok { - ls = &paych.LaneState{ - Redeemed: types.NewInt(0), - Nonce: 0, + if ok { + n, err := ls.Nonce() + if err != nil { + return nil, err + } + if v.Voucher.Nonce < n { + continue } - laneStates[v.Voucher.Lane] = ls } - if v.Voucher.Nonce < ls.Nonce { - continue - } - - ls.Nonce = v.Voucher.Nonce - ls.Redeemed = v.Voucher.Amount + laneStates[v.Voucher.Lane] = laneState{v.Voucher.Amount, v.Voucher.Nonce} } return laneStates, nil } // Get the total redeemed amount across all lanes, after applying the voucher -func (ca *channelAccessor) totalRedeemedWithVoucher(laneStates map[uint64]*paych.LaneState, sv *paych.SignedVoucher) (big.Int, error) { +func (ca *channelAccessor) totalRedeemedWithVoucher(laneStates map[uint64]paych.LaneState, sv *paych0.SignedVoucher) (big.Int, error) { // TODO: merges if len(sv.Merges) != 0 { return big.Int{}, xerrors.Errorf("dont currently support paych lane merges") @@ -554,17 +580,31 @@ func (ca *channelAccessor) totalRedeemedWithVoucher(laneStates map[uint64]*paych total := big.NewInt(0) for _, ls := range laneStates { - total = big.Add(total, ls.Redeemed) + r, err := ls.Redeemed() + if err != nil { + return big.Int{}, err + } + total = big.Add(total, r) } lane, ok := laneStates[sv.Lane] if ok { // If the voucher is for an existing lane, and the voucher nonce // is higher than the lane nonce - if sv.Nonce > lane.Nonce { + n, err := lane.Nonce() + if err != nil { + return big.Int{}, err + } + + if sv.Nonce > n { // Add the delta between the redeemed amount and the voucher // amount to the total - delta := big.Sub(sv.Amount, lane.Redeemed) + r, err := lane.Redeemed() + if err != nil { + return big.Int{}, err + } + + delta := big.Sub(sv.Amount, r) total = big.Add(total, delta) } } else { diff --git a/paychmgr/paych_test.go b/paychmgr/paych_test.go index 18c6655da..b27b1e540 100644 --- a/paychmgr/paych_test.go +++ b/paychmgr/paych_test.go @@ -5,31 +5,24 @@ import ( "context" "testing" - "github.com/filecoin-project/lotus/api" - - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/ipfs/go-cid" - - "github.com/filecoin-project/go-state-types/crypto" - "github.com/filecoin-project/lotus/lib/sigs" - - "github.com/stretchr/testify/require" - - "github.com/filecoin-project/go-state-types/big" - - "github.com/filecoin-project/go-state-types/abi" - tutils "github.com/filecoin-project/specs-actors/support/testing" - - "github.com/filecoin-project/specs-actors/actors/builtin/paych" - - "github.com/filecoin-project/specs-actors/actors/builtin/account" - - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/lotus/chain/types" - ds "github.com/ipfs/go-datastore" ds_sync "github.com/ipfs/go-datastore/sync" + "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" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/specs-actors/actors/builtin" + paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" + tutils "github.com/filecoin-project/specs-actors/support/testing" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" + paychmock "github.com/filecoin-project/lotus/chain/actors/builtin/paych/mock" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/sigs" ) func TestCheckVoucherValid(t *testing.T) { @@ -46,8 +39,8 @@ func TestCheckVoucherValid(t *testing.T) { toAcct := tutils.NewActorAddr(t, "toAct") mock := newMockManagerAPI() - mock.setAccountState(fromAcct, account.State{Address: from}) - mock.setAccountState(toAcct, account.State{Address: to}) + mock.setAccountAddress(fromAcct, from) + mock.setAccountAddress(toAcct, to) tcases := []struct { name string @@ -96,10 +89,7 @@ func TestCheckVoucherValid(t *testing.T) { voucherLane: 1, voucherNonce: 2, laneStates: map[uint64]paych.LaneState{ - 1: { - Redeemed: big.NewInt(2), - Nonce: 3, - }, + 1: paychmock.NewMockLaneState(big.NewInt(2), 3), }, }, { name: "passes when nonce higher", @@ -110,10 +100,7 @@ func TestCheckVoucherValid(t *testing.T) { voucherLane: 1, voucherNonce: 3, laneStates: map[uint64]paych.LaneState{ - 1: { - Redeemed: big.NewInt(2), - Nonce: 2, - }, + 1: paychmock.NewMockLaneState(big.NewInt(2), 2), }, }, { name: "passes when nonce for different lane", @@ -124,10 +111,7 @@ func TestCheckVoucherValid(t *testing.T) { voucherLane: 2, voucherNonce: 2, laneStates: map[uint64]paych.LaneState{ - 1: { - Redeemed: big.NewInt(2), - Nonce: 3, - }, + 1: paychmock.NewMockLaneState(big.NewInt(2), 3), }, }, { name: "fails when voucher has higher nonce but lower value than lane state", @@ -139,10 +123,7 @@ func TestCheckVoucherValid(t *testing.T) { voucherLane: 1, voucherNonce: 3, laneStates: map[uint64]paych.LaneState{ - 1: { - Redeemed: big.NewInt(6), - Nonce: 2, - }, + 1: paychmock.NewMockLaneState(big.NewInt(6), 2), }, }, { name: "fails when voucher + ToSend > balance", @@ -168,10 +149,7 @@ func TestCheckVoucherValid(t *testing.T) { voucherNonce: 2, laneStates: map[uint64]paych.LaneState{ // Lane 1 (same as voucher lane 1) - 1: { - Redeemed: big.NewInt(4), - Nonce: 1, - }, + 1: paychmock.NewMockLaneState(big.NewInt(4), 1), }, }, { // required balance = toSend + total redeemed @@ -188,10 +166,7 @@ func TestCheckVoucherValid(t *testing.T) { voucherNonce: 1, laneStates: map[uint64]paych.LaneState{ // Lane 2 (different from voucher lane 1) - 2: { - Redeemed: big.NewInt(4), - Nonce: 1, - }, + 2: paychmock.NewMockLaneState(big.NewInt(4), 1), }, }} @@ -208,18 +183,8 @@ func TestCheckVoucherValid(t *testing.T) { Balance: tcase.actorBalance, } - // Set the state of the channel's lanes - laneStates, err := mock.storeLaneStates(tcase.laneStates) - require.NoError(t, err) - - mock.setPaychState(ch, act, paych.State{ - From: fromAcct, - To: toAcct, - ToSend: tcase.toSend, - SettlingAt: abi.ChainEpoch(0), - MinSettleHeight: abi.ChainEpoch(0), - LaneStates: laneStates, - }) + mock.setPaychState(ch, act, paychmock.NewMockPayChState( + fromAcct, toAcct, abi.ChainEpoch(0), tcase.toSend, tcase.laneStates)) // Create a manager mgr, err := newManager(store, mock) @@ -255,22 +220,16 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) { minDelta := big.NewInt(0) mock := newMockManagerAPI() - mock.setAccountState(fromAcct, account.State{Address: from}) - mock.setAccountState(toAcct, account.State{Address: to}) + mock.setAccountAddress(fromAcct, from) + mock.setAccountAddress(toAcct, to) store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore())) actorBalance := big.NewInt(10) toSend := big.NewInt(1) laneStates := map[uint64]paych.LaneState{ - 1: { - Nonce: 1, - Redeemed: big.NewInt(3), - }, - 2: { - Nonce: 1, - Redeemed: big.NewInt(4), - }, + 1: paychmock.NewMockLaneState(big.NewInt(3), 1), + 2: paychmock.NewMockLaneState(big.NewInt(4), 1), } act := &types.Actor{ @@ -280,16 +239,7 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) { Balance: actorBalance, } - lsCid, err := mock.storeLaneStates(laneStates) - require.NoError(t, err) - mock.setPaychState(ch, act, paych.State{ - From: fromAcct, - To: toAcct, - ToSend: toSend, - SettlingAt: abi.ChainEpoch(0), - MinSettleHeight: abi.ChainEpoch(0), - LaneStates: lsCid, - }) + mock.setPaychState(ch, act, paychmock.NewMockPayChState(fromAcct, toAcct, abi.ChainEpoch(0), toSend, laneStates)) mgr, err := newManager(store, mock) require.NoError(t, err) @@ -389,7 +339,7 @@ func TestCreateVoucher(t *testing.T) { // Create a voucher in lane 1 voucherLane1Amt := big.NewInt(5) - voucher := paych.SignedVoucher{ + voucher := paych0.SignedVoucher{ Lane: 1, Amount: voucherLane1Amt, } @@ -404,7 +354,7 @@ func TestCreateVoucher(t *testing.T) { // Create a voucher in lane 1 again, with a higher amount voucherLane1Amt = big.NewInt(8) - voucher = paych.SignedVoucher{ + voucher = paych0.SignedVoucher{ Lane: 1, Amount: voucherLane1Amt, } @@ -419,7 +369,7 @@ func TestCreateVoucher(t *testing.T) { // Create a voucher in lane 2 that covers all the remaining funds // in the channel voucherLane2Amt := big.Sub(s.amt, voucherLane1Amt) - voucher = paych.SignedVoucher{ + voucher = paych0.SignedVoucher{ Lane: 2, Amount: voucherLane2Amt, } @@ -433,7 +383,7 @@ func TestCreateVoucher(t *testing.T) { // Create a voucher in lane 2 that exceeds the remaining funds in the // channel voucherLane2Amt = big.Add(voucherLane2Amt, big.NewInt(1)) - voucher = paych.SignedVoucher{ + voucher = paych0.SignedVoucher{ Lane: 2, Amount: voucherLane2Amt, } @@ -567,8 +517,8 @@ func TestAllocateLaneWithExistingLaneState(t *testing.T) { toAcct := tutils.NewActorAddr(t, "toAct") mock := newMockManagerAPI() - mock.setAccountState(fromAcct, account.State{Address: from}) - mock.setAccountState(toAcct, account.State{Address: to}) + mock.setAccountAddress(fromAcct, from) + mock.setAccountAddress(toAcct, to) mock.addWalletAddress(to) store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore())) @@ -584,16 +534,7 @@ func TestAllocateLaneWithExistingLaneState(t *testing.T) { Balance: actorBalance, } - arr, err := adt.MakeEmptyArray(mock.store).Root() - require.NoError(t, err) - mock.setPaychState(ch, act, paych.State{ - From: fromAcct, - To: toAcct, - ToSend: toSend, - SettlingAt: abi.ChainEpoch(0), - MinSettleHeight: abi.ChainEpoch(0), - LaneStates: arr, - }) + mock.setPaychState(ch, act, paychmock.NewMockPayChState(fromAcct, toAcct, abi.ChainEpoch(0), toSend, make(map[uint64]paych.LaneState))) mgr, err := newManager(store, mock) require.NoError(t, err) @@ -681,19 +622,10 @@ func TestAddVoucherInboundWalletKey(t *testing.T) { } mock := newMockManagerAPI() - arr, err := adt.MakeEmptyArray(mock.store).Root() - require.NoError(t, err) - mock.setAccountState(fromAcct, account.State{Address: from}) - mock.setAccountState(toAcct, account.State{Address: to}) + mock.setAccountAddress(fromAcct, from) + mock.setAccountAddress(toAcct, to) - mock.setPaychState(ch, act, paych.State{ - From: fromAcct, - To: toAcct, - ToSend: types.NewInt(0), - SettlingAt: abi.ChainEpoch(0), - MinSettleHeight: abi.ChainEpoch(0), - LaneStates: arr, - }) + mock.setPaychState(ch, act, paychmock.NewMockPayChState(fromAcct, toAcct, abi.ChainEpoch(0), types.NewInt(0), make(map[uint64]paych.LaneState))) // Create a manager store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore())) @@ -840,7 +772,7 @@ func TestCheckSpendable(t *testing.T) { // Check that the secret and proof were passed through correctly lastCall := s.mock.getLastCall() - var p paych.UpdateChannelStateParams + var p paych0.UpdateChannelStateParams err = p.UnmarshalCBOR(bytes.NewReader(lastCall.Params)) require.NoError(t, err) require.Equal(t, otherProof, p.Proof) @@ -854,7 +786,7 @@ func TestCheckSpendable(t *testing.T) { require.True(t, spendable) lastCall = s.mock.getLastCall() - var p2 paych.UpdateChannelStateParams + var p2 paych0.UpdateChannelStateParams err = p2.UnmarshalCBOR(bytes.NewReader(lastCall.Params)) require.NoError(t, err) require.Equal(t, proof, p2.Proof) @@ -911,7 +843,7 @@ func TestSubmitVoucher(t *testing.T) { // Check that the secret and proof were passed through correctly msg := s.mock.pushedMessages(submitCid) - var p paych.UpdateChannelStateParams + var p paych0.UpdateChannelStateParams err = p.UnmarshalCBOR(bytes.NewReader(msg.Message.Params)) require.NoError(t, err) require.Equal(t, submitProof, p.Proof) @@ -931,7 +863,7 @@ func TestSubmitVoucher(t *testing.T) { require.NoError(t, err) msg = s.mock.pushedMessages(submitCid) - var p2 paych.UpdateChannelStateParams + var p2 paych0.UpdateChannelStateParams err = p2.UnmarshalCBOR(bytes.NewReader(msg.Message.Params)) require.NoError(t, err) require.Equal(t, addVoucherProof2, p2.Proof) @@ -947,7 +879,7 @@ func TestSubmitVoucher(t *testing.T) { require.NoError(t, err) msg = s.mock.pushedMessages(submitCid) - var p3 paych.UpdateChannelStateParams + var p3 paych0.UpdateChannelStateParams err = p3.UnmarshalCBOR(bytes.NewReader(msg.Message.Params)) require.NoError(t, err) require.Equal(t, proof3, p3.Proof) @@ -986,10 +918,8 @@ func testSetupMgrWithChannel(ctx context.Context, t *testing.T) *testScaffold { toAcct := tutils.NewActorAddr(t, "toAct") mock := newMockManagerAPI() - arr, err := adt.MakeEmptyArray(mock.store).Root() - require.NoError(t, err) - mock.setAccountState(fromAcct, account.State{Address: from}) - mock.setAccountState(toAcct, account.State{Address: to}) + mock.setAccountAddress(fromAcct, from) + mock.setAccountAddress(toAcct, to) // Create channel in state balance := big.NewInt(20) @@ -999,14 +929,7 @@ func testSetupMgrWithChannel(ctx context.Context, t *testing.T) *testScaffold { Nonce: 0, Balance: balance, } - mock.setPaychState(ch, act, paych.State{ - From: fromAcct, - To: toAcct, - ToSend: big.NewInt(0), - SettlingAt: abi.ChainEpoch(0), - MinSettleHeight: abi.ChainEpoch(0), - LaneStates: arr, - }) + mock.setPaychState(ch, act, paychmock.NewMockPayChState(fromAcct, toAcct, abi.ChainEpoch(0), big.NewInt(0), make(map[uint64]paych.LaneState))) store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore())) mgr, err := newManager(store, mock) @@ -1043,8 +966,8 @@ func testGenerateKeyPair(t *testing.T) ([]byte, []byte) { return priv, pub } -func createTestVoucher(t *testing.T, ch address.Address, voucherLane uint64, nonce uint64, voucherAmount big.Int, key []byte) *paych.SignedVoucher { - sv := &paych.SignedVoucher{ +func createTestVoucher(t *testing.T, ch address.Address, voucherLane uint64, nonce uint64, voucherAmount big.Int, key []byte) *paych0.SignedVoucher { + sv := &paych0.SignedVoucher{ ChannelAddr: ch, Lane: voucherLane, Nonce: nonce, @@ -1059,13 +982,13 @@ func createTestVoucher(t *testing.T, ch address.Address, voucherLane uint64, non return sv } -func createTestVoucherWithExtra(t *testing.T, ch address.Address, voucherLane uint64, nonce uint64, voucherAmount big.Int, key []byte) *paych.SignedVoucher { - sv := &paych.SignedVoucher{ +func createTestVoucherWithExtra(t *testing.T, ch address.Address, voucherLane uint64, nonce uint64, voucherAmount big.Int, key []byte) *paych0.SignedVoucher { + sv := &paych0.SignedVoucher{ ChannelAddr: ch, Lane: voucherLane, Nonce: nonce, Amount: voucherAmount, - Extra: &paych.ModVerifyParams{ + Extra: &paych0.ModVerifyParams{ Actor: tutils.NewActorAddr(t, "act"), }, } @@ -1083,13 +1006,13 @@ type mockBestSpendableAPI struct { mgr *Manager } -func (m *mockBestSpendableAPI) PaychVoucherList(ctx context.Context, ch address.Address) ([]*paych.SignedVoucher, error) { +func (m *mockBestSpendableAPI) PaychVoucherList(ctx context.Context, ch address.Address) ([]*paych0.SignedVoucher, error) { vi, err := m.mgr.ListVouchers(ctx, ch) if err != nil { return nil, err } - out := make([]*paych.SignedVoucher, len(vi)) + out := make([]*paych0.SignedVoucher, len(vi)) for k, v := range vi { out[k] = v.Voucher } @@ -1097,7 +1020,7 @@ func (m *mockBestSpendableAPI) PaychVoucherList(ctx context.Context, ch address. return out, nil } -func (m *mockBestSpendableAPI) PaychVoucherCheckSpendable(ctx context.Context, ch address.Address, voucher *paych.SignedVoucher, secret []byte, proof []byte) (bool, error) { +func (m *mockBestSpendableAPI) PaychVoucherCheckSpendable(ctx context.Context, ch address.Address, voucher *paych0.SignedVoucher, secret []byte, proof []byte) (bool, error) { return m.mgr.CheckVoucherSpendable(ctx, ch, voucher, secret, proof) } diff --git a/paychmgr/paychget_test.go b/paychmgr/paychget_test.go index 1f3e4c396..430e66c67 100644 --- a/paychmgr/paychget_test.go +++ b/paychmgr/paychget_test.go @@ -6,29 +6,23 @@ import ( "testing" "time" - "github.com/filecoin-project/specs-actors/actors/builtin/account" - "github.com/filecoin-project/specs-actors/actors/util/adt" - - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" - cborrpc "github.com/filecoin-project/go-cbor-util" - - init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" - - "github.com/filecoin-project/specs-actors/actors/builtin" - - "github.com/filecoin-project/lotus/chain/types" - - "github.com/filecoin-project/go-address" - - "github.com/filecoin-project/go-state-types/big" - tutils "github.com/filecoin-project/specs-actors/support/testing" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" ds_sync "github.com/ipfs/go-datastore/sync" - "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" + "github.com/filecoin-project/specs-actors/actors/builtin" + init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" + tutils "github.com/filecoin-project/specs-actors/support/testing" + + lotusinit "github.com/filecoin-project/lotus/chain/actors/builtin/init" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" + paychmock "github.com/filecoin-project/lotus/chain/actors/builtin/paych/mock" + "github.com/filecoin-project/lotus/chain/types" ) func testChannelResponse(t *testing.T, ch address.Address) types.MessageReceipt { @@ -67,7 +61,7 @@ func TestPaychGetCreateChannelMsg(t *testing.T) { pushedMsg := mock.pushedMessages(mcid) require.Equal(t, from, pushedMsg.Message.From) - require.Equal(t, builtin.InitActorAddr, pushedMsg.Message.To) + require.Equal(t, lotusinit.Address, pushedMsg.Message.To) require.Equal(t, amt, pushedMsg.Message.Value) } @@ -719,7 +713,7 @@ func TestPaychGetMergeAddFunds(t *testing.T) { // Check create message amount is correct createMsg := mock.pushedMessages(createMsgCid) require.Equal(t, from, createMsg.Message.From) - require.Equal(t, builtin.InitActorAddr, createMsg.Message.To) + require.Equal(t, lotusinit.Address, createMsg.Message.To) require.Equal(t, createAmt, createMsg.Message.Value) // Check merged add funds amount is the sum of the individual @@ -815,7 +809,7 @@ func TestPaychGetMergeAddFundsCtxCancelOne(t *testing.T) { // Check create message amount is correct createMsg := mock.pushedMessages(createMsgCid) require.Equal(t, from, createMsg.Message.From) - require.Equal(t, builtin.InitActorAddr, createMsg.Message.To) + require.Equal(t, lotusinit.Address, createMsg.Message.To) require.Equal(t, createAmt, createMsg.Message.Value) // Check merged add funds amount only includes the second add funds amount @@ -897,7 +891,7 @@ func TestPaychGetMergeAddFundsCtxCancelAll(t *testing.T) { // Check create message amount is correct createMsg := mock.pushedMessages(createMsgCid) require.Equal(t, from, createMsg.Message.From) - require.Equal(t, builtin.InitActorAddr, createMsg.Message.To) + require.Equal(t, lotusinit.Address, createMsg.Message.To) require.Equal(t, createAmt, createMsg.Message.Value) } @@ -976,25 +970,15 @@ func TestPaychAvailableFunds(t *testing.T) { require.EqualValues(t, 0, av.VoucherReedeemedAmt.Int64()) // Create channel in state - arr, err := adt.MakeEmptyArray(mock.store).Root() - require.NoError(t, err) - mock.setAccountState(fromAcct, account.State{Address: from}) - mock.setAccountState(toAcct, account.State{Address: to}) + mock.setAccountAddress(fromAcct, from) + mock.setAccountAddress(toAcct, to) act := &types.Actor{ Code: builtin.AccountActorCodeID, Head: cid.Cid{}, Nonce: 0, Balance: createAmt, } - mock.setPaychState(ch, act, paych.State{ - From: fromAcct, - To: toAcct, - ToSend: big.NewInt(0), - SettlingAt: abi.ChainEpoch(0), - MinSettleHeight: abi.ChainEpoch(0), - LaneStates: arr, - }) - + mock.setPaychState(ch, act, paychmock.NewMockPayChState(fromAcct, toAcct, abi.ChainEpoch(0), big.NewInt(0), make(map[uint64]paych.LaneState))) // Send create channel response response := testChannelResponse(t, ch) mock.receiveMsgResponse(createMsgCid, response) diff --git a/paychmgr/settler/settler.go b/paychmgr/settler/settler.go index 45f24cdd9..654ed66cc 100644 --- a/paychmgr/settler/settler.go +++ b/paychmgr/settler/settler.go @@ -13,8 +13,9 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" @@ -38,9 +39,9 @@ type API struct { type settlerAPI interface { PaychList(context.Context) ([]address.Address, error) PaychStatus(context.Context, address.Address) (*api.PaychStatus, error) - PaychVoucherCheckSpendable(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error) - PaychVoucherList(context.Context, address.Address) ([]*paych.SignedVoucher, error) - PaychVoucherSubmit(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error) + PaychVoucherCheckSpendable(context.Context, address.Address, *paych0.SignedVoucher, []byte, []byte) (bool, error) + PaychVoucherList(context.Context, address.Address) ([]*paych0.SignedVoucher, error) + PaychVoucherSubmit(context.Context, address.Address, *paych0.SignedVoucher, []byte, []byte) (cid.Cid, error) StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) } @@ -85,7 +86,7 @@ func (pcs *paymentChannelSettler) messageHandler(msg *types.Message, rec *types. if err != nil { return true, err } - go func(voucher *paych.SignedVoucher, submitMessageCID cid.Cid) { + go func(voucher *paych0.SignedVoucher, submitMessageCID cid.Cid) { defer wg.Done() msgLookup, err := pcs.api.StateWaitMsg(pcs.ctx, submitMessageCID, build.MessageConfidence) if err != nil { @@ -106,7 +107,7 @@ func (pcs *paymentChannelSettler) revertHandler(ctx context.Context, ts *types.T func (pcs *paymentChannelSettler) matcher(msg *types.Message) (matchOnce bool, matched bool, err error) { // Check if this is a settle payment channel message - if msg.Method != builtin.MethodsPaych.Settle { + if msg.Method != builtin0.MethodsPaych.Settle { return false, false, nil } // Check if this payment channel is of concern to this node (i.e. tracked in payment channel store), diff --git a/paychmgr/simple.go b/paychmgr/simple.go index 4cf579a47..d49ccafe6 100644 --- a/paychmgr/simple.go +++ b/paychmgr/simple.go @@ -6,22 +6,20 @@ import ( "fmt" "sync" - "github.com/filecoin-project/lotus/api" - - "golang.org/x/sync/errgroup" - - "github.com/filecoin-project/go-state-types/big" - - "github.com/filecoin-project/specs-actors/actors/builtin" - init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/ipfs/go-cid" + "golang.org/x/sync/errgroup" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/specs-actors/actors/builtin" + init0 "github.com/filecoin-project/specs-actors/actors/builtin/init" + paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors" + lotusinit "github.com/filecoin-project/lotus/chain/actors/builtin/init" "github.com/filecoin-project/lotus/chain/types" ) @@ -320,7 +318,11 @@ func (ca *channelAccessor) currentAvailableFunds(channelID string, queuedAmt typ } for _, ls := range laneStates { - totalRedeemed = types.BigAdd(totalRedeemed, ls.Redeemed) + r, err := ls.Redeemed() + if err != nil { + return nil, err + } + totalRedeemed = types.BigAdd(totalRedeemed, r) } } @@ -385,12 +387,12 @@ func (ca *channelAccessor) processTask(ctx context.Context, amt types.BigInt) *p // createPaych sends a message to create the channel and returns the message cid func (ca *channelAccessor) createPaych(ctx context.Context, amt types.BigInt) (cid.Cid, error) { - params, aerr := actors.SerializeParams(&paych.ConstructorParams{From: ca.from, To: ca.to}) + params, aerr := actors.SerializeParams(&paych0.ConstructorParams{From: ca.from, To: ca.to}) if aerr != nil { return cid.Undef, aerr } - enc, aerr := actors.SerializeParams(&init_.ExecParams{ + enc, aerr := actors.SerializeParams(&init0.ExecParams{ CodeCID: builtin.PaymentChannelActorCodeID, ConstructorParams: params, }) @@ -399,7 +401,7 @@ func (ca *channelAccessor) createPaych(ctx context.Context, amt types.BigInt) (c } msg := &types.Message{ - To: builtin.InitActorAddr, + To: lotusinit.Address, From: ca.from, Value: amt, Method: builtin.MethodsInit.Exec, @@ -455,7 +457,7 @@ func (ca *channelAccessor) waitPaychCreateMsg(channelID string, mcid cid.Cid) er return err } - var decodedReturn init_.ExecReturn + var decodedReturn init0.ExecReturn err = decodedReturn.UnmarshalCBOR(bytes.NewReader(mwait.Receipt.Return)) if err != nil { log.Error(err) diff --git a/paychmgr/state.go b/paychmgr/state.go index 00fe2adce..65963d2a0 100644 --- a/paychmgr/state.go +++ b/paychmgr/state.go @@ -3,13 +3,9 @@ package paychmgr import ( "context" - "github.com/filecoin-project/specs-actors/actors/util/adt" - - "github.com/filecoin-project/specs-actors/actors/builtin/account" - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" + "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/types" ) @@ -17,14 +13,8 @@ type stateAccessor struct { sm stateManagerAPI } -func (ca *stateAccessor) loadPaychActorState(ctx context.Context, ch address.Address) (*types.Actor, *paych.State, error) { - var pcast paych.State - act, err := ca.sm.LoadActorState(ctx, ch, &pcast, nil) - if err != nil { - return nil, nil, err - } - - return act, &pcast, nil +func (ca *stateAccessor) loadPaychActorState(ctx context.Context, ch address.Address) (*types.Actor, paych.State, error) { + return ca.sm.GetPaychState(ctx, ch, nil) } func (ca *stateAccessor) loadStateChannelInfo(ctx context.Context, ch address.Address, dir uint64) (*ChannelInfo, error) { @@ -33,17 +23,23 @@ func (ca *stateAccessor) loadStateChannelInfo(ctx context.Context, ch address.Ad return nil, err } - var account account.State - _, err = ca.sm.LoadActorState(ctx, st.From, &account, nil) + // Load channel "From" account actor state + f, err := st.From() if err != nil { return nil, err } - from := account.Address - _, err = ca.sm.LoadActorState(ctx, st.To, &account, nil) + from, err := ca.sm.ResolveToKeyAddress(ctx, f, nil) + if err != nil { + return nil, err + } + t, err := st.To() + if err != nil { + return nil, err + } + to, err := ca.sm.ResolveToKeyAddress(ctx, t, nil) if err != nil { return nil, err } - to := account.Address nextLane, err := ca.nextLaneFromState(ctx, st) if err != nil { @@ -67,25 +63,24 @@ func (ca *stateAccessor) loadStateChannelInfo(ctx context.Context, ch address.Ad return ci, nil } -func (ca *stateAccessor) nextLaneFromState(ctx context.Context, st *paych.State) (uint64, error) { - store := ca.sm.AdtStore(ctx) - laneStates, err := adt.AsArray(store, st.LaneStates) +func (ca *stateAccessor) nextLaneFromState(ctx context.Context, st paych.State) (uint64, error) { + laneCount, err := st.LaneCount() if err != nil { return 0, err } - if laneStates.Length() == 0 { + if laneCount == 0 { return 0, nil } - maxID := int64(0) - if err := laneStates.ForEach(nil, func(i int64) error { - if i > maxID { - maxID = i + maxID := uint64(0) + if err := st.ForEachLaneState(func(idx uint64, _ paych.LaneState) error { + if idx > maxID { + maxID = idx } return nil }); err != nil { return 0, err } - return uint64(maxID + 1), nil + return maxID + 1, nil } diff --git a/paychmgr/store.go b/paychmgr/store.go index 46249fa36..23916669e 100644 --- a/paychmgr/store.go +++ b/paychmgr/store.go @@ -12,12 +12,13 @@ import ( "github.com/filecoin-project/lotus/chain/types" cborutil "github.com/filecoin-project/go-cbor-util" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/namespace" dsq "github.com/ipfs/go-datastore/query" + paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" + "github.com/filecoin-project/go-address" cborrpc "github.com/filecoin-project/go-cbor-util" @@ -48,7 +49,7 @@ const ( ) type VoucherInfo struct { - Voucher *paych.SignedVoucher + Voucher *paych0.SignedVoucher Proof []byte Submitted bool } @@ -102,7 +103,7 @@ func (ci *ChannelInfo) to() address.Address { // infoForVoucher gets the VoucherInfo for the given voucher. // returns nil if the channel doesn't have the voucher. -func (ci *ChannelInfo) infoForVoucher(sv *paych.SignedVoucher) (*VoucherInfo, error) { +func (ci *ChannelInfo) infoForVoucher(sv *paych0.SignedVoucher) (*VoucherInfo, error) { for _, v := range ci.Vouchers { eq, err := cborutil.Equals(sv, v.Voucher) if err != nil { @@ -115,7 +116,7 @@ func (ci *ChannelInfo) infoForVoucher(sv *paych.SignedVoucher) (*VoucherInfo, er return nil, nil } -func (ci *ChannelInfo) hasVoucher(sv *paych.SignedVoucher) (bool, error) { +func (ci *ChannelInfo) hasVoucher(sv *paych0.SignedVoucher) (bool, error) { vi, err := ci.infoForVoucher(sv) return vi != nil, err } @@ -123,7 +124,7 @@ func (ci *ChannelInfo) hasVoucher(sv *paych.SignedVoucher) (bool, error) { // markVoucherSubmitted marks the voucher, and any vouchers of lower nonce // in the same lane, as being submitted. // Note: This method doesn't write anything to the store. -func (ci *ChannelInfo) markVoucherSubmitted(sv *paych.SignedVoucher) error { +func (ci *ChannelInfo) markVoucherSubmitted(sv *paych0.SignedVoucher) error { vi, err := ci.infoForVoucher(sv) if err != nil { return err @@ -147,7 +148,7 @@ func (ci *ChannelInfo) markVoucherSubmitted(sv *paych.SignedVoucher) error { } // wasVoucherSubmitted returns true if the voucher has been submitted -func (ci *ChannelInfo) wasVoucherSubmitted(sv *paych.SignedVoucher) (bool, error) { +func (ci *ChannelInfo) wasVoucherSubmitted(sv *paych0.SignedVoucher) (bool, error) { vi, err := ci.infoForVoucher(sv) if err != nil { return false, err @@ -276,7 +277,7 @@ func (ps *Store) VouchersForPaych(ch address.Address) ([]*VoucherInfo, error) { return ci.Vouchers, nil } -func (ps *Store) MarkVoucherSubmitted(ci *ChannelInfo, sv *paych.SignedVoucher) error { +func (ps *Store) MarkVoucherSubmitted(ci *ChannelInfo, sv *paych0.SignedVoucher) error { err := ci.markVoucherSubmitted(sv) if err != nil { return err diff --git a/paychmgr/util.go b/paychmgr/util.go index 0509f8a24..2a8181c15 100644 --- a/paychmgr/util.go +++ b/paychmgr/util.go @@ -4,21 +4,22 @@ import ( "context" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" + + paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych" ) type BestSpendableAPI interface { - PaychVoucherList(context.Context, address.Address) ([]*paych.SignedVoucher, error) - PaychVoucherCheckSpendable(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error) + PaychVoucherList(context.Context, address.Address) ([]*paych0.SignedVoucher, error) + PaychVoucherCheckSpendable(context.Context, address.Address, *paych0.SignedVoucher, []byte, []byte) (bool, error) } -func BestSpendableByLane(ctx context.Context, api BestSpendableAPI, ch address.Address) (map[uint64]*paych.SignedVoucher, error) { +func BestSpendableByLane(ctx context.Context, api BestSpendableAPI, ch address.Address) (map[uint64]*paych0.SignedVoucher, error) { vouchers, err := api.PaychVoucherList(ctx, ch) if err != nil { return nil, err } - bestByLane := make(map[uint64]*paych.SignedVoucher) + bestByLane := make(map[uint64]*paych0.SignedVoucher) for _, voucher := range vouchers { spendable, err := api.PaychVoucherCheckSpendable(ctx, ch, voucher, nil, nil) if err != nil { diff --git a/scripts/lotus-miner.service b/scripts/lotus-miner.service index c079f44a9..54c48d411 100644 --- a/scripts/lotus-miner.service +++ b/scripts/lotus-miner.service @@ -2,7 +2,7 @@ Description=Lotus Miner After=network.target After=lotus-daemon.service -Requires=lotus-daemon.service +Wants=lotus-daemon.service [Service] ExecStart=/usr/local/bin/lotus-miner run diff --git a/storage/adapter_storage_miner.go b/storage/adapter_storage_miner.go index f7431299d..380fb4471 100644 --- a/storage/adapter_storage_miner.go +++ b/storage/adapter_storage_miner.go @@ -4,7 +4,7 @@ import ( "bytes" "context" - "github.com/filecoin-project/go-bitfield" + "github.com/filecoin-project/go-state-types/network" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -14,15 +14,16 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/util/adt" + + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/apibstore" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/builtin/market" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" @@ -84,7 +85,7 @@ func (s SealingAPIAdapter) StateMinerWorkerAddress(ctx context.Context, maddr ad return mi.Worker, nil } -func (s SealingAPIAdapter) StateMinerDeadlines(ctx context.Context, maddr address.Address, tok sealing.TipSetToken) ([]*miner.Deadline, error) { +func (s SealingAPIAdapter) StateMinerDeadlines(ctx context.Context, maddr address.Address, tok sealing.TipSetToken) ([]api.Deadline, error) { tsk, err := types.TipSetKeyFromBytes(tok) if err != nil { return nil, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) @@ -137,7 +138,7 @@ func (s SealingAPIAdapter) StateComputeDataCommitment(ctx context.Context, maddr return cid.Undef, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) } - ccparams, err := actors.SerializeParams(&market.ComputeDataCommitmentParams{ + ccparams, err := actors.SerializeParams(&market0.ComputeDataCommitmentParams{ DealIDs: deals, SectorType: sectorType, }) @@ -146,10 +147,10 @@ func (s SealingAPIAdapter) StateComputeDataCommitment(ctx context.Context, maddr } ccmt := &types.Message{ - To: builtin.StorageMarketActorAddr, + To: market.Address, From: maddr, Value: types.NewInt(0), - Method: builtin.MethodsMarket.ComputeDataCommitment, + Method: builtin0.MethodsMarket.ComputeDataCommitment, Params: ccparams, } r, err := s.delegate.StateCall(ctx, ccmt, tsk) @@ -179,32 +180,19 @@ func (s SealingAPIAdapter) StateSectorPreCommitInfo(ctx context.Context, maddr a return nil, xerrors.Errorf("handleSealFailed(%d): temp error: %+v", sectorNumber, err) } - st, err := s.delegate.ChainReadObj(ctx, act.Head) - if err != nil { - return nil, xerrors.Errorf("handleSealFailed(%d): temp error: %+v", sectorNumber, err) - } - - var state miner.State - if err := state.UnmarshalCBOR(bytes.NewReader(st)); err != nil { - return nil, xerrors.Errorf("handleSealFailed(%d): temp error: unmarshaling miner state: %+v", sectorNumber, err) - } stor := store.ActorStore(ctx, apibstore.NewAPIBlockstore(s.delegate)) - precommits, err := adt.AsMap(stor, state.PreCommittedSectors) + + state, err := miner.Load(stor, act) if err != nil { - return nil, err + return nil, xerrors.Errorf("handleSealFailed(%d): temp error: loading miner state: %+v", sectorNumber, err) } - var pci miner.SectorPreCommitOnChainInfo - ok, err := precommits.Get(abi.UIntKey(uint64(sectorNumber)), &pci) + pci, err := state.GetPrecommittedSector(sectorNumber) if err != nil { return nil, err } - if !ok { - var allocated bitfield.BitField - if err := stor.Get(ctx, state.AllocatedSectors, &allocated); err != nil { - return nil, xerrors.Errorf("loading allocated sector bitfield: %w", err) - } - set, err := allocated.IsSet(uint64(sectorNumber)) + if pci == nil { + set, err := state.IsAllocated(sectorNumber) if err != nil { return nil, xerrors.Errorf("checking if sector is allocated: %w", err) } @@ -215,7 +203,7 @@ func (s SealingAPIAdapter) StateSectorPreCommitInfo(ctx context.Context, maddr a return nil, nil } - return &pci, nil + return pci, nil } func (s SealingAPIAdapter) StateSectorGetInfo(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok sealing.TipSetToken) (*miner.SectorOnChainInfo, error) { @@ -261,6 +249,15 @@ func (s SealingAPIAdapter) StateMarketStorageDeal(ctx context.Context, dealID ab return deal.Proposal, nil } +func (s SealingAPIAdapter) StateNetworkVersion(ctx context.Context, tok sealing.TipSetToken) (network.Version, error) { + tsk, err := types.TipSetKeyFromBytes(tok) + if err != nil { + return network.VersionMax, err + } + + return s.delegate.StateNetworkVersion(ctx, tsk) +} + func (s SealingAPIAdapter) SendMsg(ctx context.Context, from, to address.Address, method abi.MethodNum, value, maxFee abi.TokenAmount, params []byte) (cid.Cid, error) { msg := types.Message{ To: to, diff --git a/storage/addresses.go b/storage/addresses.go index bef845367..f5640794e 100644 --- a/storage/addresses.go +++ b/storage/addresses.go @@ -3,12 +3,13 @@ package storage import ( "context" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types" ) @@ -27,7 +28,7 @@ type addrSelectApi interface { StateAccountKey(context.Context, address.Address, types.TipSetKey) (address.Address, error) } -func AddressFor(ctx context.Context, a addrSelectApi, mi api.MinerInfo, use AddrUse, minFunds abi.TokenAmount) (address.Address, error) { +func AddressFor(ctx context.Context, a addrSelectApi, mi miner.MinerInfo, use AddrUse, minFunds abi.TokenAmount) (address.Address, error) { switch use { case PreCommitAddr, CommitAddr: // always use worker, at least for now @@ -60,7 +61,7 @@ func AddressFor(ctx context.Context, a addrSelectApi, mi api.MinerInfo, use Addr return addr, nil } - log.Warnw("control address didn't have enough funds for PoSt message", "address", addr, "required", types.FIL(minFunds), "balance", types.FIL(b)) + log.Warnw("control address didn't have enough funds for window post message", "address", addr, "required", types.FIL(minFunds), "balance", types.FIL(b)) } // Try to use the owner account if we can, fallback to worker if we can't diff --git a/storage/miner.go b/storage/miner.go index bf026fc30..c1b50fe89 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -5,10 +5,14 @@ import ( "errors" "time" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof" + + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/go-state-types/dline" "github.com/filecoin-project/go-bitfield" - "github.com/filecoin-project/specs-actors/actors/runtime/proof" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" @@ -21,11 +25,11 @@ import ( "github.com/filecoin-project/go-state-types/crypto" sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/types" @@ -67,13 +71,13 @@ type SealingStateEvt struct { type storageMinerApi interface { // Call a read only method on actors (no interaction with the chain required) StateCall(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error) - StateMinerDeadlines(ctx context.Context, maddr address.Address, tok types.TipSetKey) ([]*miner.Deadline, error) - StateMinerPartitions(context.Context, address.Address, uint64, types.TipSetKey) ([]*miner.Partition, error) - StateMinerSectors(context.Context, address.Address, *bitfield.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) + StateMinerSectors(context.Context, address.Address, *bitfield.BitField, types.TipSetKey) ([]*miner.SectorOnChainInfo, error) StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error) - StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*api.SectorLocation, error) - StateMinerInfo(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error) + StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*miner.SectorLocation, error) + StateMinerInfo(context.Context, address.Address, types.TipSetKey) (miner.MinerInfo, error) + StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) ([]api.Deadline, error) + StateMinerPartitions(context.Context, address.Address, uint64, types.TipSetKey) ([]api.Partition, error) StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*dline.Info, error) StateMinerPreCommitDepositForPower(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error) StateMinerInitialPledgeCollateral(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error) @@ -85,6 +89,7 @@ type storageMinerApi interface { StateMinerFaults(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error) StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error) StateAccountKey(context.Context, address.Address, types.TipSetKey) (address.Address, error) + StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error) MpoolPushMessage(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error) @@ -141,7 +146,8 @@ func (m *Miner) Run(ctx context.Context) error { evts := events.NewEvents(ctx, m.api) adaptedAPI := NewSealingAPIAdapter(m.api) - pcp := sealing.NewBasicPreCommitPolicy(adaptedAPI, miner.MaxSectorExpirationExtension-(miner.WPoStProvingPeriod*2), md.PeriodStart%miner.WPoStProvingPeriod) + // TODO: Maybe we update this policy after actor upgrades? + pcp := sealing.NewBasicPreCommitPolicy(adaptedAPI, miner0.MaxSectorExpirationExtension-(miner0.WPoStProvingPeriod*2), md.PeriodStart%miner0.WPoStProvingPeriod) m.sealing = sealing.New(adaptedAPI, fc, NewEventsAdapter(evts), m.maddr, m.ds, m.sealer, m.sc, m.verif, &pcp, sealing.GetSealingConfigFunc(m.getSealConfig), m.handleSealingNotifications) go m.sealing.Run(ctx) //nolint:errcheck // logged intside the function @@ -229,9 +235,9 @@ func (wpp *StorageWpp) GenerateCandidates(ctx context.Context, randomness abi.Po return cds, nil } -func (wpp *StorageWpp) ComputeProof(ctx context.Context, ssi []proof.SectorInfo, rand abi.PoStRandomness) ([]proof.PoStProof, error) { +func (wpp *StorageWpp) ComputeProof(ctx context.Context, ssi []proof0.SectorInfo, rand abi.PoStRandomness) ([]proof0.PoStProof, error) { if build.InsecurePoStValidation { - return []proof.PoStProof{{ProofBytes: []byte("valid proof")}}, nil + return []proof0.PoStProof{{ProofBytes: []byte("valid proof")}}, nil } log.Infof("Computing WinningPoSt ;%+v; %v", ssi, rand) diff --git a/storage/mockstorage/preseal.go b/storage/mockstorage/preseal.go index da063020d..8ca789ba6 100644 --- a/storage/mockstorage/preseal.go +++ b/storage/mockstorage/preseal.go @@ -9,7 +9,8 @@ import ( "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/extern/sector-storage/mock" - "github.com/filecoin-project/specs-actors/actors/builtin/market" + + market0 "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" @@ -48,7 +49,7 @@ func PreSeal(ssize abi.SectorSize, maddr address.Address, sectors int) (*genesis r := mock.CommDR(d) preseal.CommR, _ = commcid.ReplicaCommitmentV1ToCID(r[:]) preseal.SectorID = abi.SectorNumber(i + 1) - preseal.Deal = market.DealProposal{ + preseal.Deal = market0.DealProposal{ PieceCID: preseal.CommD, PieceSize: abi.PaddedPieceSize(ssize), Client: k.Address, diff --git a/storage/wdpost_journal.go b/storage/wdpost_journal.go index c1a4d4817..48eb2f2b1 100644 --- a/storage/wdpost_journal.go +++ b/storage/wdpost_journal.go @@ -3,7 +3,7 @@ package storage import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/dline" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/ipfs/go-cid" ) diff --git a/storage/wdpost_run.go b/storage/wdpost_run.go index 7aa90bbba..9a497f879 100644 --- a/storage/wdpost_run.go +++ b/storage/wdpost_run.go @@ -5,26 +5,26 @@ import ( "context" "time" - "github.com/filecoin-project/go-state-types/dline" - - "github.com/filecoin-project/specs-actors/actors/runtime/proof" - "github.com/filecoin-project/go-bitfield" "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/go-state-types/crypto" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/go-state-types/dline" "github.com/ipfs/go-cid" "go.opencensus.io/trace" "golang.org/x/xerrors" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/journal" ) @@ -78,7 +78,7 @@ func (s *WindowPoStScheduler) doPost(ctx context.Context, deadline *dline.Info, posts, err := s.runPost(ctx, *deadline, ts) if err != nil { - log.Errorf("runPost failed: %+v", err) + log.Errorf("run window post failed: %+v", err) s.failPost(err, deadline) return } @@ -92,7 +92,7 @@ func (s *WindowPoStScheduler) doPost(ctx context.Context, deadline *dline.Info, post := &posts[i] sm, err := s.submitPost(ctx, post) if err != nil { - log.Errorf("submitPost failed: %+v", err) + log.Errorf("submit window post failed: %+v", err) s.failPost(err, deadline) } else { recordProofsEvent(post.Partitions, sm.Cid()) @@ -153,7 +153,7 @@ func (s *WindowPoStScheduler) checkSectors(ctx context.Context, check bitfield.B return sbf, nil } -func (s *WindowPoStScheduler) checkNextRecoveries(ctx context.Context, dlIdx uint64, partitions []*miner.Partition) ([]miner.RecoveryDeclaration, *types.SignedMessage, error) { +func (s *WindowPoStScheduler) checkNextRecoveries(ctx context.Context, dlIdx uint64, partitions []api.Partition) ([]miner.RecoveryDeclaration, *types.SignedMessage, error) { ctx, span := trace.StartSpan(ctx, "storage.checkNextRecoveries") defer span.End() @@ -163,7 +163,7 @@ func (s *WindowPoStScheduler) checkNextRecoveries(ctx context.Context, dlIdx uin } for partIdx, partition := range partitions { - unrecovered, err := bitfield.SubtractBitField(partition.Faults, partition.Recoveries) + unrecovered, err := bitfield.SubtractBitField(partition.FaultySectors, partition.RecoveringSectors) if err != nil { return nil, nil, xerrors.Errorf("subtracting recovered set from fault set: %w", err) } @@ -218,7 +218,7 @@ func (s *WindowPoStScheduler) checkNextRecoveries(ctx context.Context, dlIdx uin msg := &types.Message{ To: s.actor, From: s.worker, - Method: builtin.MethodsMiner.DeclareFaultsRecovered, + Method: builtin0.MethodsMiner.DeclareFaultsRecovered, Params: enc, Value: types.NewInt(0), } @@ -244,7 +244,7 @@ func (s *WindowPoStScheduler) checkNextRecoveries(ctx context.Context, dlIdx uin return recoveries, sm, nil } -func (s *WindowPoStScheduler) checkNextFaults(ctx context.Context, dlIdx uint64, partitions []*miner.Partition) ([]miner.FaultDeclaration, *types.SignedMessage, error) { +func (s *WindowPoStScheduler) checkNextFaults(ctx context.Context, dlIdx uint64, partitions []api.Partition) ([]miner.FaultDeclaration, *types.SignedMessage, error) { ctx, span := trace.StartSpan(ctx, "storage.checkNextFaults") defer span.End() @@ -254,17 +254,12 @@ func (s *WindowPoStScheduler) checkNextFaults(ctx context.Context, dlIdx uint64, } for partIdx, partition := range partitions { - toCheck, err := partition.ActiveSectors() - if err != nil { - return nil, nil, xerrors.Errorf("getting active sectors: %w", err) - } - - good, err := s.checkSectors(ctx, toCheck) + good, err := s.checkSectors(ctx, partition.ActiveSectors) if err != nil { return nil, nil, xerrors.Errorf("checking sectors: %w", err) } - faulty, err := bitfield.SubtractBitField(toCheck, good) + faulty, err := bitfield.SubtractBitField(partition.ActiveSectors, good) if err != nil { return nil, nil, xerrors.Errorf("calculating faulty sector set: %w", err) } @@ -302,7 +297,7 @@ func (s *WindowPoStScheduler) checkNextFaults(ctx context.Context, dlIdx uint64, msg := &types.Message{ To: s.actor, From: s.worker, - Method: builtin.MethodsMiner.DeclareFaults, + Method: builtin0.MethodsMiner.DeclareFaults, Params: enc, Value: types.NewInt(0), // TODO: Is there a fee? } @@ -337,7 +332,7 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty // check faults / recoveries for the *next* deadline. It's already too // late to declare them for this deadline - declDeadline := (di.Index + 2) % miner.WPoStPeriodDeadlines + declDeadline := (di.Index + 2) % di.WPoStPeriodDeadlines partitions, err := s.api.StateMinerPartitions(context.TODO(), s.actor, declDeadline, ts.Key()) if err != nil { @@ -397,7 +392,7 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty rand, err := s.api.ChainGetRandomnessFromBeacon(ctx, ts.Key(), crypto.DomainSeparationTag_WindowedPoStChallengeSeed, di.Challenge, buf.Bytes()) if err != nil { - return nil, xerrors.Errorf("failed to get chain randomness for windowPost (ts=%d; deadline=%d): %w", ts.Height(), di, err) + return nil, xerrors.Errorf("failed to get chain randomness for window post (ts=%d; deadline=%d): %w", ts.Height(), di, err) } // Get the partitions for the given deadline @@ -431,16 +426,13 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty postSkipped := bitfield.New() var postOut []proof.PoStProof somethingToProve := true + for retries := 0; retries < 5; retries++ { + var partitions []miner.PoStPartition var sinfos []proof.SectorInfo for partIdx, partition := range batch { // TODO: Can do this in parallel - toProve, err := partition.ActiveSectors() - if err != nil { - return nil, xerrors.Errorf("getting active sectors: %w", err) - } - - toProve, err = bitfield.MergeBitFields(toProve, partition.Recoveries) + toProve, err := bitfield.MergeBitFields(partition.ActiveSectors, partition.RecoveringSectors) if err != nil { return nil, xerrors.Errorf("adding recoveries to set of sectors to prove: %w", err) } @@ -467,7 +459,7 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty skipCount += sc - ssi, err := s.sectorsForProof(ctx, good, partition.Sectors, ts) + ssi, err := s.sectorsForProof(ctx, good, partition.AllSectors, ts) if err != nil { return nil, xerrors.Errorf("getting sorted sector info: %w", err) } @@ -477,7 +469,7 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty } sinfos = append(sinfos, ssi...) - params.Partitions = append(params.Partitions, miner.PoStPartition{ + partitions = append(partitions, miner.PoStPartition{ Index: uint64(batchPartitionStartIdx + partIdx), Skipped: skipped, }) @@ -490,7 +482,7 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty } // Generate proof - log.Infow("running windowPost", + log.Infow("running window post", "chain-random", rand, "deadline", di, "height", ts.Height(), @@ -507,20 +499,22 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty postOut, ps, err = s.prover.GenerateWindowPoSt(ctx, abi.ActorID(mid), sinfos, abi.PoStRandomness(rand)) elapsed := time.Since(tsStart) - log.Infow("computing window PoSt", "batch", batchIdx, "elapsed", elapsed) + log.Infow("computing window post", "batch", batchIdx, "elapsed", elapsed) if err == nil { // Proof generation successful, stop retrying + params.Partitions = append(params.Partitions, partitions...) + break } // Proof generation failed, so retry if len(ps) == 0 { - return nil, xerrors.Errorf("running post failed: %w", err) + return nil, xerrors.Errorf("running window post failed: %w", err) } - log.Warnw("generate window PoSt skipped sectors", "sectors", ps, "error", err, "try", retries) + log.Warnw("generate window post skipped sectors", "sectors", ps, "error", err, "try", retries) skipCount += uint64(len(ps)) for _, sector := range ps { @@ -547,7 +541,7 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty commEpoch := di.Open commRand, err := s.api.ChainGetRandomnessFromTickets(ctx, ts.Key(), crypto.DomainSeparationTag_PoStChainCommit, commEpoch, nil) if err != nil { - return nil, xerrors.Errorf("failed to get chain randomness for windowPost (ts=%d; deadline=%d): %w", ts.Height(), commEpoch, err) + return nil, xerrors.Errorf("failed to get chain randomness for window post (ts=%d; deadline=%d): %w", ts.Height(), commEpoch, err) } for i := range posts { @@ -558,9 +552,9 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty return posts, nil } -func (s *WindowPoStScheduler) batchPartitions(partitions []*miner.Partition) ([][]*miner.Partition, error) { +func (s *WindowPoStScheduler) batchPartitions(partitions []api.Partition) ([][]api.Partition, error) { // Get the number of sectors allowed in a partition, for this proof size - sectorsPerPartition, err := builtin.PoStProofWindowPoStPartitionSectors(s.proofType) + sectorsPerPartition, err := builtin0.PoStProofWindowPoStPartitionSectors(s.proofType) if err != nil { return nil, xerrors.Errorf("getting sectors per partition: %w", err) } @@ -575,7 +569,9 @@ func (s *WindowPoStScheduler) batchPartitions(partitions []*miner.Partition) ([] // sectors per partition 3: ooo // partitions per message 2: oooOOO // <1><2> (3rd doesn't fit) - partitionsPerMsg := int(miner.AddressedSectorsMax / sectorsPerPartition) + // TODO(NETUPGRADE): we're going to need some form of policy abstraction + // where we can get policy from the future. Unfortunately, we can't just get this from the state. + partitionsPerMsg := int(miner0.AddressedSectorsMax / sectorsPerPartition) // The number of messages will be: // ceiling(number of partitions / partitions per message) @@ -585,7 +581,7 @@ func (s *WindowPoStScheduler) batchPartitions(partitions []*miner.Partition) ([] } // Split the partitions into batches - batches := make([][]*miner.Partition, 0, batchCount) + batches := make([][]api.Partition, 0, batchCount) for i := 0; i < len(partitions); i += partitionsPerMsg { end := i + partitionsPerMsg if end > len(partitions) { @@ -597,7 +593,7 @@ func (s *WindowPoStScheduler) batchPartitions(partitions []*miner.Partition) ([] } func (s *WindowPoStScheduler) sectorsForProof(ctx context.Context, goodSectors, allSectors bitfield.BitField, ts *types.TipSet) ([]proof.SectorInfo, error) { - sset, err := s.api.StateMinerSectors(ctx, s.actor, &goodSectors, false, ts.Key()) + sset, err := s.api.StateMinerSectors(ctx, s.actor, &goodSectors, ts.Key()) if err != nil { return nil, err } @@ -607,17 +603,17 @@ func (s *WindowPoStScheduler) sectorsForProof(ctx context.Context, goodSectors, } substitute := proof.SectorInfo{ - SectorNumber: sset[0].ID, - SealedCID: sset[0].Info.SealedCID, - SealProof: sset[0].Info.SealProof, + SectorNumber: sset[0].SectorNumber, + SealedCID: sset[0].SealedCID, + SealProof: sset[0].SealProof, } sectorByID := make(map[uint64]proof.SectorInfo, len(sset)) for _, sector := range sset { - sectorByID[uint64(sector.ID)] = proof.SectorInfo{ - SectorNumber: sector.ID, - SealedCID: sector.Info.SealedCID, - SealProof: sector.Info.SealProof, + sectorByID[uint64(sector.SectorNumber)] = proof.SectorInfo{ + SectorNumber: sector.SectorNumber, + SealedCID: sector.SealedCID, + SealProof: sector.SealProof, } } @@ -644,13 +640,13 @@ func (s *WindowPoStScheduler) submitPost(ctx context.Context, proof *miner.Submi enc, aerr := actors.SerializeParams(proof) if aerr != nil { - return nil, xerrors.Errorf("could not serialize submit post parameters: %w", aerr) + return nil, xerrors.Errorf("could not serialize submit window post parameters: %w", aerr) } msg := &types.Message{ To: s.actor, From: s.worker, - Method: builtin.MethodsMiner.SubmitWindowedPoSt, + Method: builtin0.MethodsMiner.SubmitWindowedPoSt, Params: enc, Value: types.NewInt(0), } @@ -705,7 +701,7 @@ func (s *WindowPoStScheduler) setSender(ctx context.Context, msg *types.Message, pa, err := AddressFor(ctx, s.api, mi, PoStAddr, minFunds) if err != nil { - log.Errorw("error selecting address for post", "error", err) + log.Errorw("error selecting address for window post", "error", err) msg.From = s.worker return } diff --git a/storage/wdpost_run_test.go b/storage/wdpost_run_test.go index af529a75e..10be2fbcd 100644 --- a/storage/wdpost_run_test.go +++ b/storage/wdpost_run_test.go @@ -5,29 +5,29 @@ import ( "context" "testing" - "github.com/filecoin-project/go-state-types/dline" - - "golang.org/x/xerrors" - "github.com/stretchr/testify/require" + "github.com/ipfs/go-cid" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-bitfield" - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/chain/types" - "github.com/ipfs/go-cid" - - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/runtime/proof" - "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/network" + builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" + miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof" tutils "github.com/filecoin-project/specs-actors/support/testing" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/types" ) type mockStorageMinerAPI struct { - partitions []*miner.Partition + partitions []api.Partition pushedMessages chan *types.Message } @@ -37,6 +37,17 @@ func newMockStorageMinerAPI() *mockStorageMinerAPI { } } +func (m *mockStorageMinerAPI) StateMinerInfo(ctx context.Context, a address.Address, key types.TipSetKey) (miner.MinerInfo, error) { + return miner.MinerInfo{ + Worker: tutils.NewIDAddr(nil, 101), + Owner: tutils.NewIDAddr(nil, 101), + }, nil +} + +func (m *mockStorageMinerAPI) StateNetworkVersion(ctx context.Context, key types.TipSetKey) (network.Version, error) { + panic("implement me") +} + func (m *mockStorageMinerAPI) ChainGetRandomnessFromTickets(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) { return abi.Randomness("ticket rand"), nil } @@ -45,32 +56,28 @@ func (m *mockStorageMinerAPI) ChainGetRandomnessFromBeacon(ctx context.Context, return abi.Randomness("beacon rand"), nil } -func (m *mockStorageMinerAPI) setPartitions(ps []*miner.Partition) { +func (m *mockStorageMinerAPI) setPartitions(ps []api.Partition) { m.partitions = append(m.partitions, ps...) } -func (m *mockStorageMinerAPI) StateMinerPartitions(ctx context.Context, address address.Address, u uint64, key types.TipSetKey) ([]*miner.Partition, error) { +func (m *mockStorageMinerAPI) StateMinerPartitions(ctx context.Context, a address.Address, dlIdx uint64, tsk types.TipSetKey) ([]api.Partition, error) { return m.partitions, nil } -func (m *mockStorageMinerAPI) StateMinerSectors(ctx context.Context, address address.Address, field *bitfield.BitField, b bool, key types.TipSetKey) ([]*api.ChainSectorInfo, error) { - var sis []*api.ChainSectorInfo - _ = field.ForEach(func(i uint64) error { - sis = append(sis, &api.ChainSectorInfo{ - Info: miner.SectorOnChainInfo{ - SectorNumber: abi.SectorNumber(i), - }, - ID: abi.SectorNumber(i), +func (m *mockStorageMinerAPI) StateMinerSectors(ctx context.Context, address address.Address, snos *bitfield.BitField, key types.TipSetKey) ([]*miner.SectorOnChainInfo, error) { + var sis []*miner.SectorOnChainInfo + if snos == nil { + panic("unsupported") + } + _ = snos.ForEach(func(i uint64) error { + sis = append(sis, &miner.SectorOnChainInfo{ + SectorNumber: abi.SectorNumber(i), }) return nil }) return sis, nil } -func (m *mockStorageMinerAPI) StateMinerInfo(ctx context.Context, address address.Address, key types.TipSetKey) (api.MinerInfo, error) { - return api.MinerInfo{}, xerrors.Errorf("err") -} - func (m *mockStorageMinerAPI) MpoolPushMessage(ctx context.Context, message *types.Message, spec *api.MessageSendSpec) (*types.SignedMessage, error) { m.pushedMessages <- message return &types.SignedMessage{ @@ -89,12 +96,12 @@ func (m *mockStorageMinerAPI) StateWaitMsg(ctx context.Context, cid cid.Cid, con type mockProver struct { } -func (m *mockProver) GenerateWinningPoSt(context.Context, abi.ActorID, []proof.SectorInfo, abi.PoStRandomness) ([]proof.PoStProof, error) { +func (m *mockProver) GenerateWinningPoSt(context.Context, abi.ActorID, []proof0.SectorInfo, abi.PoStRandomness) ([]proof0.PoStProof, error) { panic("implement me") } -func (m *mockProver) GenerateWindowPoSt(ctx context.Context, aid abi.ActorID, sis []proof.SectorInfo, pr abi.PoStRandomness) ([]proof.PoStProof, []abi.SectorID, error) { - return []proof.PoStProof{ +func (m *mockProver) GenerateWindowPoSt(ctx context.Context, aid abi.ActorID, sis []proof0.SectorInfo, pr abi.PoStRandomness) ([]proof0.PoStProof, []abi.SectorID, error) { + return []proof0.PoStProof{ { PoStProof: abi.RegisteredPoStProof_StackedDrgWindow2KiBV1, ProofBytes: []byte("post-proof"), @@ -123,25 +130,31 @@ func TestWDPostDoPost(t *testing.T) { mockStgMinerAPI := newMockStorageMinerAPI() // Get the number of sectors allowed in a partition for this proof type - sectorsPerPartition, err := builtin.PoStProofWindowPoStPartitionSectors(proofType) + sectorsPerPartition, err := builtin0.PoStProofWindowPoStPartitionSectors(proofType) require.NoError(t, err) // Work out the number of partitions that can be included in a message // without exceeding the message sector limit - partitionsPerMsg := int(miner.AddressedSectorsMax / sectorsPerPartition) + + require.NoError(t, err) + partitionsPerMsg := int(miner0.AddressedSectorsMax / sectorsPerPartition) // Enough partitions to fill expectedMsgCount-1 messages partitionCount := (expectedMsgCount - 1) * partitionsPerMsg // Add an extra partition that should be included in the last message partitionCount++ - var partitions []*miner.Partition + var partitions []api.Partition for p := 0; p < partitionCount; p++ { sectors := bitfield.New() for s := uint64(0); s < sectorsPerPartition; s++ { sectors.Set(s) } - partitions = append(partitions, &miner.Partition{ - Sectors: sectors, + partitions = append(partitions, api.Partition{ + AllSectors: sectors, + FaultySectors: bitfield.New(), + RecoveringSectors: bitfield.New(), + LiveSectors: sectors, + ActiveSectors: sectors, }) } mockStgMinerAPI.setPartitions(partitions) @@ -156,14 +169,20 @@ func TestWDPostDoPost(t *testing.T) { worker: workerAct, } - di := &dline.Info{} + di := &dline.Info{ + WPoStPeriodDeadlines: miner0.WPoStPeriodDeadlines, + WPoStProvingPeriod: miner0.WPoStProvingPeriod, + WPoStChallengeWindow: miner0.WPoStChallengeWindow, + WPoStChallengeLookback: miner0.WPoStChallengeLookback, + FaultDeclarationCutoff: miner0.FaultDeclarationCutoff, + } ts := mockTipSet(t) scheduler.doPost(ctx, di, ts) // Read the window PoST messages for i := 0; i < expectedMsgCount; i++ { msg := <-mockStgMinerAPI.pushedMessages - require.Equal(t, builtin.MethodsMiner.SubmitWindowedPoSt, msg.Method) + require.Equal(t, builtin0.MethodsMiner.SubmitWindowedPoSt, msg.Method) var params miner.SubmitWindowedPoStParams err := params.UnmarshalCBOR(bytes.NewReader(msg.Params)) require.NoError(t, err) @@ -204,7 +223,7 @@ func (m *mockStorageMinerAPI) StateCall(ctx context.Context, message *types.Mess panic("implement me") } -func (m *mockStorageMinerAPI) StateMinerDeadlines(ctx context.Context, maddr address.Address, tok types.TipSetKey) ([]*miner.Deadline, error) { +func (m *mockStorageMinerAPI) StateMinerDeadlines(ctx context.Context, maddr address.Address, tok types.TipSetKey) ([]api.Deadline, error) { panic("implement me") } @@ -216,12 +235,25 @@ func (m *mockStorageMinerAPI) StateSectorGetInfo(ctx context.Context, address ad panic("implement me") } -func (m *mockStorageMinerAPI) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*api.SectorLocation, error) { +func (m *mockStorageMinerAPI) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*miner.SectorLocation, error) { panic("implement me") } func (m *mockStorageMinerAPI) StateMinerProvingDeadline(ctx context.Context, address address.Address, key types.TipSetKey) (*dline.Info, error) { - panic("implement me") + return &dline.Info{ + CurrentEpoch: 0, + PeriodStart: 0, + Index: 0, + Open: 0, + Close: 0, + Challenge: 0, + FaultCutoff: 0, + WPoStPeriodDeadlines: miner0.WPoStPeriodDeadlines, + WPoStProvingPeriod: miner0.WPoStProvingPeriod, + WPoStChallengeWindow: miner0.WPoStChallengeWindow, + WPoStChallengeLookback: miner0.WPoStChallengeLookback, + FaultDeclarationCutoff: miner0.FaultDeclarationCutoff, + }, nil } func (m *mockStorageMinerAPI) StateMinerPreCommitDepositForPower(ctx context.Context, address address.Address, info miner.SectorPreCommitInfo, key types.TipSetKey) (types.BigInt, error) { @@ -237,7 +269,9 @@ func (m *mockStorageMinerAPI) StateSearchMsg(ctx context.Context, cid cid.Cid) ( } func (m *mockStorageMinerAPI) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) { - panic("implement me") + return &types.Actor{ + Code: builtin0.StorageMinerActorCodeID, + }, nil } func (m *mockStorageMinerAPI) StateGetReceipt(ctx context.Context, cid cid.Cid, key types.TipSetKey) (*types.MessageReceipt, error) { @@ -257,11 +291,15 @@ func (m *mockStorageMinerAPI) StateMinerRecoveries(ctx context.Context, address } func (m *mockStorageMinerAPI) StateAccountKey(ctx context.Context, address address.Address, key types.TipSetKey) (address.Address, error) { - panic("implement me") + return address, nil } func (m *mockStorageMinerAPI) GasEstimateMessageGas(ctx context.Context, message *types.Message, spec *api.MessageSendSpec, key types.TipSetKey) (*types.Message, error) { - panic("implement me") + msg := *message + msg.GasFeeCap = big.NewInt(1) + msg.GasPremium = big.NewInt(1) + msg.GasLimit = 2 + return &msg, nil } func (m *mockStorageMinerAPI) ChainHead(ctx context.Context) (*types.TipSet, error) { @@ -293,13 +331,15 @@ func (m *mockStorageMinerAPI) ChainGetTipSet(ctx context.Context, key types.TipS } func (m *mockStorageMinerAPI) WalletSign(ctx context.Context, address address.Address, bytes []byte) (*crypto.Signature, error) { - panic("implement me") + return nil, nil } func (m *mockStorageMinerAPI) WalletBalance(ctx context.Context, address address.Address) (types.BigInt, error) { - panic("implement me") + return big.NewInt(333), nil } func (m *mockStorageMinerAPI) WalletHas(ctx context.Context, address address.Address) (bool, error) { - panic("implement me") + return true, nil } + +var _ storageMinerApi = &mockStorageMinerAPI{} diff --git a/storage/wdpost_sched.go b/storage/wdpost_sched.go index 037f4e481..7e60fd9ee 100644 --- a/storage/wdpost_sched.go +++ b/storage/wdpost_sched.go @@ -4,12 +4,11 @@ import ( "context" "time" - "github.com/filecoin-project/go-state-types/dline" - "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/dline" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/api" @@ -110,7 +109,7 @@ func (s *WindowPoStScheduler) Run(ctx context.Context) { select { case changes, ok := <-notifs: if !ok { - log.Warn("WindowPoStScheduler notifs channel closed") + log.Warn("window post scheduler notifs channel closed") notifs = nil continue } @@ -151,10 +150,10 @@ func (s *WindowPoStScheduler) Run(ctx context.Context) { } if err := s.revert(ctx, lowest); err != nil { - log.Error("handling head reverts in windowPost sched: %+v", err) + log.Error("handling head reverts in window post sched: %+v", err) } if err := s.update(ctx, highest); err != nil { - log.Error("handling head updates in windowPost sched: %+v", err) + log.Error("handling head updates in window post sched: %+v", err) } span.End() @@ -184,7 +183,7 @@ func (s *WindowPoStScheduler) revert(ctx context.Context, newLowest *types.TipSe func (s *WindowPoStScheduler) update(ctx context.Context, new *types.TipSet) error { if new == nil { - return xerrors.Errorf("no new tipset in WindowPoStScheduler.update") + return xerrors.Errorf("no new tipset in window post sched update") } di, err := s.api.StateMinerProvingDeadline(ctx, s.actor, new.Key()) @@ -206,7 +205,7 @@ func (s *WindowPoStScheduler) update(ctx context.Context, new *types.TipSet) err // (Need to get correct deadline above, which is tricky) if di.Open+StartConfidence >= new.Height() { - log.Info("not starting windowPost yet, waiting for startconfidence", di.Open, di.Open+StartConfidence, new.Height()) + log.Info("not starting window post yet, waiting for startconfidence", di.Open, di.Open+StartConfidence, new.Height()) return nil } @@ -216,7 +215,7 @@ func (s *WindowPoStScheduler) update(ctx context.Context, new *types.TipSet) err s.activeEPS = 0 } s.failLk.Unlock()*/ - log.Infof("at %d, doPost for P %d, dd %d", new.Height(), di.PeriodStart, di.Index) + log.Infof("at %d, do window post for P %d, dd %d", new.Height(), di.PeriodStart, di.Index) s.doPost(ctx, di, new) @@ -238,7 +237,7 @@ func (s *WindowPoStScheduler) abortActivePoSt() { } }) - log.Warnf("Aborting Window PoSt (Deadline: %+v)", s.activeDeadline) + log.Warnf("Aborting window post (Deadline: %+v)", s.activeDeadline) } s.activeDeadline = nil diff --git a/tools/stats/metrics.go b/tools/stats/metrics.go index ae79d9273..22069c3d0 100644 --- a/tools/stats/metrics.go +++ b/tools/stats/metrics.go @@ -10,18 +10,15 @@ import ( "strings" "time" - "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin/reward" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/util/adt" - "golang.org/x/xerrors" "github.com/ipfs/go-cid" "github.com/multiformats/go-multihash" + "golang.org/x/xerrors" cbg "github.com/whyrusleeping/cbor-gen" @@ -189,7 +186,7 @@ func RecordTipsetPoints(ctx context.Context, api api.FullNode, pl *PointList, ti pl.AddPoint(p) } { - blks := len(cids) + blks := int64(len(cids)) p = NewPoint("chain.gas_fill_ratio", float64(totalGasLimit)/float64(blks*build.BlockGasTarget)) pl.AddPoint(p) p = NewPoint("chain.gas_capacity_ratio", float64(totalUniqGasLimit)/float64(blks*build.BlockGasTarget)) @@ -245,7 +242,7 @@ func RecordTipsetStatePoints(ctx context.Context, api api.FullNode, pl *PointLis //p := NewPoint("chain.pledge_collateral", pcFilFloat) //pl.AddPoint(p) - netBal, err := api.WalletBalance(ctx, builtin.RewardActorAddr) + netBal, err := api.WalletBalance(ctx, reward.Address) if err != nil { return err } @@ -255,55 +252,22 @@ func RecordTipsetStatePoints(ctx context.Context, api api.FullNode, pl *PointLis p := NewPoint("network.balance", netBalFilFloat) pl.AddPoint(p) - totalPower, err := api.StateMinerPower(ctx, address.Address{}, tipset.Key()) + miners, err := api.StateListMiners(ctx, tipset.Key()) if err != nil { return err } - p = NewPoint("chain.power", totalPower.TotalPower.QualityAdjPower.Int64()) - pl.AddPoint(p) - - powerActor, err := api.StateGetActor(ctx, builtin.StoragePowerActorAddr, tipset.Key()) - if err != nil { - return err - } - - powerRaw, err := api.ChainReadObj(ctx, powerActor.Head) - if err != nil { - return err - } - - var powerActorState power.State - - if err := powerActorState.UnmarshalCBOR(bytes.NewReader(powerRaw)); err != nil { - return fmt.Errorf("failed to unmarshal power actor state: %w", err) - } - - s := &apiIpldStore{ctx, api} - mp, err := adt.AsMap(s, powerActorState.Claims) - if err != nil { - return err - } - - var claim power.Claim - err = mp.ForEach(&claim, func(key string) error { - addr, err := address.NewFromBytes([]byte(key)) + for _, addr := range miners { + mp, err := api.StateMinerPower(ctx, addr, tipset.Key()) if err != nil { return err } - if claim.QualityAdjPower.Int64() == 0 { - return nil + if !mp.MinerPower.QualityAdjPower.IsZero() { + p = NewPoint("chain.miner_power", mp.MinerPower.QualityAdjPower.Int64()) + p.AddTag("miner", addr.String()) + pl.AddPoint(p) } - - p = NewPoint("chain.miner_power", claim.QualityAdjPower.Int64()) - p.AddTag("miner", addr.String()) - pl.AddPoint(p) - - return nil - }) - if err != nil { - return err } return nil