diff --git a/.circleci/config.yml b/.circleci/config.yml index d49d40bf93b..d8c7abf1623 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -225,12 +225,17 @@ jobs: cd extern/test-vectors git fetch git checkout origin/<< parameters.vectors-branch >> - - run: - name: go get vectors branch - command: go get github.com/filecoin-project/test-vectors@<< parameters.vectors-branch >> - go/install-gotestsum: gobin: $HOME/.local/bin version: 0.5.2 + - run: + name: install statediff globally + command: | + ## statediff is optional; we succeed even if compilation fails. + mkdir -p /tmp/statediff + git clone https://github.com/filecoin-project/statediff.git /tmp/statediff + cd /tmp/statediff + go install ./cmd/statediff || exit 0 - run: name: go test environment: diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000000..49e461d00e0 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,15 @@ +## filecoin-project/lotus CODEOWNERS +## Refer to https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners. +## +## These users or groups will be automatically assigned as reviewers every time +## a PR is submitted that modifies code in the specified locations. +## +## The Lotus repo configuration requires that at least ONE codeowner approves +## the PR before merging. + +### Global owners. +* @magik6k @whyrusleeping @Kubuxu + +### Conformance testing. +conformance/ @raulk +extern/test-vectors @raulk diff --git a/.gitmodules b/.gitmodules index ad09aba35d5..4b450aaf3dd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,3 +8,6 @@ [submodule "extern/test-vectors"] path = extern/test-vectors url = https://github.com/filecoin-project/test-vectors.git +[submodule "extern/fil-blst"] + path = extern/fil-blst + url = https://github.com/filecoin-project/fil-blst.git diff --git a/CHANGELOG.md b/CHANGELOG.md index ccefeda1073..8617554a9d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,174 @@ # Lotus changelog +# 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: + +- Upgrading the Drand network used from the test Drand network to the League of Entropy main drand network. This is the same Drand network that will be used in the Filecoin mainnet. +- Upgrading to specs-actors v0.9.8, which adds a new method to the Multisig actor. + +## Changes + +#### Core Lotus + +- Fix IsAncestorOf (https://github.com/filecoin-project/lotus/pull/3717) +- Update to specs-actors v0.9.8 (https://github.com/filecoin-project/lotus/pull/3725) +- Increase chain throughput by 20% (https://github.com/filecoin-project/lotus/pull/3732) +- Updare to go-libp2p-pubsub `master` (https://github.com/filecoin-project/lotus/pull/3735) +- Drand upgrade (https://github.com/filecoin-project/lotus/pull/3670) +- Multisig API additions (https://github.com/filecoin-project/lotus/pull/3590) + +#### Storage Miner + +- Increase the number of times precommit2 is attempted before moving back to precommit1 (https://github.com/filecoin-project/lotus/pull/3720) + +#### Message pool + +- Relax mpool add strictness checks for local pushes (https://github.com/filecoin-project/lotus/pull/3724) + + +#### Maintenance + +- Fix devnets (https://github.com/filecoin-project/lotus/pull/3712) +- Fix(chainwatch): compare prev miner with cur miner (https://github.com/filecoin-project/lotus/pull/3715) +- CI: fix statediff build; make optional (https://github.com/filecoin-project/lotus/pull/3729) +- Feat: Chaos abort (https://github.com/filecoin-project/lotus/pull/3733) + +## Contributors + +The following contributors had commits go into this release. +We are grateful for every contribution! + +| Contributor | Commits | Lines ± | +|--------------------|---------|---------------| +| arajasek | 28 | +1144/-239 | +| Kubuxu | 19 | +452/-261 | +| whyrusleeping | 13 | +456/-87 | +| vyzo | 11 | +318/-20 | +| raulk | 10 | +1289/-350 | +| magik6k | 6 | +188/-55 | +| dirkmc | 3 | +31/-8 | +| alanshaw | 3 | +176/-37 | +| Stebalien | 2 | +9/-12 | +| lanzafame | 1 | +1/-1 | +| frrist | 1 | +1/-1 | +| mishmosh | 1 | +1/-1 | +| nonsense | 1 | +1/-0 | + +# 0.6.2 / 2020-09-09 + +This release introduces some critical fixes to message selection and gas estimation logic. It also adds the ability for nodes to mark a certain tipset as checkpointed, as well as various minor improvements and bugfixes. + +## Changes + +#### Messagepool + +- Warn when optimal selection fails to pack a block and we fall back to random selection (https://github.com/filecoin-project/lotus/pull/3708) +- Add basic command for printing gas performance of messages in the mpool (https://github.com/filecoin-project/lotus/pull/3701) +- Adjust optimal selection to always try to fill blocks (https://github.com/filecoin-project/lotus/pull/3685) +- Fix very minor bug in repub baseFeeLowerBound (https://github.com/filecoin-project/lotus/pull/3663) +- Add an auto flag to mpool replace (https://github.com/filecoin-project/lotus/pull/3676) +- Fix mpool optimal selection packing failure (https://github.com/filecoin-project/lotus/pull/3698) + +#### Core Lotus + +- Don't use latency as initital estimate for blocksync (https://github.com/filecoin-project/lotus/pull/3648) +- Add niceSleep 1 second when drand errors (https://github.com/filecoin-project/lotus/pull/3664) +- Fix isChainNearSync check in block validator (https://github.com/filecoin-project/lotus/pull/3650) +- Add peer to peer manager before fetching the tipset (https://github.com/filecoin-project/lotus/pull/3667) +- Add StageFetchingMessages to sync status (https://github.com/filecoin-project/lotus/pull/3668) +- Pass tipset through upgrade logic (https://github.com/filecoin-project/lotus/pull/3673) +- Allow nodes to mark tipsets as checkpointed (https://github.com/filecoin-project/lotus/pull/3680) +- Remove hard-coded late-fee in window PoSt (https://github.com/filecoin-project/lotus/pull/3702) +- Gas: Fix median calc (https://github.com/filecoin-project/lotus/pull/3686) + +#### Storage + +- Storage manager: bail out with an error if unsealed cid is undefined (https://github.com/filecoin-project/lotus/pull/3655) +- Storage: return true from Sealer.ReadPiece() on success (https://github.com/filecoin-project/lotus/pull/3657) + +#### Maintenance + +- Resolve lotus, test-vectors, statediff dependency cycle (https://github.com/filecoin-project/lotus/pull/3688) +- Paych: add docs on how to use paych status (https://github.com/filecoin-project/lotus/pull/3690) +- Initial CODEOWNERS (https://github.com/filecoin-project/lotus/pull/3691) + +# 0.6.1 / 2020-09-08 + +This optional release introduces a minor improvement to the sync process, ensuring nodes don't fall behind and then resync. + +## Changes + +- Update `test-vectors` (https://github.com/filecoin-project/lotus/pull/3645) +- Revert "only subscribe to pubsub topics once we are synced" (https://github.com/filecoin-project/lotus/pull/3643) + +# 0.6.0 / 2020-09-07 + +This consensus-breaking release of Lotus is designed to test a network upgrade on the space race testnet. The changes that break consensus are: + +- Tweaking of some cryptoecon parameters in specs-actors 0.9.7 (https://github.com/filecoin-project/specs-actors/releases/tag/v0.9.7) +- Rebalancing FIL distribution to make testnet FIL scarce, which prevents base fee spikes and sets better expectations for mainnet + +This release also introduces many improvements to Lotus! Among them are a new version of go-fil-markets that supports non-blocking retrieval, various spam reduction measures in the messagepool and p2p logic, and UX improvements to payment channels, dealmaking, and state inspection. + +## Changes + +#### Core Lotus and dependencies + +- Implement faucet funds reallocation logic (https://github.com/filecoin-project/lotus/pull/3632) +- Network upgrade: Upgrade to correct fork threshold (https://github.com/filecoin-project/lotus/pull/3628) +- Update to specs 0.9.7 and markets 0.6.0 (https://github.com/filecoin-project/lotus/pull/3627) +- Network upgrade: Perform base fee tamping (https://github.com/filecoin-project/lotus/pull/3623) +- Chain events: if cache best() is nil, return chain head (https://github.com/filecoin-project/lotus/pull/3611) +- Update to specs actors v0.9.6 (https://github.com/filecoin-project/lotus/pull/3603) + +#### Messagepool + +- Temporarily allow negative chains (https://github.com/filecoin-project/lotus/pull/3625) +- Improve publish/republish logic (https://github.com/filecoin-project/lotus/pull/3592) +- Fix selection bug; priority messages were not included if other chains were negative (https://github.com/filecoin-project/lotus/pull/3580) +- Add defensive check for minimum GasFeeCap for inclusion within the next 20 blocks (https://github.com/filecoin-project/lotus/pull/3579) +- Add additional info about gas premium (https://github.com/filecoin-project/lotus/pull/3578) +- Fix GasPremium capping logic (https://github.com/filecoin-project/lotus/pull/3552) + +#### Payment channels + +- Get available funds by address or by from/to (https://github.com/filecoin-project/lotus/pull/3547) +- Create `lotus paych status` command (https://github.com/filecoin-project/lotus/pull/3523) +- Rename CLI command from "paych get" to "paych add-funds" (https://github.com/filecoin-project/lotus/pull/3520) + +#### Peer-to-peer + +- Only subscribe to pubsub topics once we are synced (https://github.com/filecoin-project/lotus/pull/3602) +- Reduce mpool add failure log spam (https://github.com/filecoin-project/lotus/pull/3562) +- Republish messages even if the chains have negative performance(https://github.com/filecoin-project/lotus/pull/3557) +- Adjust gossipsub gossip factor (https://github.com/filecoin-project/lotus/pull/3556) +- Integrate pubsub Random Early Drop (https://github.com/filecoin-project/lotus/pull/3518) + +#### Miscellaneous + +- Fix panic in OnDealExpiredSlashed (https://github.com/filecoin-project/lotus/pull/3553) +- Robustify state manager against holes in actor method numbers (https://github.com/filecoin-project/lotus/pull/3538) + +#### UX + +- VM: Fix an error message (https://github.com/filecoin-project/lotus/pull/3608) +- Documentation: Batch replacement,update lotus-storage-miner to lotus-miner (https://github.com/filecoin-project/lotus/pull/3571) +- CLI: Robust actor lookup (https://github.com/filecoin-project/lotus/pull/3535) +- Add agent flag to net peers (https://github.com/filecoin-project/lotus/pull/3534) +- Add watch option to storage-deals list (https://github.com/filecoin-project/lotus/pull/3527) + +#### Testing & tooling + +- Decommission chain-validation (https://github.com/filecoin-project/lotus/pull/3606) +- Metrics: add expected height metric (https://github.com/filecoin-project/lotus/pull/3586) +- PCR: Use current tipset during refund (https://github.com/filecoin-project/lotus/pull/3570) +- Lotus-shed: Add math command (https://github.com/filecoin-project/lotus/pull/3568) +- PCR: Add tipset aggergation (https://github.com/filecoin-project/lotus/pull/3565)- Fix broken paych tests (https://github.com/filecoin-project/lotus/pull/3551) +- Make chain export ~1000x times faster (https://github.com/filecoin-project/lotus/pull/3533) +- Chainwatch: Stop SyncIncomingBlocks from leaking into chainwatch processing; No panics during processing (https://github.com/filecoin-project/lotus/pull/3526) +- Conformance: various changes (https://github.com/filecoin-project/lotus/pull/3521) + # 0.5.10 / 2020-09-03 This patch includes a crucial fix to the message pool selection logic, strongly disfavouring messages that might cause a miner penalty. diff --git a/api/api_full.go b/api/api_full.go index f913483b3a2..23226443a37 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -2,23 +2,29 @@ package api import ( "context" + "fmt" "time" + "github.com/filecoin-project/go-state-types/dline" + + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/ipfs/go-cid" "github.com/libp2p/go-libp2p-core/peer" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-multistore" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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/specs-actors/actors/crypto" "github.com/filecoin-project/lotus/chain/types" marketevents "github.com/filecoin-project/lotus/markets/loggers" @@ -112,7 +118,8 @@ type FullNode interface { // The exported chain data includes the header chain from the given tipset // back to genesis, the entire genesis state, and the most recent 'nroots' // state trees. - ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk types.TipSetKey) (<-chan []byte, error) + // If oldmsgskip is set, messages from before the requested roots are also not included. + ChainExport(ctx context.Context, nroots abi.ChainEpoch, oldmsgskip bool, tsk types.TipSetKey) (<-chan []byte, error) // MethodGroup: Beacon // The Beacon method group contains methods for interacting with the random beacon (DRAND) @@ -153,10 +160,16 @@ type FullNode interface { // yet synced block headers. SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error) + // SyncCheckpoint marks a blocks as checkpointed, meaning that it won't ever fork away from it. + SyncCheckpoint(ctx context.Context, tsk types.TipSetKey) error + // SyncMarkBad marks a blocks as bad, meaning that it won't ever by synced. // Use with extreme caution. SyncMarkBad(ctx context.Context, bcid cid.Cid) error + // SyncUnmarkBad unmarks a blocks as bad, making it possible to be validated and synced again. + SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error + // SyncCheckBad checks if a block was marked as bad, and if it was, returns // the reason. SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) @@ -270,6 +283,9 @@ type FullNode interface { // ClientListTransfers returns the status of all ongoing transfers of data ClientListDataTransfers(ctx context.Context) ([]DataTransferChannel, error) ClientDataTransferUpdates(ctx context.Context) (<-chan DataTransferChannel, error) + // ClientRetrieveTryRestartInsufficientFunds attempts to restart stalled retrievals on a given payment channel + // which are stuck due to insufficient funds + ClientRetrieveTryRestartInsufficientFunds(ctx context.Context, paymentChannel address.Address) error // ClientUnimport removes references to the specified file from filestore //ClientUnimport(path string) @@ -300,12 +316,12 @@ type FullNode interface { // 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, *abi.BitField, bool, types.TipSetKey) ([]*ChainSectorInfo, error) + StateMinerSectors(context.Context, address.Address, *bitfield.BitField, bool, types.TipSetKey) ([]*ChainSectorInfo, error) // StateMinerActiveSectors returns info about sectors that a given miner is actively proving. StateMinerActiveSectors(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, 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) (*miner.DeadlineInfo, error) + 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 @@ -315,11 +331,11 @@ type FullNode interface { // StateMinerPartitions loads miner partitions for the specified miner/deadline StateMinerPartitions(context.Context, address.Address, uint64, types.TipSetKey) ([]*miner.Partition, error) // StateMinerFaults returns a bitfield indicating the faulty sectors of the given miner - StateMinerFaults(context.Context, address.Address, types.TipSetKey) (abi.BitField, error) + 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 StateAllMinerFaults(ctx context.Context, lookback abi.ChainEpoch, ts types.TipSetKey) ([]*Fault, error) // StateMinerRecoveries returns a bitfield indicating the recovering sectors of the given miner - StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (abi.BitField, error) + StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error) // StateMinerInitialPledgeCollateral returns the precommit deposit for the specified miner's sector StateMinerPreCommitDepositForPower(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error) // StateMinerInitialPledgeCollateral returns the initial pledge collateral for the specified miner's sector @@ -384,6 +400,9 @@ type FullNode interface { // MsigGetAvailableBalance returns the portion of a multisig's balance that can be withdrawn or spent MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) + // MsigGetVested returns the amount of FIL that vested in a multisig in a certain period. + // It takes the following params: , , + MsigGetVested(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error) // MsigCreate creates a multisig wallet // It takes the following params: , , //, , @@ -400,17 +419,29 @@ type FullNode interface { // It takes the following params: , , , , // , , MsigCancel(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) + // MsigAddPropose proposes adding a signer in the multisig + // It takes the following params: , , + // , + MsigAddPropose(context.Context, address.Address, address.Address, address.Address, bool) (cid.Cid, error) + // MsigAddApprove approves a previously proposed AddSigner message + // It takes the following params: , , , + // , , + MsigAddApprove(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, bool) (cid.Cid, error) + // MsigAddCancel cancels a previously proposed AddSigner message + // It takes the following params: , , , + // , + MsigAddCancel(context.Context, address.Address, address.Address, uint64, address.Address, bool) (cid.Cid, error) // MsigSwapPropose proposes swapping 2 signers in the multisig // It takes the following params: , , - // + // , MsigSwapPropose(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error) // MsigSwapApprove approves a previously proposed SwapSigner // It takes the following params: , , , - // , + // , , MsigSwapApprove(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error) // MsigSwapCancel cancels a previously proposed SwapSigner message // It takes the following params: , , , - // + // , MsigSwapCancel(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error) MarketEnsureAvailable(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error) @@ -421,7 +452,8 @@ type FullNode interface { PaychGet(ctx context.Context, from, to address.Address, amt types.BigInt) (*ChannelInfo, error) PaychGetWaitReady(context.Context, cid.Cid) (address.Address, error) - PaychAvailableFunds(from, to address.Address) (*ChannelAvailableFunds, error) + PaychAvailableFunds(ch address.Address) (*ChannelAvailableFunds, error) + PaychAvailableFundsByFromTo(from, to address.Address) (*ChannelAvailableFunds, error) PaychList(context.Context) ([]address.Address, error) PaychStatus(context.Context, address.Address) (*PaychStatus, error) PaychSettle(context.Context, address.Address) (cid.Cid, error) @@ -540,7 +572,12 @@ type ChannelInfo struct { } type ChannelAvailableFunds struct { + // Channel is the address of the channel Channel *address.Address + // From is the from address of the channel (channel creator) + From address.Address + // To is the to address of the channel + To address.Address // ConfirmedAmt is the amount of funds that have been confirmed on-chain // for the channel ConfirmedAmt types.BigInt @@ -697,8 +734,28 @@ const ( StageMessages StageSyncComplete StageSyncErrored + StageFetchingMessages ) +func (v SyncStateStage) String() string { + switch v { + case StageHeaders: + return "header sync" + case StagePersistHeaders: + return "persisting headers" + case StageMessages: + return "message sync" + case StageSyncComplete: + return "complete" + case StageSyncErrored: + return "error" + case StageFetchingMessages: + return "fetching messages" + default: + return fmt.Sprintf("", v) + } +} + type MpoolChange int const ( @@ -732,7 +789,7 @@ type CirculatingSupply struct { type MiningBaseInfo struct { MinerPower types.BigInt NetworkPower types.BigInt - Sectors []abi.SectorInfo + Sectors []proof.SectorInfo WorkerKey address.Address SectorSize abi.SectorSize PrevBeaconEntry types.BeaconEntry @@ -749,7 +806,7 @@ type BlockTemplate struct { Messages []*types.SignedMessage Epoch abi.ChainEpoch Timestamp uint64 - WinningPoStProof []abi.PoStProof + WinningPoStProof []proof.PoStProof } type DataSize struct { diff --git a/api/api_storage.go b/api/api_storage.go index 48f6e9e4551..37bef2d6cc2 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -11,11 +11,11 @@ import ( "github.com/filecoin-project/go-fil-markets/piecestore" "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/extern/sector-storage/fsutil" "github.com/filecoin-project/lotus/extern/sector-storage/stores" "github.com/filecoin-project/lotus/extern/sector-storage/storiface" - "github.com/filecoin-project/specs-actors/actors/abi" ) // StorageMiner is a low-level interface to the Filecoin network storage miner node diff --git a/api/api_worker.go b/api/api_worker.go index 00c4df8bcec..ac1446fdd0f 100644 --- a/api/api_worker.go +++ b/api/api_worker.go @@ -6,10 +6,10 @@ import ( "github.com/ipfs/go-cid" + "github.com/filecoin-project/go-state-types/abi" "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" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/build" diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index dff614001f2..fdb9843ff7f 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -5,6 +5,8 @@ import ( "io" "time" + "github.com/filecoin-project/go-state-types/dline" + "github.com/ipfs/go-cid" metrics "github.com/libp2p/go-libp2p-core/metrics" "github.com/libp2p/go-libp2p-core/network" @@ -12,22 +14,23 @@ import ( protocol "github.com/libp2p/go-libp2p-core/protocol" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-fil-markets/piecestore" "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-jsonrpc/auth" "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/go-state-types/crypto" "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/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" "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-actors/actors/crypto" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/api" @@ -92,7 +95,7 @@ type FullNodeStruct struct { ChainGetNode func(ctx context.Context, p string) (*api.IpldObject, error) `perm:"read"` ChainGetMessage func(context.Context, cid.Cid) (*types.Message, error) `perm:"read"` ChainGetPath func(context.Context, types.TipSetKey, types.TipSetKey) ([]*api.HeadChange, error) `perm:"read"` - ChainExport func(context.Context, abi.ChainEpoch, types.TipSetKey) (<-chan []byte, error) `perm:"read"` + ChainExport func(context.Context, abi.ChainEpoch, bool, types.TipSetKey) (<-chan []byte, error) `perm:"read"` BeaconGetEntry func(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"` @@ -104,7 +107,9 @@ type FullNodeStruct struct { SyncState func(context.Context) (*api.SyncState, error) `perm:"read"` SyncSubmitBlock func(ctx context.Context, blk *types.BlockMsg) error `perm:"write"` SyncIncomingBlocks func(ctx context.Context) (<-chan *types.BlockHeader, error) `perm:"read"` + SyncCheckpoint func(ctx context.Context, key types.TipSetKey) error `perm:"admin"` SyncMarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"` + SyncUnmarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"` SyncCheckBad func(ctx context.Context, bcid cid.Cid) (string, error) `perm:"read"` MpoolGetConfig func(context.Context) (*types.MpoolConfig, error) `perm:"read"` @@ -136,36 +141,37 @@ type FullNodeStruct struct { WalletImport func(context.Context, *types.KeyInfo) (address.Address, error) `perm:"admin"` WalletDelete func(context.Context, address.Address) error `perm:"write"` - ClientImport func(ctx context.Context, ref api.FileRef) (*api.ImportRes, error) `perm:"admin"` - ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"` - ClientRemoveImport func(ctx context.Context, importID multistore.StoreID) error `perm:"admin"` - ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, error) `perm:"write"` - ClientFindData func(ctx context.Context, root cid.Cid, piece *cid.Cid) ([]api.QueryOffer, error) `perm:"read"` - ClientMinerQueryOffer func(ctx context.Context, miner address.Address, root cid.Cid, piece *cid.Cid) (api.QueryOffer, error) `perm:"read"` - ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"` - ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"` - ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"` - ClientGetDealUpdates func(ctx context.Context) (<-chan api.DealInfo, error) `perm:"read"` - ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error `perm:"admin"` - ClientRetrieveWithEvents func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) `perm:"admin"` - ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"` - ClientCalcCommP func(ctx context.Context, inpath string) (*api.CommPRet, error) `perm:"read"` - ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"` - ClientDealSize func(ctx context.Context, root cid.Cid) (api.DataSize, error) `perm:"read"` - ClientListDataTransfers func(ctx context.Context) ([]api.DataTransferChannel, error) `perm:"write"` - ClientDataTransferUpdates func(ctx context.Context) (<-chan api.DataTransferChannel, error) `perm:"write"` + ClientImport func(ctx context.Context, ref api.FileRef) (*api.ImportRes, error) `perm:"admin"` + ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"` + ClientRemoveImport func(ctx context.Context, importID multistore.StoreID) error `perm:"admin"` + ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, error) `perm:"write"` + ClientFindData func(ctx context.Context, root cid.Cid, piece *cid.Cid) ([]api.QueryOffer, error) `perm:"read"` + ClientMinerQueryOffer func(ctx context.Context, miner address.Address, root cid.Cid, piece *cid.Cid) (api.QueryOffer, error) `perm:"read"` + ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"` + ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"` + ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"` + ClientGetDealUpdates func(ctx context.Context) (<-chan api.DealInfo, error) `perm:"read"` + ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error `perm:"admin"` + ClientRetrieveWithEvents func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) `perm:"admin"` + ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"` + ClientCalcCommP func(ctx context.Context, inpath string) (*api.CommPRet, error) `perm:"read"` + ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"` + ClientDealSize func(ctx context.Context, root cid.Cid) (api.DataSize, error) `perm:"read"` + ClientListDataTransfers func(ctx context.Context) ([]api.DataTransferChannel, error) `perm:"write"` + ClientDataTransferUpdates func(ctx context.Context) (<-chan api.DataTransferChannel, error) `perm:"write"` + 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, *abi.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, 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"` - StateMinerProvingDeadline func(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, 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"` - StateMinerFaults func(context.Context, address.Address, types.TipSetKey) (abi.BitField, 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) (abi.BitField, error) `perm:"read"` + StateMinerRecoveries func(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error) `perm:"read"` StateMinerPreCommitDepositForPower func(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error) `perm:"read"` StateMinerInitialPledgeCollateral func(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error) `perm:"read"` StateMinerAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"` @@ -197,32 +203,37 @@ type FullNodeStruct struct { StateCirculatingSupply func(context.Context, types.TipSetKey) (api.CirculatingSupply, 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"` MsigCreate func(context.Context, uint64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"` MsigPropose func(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"` MsigApprove func(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"` MsigCancel func(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"` + MsigAddPropose func(context.Context, address.Address, address.Address, address.Address, bool) (cid.Cid, error) `perm:"sign"` + MsigAddApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, bool) (cid.Cid, error) `perm:"sign"` + MsigAddCancel func(context.Context, address.Address, address.Address, uint64, address.Address, bool) (cid.Cid, error) `perm:"sign"` MsigSwapPropose func(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"` MsigSwapApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"` MsigSwapCancel func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error) `perm:"sign"` MarketEnsureAvailable func(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"` - PaychGet func(ctx context.Context, from, to address.Address, amt types.BigInt) (*api.ChannelInfo, error) `perm:"sign"` - PaychGetWaitReady func(context.Context, cid.Cid) (address.Address, error) `perm:"sign"` - PaychAvailableFunds func(address.Address, address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"` - PaychList func(context.Context) ([]address.Address, error) `perm:"read"` - PaychStatus func(context.Context, address.Address) (*api.PaychStatus, error) `perm:"read"` - PaychSettle func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"` - PaychCollect func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"` - PaychAllocateLane func(context.Context, address.Address) (uint64, error) `perm:"sign"` - PaychNewPayment func(ctx context.Context, from, to address.Address, vouchers []api.VoucherSpec) (*api.PaymentInfo, error) `perm:"sign"` - PaychVoucherCheck func(context.Context, *paych.SignedVoucher) error `perm:"read"` - PaychVoucherCheckValid func(context.Context, address.Address, *paych.SignedVoucher) error `perm:"read"` - PaychVoucherCheckSpendable func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error) `perm:"read"` - PaychVoucherAdd func(context.Context, address.Address, *paych.SignedVoucher, []byte, types.BigInt) (types.BigInt, error) `perm:"write"` - PaychVoucherCreate func(context.Context, address.Address, big.Int, uint64) (*api.VoucherCreateResult, error) `perm:"sign"` - PaychVoucherList func(context.Context, address.Address) ([]*paych.SignedVoucher, error) `perm:"write"` - PaychVoucherSubmit func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error) `perm:"sign"` + PaychGet func(ctx context.Context, from, to address.Address, amt types.BigInt) (*api.ChannelInfo, error) `perm:"sign"` + PaychGetWaitReady func(context.Context, cid.Cid) (address.Address, error) `perm:"sign"` + PaychAvailableFunds func(address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"` + PaychAvailableFundsByFromTo func(address.Address, address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"` + PaychList func(context.Context) ([]address.Address, error) `perm:"read"` + PaychStatus func(context.Context, address.Address) (*api.PaychStatus, error) `perm:"read"` + PaychSettle func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"` + PaychCollect func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"` + PaychAllocateLane func(context.Context, address.Address) (uint64, error) `perm:"sign"` + PaychNewPayment func(ctx context.Context, from, to address.Address, vouchers []api.VoucherSpec) (*api.PaymentInfo, error) `perm:"sign"` + PaychVoucherCheck func(context.Context, *paych.SignedVoucher) error `perm:"read"` + PaychVoucherCheckValid func(context.Context, address.Address, *paych.SignedVoucher) error `perm:"read"` + PaychVoucherCheckSpendable func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error) `perm:"read"` + PaychVoucherAdd func(context.Context, address.Address, *paych.SignedVoucher, []byte, types.BigInt) (types.BigInt, error) `perm:"write"` + PaychVoucherCreate func(context.Context, address.Address, big.Int, uint64) (*api.VoucherCreateResult, error) `perm:"sign"` + PaychVoucherList func(context.Context, address.Address) ([]*paych.SignedVoucher, error) `perm:"write"` + PaychVoucherSubmit func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error) `perm:"sign"` } } @@ -493,6 +504,10 @@ func (c *FullNodeStruct) ClientDataTransferUpdates(ctx context.Context) (<-chan return c.Internal.ClientDataTransferUpdates(ctx) } +func (c *FullNodeStruct) ClientRetrieveTryRestartInsufficientFunds(ctx context.Context, paymentChannel address.Address) error { + return c.Internal.ClientRetrieveTryRestartInsufficientFunds(ctx, paymentChannel) +} + func (c *FullNodeStruct) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) { return c.Internal.GasEstimateGasPremium(ctx, nblocksincl, sender, gaslimit, tsk) } @@ -677,8 +692,8 @@ func (c *FullNodeStruct) ChainGetPath(ctx context.Context, from types.TipSetKey, return c.Internal.ChainGetPath(ctx, from, to) } -func (c *FullNodeStruct) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk types.TipSetKey) (<-chan []byte, error) { - return c.Internal.ChainExport(ctx, nroots, tsk) +func (c *FullNodeStruct) ChainExport(ctx context.Context, nroots abi.ChainEpoch, iom bool, tsk types.TipSetKey) (<-chan []byte, error) { + return c.Internal.ChainExport(ctx, nroots, iom, tsk) } func (c *FullNodeStruct) BeaconGetEntry(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) { @@ -697,10 +712,18 @@ func (c *FullNodeStruct) SyncIncomingBlocks(ctx context.Context) (<-chan *types. return c.Internal.SyncIncomingBlocks(ctx) } +func (c *FullNodeStruct) SyncCheckpoint(ctx context.Context, tsk types.TipSetKey) error { + return c.Internal.SyncCheckpoint(ctx, tsk) +} + func (c *FullNodeStruct) SyncMarkBad(ctx context.Context, bcid cid.Cid) error { return c.Internal.SyncMarkBad(ctx, bcid) } +func (c *FullNodeStruct) SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error { + return c.Internal.SyncUnmarkBad(ctx, bcid) +} + func (c *FullNodeStruct) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) { return c.Internal.SyncCheckBad(ctx, bcid) } @@ -709,7 +732,7 @@ 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 *abi.BitField, filterOut bool, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) { +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) } @@ -717,7 +740,7 @@ func (c *FullNodeStruct) StateMinerActiveSectors(ctx context.Context, addr addre return c.Internal.StateMinerActiveSectors(ctx, addr, tsk) } -func (c *FullNodeStruct) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*miner.DeadlineInfo, error) { +func (c *FullNodeStruct) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) { return c.Internal.StateMinerProvingDeadline(ctx, addr, tsk) } @@ -737,7 +760,7 @@ func (c *FullNodeStruct) StateMinerPartitions(ctx context.Context, m address.Add return c.Internal.StateMinerPartitions(ctx, m, dlIdx, tsk) } -func (c *FullNodeStruct) StateMinerFaults(ctx context.Context, actor address.Address, tsk types.TipSetKey) (abi.BitField, error) { +func (c *FullNodeStruct) StateMinerFaults(ctx context.Context, actor address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { return c.Internal.StateMinerFaults(ctx, actor, tsk) } @@ -745,7 +768,7 @@ func (c *FullNodeStruct) StateAllMinerFaults(ctx context.Context, cutoff abi.Cha return c.Internal.StateAllMinerFaults(ctx, cutoff, endTsk) } -func (c *FullNodeStruct) StateMinerRecoveries(ctx context.Context, actor address.Address, tsk types.TipSetKey) (abi.BitField, error) { +func (c *FullNodeStruct) StateMinerRecoveries(ctx context.Context, actor address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { return c.Internal.StateMinerRecoveries(ctx, actor, tsk) } @@ -865,6 +888,10 @@ func (c *FullNodeStruct) MsigGetAvailableBalance(ctx context.Context, a address. return c.Internal.MsigGetAvailableBalance(ctx, a, tsk) } +func (c *FullNodeStruct) MsigGetVested(ctx context.Context, a address.Address, sTsk types.TipSetKey, eTsk types.TipSetKey) (types.BigInt, error) { + return c.Internal.MsigGetVested(ctx, a, sTsk, eTsk) +} + func (c *FullNodeStruct) MsigCreate(ctx context.Context, req uint64, addrs []address.Address, duration abi.ChainEpoch, val types.BigInt, src address.Address, gp types.BigInt) (cid.Cid, error) { return c.Internal.MsigCreate(ctx, req, addrs, duration, val, src, gp) } @@ -881,6 +908,18 @@ func (c *FullNodeStruct) MsigCancel(ctx context.Context, msig address.Address, t return c.Internal.MsigCancel(ctx, msig, txID, to, amt, src, method, params) } +func (c *FullNodeStruct) MsigAddPropose(ctx context.Context, msig address.Address, src address.Address, newAdd address.Address, inc bool) (cid.Cid, error) { + return c.Internal.MsigAddPropose(ctx, msig, src, newAdd, inc) +} + +func (c *FullNodeStruct) MsigAddApprove(ctx context.Context, msig address.Address, src address.Address, txID uint64, proposer address.Address, newAdd address.Address, inc bool) (cid.Cid, error) { + return c.Internal.MsigAddApprove(ctx, msig, src, txID, proposer, newAdd, inc) +} + +func (c *FullNodeStruct) MsigAddCancel(ctx context.Context, msig address.Address, src address.Address, txID uint64, newAdd address.Address, inc bool) (cid.Cid, error) { + return c.Internal.MsigAddCancel(ctx, msig, src, txID, newAdd, inc) +} + func (c *FullNodeStruct) MsigSwapPropose(ctx context.Context, msig address.Address, src address.Address, oldAdd address.Address, newAdd address.Address) (cid.Cid, error) { return c.Internal.MsigSwapPropose(ctx, msig, src, oldAdd, newAdd) } @@ -905,8 +944,12 @@ func (c *FullNodeStruct) PaychGetWaitReady(ctx context.Context, sentinel cid.Cid return c.Internal.PaychGetWaitReady(ctx, sentinel) } -func (c *FullNodeStruct) PaychAvailableFunds(from address.Address, to address.Address) (*api.ChannelAvailableFunds, error) { - return c.Internal.PaychAvailableFunds(from, to) +func (c *FullNodeStruct) PaychAvailableFunds(ch address.Address) (*api.ChannelAvailableFunds, error) { + return c.Internal.PaychAvailableFunds(ch) +} + +func (c *FullNodeStruct) PaychAvailableFundsByFromTo(from, to address.Address) (*api.ChannelAvailableFunds, error) { + return c.Internal.PaychAvailableFundsByFromTo(from, to) } func (c *FullNodeStruct) PaychList(ctx context.Context) ([]address.Address, error) { diff --git a/api/cbor_gen.go b/api/cbor_gen.go index 8889e6021c6..7ab575b287d 100644 --- a/api/cbor_gen.go +++ b/api/cbor_gen.go @@ -6,7 +6,7 @@ import ( "fmt" "io" - abi "github.com/filecoin-project/specs-actors/actors/abi" + abi "github.com/filecoin-project/go-state-types/abi" paych "github.com/filecoin-project/specs-actors/actors/builtin/paych" cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index c3b4962d5f8..d00643a02d1 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -28,9 +28,9 @@ import ( "github.com/filecoin-project/go-jsonrpc/auth" "github.com/filecoin-project/go-multistore" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "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/lotus/api" "github.com/filecoin-project/lotus/api/apistruct" @@ -105,7 +105,7 @@ func init() { addExample(network.Connected) addExample(dtypes.NetworkName("lotus")) addExample(api.SyncStateStage(1)) - addExample(build.APIVersion) + addExample(build.FullAPIVersion) addExample(api.PCHInbound) addExample(time.Minute) addExample(datatransfer.TransferID(3)) diff --git a/api/test/blockminer.go b/api/test/blockminer.go index c6433efea9e..6b28a579416 100644 --- a/api/test/blockminer.go +++ b/api/test/blockminer.go @@ -7,8 +7,8 @@ import ( "testing" "time" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/miner" - "github.com/filecoin-project/specs-actors/actors/abi" ) type BlockMiner struct { diff --git a/api/test/ccupgrade.go b/api/test/ccupgrade.go index 3666aa3db8a..130b55cb863 100644 --- a/api/test/ccupgrade.go +++ b/api/test/ccupgrade.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/impl" diff --git a/api/test/deals.go b/api/test/deals.go index 1dcc1c8d71b..12cd0607ac7 100644 --- a/api/test/deals.go +++ b/api/test/deals.go @@ -20,11 +20,11 @@ import ( "github.com/ipld/go-car" "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" "github.com/filecoin-project/lotus/miner" - "github.com/filecoin-project/specs-actors/actors/abi" dag "github.com/ipfs/go-merkledag" dstest "github.com/ipfs/go-merkledag/test" unixfile "github.com/ipfs/go-unixfs/file" diff --git a/api/test/mining.go b/api/test/mining.go index f912ff30568..e19774a767a 100644 --- a/api/test/mining.go +++ b/api/test/mining.go @@ -12,7 +12,7 @@ import ( logging "github.com/ipfs/go-log/v2" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/stretchr/testify/require" "github.com/filecoin-project/lotus/build" diff --git a/api/test/paych.go b/api/test/paych.go index b0ccc0a5c09..36eb2c25622 100644 --- a/api/test/paych.go +++ b/api/test/paych.go @@ -10,8 +10,8 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/ipfs/go-cid" diff --git a/api/test/test.go b/api/test/test.go index 98a9a2e48a5..409274ff1ce 100644 --- a/api/test/test.go +++ b/api/test/test.go @@ -65,6 +65,8 @@ func TestApis(t *testing.T, b APIBuilder) { var OneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}} func (ts *testSuite) testVersion(t *testing.T) { + build.RunningNodeType = build.NodeFull + ctx := context.Background() apis, _ := ts.makeNodes(t, 1, OneMiner) api := apis[0] diff --git a/api/test/util.go b/api/test/util.go index 57a6fcae395..8695e2e2efb 100644 --- a/api/test/util.go +++ b/api/test/util.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/chain/types" diff --git a/api/test/window_post.go b/api/test/window_post.go index c5c8ec0718e..3f15c754b43 100644 --- a/api/test/window_post.go +++ b/api/test/window_post.go @@ -12,9 +12,9 @@ import ( "github.com/stretchr/testify/require" "github.com/filecoin-project/go-address" + "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" - "github.com/filecoin-project/specs-actors/actors/abi" miner2 "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/api" @@ -192,7 +192,7 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector // Drop the partition err = parts[0].Sectors.ForEach(func(sid uint64) error { - return miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkFailed(abi.SectorID{ + return miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkCorrupted(abi.SectorID{ Miner: abi.ActorID(mid), Number: abi.SectorNumber(sid), }, true) diff --git a/api/types.go b/api/types.go index 37cc4a7fa93..dc843281805 100644 --- a/api/types.go +++ b/api/types.go @@ -6,8 +6,8 @@ import ( "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/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/ipfs/go-cid" diff --git a/api/utils.go b/api/utils.go index 13d5c92cb94..a9d02c31bb2 100644 --- a/api/utils.go +++ b/api/utils.go @@ -4,7 +4,7 @@ import ( "context" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" ) type SignFunc = func(context.Context, []byte) (*crypto.Signature, error) diff --git a/build/drand.go b/build/drand.go index ef3f2c49826..73299249a33 100644 --- a/build/drand.go +++ b/build/drand.go @@ -1,15 +1,26 @@ package build -import "github.com/filecoin-project/lotus/node/modules/dtypes" +import ( + "sort" -var DrandNetwork = DrandIncentinet - -func DrandConfig() dtypes.DrandConfig { - return DrandConfigs[DrandNetwork] -} + "github.com/filecoin-project/lotus/node/modules/dtypes" +) type DrandEnum int +func DrandConfigSchedule() dtypes.DrandSchedule { + out := dtypes.DrandSchedule{} + for start, config := range DrandSchedule { + out = append(out, dtypes.DrandPoint{Start: start, Config: DrandConfigs[config]}) + } + + sort.Slice(out, func(i, j int) bool { + return out[i].Start < out[j].Start + }) + + return out +} + const ( DrandMainnet DrandEnum = iota + 1 DrandTestnet diff --git a/build/params_2k.go b/build/params_2k.go index 12005f00525..0ef1d9b3407 100644 --- a/build/params_2k.go +++ b/build/params_2k.go @@ -3,13 +3,22 @@ package build import ( - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" ) +const UpgradeBreezeHeight = -1 +const BreezeGasTampingDuration = 0 + +const UpgradeSmokeHeight = -1 + +var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ + 0: DrandMainnet, +} + func init() { power.ConsensusMinerMinPower = big.NewInt(2048) miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ @@ -20,7 +29,7 @@ func init() { BuildType |= Build2k } -const BlockDelaySecs = uint64(4) +const BlockDelaySecs = uint64(30) const PropagationDelaySecs = uint64(1) diff --git a/build/params_shared_funcs.go b/build/params_shared_funcs.go index cdb8e70d37d..2c585271a6b 100644 --- a/build/params_shared_funcs.go +++ b/build/params_shared_funcs.go @@ -5,7 +5,7 @@ import ( "github.com/libp2p/go-libp2p-core/protocol" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/node/modules/dtypes" @@ -36,3 +36,11 @@ func MessagesTopic(netName dtypes.NetworkName) string { return "/fil/msgs/" + st func DhtProtocolName(netName dtypes.NetworkName) protocol.ID { return protocol.ID("/fil/kad/" + string(netName)) } + +func UseNewestNetwork() bool { + // TODO: Put these in a container we can iterate over + if UpgradeBreezeHeight <= 0 && UpgradeSmokeHeight <= 0 { + return true + } + return false +} diff --git a/build/params_shared_vals.go b/build/params_shared_vals.go index 2fce61ee76e..4a46b7fd114 100644 --- a/build/params_shared_vals.go +++ b/build/params_shared_vals.go @@ -5,7 +5,9 @@ package build import ( "math/big" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/network" + + "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" ) @@ -20,6 +22,7 @@ const UnixfsLinksPerLevel = 1024 // Consensus / Network const AllowableClockDriftSecs = uint64(1) +const NewestNetworkVersion = network.Version2 // Epochs const ForkLengthThreshold = Finality diff --git a/build/params_testground.go b/build/params_testground.go index bdd56fbb18e..395d2a855e7 100644 --- a/build/params_testground.go +++ b/build/params_testground.go @@ -10,7 +10,8 @@ package build import ( "math/big" - "github.com/filecoin-project/specs-actors/actors/abi" + "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" ) @@ -69,4 +70,15 @@ var ( PackingEfficiencyNum int64 = 4 PackingEfficiencyDenom int64 = 5 + + UpgradeBreezeHeight abi.ChainEpoch = -1 + BreezeGasTampingDuration abi.ChainEpoch = 0 + + UpgradeSmokeHeight abi.ChainEpoch = -1 + + DrandSchedule = map[abi.ChainEpoch]DrandEnum{ + 0: DrandMainnet, + } + + NewestNetworkVersion = network.Version2 ) diff --git a/build/params_testnet.go b/build/params_testnet.go index f422b3861e8..932ad7a7d17 100644 --- a/build/params_testnet.go +++ b/build/params_testnet.go @@ -5,13 +5,23 @@ package build import ( - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" ) +var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ + 0: DrandIncentinet, + UpgradeSmokeHeight: DrandMainnet, +} + +const UpgradeBreezeHeight = 41280 +const BreezeGasTampingDuration = 120 + +const UpgradeSmokeHeight = 51000 + func init() { power.ConsensusMinerMinPower = big.NewInt(10 << 40) miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ diff --git a/build/version.go b/build/version.go index a3c5d155230..2466d80234a 100644 --- a/build/version.go +++ b/build/version.go @@ -1,6 +1,10 @@ package build -import "fmt" +import ( + "fmt" + + "golang.org/x/xerrors" +) var CurrentCommit string var BuildType int @@ -25,7 +29,7 @@ func buildType() string { } // BuildVersion is the local build version, set by build system -const BuildVersion = "0.5.10" +const BuildVersion = "0.7.0" func UserVersion() string { return BuildVersion + buildType() + CurrentCommit @@ -52,8 +56,37 @@ func (ve Version) EqMajorMinor(v2 Version) bool { return ve&minorMask == v2&minorMask } -// APIVersion is a semver version of the rpc api exposed -var APIVersion Version = newVer(0, 14, 0) +type NodeType int + +const ( + NodeUnknown NodeType = iota + + NodeFull + NodeMiner + NodeWorker +) + +var RunningNodeType NodeType + +func VersionForType(nodeType NodeType) (Version, error) { + switch nodeType { + case NodeFull: + return FullAPIVersion, nil + case NodeMiner: + return MinerAPIVersion, nil + case NodeWorker: + return WorkerAPIVersion, nil + default: + return Version(0), xerrors.Errorf("unknown node type %d", nodeType) + } +} + +// semver versions of the rpc api exposed +var ( + FullAPIVersion = newVer(0, 14, 0) + MinerAPIVersion = newVer(0, 14, 0) + WorkerAPIVersion = newVer(0, 14, 0) +) //nolint:varcheck,deadcode const ( diff --git a/chain/actors/aerrors/error.go b/chain/actors/aerrors/error.go index e687982c8c9..12f802c8fcd 100644 --- a/chain/actors/aerrors/error.go +++ b/chain/actors/aerrors/error.go @@ -3,7 +3,7 @@ package aerrors import ( "fmt" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/filecoin-project/go-state-types/exitcode" "golang.org/x/xerrors" ) diff --git a/chain/actors/aerrors/error_test.go b/chain/actors/aerrors/error_test.go index 4d87ac396ed..3bfd3d042f5 100644 --- a/chain/actors/aerrors/error_test.go +++ b/chain/actors/aerrors/error_test.go @@ -3,8 +3,8 @@ package aerrors_test import ( "testing" + "github.com/filecoin-project/go-state-types/exitcode" . "github.com/filecoin-project/lotus/chain/actors/aerrors" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/stretchr/testify/assert" "golang.org/x/xerrors" diff --git a/chain/actors/aerrors/wrap.go b/chain/actors/aerrors/wrap.go index 338659966a1..0552829f91d 100644 --- a/chain/actors/aerrors/wrap.go +++ b/chain/actors/aerrors/wrap.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/filecoin-project/go-state-types/exitcode" cbor "github.com/ipfs/go-ipld-cbor" "golang.org/x/xerrors" ) diff --git a/chain/badtscache.go b/chain/badtscache.go index 10323730788..3c5bf05ef11 100644 --- a/chain/badtscache.go +++ b/chain/badtscache.go @@ -56,6 +56,10 @@ func (bts *BadBlockCache) Add(c cid.Cid, bbr BadBlockReason) { bts.badBlocks.Add(c, bbr) } +func (bts *BadBlockCache) Remove(c cid.Cid) { + bts.badBlocks.Remove(c) +} + func (bts *BadBlockCache) Has(c cid.Cid) (BadBlockReason, bool) { rval, ok := bts.badBlocks.Get(c) if !ok { diff --git a/chain/beacon/beacon.go b/chain/beacon/beacon.go index 23b062beabd..9543bec54b3 100644 --- a/chain/beacon/beacon.go +++ b/chain/beacon/beacon.go @@ -3,7 +3,7 @@ package beacon import ( "context" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" logging "github.com/ipfs/go-log" "golang.org/x/xerrors" @@ -18,6 +18,23 @@ type Response struct { Err error } +type Schedule []BeaconPoint + +func (bs Schedule) BeaconForEpoch(e abi.ChainEpoch) RandomBeacon { + for i := len(bs) - 1; i >= 0; i-- { + bp := bs[i] + if e >= bp.Start { + return bp.Beacon + } + } + return bs[0].Beacon +} + +type BeaconPoint struct { + Start abi.ChainEpoch + Beacon RandomBeacon +} + // RandomBeacon represents a system that provides randomness to Lotus. // Other components interrogate the RandomBeacon to acquire randomness that's // valid for a specific chain epoch. Also to verify beacon entries that have @@ -25,11 +42,30 @@ type Response struct { type RandomBeacon interface { Entry(context.Context, uint64) <-chan Response VerifyEntry(types.BeaconEntry, types.BeaconEntry) error - MaxBeaconRoundForEpoch(abi.ChainEpoch, types.BeaconEntry) uint64 + MaxBeaconRoundForEpoch(abi.ChainEpoch) uint64 } -func ValidateBlockValues(b RandomBeacon, h *types.BlockHeader, prevEntry types.BeaconEntry) error { - maxRound := b.MaxBeaconRoundForEpoch(h.Height, prevEntry) +func ValidateBlockValues(bSchedule Schedule, h *types.BlockHeader, parentEpoch abi.ChainEpoch, + prevEntry types.BeaconEntry) error { + { + parentBeacon := bSchedule.BeaconForEpoch(parentEpoch) + currBeacon := bSchedule.BeaconForEpoch(h.Height) + if parentBeacon != currBeacon { + if len(h.BeaconEntries) != 2 { + return xerrors.Errorf("expected two beacon entries at beacon fork, got %d", len(h.BeaconEntries)) + } + err := currBeacon.VerifyEntry(h.BeaconEntries[1], h.BeaconEntries[0]) + if err != nil { + return xerrors.Errorf("beacon at fork point invalid: (%v, %v): %w", + h.BeaconEntries[1], h.BeaconEntries[0], err) + } + return nil + } + } + + // TODO: fork logic + b := bSchedule.BeaconForEpoch(h.Height) + maxRound := b.MaxBeaconRoundForEpoch(h.Height) if maxRound == prevEntry.Round { if len(h.BeaconEntries) != 0 { return xerrors.Errorf("expected not to have any beacon entries in this block, got %d", len(h.BeaconEntries)) @@ -56,10 +92,35 @@ func ValidateBlockValues(b RandomBeacon, h *types.BlockHeader, prevEntry types.B return nil } -func BeaconEntriesForBlock(ctx context.Context, beacon RandomBeacon, round abi.ChainEpoch, prev types.BeaconEntry) ([]types.BeaconEntry, error) { +func BeaconEntriesForBlock(ctx context.Context, bSchedule Schedule, epoch abi.ChainEpoch, parentEpoch abi.ChainEpoch, prev types.BeaconEntry) ([]types.BeaconEntry, error) { + { + parentBeacon := bSchedule.BeaconForEpoch(parentEpoch) + currBeacon := bSchedule.BeaconForEpoch(epoch) + if parentBeacon != currBeacon { + // Fork logic + round := currBeacon.MaxBeaconRoundForEpoch(epoch) + out := make([]types.BeaconEntry, 2) + rch := currBeacon.Entry(ctx, round-1) + res := <-rch + if res.Err != nil { + return nil, xerrors.Errorf("getting entry %d returned error: %w", round-1, res.Err) + } + out[0] = res.Entry + rch = currBeacon.Entry(ctx, round) + res = <-rch + if res.Err != nil { + return nil, xerrors.Errorf("getting entry %d returned error: %w", round, res.Err) + } + out[1] = res.Entry + return out, nil + } + } + + beacon := bSchedule.BeaconForEpoch(epoch) + start := build.Clock.Now() - maxRound := beacon.MaxBeaconRoundForEpoch(round, prev) + maxRound := beacon.MaxBeaconRoundForEpoch(epoch) if maxRound == prev.Round { return nil, nil } @@ -82,7 +143,7 @@ func BeaconEntriesForBlock(ctx context.Context, beacon RandomBeacon, round abi.C out = append(out, resp.Entry) cur = resp.Entry.Round - 1 case <-ctx.Done(): - return nil, xerrors.Errorf("context timed out waiting on beacon entry to come back for round %d: %w", round, ctx.Err()) + return nil, xerrors.Errorf("context timed out waiting on beacon entry to come back for epoch %d: %w", epoch, ctx.Err()) } } diff --git a/chain/beacon/drand/drand.go b/chain/beacon/drand/drand.go index 76bf01493a2..6e8e83a207d 100644 --- a/chain/beacon/drand/drand.go +++ b/chain/beacon/drand/drand.go @@ -19,7 +19,7 @@ import ( logging "github.com/ipfs/go-log" pubsub "github.com/libp2p/go-libp2p-pubsub" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/beacon" @@ -187,7 +187,7 @@ func (db *DrandBeacon) VerifyEntry(curr types.BeaconEntry, prev types.BeaconEntr return err } -func (db *DrandBeacon) MaxBeaconRoundForEpoch(filEpoch abi.ChainEpoch, prevEntry types.BeaconEntry) uint64 { +func (db *DrandBeacon) MaxBeaconRoundForEpoch(filEpoch abi.ChainEpoch) uint64 { // TODO: sometimes the genesis time for filecoin is zero and this goes negative latestTs := ((uint64(filEpoch) * db.filRoundTime) + db.filGenTime) - db.filRoundTime dround := (latestTs - db.drandGenTime) / uint64(db.interval.Seconds()) diff --git a/chain/beacon/drand/drand_test.go b/chain/beacon/drand/drand_test.go index 8d7c1b2cc69..0cb9c2ba8fc 100644 --- a/chain/beacon/drand/drand_test.go +++ b/chain/beacon/drand/drand_test.go @@ -12,7 +12,7 @@ import ( ) func TestPrintGroupInfo(t *testing.T) { - server := build.DrandConfig().Servers[0] + server := build.DrandConfigs[build.DrandIncentinet].Servers[0] c, err := hclient.New(server, nil, nil) assert.NoError(t, err) cg := c.(interface { diff --git a/chain/beacon/mock.go b/chain/beacon/mock.go index dc45ae895f3..502ff2ba579 100644 --- a/chain/beacon/mock.go +++ b/chain/beacon/mock.go @@ -6,8 +6,8 @@ import ( "encoding/binary" "time" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/minio/blake2b-simd" "golang.org/x/xerrors" ) @@ -53,11 +53,7 @@ func (mb *mockBeacon) VerifyEntry(from types.BeaconEntry, to types.BeaconEntry) return nil } -func (mb *mockBeacon) IsEntryForEpoch(e types.BeaconEntry, epoch abi.ChainEpoch, nulls int) (bool, error) { - return int64(e.Round) <= int64(epoch) && int64(epoch)-int64(nulls) >= int64(e.Round), nil -} - -func (mb *mockBeacon) MaxBeaconRoundForEpoch(epoch abi.ChainEpoch, prevEntry types.BeaconEntry) uint64 { +func (mb *mockBeacon) MaxBeaconRoundForEpoch(epoch abi.ChainEpoch) uint64 { return uint64(epoch) } diff --git a/chain/checkpoint.go b/chain/checkpoint.go new file mode 100644 index 00000000000..8f99d73e43d --- /dev/null +++ b/chain/checkpoint.go @@ -0,0 +1,81 @@ +package chain + +import ( + "encoding/json" + + "github.com/filecoin-project/lotus/chain/types" + + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/ipfs/go-datastore" + "golang.org/x/xerrors" +) + +var CheckpointKey = datastore.NewKey("/chain/checks") + +func loadCheckpoint(ds dtypes.MetadataDS) (types.TipSetKey, error) { + haveChks, err := ds.Has(CheckpointKey) + if err != nil { + return types.EmptyTSK, err + } + + if !haveChks { + return types.EmptyTSK, nil + } + + tskBytes, err := ds.Get(CheckpointKey) + if err != nil { + return types.EmptyTSK, err + } + + var tsk types.TipSetKey + err = json.Unmarshal(tskBytes, &tsk) + if err != nil { + return types.EmptyTSK, err + } + + return tsk, err +} + +func (syncer *Syncer) SetCheckpoint(tsk types.TipSetKey) error { + if tsk == types.EmptyTSK { + return xerrors.Errorf("called with empty tsk") + } + + syncer.checkptLk.Lock() + defer syncer.checkptLk.Unlock() + + ts, err := syncer.ChainStore().LoadTipSet(tsk) + if err != nil { + return xerrors.Errorf("cannot find tipset: %w", err) + } + + hts := syncer.ChainStore().GetHeaviestTipSet() + anc, err := syncer.ChainStore().IsAncestorOf(ts, hts) + if err != nil { + return xerrors.Errorf("cannot determine whether checkpoint tipset is in main-chain: %w", err) + } + + if !hts.Equals(ts) && !anc { + return xerrors.Errorf("cannot mark tipset as checkpoint, since it isn't in the main-chain: %w", err) + } + + tskBytes, err := json.Marshal(tsk) + if err != nil { + return err + } + + err = syncer.ds.Put(CheckpointKey, tskBytes) + if err != nil { + return err + } + + syncer.checkpt = tsk + + return nil +} + +func (syncer *Syncer) GetCheckpoint() types.TipSetKey { + syncer.checkptLk.Lock() + defer syncer.checkptLk.Unlock() + return syncer.checkpt +} diff --git a/chain/events/events.go b/chain/events/events.go index 4550fc98a9b..e35e91366c3 100644 --- a/chain/events/events.go +++ b/chain/events/events.go @@ -5,7 +5,7 @@ import ( "sync" "time" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" "golang.org/x/xerrors" @@ -35,6 +35,7 @@ type eventAPI interface { ChainNotify(context.Context) (<-chan []*api.HeadChange, error) ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error) ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) + ChainHead(context.Context) (*types.TipSet, error) StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) ChainGetTipSet(context.Context, types.TipSetKey) (*types.TipSet, error) @@ -57,7 +58,7 @@ type Events struct { func NewEvents(ctx context.Context, api eventAPI) *Events { gcConfidence := 2 * build.ForkLengthThreshold - tsc := newTSCache(gcConfidence, api.ChainGetTipSetByHeight) + tsc := newTSCache(gcConfidence, api) e := &Events{ api: api, diff --git a/chain/events/events_called.go b/chain/events/events_called.go index 196034a9a52..7532060937d 100644 --- a/chain/events/events_called.go +++ b/chain/events/events_called.go @@ -5,7 +5,7 @@ import ( "math" "sync" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" "golang.org/x/xerrors" @@ -307,7 +307,10 @@ func (e *hcEvents) onHeadChanged(check CheckFunc, hnd EventHandler, rev RevertHa defer e.lk.Unlock() // Check if the event has already occurred - ts := e.tsc.best() + ts, err := e.tsc.best() + if err != nil { + return 0, xerrors.Errorf("error getting best tipset: %w", err) + } done, more, err := check(ts) if err != nil { return 0, xerrors.Errorf("called check error (h: %d): %w", ts.Height(), err) diff --git a/chain/events/events_height.go b/chain/events/events_height.go index b419f06d279..c8dd905d9b1 100644 --- a/chain/events/events_height.go +++ b/chain/events/events_height.go @@ -4,8 +4,9 @@ import ( "context" "sync" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "go.opencensus.io/trace" + "golang.org/x/xerrors" "github.com/filecoin-project/lotus/chain/types" ) @@ -150,8 +151,12 @@ func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error { func (e *heightEvents) ChainAt(hnd HeightHandler, rev RevertHandler, confidence int, h abi.ChainEpoch) error { e.lk.Lock() // Tricky locking, check your locks if you modify this function! - bestH := e.tsc.best().Height() + best, err := e.tsc.best() + if err != nil { + return xerrors.Errorf("error getting best tipset: %w", err) + } + bestH := best.Height() if bestH >= h+abi.ChainEpoch(confidence) { ts, err := e.tsc.getNonNull(h) if err != nil { @@ -170,7 +175,11 @@ func (e *heightEvents) ChainAt(hnd HeightHandler, rev RevertHandler, confidence } e.lk.Lock() - bestH = e.tsc.best().Height() + best, err = e.tsc.best() + if err != nil { + return xerrors.Errorf("error getting best tipset: %w", err) + } + bestH = best.Height() } defer e.lk.Unlock() diff --git a/chain/events/events_test.go b/chain/events/events_test.go index 1204e39389e..0e4fd34b213 100644 --- a/chain/events/events_test.go +++ b/chain/events/events_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" @@ -46,6 +46,10 @@ type fakeCS struct { sub func(rev, app []*types.TipSet) } +func (fcs *fakeCS) ChainHead(ctx context.Context) (*types.TipSet, error) { + panic("implement me") +} + func (fcs *fakeCS) ChainGetTipSet(ctx context.Context, key types.TipSetKey) (*types.TipSet, error) { return fcs.tipsets[key], nil } @@ -110,7 +114,11 @@ func (fcs *fakeCS) makeTs(t *testing.T, parents []cid.Cid, h abi.ChainEpoch, msg func (fcs *fakeCS) ChainNotify(context.Context) (<-chan []*api.HeadChange, error) { out := make(chan []*api.HeadChange, 1) - out <- []*api.HeadChange{{Type: store.HCCurrent, Val: fcs.tsc.best()}} + best, err := fcs.tsc.best() + if err != nil { + return nil, err + } + out <- []*api.HeadChange{{Type: store.HCCurrent, Val: best}} fcs.sub = func(rev, app []*types.TipSet) { notif := make([]*api.HeadChange, len(rev)+len(app)) @@ -174,7 +182,8 @@ func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid, nulls ...int) { / var revs []*types.TipSet for i := 0; i < rev; i++ { - ts := fcs.tsc.best() + ts, err := fcs.tsc.best() + require.NoError(fcs.t, err) if _, ok := nullm[int(ts.Height())]; !ok { revs = append(revs, ts) @@ -196,7 +205,9 @@ func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid, nulls ...int) { / continue } - ts := fcs.makeTs(fcs.t, fcs.tsc.best().Key().Cids(), fcs.h, mc) + best, err := fcs.tsc.best() + require.NoError(fcs.t, err) + ts := fcs.makeTs(fcs.t, best.Key().Cids(), fcs.h, mc) require.NoError(fcs.t, fcs.tsc.add(ts)) if hasMsgs { diff --git a/chain/events/state/predicates.go b/chain/events/state/predicates.go index 2019a38eb3a..b30e69b4846 100644 --- a/chain/events/state/predicates.go +++ b/chain/events/state/predicates.go @@ -5,8 +5,8 @@ import ( "context" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" diff --git a/chain/events/state/predicates_test.go b/chain/events/state/predicates_test.go index 944b7e61cb0..a1dccfadc41 100644 --- a/chain/events/state/predicates_test.go +++ b/chain/events/state/predicates_test.go @@ -13,11 +13,11 @@ import ( cbornode "github.com/ipfs/go-ipld-cbor" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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/crypto" "github.com/filecoin-project/specs-actors/actors/util/adt" tutils "github.com/filecoin-project/specs-actors/support/testing" diff --git a/chain/events/tscache.go b/chain/events/tscache.go index 3852c9930c0..d47c71480e3 100644 --- a/chain/events/tscache.go +++ b/chain/events/tscache.go @@ -3,13 +3,16 @@ package events import ( "context" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "golang.org/x/xerrors" "github.com/filecoin-project/lotus/chain/types" ) -type tsByHFunc func(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) +type tsCacheAPI interface { + ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) + ChainHead(context.Context) (*types.TipSet, error) +} // tipSetCache implements a simple ring-buffer cache to keep track of recent // tipsets @@ -18,10 +21,10 @@ type tipSetCache struct { start int len int - storage tsByHFunc + storage tsCacheAPI } -func newTSCache(cap abi.ChainEpoch, storage tsByHFunc) *tipSetCache { +func newTSCache(cap abi.ChainEpoch, storage tsCacheAPI) *tipSetCache { return &tipSetCache{ cache: make([]*types.TipSet, cap), start: 0, @@ -94,7 +97,7 @@ func (tsc *tipSetCache) getNonNull(height abi.ChainEpoch) (*types.TipSet, error) func (tsc *tipSetCache) get(height abi.ChainEpoch) (*types.TipSet, error) { if tsc.len == 0 { log.Warnf("tipSetCache.get: cache is empty, requesting from storage (h=%d)", height) - return tsc.storage(context.TODO(), height, types.EmptyTSK) + return tsc.storage.ChainGetTipSetByHeight(context.TODO(), height, types.EmptyTSK) } headH := tsc.cache[tsc.start].Height() @@ -114,14 +117,18 @@ func (tsc *tipSetCache) get(height abi.ChainEpoch) (*types.TipSet, error) { if height < tail.Height() { log.Warnf("tipSetCache.get: requested tipset not in cache, requesting from storage (h=%d; tail=%d)", height, tail.Height()) - return tsc.storage(context.TODO(), height, tail.Key()) + return tsc.storage.ChainGetTipSetByHeight(context.TODO(), height, tail.Key()) } return tsc.cache[normalModulo(tsc.start-int(headH-height), clen)], nil } -func (tsc *tipSetCache) best() *types.TipSet { - return tsc.cache[tsc.start] +func (tsc *tipSetCache) best() (*types.TipSet, error) { + best := tsc.cache[tsc.start] + if best == nil { + return tsc.storage.ChainHead(context.TODO()) + } + return best, nil } func normalModulo(n, m int) int { diff --git a/chain/events/tscache_test.go b/chain/events/tscache_test.go index 1278e58e9c2..ab6336f24b6 100644 --- a/chain/events/tscache_test.go +++ b/chain/events/tscache_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/stretchr/testify/require" "github.com/filecoin-project/go-address" @@ -13,10 +13,7 @@ import ( ) func TestTsCache(t *testing.T) { - tsc := newTSCache(50, func(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) { - t.Fatal("storage call") - return &types.TipSet{}, nil - }) + tsc := newTSCache(50, &tsCacheAPIFailOnStorageCall{t: t}) h := abi.ChainEpoch(75) @@ -43,7 +40,12 @@ func TestTsCache(t *testing.T) { for i := 0; i < 9000; i++ { if i%90 > 60 { - if err := tsc.revert(tsc.best()); err != nil { + best, err := tsc.best() + if err != nil { + t.Fatal(err, "; i:", i) + return + } + if err := tsc.revert(best); err != nil { t.Fatal(err, "; i:", i) return } @@ -55,11 +57,21 @@ func TestTsCache(t *testing.T) { } +type tsCacheAPIFailOnStorageCall struct { + t *testing.T +} + +func (tc *tsCacheAPIFailOnStorageCall) ChainGetTipSetByHeight(ctx context.Context, epoch abi.ChainEpoch, key types.TipSetKey) (*types.TipSet, error) { + tc.t.Fatal("storage call") + return &types.TipSet{}, nil +} +func (tc *tsCacheAPIFailOnStorageCall) ChainHead(ctx context.Context) (*types.TipSet, error) { + tc.t.Fatal("storage call") + return &types.TipSet{}, nil +} + func TestTsCacheNulls(t *testing.T) { - tsc := newTSCache(50, func(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) { - t.Fatal("storage call") - return &types.TipSet{}, nil - }) + tsc := newTSCache(50, &tsCacheAPIFailOnStorageCall{t: t}) h := abi.ChainEpoch(75) @@ -91,7 +103,9 @@ func TestTsCacheNulls(t *testing.T) { add() add() - require.Equal(t, h-1, tsc.best().Height()) + best, err := tsc.best() + require.NoError(t, err) + require.Equal(t, h-1, best.Height()) ts, err := tsc.get(h - 1) require.NoError(t, err) @@ -109,9 +123,17 @@ func TestTsCacheNulls(t *testing.T) { require.NoError(t, err) require.Equal(t, h-8, ts.Height()) - require.NoError(t, tsc.revert(tsc.best())) - require.NoError(t, tsc.revert(tsc.best())) - require.Equal(t, h-8, tsc.best().Height()) + best, err = tsc.best() + require.NoError(t, err) + require.NoError(t, tsc.revert(best)) + + best, err = tsc.best() + require.NoError(t, err) + require.NoError(t, tsc.revert(best)) + + best, err = tsc.best() + require.NoError(t, err) + require.Equal(t, h-8, best.Height()) h += 50 add() @@ -120,3 +142,27 @@ func TestTsCacheNulls(t *testing.T) { require.NoError(t, err) require.Equal(t, h-1, ts.Height()) } + +type tsCacheAPIStorageCallCounter struct { + t *testing.T + chainGetTipSetByHeight int + chainHead int +} + +func (tc *tsCacheAPIStorageCallCounter) ChainGetTipSetByHeight(ctx context.Context, epoch abi.ChainEpoch, key types.TipSetKey) (*types.TipSet, error) { + tc.chainGetTipSetByHeight++ + return &types.TipSet{}, nil +} +func (tc *tsCacheAPIStorageCallCounter) ChainHead(ctx context.Context) (*types.TipSet, error) { + tc.chainHead++ + return &types.TipSet{}, nil +} + +func TestTsCacheEmpty(t *testing.T) { + // Calling best on an empty cache should just call out to the chain API + callCounter := &tsCacheAPIStorageCallCounter{t: t} + tsc := newTSCache(50, callCounter) + _, err := tsc.best() + require.NoError(t, err) + require.Equal(t, 1, callCounter.chainHead) +} diff --git a/chain/blocksync/cbor_gen.go b/chain/exchange/cbor_gen.go similarity index 99% rename from chain/blocksync/cbor_gen.go rename to chain/exchange/cbor_gen.go index cd43f4a6462..dc91babe3c7 100644 --- a/chain/blocksync/cbor_gen.go +++ b/chain/exchange/cbor_gen.go @@ -1,6 +1,6 @@ // Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. -package blocksync +package exchange import ( "fmt" diff --git a/chain/blocksync/client.go b/chain/exchange/client.go similarity index 76% rename from chain/blocksync/client.go rename to chain/exchange/client.go index 38e1f6d2c2d..22f7a945742 100644 --- a/chain/blocksync/client.go +++ b/chain/exchange/client.go @@ -1,4 +1,4 @@ -package blocksync +package exchange import ( "bufio" @@ -7,13 +7,16 @@ import ( "math/rand" "time" - host "github.com/libp2p/go-libp2p-core/host" - inet "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" + "go.opencensus.io/trace" + "go.uber.org/fx" "golang.org/x/xerrors" cborutil "github.com/filecoin-project/go-cbor-util" + "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" @@ -21,11 +24,9 @@ import ( "github.com/filecoin-project/lotus/lib/peermgr" ) -// Protocol client. -// FIXME: Rename to just `Client`. Not done at the moment to avoid -// disrupting too much of the consumer code, should be done along -// https://github.com/filecoin-project/lotus/issues/2612. -type BlockSync struct { +// client implements exchange.Client, using the libp2p ChainExchange protocol +// as the fetching mechanism. +type client struct { // Connection manager used to contact the server. // FIXME: We should have a reduced interface here, initialized // just with our protocol ID, we shouldn't be able to open *any* @@ -35,13 +36,14 @@ type BlockSync struct { peerTracker *bsPeerTracker } -func NewClient( - host host.Host, - pmgr peermgr.MaybePeerMgr, -) *BlockSync { - return &BlockSync{ +var _ Client = (*client)(nil) + +// NewClient creates a new libp2p-based exchange.Client that uses the libp2p +// ChainExhange protocol as the fetching mechanism. +func NewClient(lc fx.Lifecycle, host host.Host, pmgr peermgr.MaybePeerMgr) Client { + return &client{ host: host, - peerTracker: newPeerTracker(pmgr.Mgr), + peerTracker: newPeerTracker(lc, host, pmgr.Mgr), } } @@ -62,11 +64,7 @@ func NewClient( // 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 (client *BlockSync) doRequest( - ctx context.Context, - req *Request, - singlePeer *peer.ID, -) (*validatedResponse, error) { +func (c *client) doRequest(ctx context.Context, req *Request, singlePeer *peer.ID) (*validatedResponse, error) { // Validate request. if req.Length == 0 { return nil, xerrors.Errorf("invalid request of length 0") @@ -86,7 +84,7 @@ func (client *BlockSync) doRequest( if singlePeer != nil { peers = []peer.ID{*singlePeer} } else { - peers = client.getShuffledPeers() + peers = c.getShuffledPeers() if len(peers) == 0 { return nil, xerrors.Errorf("no peers available") } @@ -107,9 +105,9 @@ func (client *BlockSync) doRequest( } // Send request, read response. - res, err := client.sendRequestToPeer(ctx, peer, req) + res, err := c.sendRequestToPeer(ctx, peer, req) if err != nil { - if !xerrors.Is(err, inet.ErrNoConn) { + if !xerrors.Is(err, network.ErrNoConn) { log.Warnf("could not connect to peer %s: %s", peer.String(), err) } @@ -117,15 +115,15 @@ func (client *BlockSync) doRequest( } // Process and validate response. - validRes, err := client.processResponse(req, res) + validRes, err := c.processResponse(req, res) if err != nil { log.Warnf("processing peer %s response failed: %s", peer.String(), err) continue } - client.peerTracker.logGlobalSuccess(build.Clock.Since(globalTime)) - client.host.ConnManager().TagPeer(peer, "bsync", SUCCESS_PEER_TAG_VALUE) + c.peerTracker.logGlobalSuccess(build.Clock.Since(globalTime)) + c.host.ConnManager().TagPeer(peer, "bsync", SuccessPeerTagValue) return validRes, nil } @@ -144,11 +142,8 @@ func (client *BlockSync) doRequest( // We are conflating in the single error returned both status and validation // errors. Peer penalization should happen here then, before returning, so // we can apply the correct penalties depending on the cause of the error. -func (client *BlockSync) processResponse( - req *Request, - res *Response, - // FIXME: Add the `peer` as argument once we implement penalties. -) (*validatedResponse, error) { +// FIXME: Add the `peer` as argument once we implement penalties. +func (c *client) processResponse(req *Request, res *Response) (*validatedResponse, error) { err := res.statusToError() if err != nil { return nil, xerrors.Errorf("status error: %s", err) @@ -246,16 +241,8 @@ func (client *BlockSync) processResponse( return validRes, nil } -// GetBlocks fetches count blocks from the network, from the provided tipset -// *backwards*, returning as many tipsets as count. -// -// {hint/usage}: This is used by the Syncer during normal chain syncing and when -// resolving forks. -func (client *BlockSync) GetBlocks( - ctx context.Context, - tsk types.TipSetKey, - count int, -) ([]*types.TipSet, error) { +// 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") defer span.End() if span.IsRecordingEvents() { @@ -271,7 +258,7 @@ func (client *BlockSync) GetBlocks( Options: Headers, } - validRes, err := client.doRequest(ctx, req, nil) + validRes, err := c.doRequest(ctx, req, nil) if err != nil { return nil, err } @@ -279,11 +266,8 @@ func (client *BlockSync) GetBlocks( return validRes.tipsets, nil } -func (client *BlockSync) GetFullTipSet( - ctx context.Context, - peer peer.ID, - tsk types.TipSetKey, -) (*store.FullTipSet, error) { +// GetFullTipSet implements Client.GetFullTipSet(). Refer to the godocs there. +func (c *client) GetFullTipSet(ctx context.Context, peer peer.ID, tsk types.TipSetKey) (*store.FullTipSet, error) { // TODO: round robin through these peers on error req := &Request{ @@ -292,7 +276,7 @@ func (client *BlockSync) GetFullTipSet( Options: Headers | Messages, } - validRes, err := client.doRequest(ctx, req, &peer) + validRes, err := c.doRequest(ctx, req, &peer) if err != nil { return nil, err } @@ -302,11 +286,8 @@ func (client *BlockSync) GetFullTipSet( // *one* tipset here, so it's safe to index directly. } -func (client *BlockSync) GetChainMessages( - ctx context.Context, - head *types.TipSet, - length uint64, -) ([]*CompactedMessages, error) { +// GetChainMessages implements Client.GetChainMessages(). Refer to the godocs there. +func (c *client) GetChainMessages(ctx context.Context, head *types.TipSet, length uint64) ([]*CompactedMessages, error) { ctx, span := trace.StartSpan(ctx, "GetChainMessages") if span.IsRecordingEvents() { span.AddAttributes( @@ -322,7 +303,7 @@ func (client *BlockSync) GetChainMessages( Options: Messages, } - validRes, err := client.doRequest(ctx, req, nil) + validRes, err := c.doRequest(ctx, req, nil) if err != nil { return nil, err } @@ -333,11 +314,7 @@ func (client *BlockSync) GetChainMessages( // Send a request to a peer. Write request in the stream and read the // response back. We do not do any processing of the request/response // here. -func (client *BlockSync) sendRequestToPeer( - ctx context.Context, - peer peer.ID, - req *Request, -) (_ *Response, err error) { +func (c *client) sendRequestToPeer(ctx context.Context, peer peer.ID, req *Request) (_ *Response, err error) { // Trace code. ctx, span := trace.StartSpan(ctx, "sendRequestToPeer") defer span.End() @@ -358,34 +335,33 @@ func (client *BlockSync) sendRequestToPeer( }() // -- TRACE -- - supported, err := client.host.Peerstore().SupportsProtocols(peer, BlockSyncProtocolID) + supported, err := c.host.Peerstore().SupportsProtocols(peer, BlockSyncProtocolID, ChainExchangeProtocolID) if err != nil { + c.RemovePeer(peer) return nil, xerrors.Errorf("failed to get protocols for peer: %w", err) } - if len(supported) == 0 || supported[0] != BlockSyncProtocolID { - return nil, xerrors.Errorf("peer %s does not support protocol %s", - peer, BlockSyncProtocolID) - // FIXME: `ProtoBook` should support a *single* protocol check that returns - // a bool instead of a list. + if len(supported) == 0 || (supported[0] != BlockSyncProtocolID && supported[0] != ChainExchangeProtocolID) { + return nil, xerrors.Errorf("peer %s does not support protocols %s", + peer, []string{BlockSyncProtocolID, ChainExchangeProtocolID}) } connectionStart := build.Clock.Now() // Open stream to peer. - stream, err := client.host.NewStream( - inet.WithNoDial(ctx, "should already have connection"), + stream, err := c.host.NewStream( + network.WithNoDial(ctx, "should already have connection"), peer, - BlockSyncProtocolID) + ChainExchangeProtocolID, BlockSyncProtocolID) if err != nil { - client.RemovePeer(peer) + c.RemovePeer(peer) return nil, xerrors.Errorf("failed to open stream to peer: %w", err) } // Write request. - _ = stream.SetWriteDeadline(time.Now().Add(WRITE_REQ_DEADLINE)) + _ = stream.SetWriteDeadline(time.Now().Add(WriteReqDeadline)) if err := cborutil.WriteCborRPC(stream, req); err != nil { _ = stream.SetWriteDeadline(time.Time{}) - client.peerTracker.logFailure(peer, build.Clock.Since(connectionStart)) + c.peerTracker.logFailure(peer, build.Clock.Since(connectionStart), req.Length) // FIXME: Should we also remove peer here? return nil, err } @@ -395,11 +371,11 @@ func (client *BlockSync) sendRequestToPeer( // Read response. var res Response err = cborutil.ReadCborRPC( - bufio.NewReader(incrt.New(stream, READ_RES_MIN_SPEED, READ_RES_DEADLINE)), + bufio.NewReader(incrt.New(stream, ReadResMinSpeed, ReadResDeadline)), &res) if err != nil { - client.peerTracker.logFailure(peer, build.Clock.Since(connectionStart)) - return nil, xerrors.Errorf("failed to read blocksync response: %w", err) + c.peerTracker.logFailure(peer, build.Clock.Since(connectionStart), req.Length) + return nil, xerrors.Errorf("failed to read chainxchg response: %w", err) } // FIXME: Move all this together at the top using a defer as done elsewhere. @@ -412,32 +388,34 @@ func (client *BlockSync) sendRequestToPeer( ) } - client.peerTracker.logSuccess(peer, build.Clock.Since(connectionStart)) + c.peerTracker.logSuccess(peer, build.Clock.Since(connectionStart), uint64(len(res.Chain))) // FIXME: We should really log a success only after we validate the response. // It might be a bit hard to do. return &res, nil } -func (client *BlockSync) AddPeer(p peer.ID) { - client.peerTracker.addPeer(p) +// AddPeer implements Client.AddPeer(). Refer to the godocs there. +func (c *client) AddPeer(p peer.ID) { + c.peerTracker.addPeer(p) } -func (client *BlockSync) RemovePeer(p peer.ID) { - client.peerTracker.removePeer(p) +// RemovePeer implements Client.RemovePeer(). Refer to the godocs there. +func (c *client) RemovePeer(p peer.ID) { + c.peerTracker.removePeer(p) } // getShuffledPeers returns a preference-sorted set of peers (by latency // and failure counting), shuffling the first few peers so we don't always // pick the same peer. // FIXME: Consider merging with `shufflePrefix()s`. -func (client *BlockSync) getShuffledPeers() []peer.ID { - peers := client.peerTracker.prefSortedPeers() +func (c *client) getShuffledPeers() []peer.ID { + peers := c.peerTracker.prefSortedPeers() shufflePrefix(peers) return peers } func shufflePrefix(peers []peer.ID) { - prefix := SHUFFLE_PEERS_PREFIX + prefix := ShufflePeersPrefix if len(peers) < prefix { prefix = len(peers) } diff --git a/chain/exchange/doc.go b/chain/exchange/doc.go new file mode 100644 index 00000000000..b20ee0c1fe2 --- /dev/null +++ b/chain/exchange/doc.go @@ -0,0 +1,19 @@ +// Package exchange contains the ChainExchange server and client components. +// +// ChainExchange is the basic chain synchronization protocol of Filecoin. +// ChainExchange is an RPC-oriented protocol, with a single operation to +// request blocks for now. +// +// A request contains a start anchor block (referred to with a CID), and a +// amount of blocks requested beyond the anchor (including the anchor itself). +// +// A client can also pass options, encoded as a 64-bit bitfield. Lotus supports +// two options at the moment: +// +// - include block contents +// - include block messages +// +// The response will include a status code, an optional message, and the +// response payload in case of success. The payload is a slice of serialized +// tipsets. +package exchange diff --git a/chain/exchange/interfaces.go b/chain/exchange/interfaces.go new file mode 100644 index 00000000000..79d8fd4b1e2 --- /dev/null +++ b/chain/exchange/interfaces.go @@ -0,0 +1,51 @@ +package exchange + +import ( + "context" + + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" +) + +// Server is the responder side of the ChainExchange protocol. It accepts +// requests from clients and services them by returning the requested +// chain data. +type Server interface { + // HandleStream is the protocol handler to be registered on a libp2p + // protocol router. + // + // In the current version of the protocol, streams are single-use. The + // server will read a single Request, and will respond with a single + // Response. It will dispose of the stream straight after. + HandleStream(stream network.Stream) +} + +// Client is the requesting side of the ChainExchange protocol. It acts as +// a proxy for other components to request chain data from peers. It is chiefly +// used by the Syncer. +type Client interface { + // GetBlocks fetches block headers from the network, from the provided + // tipset *backwards*, returning as many tipsets as the count parameter, + // 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) + + // GetFullTipSet fetches a full tipset from a given peer. If successful, + // the fetched object contains block headers and all messages in full form. + GetFullTipSet(ctx context.Context, peer peer.ID, tsk types.TipSetKey) (*store.FullTipSet, error) + + // AddPeer adds a peer to the pool of peers that the Client requests + // data from. + AddPeer(peer peer.ID) + + // RemovePeer removes a peer from the pool of peers that the Client + // requests data from. + RemovePeer(peer peer.ID) +} diff --git a/chain/blocksync/peer_tracker.go b/chain/exchange/peer_tracker.go similarity index 78% rename from chain/blocksync/peer_tracker.go rename to chain/exchange/peer_tracker.go index f1f6ede07ac..902baadcee0 100644 --- a/chain/blocksync/peer_tracker.go +++ b/chain/exchange/peer_tracker.go @@ -1,13 +1,16 @@ -package blocksync +package exchange // FIXME: This needs to be reviewed. import ( + "context" "sort" "sync" "time" + host "github.com/libp2p/go-libp2p-core/host" "github.com/libp2p/go-libp2p-core/peer" + "go.uber.org/fx" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/lib/peermgr" @@ -29,11 +32,30 @@ type bsPeerTracker struct { pmgr *peermgr.PeerMgr } -func newPeerTracker(pmgr *peermgr.PeerMgr) *bsPeerTracker { - return &bsPeerTracker{ +func newPeerTracker(lc fx.Lifecycle, h host.Host, pmgr *peermgr.PeerMgr) *bsPeerTracker { + bsPt := &bsPeerTracker{ peers: make(map[peer.ID]*peerStats), pmgr: pmgr, } + + sub, err := h.EventBus().Subscribe(new(peermgr.NewFilPeer)) + if err != nil { + panic(err) + } + + go func() { + for newPeer := range sub.Out() { + bsPt.addPeer(newPeer.(peermgr.NewFilPeer).Id) + } + }() + + lc.Append(fx.Hook{ + OnStop: func(ctx context.Context) error { + return sub.Close() + }, + }) + + return bsPt } func (bpt *bsPeerTracker) addPeer(p peer.ID) { @@ -72,16 +94,7 @@ func (bpt *bsPeerTracker) prefSortedPeers() []peer.ID { var costI, costJ float64 getPeerInitLat := func(p peer.ID) float64 { - var res float64 - if bpt.pmgr != nil { - if lat, ok := bpt.pmgr.GetPeerLatency(p); ok { - res = float64(lat) - } - } - if res == 0 { - res = float64(bpt.avgGlobalTime) - } - return res * newPeerMul + return float64(bpt.avgGlobalTime) * newPeerMul } if pi.successes+pi.failures > 0 { @@ -107,8 +120,8 @@ func (bpt *bsPeerTracker) prefSortedPeers() []peer.ID { const ( // xInvAlpha = (N+1)/2 - localInvAlpha = 5 // 86% of the value is the last 9 - globalInvAlpha = 20 // 86% of the value is the last 39 + localInvAlpha = 10 // 86% of the value is the last 19 + globalInvAlpha = 25 // 86% of the value is the last 49 ) func (bpt *bsPeerTracker) logGlobalSuccess(dur time.Duration) { @@ -133,7 +146,7 @@ func logTime(pi *peerStats, dur time.Duration) { } -func (bpt *bsPeerTracker) logSuccess(p peer.ID, dur time.Duration) { +func (bpt *bsPeerTracker) logSuccess(p peer.ID, dur time.Duration, reqSize uint64) { bpt.lk.Lock() defer bpt.lk.Unlock() @@ -145,10 +158,13 @@ func (bpt *bsPeerTracker) logSuccess(p peer.ID, dur time.Duration) { } pi.successes++ - logTime(pi, dur) + if reqSize == 0 { + reqSize = 1 + } + logTime(pi, dur/time.Duration(reqSize)) } -func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration) { +func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration, reqSize uint64) { bpt.lk.Lock() defer bpt.lk.Unlock() @@ -160,7 +176,10 @@ func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration) { } pi.failures++ - logTime(pi, dur) + if reqSize == 0 { + reqSize = 1 + } + logTime(pi, dur/time.Duration(reqSize)) } func (bpt *bsPeerTracker) removePeer(p peer.ID) { diff --git a/chain/blocksync/protocol.go b/chain/exchange/protocol.go similarity index 88% rename from chain/blocksync/protocol.go rename to chain/exchange/protocol.go index 6a2861b8069..ca4b6183662 100644 --- a/chain/blocksync/protocol.go +++ b/chain/exchange/protocol.go @@ -1,4 +1,4 @@ -package blocksync +package exchange import ( "time" @@ -13,9 +13,17 @@ import ( "github.com/filecoin-project/lotus/chain/types" ) -var log = logging.Logger("blocksync") +var log = logging.Logger("chainxchg") -const BlockSyncProtocolID = "/fil/sync/blk/0.0.1" +const ( + // BlockSyncProtocolID is the protocol ID of the former blocksync protocol. + // Deprecated. + BlockSyncProtocolID = "/fil/sync/blk/0.0.1" + + // ChainExchangeProtocolID is the protocol ID of the chain exchange + // protocol. + ChainExchangeProtocolID = "/fil/chain/xchg/0.0.1" +) // FIXME: Bumped from original 800 to this to accommodate `syncFork()` // use of `GetBlocks()`. It seems the expectation of that API is to @@ -25,14 +33,16 @@ const BlockSyncProtocolID = "/fil/sync/blk/0.0.1" // qualifier to avoid "const initializer [...] is not a constant" error.) var MaxRequestLength = uint64(build.ForkLengthThreshold) -// Extracted constants from the code. -// FIXME: Should be reviewed and confirmed. -const SUCCESS_PEER_TAG_VALUE = 25 -const WRITE_REQ_DEADLINE = 5 * time.Second -const READ_RES_DEADLINE = WRITE_REQ_DEADLINE -const READ_RES_MIN_SPEED = 50 << 10 -const SHUFFLE_PEERS_PREFIX = 5 -const WRITE_RES_DEADLINE = 60 * time.Second +const ( + // Extracted constants from the code. + // FIXME: Should be reviewed and confirmed. + SuccessPeerTagValue = 25 + WriteReqDeadline = 5 * time.Second + ReadResDeadline = WriteReqDeadline + ReadResMinSpeed = 50 << 10 + ShufflePeersPrefix = 5 + WriteResDeadline = 60 * time.Second +) // FIXME: Rename. Make private. type Request struct { @@ -117,7 +127,7 @@ func (res *Response) statusToError() error { case NotFound: return xerrors.Errorf("not found") case GoAway: - return xerrors.Errorf("not handling 'go away' blocksync responses yet") + return xerrors.Errorf("not handling 'go away' chainxchg responses yet") case InternalError: return xerrors.Errorf("block sync peer errored: %s", res.ErrorMessage) case BadRequest: diff --git a/chain/blocksync/server.go b/chain/exchange/server.go similarity index 73% rename from chain/blocksync/server.go rename to chain/exchange/server.go index ffdf79ad0cc..54e169b3f19 100644 --- a/chain/blocksync/server.go +++ b/chain/exchange/server.go @@ -1,4 +1,4 @@ -package blocksync +package exchange import ( "bufio" @@ -18,38 +18,25 @@ import ( inet "github.com/libp2p/go-libp2p-core/network" ) -// BlockSyncService is the component that services BlockSync requests from -// peers. -// -// BlockSync is the basic chain synchronization protocol of Filecoin. BlockSync -// is an RPC-oriented protocol, with a single operation to request blocks. -// -// A request contains a start anchor block (referred to with a CID), and a -// amount of blocks requested beyond the anchor (including the anchor itself). -// -// A client can also pass options, encoded as a 64-bit bitfield. Lotus supports -// two options at the moment: -// -// - include block contents -// - include block messages -// -// The response will include a status code, an optional message, and the -// response payload in case of success. The payload is a slice of serialized -// tipsets. -// FIXME: Rename to just `Server` (will be done later, see note on `BlockSync`). -type BlockSyncService struct { +// server implements exchange.Server. It services requests for the +// libp2p ChainExchange protocol. +type server struct { cs *store.ChainStore } -func NewBlockSyncService(cs *store.ChainStore) *BlockSyncService { - return &BlockSyncService{ +var _ Server = (*server)(nil) + +// NewServer creates a new libp2p-based exchange.Server. It services requests +// for the libp2p ChainExchange protocol. +func NewServer(cs *store.ChainStore) Server { + return &server{ cs: cs, } } -// Entry point of the service, handles `Request`s. -func (server *BlockSyncService) HandleStream(stream inet.Stream) { - ctx, span := trace.StartSpan(context.Background(), "blocksync.HandleStream") +// HandleStream implements Server.HandleStream. Refer to the godocs there. +func (s *server) HandleStream(stream inet.Stream) { + ctx, span := trace.StartSpan(context.Background(), "chainxchg.HandleStream") defer span.End() defer stream.Close() //nolint:errcheck @@ -62,13 +49,13 @@ func (server *BlockSyncService) HandleStream(stream inet.Stream) { log.Infow("block sync request", "start", req.Head, "len", req.Length) - resp, err := server.processRequest(ctx, &req) + resp, err := s.processRequest(ctx, &req) if err != nil { log.Warn("failed to process request: ", err) return } - _ = stream.SetDeadline(time.Now().Add(WRITE_RES_DEADLINE)) + _ = stream.SetDeadline(time.Now().Add(WriteResDeadline)) if err := cborutil.WriteCborRPC(stream, resp); err != nil { _ = stream.SetDeadline(time.Time{}) log.Warnw("failed to write back response for handle stream", @@ -80,10 +67,7 @@ func (server *BlockSyncService) HandleStream(stream inet.Stream) { // Validate and service the request. We return either a protocol // response or an internal error. -func (server *BlockSyncService) processRequest( - ctx context.Context, - req *Request, -) (*Response, error) { +func (s *server) processRequest(ctx context.Context, req *Request) (*Response, error) { validReq, errResponse := validateRequest(ctx, req) if errResponse != nil { // The request did not pass validation, return the response @@ -91,17 +75,14 @@ func (server *BlockSyncService) processRequest( return errResponse, nil } - return server.serviceRequest(ctx, validReq) + return s.serviceRequest(ctx, validReq) } // Validate request. We either return a `validatedRequest`, or an error // `Response` indicating why we can't process it. We do not return any // internal errors here, we just signal protocol ones. -func validateRequest( - ctx context.Context, - req *Request, -) (*validatedRequest, *Response) { - _, span := trace.StartSpan(ctx, "blocksync.ValidateRequest") +func validateRequest(ctx context.Context, req *Request) (*validatedRequest, *Response) { + _, span := trace.StartSpan(ctx, "chainxchg.ValidateRequest") defer span.End() validReq := validatedRequest{} @@ -147,14 +128,11 @@ func validateRequest( return &validReq, nil } -func (server *BlockSyncService) serviceRequest( - ctx context.Context, - req *validatedRequest, -) (*Response, error) { - _, span := trace.StartSpan(ctx, "blocksync.ServiceRequest") +func (s *server) serviceRequest(ctx context.Context, req *validatedRequest) (*Response, error) { + _, span := trace.StartSpan(ctx, "chainxchg.ServiceRequest") defer span.End() - chain, err := collectChainSegment(server.cs, req) + chain, err := collectChainSegment(s.cs, req) if err != nil { log.Warn("block sync request: collectChainSegment failed: ", err) return &Response{ @@ -174,10 +152,7 @@ func (server *BlockSyncService) serviceRequest( }, nil } -func collectChainSegment( - cs *store.ChainStore, - req *validatedRequest, -) ([]*BSTipSet, error) { +func collectChainSegment(cs *store.ChainStore, req *validatedRequest) ([]*BSTipSet, error) { var bstips []*BSTipSet cur := req.head diff --git a/chain/gen/gen.go b/chain/gen/gen.go index 551c3703fa3..d661411feee 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -8,11 +8,13 @@ import ( "sync/atomic" "time" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" - "github.com/filecoin-project/specs-actors/actors/crypto" block "github.com/ipfs/go-block-format" "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" @@ -46,7 +48,7 @@ const msgsPerBlock = 20 //nolint:deadcode,varcheck var log = logging.Logger("gen") -var ValidWpostForTesting = []abi.PoStProof{{ +var ValidWpostForTesting = []proof.PoStProof{{ ProofBytes: []byte("valid proof"), }} @@ -57,7 +59,7 @@ type ChainGen struct { cs *store.ChainStore - beacon beacon.RandomBeacon + beacon beacon.Schedule sm *stmgr.StateManager @@ -250,7 +252,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) { miners := []address.Address{maddr1, maddr2} - beac := beacon.NewMockBeacon(time.Second) + beac := beacon.Schedule{{Start: 0, Beacon: beacon.NewMockBeacon(time.Second)}} //beac, err := drand.NewDrandBeacon(tpl.Timestamp, build.BlockDelaySecs) //if err != nil { //return nil, xerrors.Errorf("creating drand beacon: %w", err) @@ -336,7 +338,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add prev := mbi.PrevBeaconEntry - entries, err := beacon.BeaconEntriesForBlock(ctx, cg.beacon, round, prev) + entries, err := beacon.BeaconEntriesForBlock(ctx, cg.beacon, round, pts.Height(), prev) if err != nil { return nil, nil, nil, xerrors.Errorf("get beacon entries for block: %w", err) } @@ -356,7 +358,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add return nil, nil, nil, xerrors.Errorf("failed to cbor marshal address: %w", err) } - if len(entries) == 0 { + if round > build.UpgradeSmokeHeight { buf.Write(pts.MinTicket().VRFProof) } @@ -457,7 +459,7 @@ func (cg *ChainGen) NextTipSetFromMinersWithMessages(base *types.TipSet, miners func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticket *types.Ticket, eticket *types.ElectionProof, bvals []types.BeaconEntry, height abi.ChainEpoch, - wpost []abi.PoStProof, msgs []*types.SignedMessage) (*types.FullBlock, error) { + wpost []proof.PoStProof, msgs []*types.SignedMessage) (*types.FullBlock, error) { var ts uint64 if cg.Timestamper != nil { @@ -557,7 +559,7 @@ type mca struct { w *wallet.Wallet sm *stmgr.StateManager pv ffiwrapper.Verifier - bcn beacon.RandomBeacon + bcn beacon.Schedule } func (mca mca) ChainGetRandomnessFromTickets(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) { @@ -588,7 +590,7 @@ func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*cr type WinningPoStProver interface { GenerateCandidates(context.Context, abi.PoStRandomness, uint64) ([]uint64, error) - ComputeProof(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]abi.PoStProof, error) + ComputeProof(context.Context, []proof.SectorInfo, abi.PoStRandomness) ([]proof.PoStProof, error) } type wppProvider struct{} @@ -597,7 +599,7 @@ func (wpp *wppProvider) GenerateCandidates(ctx context.Context, _ abi.PoStRandom return []uint64{0}, nil } -func (wpp *wppProvider) ComputeProof(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]abi.PoStProof, error) { +func (wpp *wppProvider) ComputeProof(context.Context, []proof.SectorInfo, abi.PoStRandomness) ([]proof.PoStProof, error) { return ValidWpostForTesting, nil } @@ -664,15 +666,15 @@ type genFakeVerifier struct{} var _ ffiwrapper.Verifier = (*genFakeVerifier)(nil) -func (m genFakeVerifier) VerifySeal(svi abi.SealVerifyInfo) (bool, error) { +func (m genFakeVerifier) VerifySeal(svi proof.SealVerifyInfo) (bool, error) { return true, nil } -func (m genFakeVerifier) VerifyWinningPoSt(ctx context.Context, info abi.WinningPoStVerifyInfo) (bool, error) { +func (m genFakeVerifier) VerifyWinningPoSt(ctx context.Context, info proof.WinningPoStVerifyInfo) (bool, error) { panic("not supported") } -func (m genFakeVerifier) VerifyWindowPoSt(ctx context.Context, info abi.WindowPoStVerifyInfo) (bool, error) { +func (m genFakeVerifier) VerifyWindowPoSt(ctx context.Context, info proof.WindowPoStVerifyInfo) (bool, error) { panic("not supported") } diff --git a/chain/gen/gen_test.go b/chain/gen/gen_test.go index 52766af7ad4..ebc28a990d6 100644 --- a/chain/gen/gen_test.go +++ b/chain/gen/gen_test.go @@ -3,8 +3,8 @@ package gen import ( "testing" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 05c7b12732b..0a9d58924e9 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -6,6 +6,8 @@ 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" @@ -14,13 +16,13 @@ import ( "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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/crypto" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/build" @@ -404,6 +406,10 @@ 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, @@ -411,6 +417,7 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci Bstore: cs.Blockstore(), Syscalls: mkFakedSigSyscalls(cs.VMSys()), CircSupplyCalc: nil, + NtwkVersion: nwv, BaseFee: types.NewInt(0), } vm, err := vm.NewVM(&vmopt) diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index 1c3f717ad1c..b57608a5fb6 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -6,6 +6,10 @@ import ( "fmt" "math/rand" + "github.com/filecoin-project/lotus/build" + + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/lotus/chain/state" "github.com/ipfs/go-cid" @@ -14,15 +18,15 @@ 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/big" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/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" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/runtime" "github.com/filecoin-project/lotus/chain/store" @@ -61,6 +65,10 @@ 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, @@ -68,6 +76,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid Bstore: cs.Blockstore(), Syscalls: mkFakedSigSyscalls(cs.VMSys()), CircSupplyCalc: csc, + NtwkVersion: nwv, BaseFee: types.NewInt(0), } diff --git a/chain/gen/genesis/t02_reward.go b/chain/gen/genesis/t02_reward.go index 2f5922fd3c2..d499b24d085 100644 --- a/chain/gen/genesis/t02_reward.go +++ b/chain/gen/genesis/t02_reward.go @@ -3,7 +3,7 @@ package genesis import ( "context" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" diff --git a/chain/gen/genesis/util.go b/chain/gen/genesis/util.go index 10081c76355..67a4e9579a7 100644 --- a/chain/gen/genesis/util.go +++ b/chain/gen/genesis/util.go @@ -4,7 +4,7 @@ import ( "context" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" diff --git a/chain/gen/mining.go b/chain/gen/mining.go index 260c96808ea..dd867da48e1 100644 --- a/chain/gen/mining.go +++ b/chain/gen/mining.go @@ -3,7 +3,7 @@ package gen import ( "context" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/util/adt" cid "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" diff --git a/chain/gen/slashfilter/slashfilter.go b/chain/gen/slashfilter/slashfilter.go index 0d194042130..fadd3dd27ec 100644 --- a/chain/gen/slashfilter/slashfilter.go +++ b/chain/gen/slashfilter/slashfilter.go @@ -9,8 +9,8 @@ import ( ds "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/namespace" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/abi" ) type SlashFilter struct { diff --git a/chain/market/fundmgr.go b/chain/market/fundmgr.go index f7eab7e0a56..edf73d9bd62 100644 --- a/chain/market/fundmgr.go +++ b/chain/market/fundmgr.go @@ -4,8 +4,8 @@ import ( "context" "sync" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "go.uber.org/fx" "github.com/filecoin-project/specs-actors/actors/builtin" diff --git a/chain/market/fundmgr_test.go b/chain/market/fundmgr_test.go index 5e88005285e..c0e69c51c01 100644 --- a/chain/market/fundmgr_test.go +++ b/chain/market/fundmgr_test.go @@ -10,9 +10,9 @@ import ( "github.com/stretchr/testify/require" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/crypto" tutils "github.com/filecoin-project/specs-actors/support/testing" "github.com/filecoin-project/lotus/api" diff --git a/chain/messagepool/gasguess/guessgas.go b/chain/messagepool/gasguess/guessgas.go index a787b905392..af58db7d26c 100644 --- a/chain/messagepool/gasguess/guessgas.go +++ b/chain/messagepool/gasguess/guessgas.go @@ -9,7 +9,7 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin" ) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index e6238aab1af..f6799be737b 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -11,8 +11,9 @@ import ( "sync" "time" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "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/hashicorp/go-multierror" lru "github.com/hashicorp/golang-lru" "github.com/ipfs/go-cid" @@ -47,9 +48,10 @@ var rbfDenomBig = types.NewInt(RbfDenom) const RbfDenom = 256 -var RepublishInterval = pubsub.TimeCacheDuration + time.Duration(5*build.BlockDelaySecs+build.PropagationDelaySecs)*time.Second +var RepublishInterval = time.Duration(10*build.BlockDelaySecs+build.PropagationDelaySecs) * time.Second var minimumBaseFee = types.NewInt(uint64(build.MinimumBaseFee)) +var baseFeeLowerBoundFactor = types.NewInt(10) var MaxActorPendingMessages = 1000 @@ -102,6 +104,18 @@ type MessagePoolEvtMessage struct { CID cid.Cid } +// this is *temporary* mutilation until we have implemented uncapped miner penalties -- it will go +// away in the next fork. +var strictBaseFeeValidation = false + +func init() { + // if the republish interval is too short compared to the pubsub timecache, adjust it + minInterval := pubsub.TimeCacheDuration + time.Duration(build.PropagationDelaySecs) + if RepublishInterval < minInterval { + RepublishInterval = minInterval + } +} + type MessagePool struct { lk sync.Mutex @@ -165,6 +179,27 @@ func newMsgSet(nonce uint64) *msgSet { } } +func ComputeMinRBF(curPrem abi.TokenAmount) abi.TokenAmount { + minPrice := types.BigAdd(curPrem, types.BigDiv(types.BigMul(curPrem, rbfNumBig), rbfDenomBig)) + return types.BigAdd(minPrice, types.NewInt(1)) +} + +func CapGasFee(msg *types.Message, maxFee abi.TokenAmount) { + if maxFee.Equals(big.Zero()) { + maxFee = types.NewInt(build.FilecoinPrecision / 10) + } + + gl := types.NewInt(uint64(msg.GasLimit)) + totalFee := types.BigMul(msg.GasFeeCap, gl) + + if totalFee.LessThanEqual(maxFee) { + return + } + + msg.GasFeeCap = big.Div(maxFee, gl) + msg.GasPremium = big.Min(msg.GasFeeCap, msg.GasPremium) // cap premium at FeeCap +} + func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict bool) (bool, error) { nextNonce := ms.nextNonce nonceGap := false @@ -192,9 +227,7 @@ func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict bool) (boo if m.Cid() != exms.Cid() { // check if RBF passes - minPrice := exms.Message.GasPremium - minPrice = types.BigAdd(minPrice, types.BigDiv(types.BigMul(minPrice, rbfNumBig), rbfDenomBig)) - minPrice = types.BigAdd(minPrice, types.NewInt(1)) + minPrice := ComputeMinRBF(exms.Message.GasPremium) if types.BigCmp(m.Message.GasPremium, minPrice) >= 0 { log.Infow("add with RBF", "oldpremium", exms.Message.GasPremium, "newpremium", m.Message.GasPremium, "addr", m.Message.From, "nonce", m.Message.Nonce) @@ -385,13 +418,48 @@ func (mp *MessagePool) addLocal(m *types.SignedMessage, msgb []byte) error { return nil } -func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, epoch abi.ChainEpoch) error { +// verifyMsgBeforeAdd verifies that the message meets the minimum criteria for block inclusio +// and whether the message has enough funds to be included in the next 20 blocks. +// If the message is not valid for block inclusion, it returns an error. +// For local messages, if the message can be included in the next 20 blocks, it returns true to +// signal that it should be immediately published. If the message cannot be included in the next 20 +// blocks, it returns false so that the message doesn't immediately get published (and ignored by our +// peers); instead it will be published through the republish loop, once the base fee has fallen +// sufficiently. +// For non local messages, if the message cannot be included in the next 20 blocks it returns +// a (soft) validation error. +func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.TipSet, local bool) (bool, error) { + epoch := curTs.Height() minGas := vm.PricelistByEpoch(epoch).OnChainMessage(m.ChainLength()) if err := m.VMMessage().ValidForBlockInclusion(minGas.Total()); err != nil { - return xerrors.Errorf("message will not be included in a block: %w", err) + return false, xerrors.Errorf("message will not be included in a block: %w", err) + } + + // this checks if the GasFeeCap is suffisciently high for inclusion in the next 20 blocks + // if the GasFeeCap is too low, we soft reject the message (Ignore in pubsub) and rely + // on republish to push it through later, if the baseFee has fallen. + // this is a defensive check that stops minimum baseFee spam attacks from overloading validation + // queues. + // Note that for local messages, we always add them so that they can be accepted and republished + // automatically. + publish := local + if strictBaseFeeValidation && len(curTs.Blocks()) > 0 { + baseFee := curTs.Blocks()[0].ParentBaseFee + baseFeeLowerBound := getBaseFeeLowerBound(baseFee) + if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) { + if local { + log.Warnf("local message will not be immediately published because GasFeeCap doesn't meet the lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s)", + m.Message.GasFeeCap, baseFeeLowerBound) + publish = false + } else { + return false, xerrors.Errorf("GasFeeCap doesn't meet base fee lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s): %w", + m.Message.GasFeeCap, baseFeeLowerBound, ErrSoftValidationFailure) + } + } } - return nil + + return publish, nil } func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) { @@ -412,7 +480,8 @@ func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) { } mp.curTsLk.Lock() - if err := mp.addTs(m, mp.curTs); err != nil { + publish, err := mp.addTs(m, mp.curTs, true) + if err != nil { mp.curTsLk.Unlock() return cid.Undef, err } @@ -425,7 +494,11 @@ func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) { } mp.lk.Unlock() - return m.Cid(), mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb) + if publish { + err = mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb) + } + + return m.Cid(), err } func (mp *MessagePool) checkMessage(m *types.SignedMessage) error { @@ -473,7 +546,9 @@ func (mp *MessagePool) Add(m *types.SignedMessage) error { mp.curTsLk.Lock() defer mp.curTsLk.Unlock() - return mp.addTs(m, mp.curTs) + + _, err = mp.addTs(m, mp.curTs, false) + return err } func sigCacheKey(m *types.SignedMessage) (string, error) { @@ -540,28 +615,29 @@ func (mp *MessagePool) checkBalance(m *types.SignedMessage, curTs *types.TipSet) return nil } -func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet) error { +func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet, local bool) (bool, error) { snonce, err := mp.getStateNonce(m.Message.From, curTs) if err != nil { - return xerrors.Errorf("failed to look up actor state nonce: %s: %w", err, ErrSoftValidationFailure) + return false, xerrors.Errorf("failed to look up actor state nonce: %s: %w", err, ErrSoftValidationFailure) } if snonce > m.Message.Nonce { - return xerrors.Errorf("minimum expected nonce is %d: %w", snonce, ErrNonceTooLow) + return false, xerrors.Errorf("minimum expected nonce is %d: %w", snonce, ErrNonceTooLow) } mp.lk.Lock() defer mp.lk.Unlock() - if err := mp.verifyMsgBeforeAdd(m, curTs.Height()); err != nil { - return err + publish, err := mp.verifyMsgBeforeAdd(m, curTs, local) + if err != nil { + return false, err } if err := mp.checkBalance(m, curTs); err != nil { - return err + return false, err } - return mp.addLocked(m, true) + return publish, mp.addLocked(m, !local) } func (mp *MessagePool) addLoaded(m *types.SignedMessage) error { @@ -587,7 +663,8 @@ func (mp *MessagePool) addLoaded(m *types.SignedMessage) error { mp.lk.Lock() defer mp.lk.Unlock() - if err := mp.verifyMsgBeforeAdd(m, curTs.Height()); err != nil { + _, err = mp.verifyMsgBeforeAdd(m, curTs, true) + if err != nil { return err } @@ -634,7 +711,7 @@ func (mp *MessagePool) addLocked(m *types.SignedMessage, strict bool) error { incr, err := mset.add(m, mp, strict) if err != nil { - log.Info(err) + log.Debug(err) return err } @@ -781,7 +858,8 @@ func (mp *MessagePool) PushWithNonce(ctx context.Context, addr address.Address, return nil, ErrTryAgain } - if err := mp.verifyMsgBeforeAdd(msg, curTs.Height()); err != nil { + publish, err := mp.verifyMsgBeforeAdd(msg, curTs, true) + if err != nil { return nil, err } @@ -789,14 +867,18 @@ func (mp *MessagePool) PushWithNonce(ctx context.Context, addr address.Address, return nil, err } - if err := mp.addLocked(msg, true); err != nil { + if err := mp.addLocked(msg, false); err != nil { return nil, xerrors.Errorf("add locked failed: %w", err) } if err := mp.addLocal(msg, msgb); err != nil { log.Errorf("addLocal failed: %+v", err) } - return msg, mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb) + if publish { + err = mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb) + } + + return msg, err } func (mp *MessagePool) Remove(from address.Address, nonce uint64, applied bool) { @@ -1261,3 +1343,12 @@ func (mp *MessagePool) Clear(local bool) { delete(mp.pending, a) } } + +func getBaseFeeLowerBound(baseFee types.BigInt) types.BigInt { + baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor) + if baseFeeLowerBound.LessThan(minimumBaseFee) { + baseFeeLowerBound = minimumBaseFee + } + + return baseFeeLowerBound +} diff --git a/chain/messagepool/messagepool_test.go b/chain/messagepool/messagepool_test.go index 484c72746fa..a4aa059ca1d 100644 --- a/chain/messagepool/messagepool_test.go +++ b/chain/messagepool/messagepool_test.go @@ -7,6 +7,8 @@ import ( "testing" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/messagepool/gasguess" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/mock" @@ -14,7 +16,6 @@ import ( _ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/secp" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" logging "github.com/ipfs/go-log/v2" @@ -34,6 +35,8 @@ type testMpoolAPI struct { tipsets []*types.TipSet published int + + baseFee types.BigInt } func newTestMpoolAPI() *testMpoolAPI { @@ -41,6 +44,7 @@ func newTestMpoolAPI() *testMpoolAPI { bmsgs: make(map[cid.Cid][]*types.SignedMessage), statenonce: make(map[address.Address]uint64), balance: make(map[address.Address]types.BigInt), + baseFee: types.NewInt(100), } genesis := mock.MkBlock(nil, 1, 1) tma.tipsets = append(tma.tipsets, mock.TipSet(genesis)) @@ -53,6 +57,13 @@ func (tma *testMpoolAPI) nextBlock() *types.BlockHeader { return newBlk } +func (tma *testMpoolAPI) nextBlockWithHeight(height uint64) *types.BlockHeader { + newBlk := mock.MkBlock(tma.tipsets[len(tma.tipsets)-1], 1, 1) + newBlk.Height = abi.ChainEpoch(height) + tma.tipsets = append(tma.tipsets, mock.TipSet(newBlk)) + return newBlk +} + func (tma *testMpoolAPI) applyBlock(t *testing.T, b *types.BlockHeader) { t.Helper() if err := tma.cb(nil, []*types.TipSet{mock.TipSet(b)}); err != nil { @@ -182,7 +193,7 @@ func (tma *testMpoolAPI) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) } func (tma *testMpoolAPI) ChainComputeBaseFee(ctx context.Context, ts *types.TipSet) (types.BigInt, error) { - return types.NewInt(100), nil + return tma.baseFee, nil } func assertNonce(t *testing.T, mp *MessagePool, addr address.Address, val uint64) { diff --git a/chain/messagepool/pruning.go b/chain/messagepool/pruning.go index d1290e386f3..fd8199b8939 100644 --- a/chain/messagepool/pruning.go +++ b/chain/messagepool/pruning.go @@ -46,13 +46,21 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro if err != nil { return xerrors.Errorf("computing basefee: %w", err) } + baseFeeLowerBound := getBaseFeeLowerBound(baseFee) pending, _ := mp.getPendingMessages(ts, ts) - // priority actors -- not pruned - priority := make(map[address.Address]struct{}) + // protected actors -- not pruned + protected := make(map[address.Address]struct{}) + + // we never prune priority addresses for _, actor := range mp.cfg.PriorityAddrs { - priority[actor] = struct{}{} + protected[actor] = struct{}{} + } + + // we also never prune locally published messages + for actor := range mp.localAddrs { + protected[actor] = struct{}{} } // Collect all messages to track which ones to remove and create chains for block inclusion @@ -61,18 +69,18 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro var chains []*msgChain for actor, mset := range pending { - // we never prune priority actors - _, keep := priority[actor] + // we never prune protected actors + _, keep := protected[actor] if keep { keepCount += len(mset) continue } - // not a priority actor, track the messages and create chains + // not a protected actor, track the messages and create chains for _, m := range mset { pruneMsgs[m.Message.Cid()] = m } - actorChains := mp.createMessageChains(actor, mset, baseFee, ts) + actorChains := mp.createMessageChains(actor, mset, baseFeeLowerBound, ts) chains = append(chains, actorChains...) } diff --git a/chain/messagepool/repub.go b/chain/messagepool/repub.go index 1c26e94f04f..375360bce92 100644 --- a/chain/messagepool/repub.go +++ b/chain/messagepool/repub.go @@ -17,7 +17,7 @@ import ( const repubMsgLimit = 30 -var RepublishBatchDelay = 200 * time.Millisecond +var RepublishBatchDelay = 100 * time.Millisecond func (mp *MessagePool) republishPendingMessages() error { mp.curTsLk.Lock() @@ -28,6 +28,7 @@ func (mp *MessagePool) republishPendingMessages() error { mp.curTsLk.Unlock() return xerrors.Errorf("computing basefee: %w", err) } + baseFeeLowerBound := getBaseFeeLowerBound(baseFee) pending := make(map[address.Address]map[uint64]*types.SignedMessage) mp.lk.Lock() @@ -56,7 +57,11 @@ func (mp *MessagePool) republishPendingMessages() error { var chains []*msgChain for actor, mset := range pending { - next := mp.createMessageChains(actor, mset, baseFee, ts) + // We use the baseFee lower bound for createChange so that we optimistically include + // chains that might become profitable in the next 20 blocks. + // We still check the lowerBound condition for individual messages so that we don't send + // messages that will be rejected by the mpool spam protector, so this is safe to do. + next := mp.createMessageChains(actor, mset, baseFeeLowerBound, ts) chains = append(chains, next...) } @@ -68,15 +73,10 @@ func (mp *MessagePool) republishPendingMessages() error { return chains[i].Before(chains[j]) }) - // we don't republish negative performing chains; this is an error that will be screamed - // at the user - if chains[0].gasPerf < 0 { - return xerrors.Errorf("skipping republish: all message chains have negative gas performance; best gas performance: %f", chains[0].gasPerf) - } - gasLimit := int64(build.BlockGasLimit) minGas := int64(gasguess.MinGas) var msgs []*types.SignedMessage +loop: for i := 0; i < len(chains); { chain := chains[i] @@ -90,12 +90,6 @@ func (mp *MessagePool) republishPendingMessages() error { break } - // we don't republish negative performing chains, as they won't be included in - // a block anyway - if chain.gasPerf < 0 { - break - } - // has the chain been invalidated? if !chain.valid { i++ @@ -104,15 +98,25 @@ func (mp *MessagePool) republishPendingMessages() error { // does it fit in a block? if chain.gasLimit <= gasLimit { - gasLimit -= chain.gasLimit - msgs = append(msgs, chain.msgs...) + // check the baseFee lower bound -- only republish messages that can be included in the chain + // within the next 20 blocks. + for _, m := range chain.msgs { + if !allowNegativeChains(ts.Height()) && m.Message.GasFeeCap.LessThan(baseFeeLowerBound) { + chain.Invalidate() + continue loop + } + gasLimit -= m.Message.GasLimit + msgs = append(msgs, m) + } + + // we processed the whole chain, advance i++ continue } // we can't fit the current chain but there is gas to spare // trim it and push it down - chain.Trim(gasLimit, mp, baseFee, ts) + chain.Trim(gasLimit, mp, baseFee, true) for j := i; j < len(chains)-1; j++ { if chains[j].Before(chains[j+1]) { break diff --git a/chain/messagepool/repub_test.go b/chain/messagepool/repub_test.go index c89367f0e6c..491f484f5ae 100644 --- a/chain/messagepool/repub_test.go +++ b/chain/messagepool/repub_test.go @@ -4,10 +4,10 @@ import ( "testing" "time" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/messagepool/gasguess" "github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/ipfs/go-datastore" ) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 5ba679d761a..2ddbed0ad18 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -3,21 +3,29 @@ package messagepool import ( "context" "math/big" + "math/rand" "sort" "time" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + tbig "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/messagepool/gasguess" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" - abig "github.com/filecoin-project/specs-actors/actors/abi/big" ) var bigBlockGasLimit = big.NewInt(build.BlockGasLimit) +// this is *temporary* mutilation until we have implemented uncapped miner penalties -- it will go +// away in the next fork. +func allowNegativeChains(epoch abi.ChainEpoch) bool { + return epoch < build.UpgradeBreezeHeight+5 +} + const MaxBlocks = 15 type msgChain struct { @@ -100,9 +108,9 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64 return chains[i].Before(chains[j]) }) - if len(chains) != 0 && chains[0].gasPerf < 0 { + if !allowNegativeChains(curTs.Height()) && len(chains) != 0 && chains[0].gasPerf < 0 { log.Warnw("all messages in mpool have non-positive gas performance", "bestGasPerf", chains[0].gasPerf) - return nil, nil + return result, nil } // 3. Parition chains into blocks (without trimming) @@ -153,7 +161,7 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64 last := len(chains) for i, chain := range chains { // did we run out of performing chains? - if chain.gasPerf < 0 { + if !allowNegativeChains(curTs.Height()) && chain.gasPerf < 0 { break } @@ -191,9 +199,11 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64 gasLimit -= chainGasLimit // resort to account for already merged chains and effective performance adjustments - sort.Slice(chains[i+1:], func(i, j int) bool { + // the sort *must* be stable or we end up getting negative gasPerfs pushed up. + sort.SliceStable(chains[i+1:], func(i, j int) bool { return chains[i].BeforeEffective(chains[j]) }) + continue } @@ -217,7 +227,7 @@ tailLoop: for gasLimit >= minGas && last < len(chains) { // trim if necessary if chains[last].gasLimit > gasLimit { - chains[last].Trim(gasLimit, mp, baseFee, ts) + chains[last].Trim(gasLimit, mp, baseFee, allowNegativeChains(curTs.Height())) } // push down if it hasn't been invalidated @@ -243,7 +253,7 @@ tailLoop: } // if gasPerf < 0 we have no more profitable chains - if chain.gasPerf < 0 { + if !allowNegativeChains(curTs.Height()) && chain.gasPerf < 0 { break tailLoop } @@ -284,7 +294,7 @@ tailLoop: } // dependencies fit, just trim it - chain.Trim(gasLimit-depGasLimit, mp, baseFee, ts) + chain.Trim(gasLimit-depGasLimit, mp, baseFee, allowNegativeChains(curTs.Height())) last += i continue tailLoop } @@ -297,6 +307,79 @@ tailLoop: log.Infow("pack tail chains done", "took", dt) } + // if we have gasLimit to spare, pick some random (non-negative) chains to fill the block + // we pick randomly so that we minimize the probability of duplication among all miners + if gasLimit >= minGas { + randomCount := 0 + + startRandom := time.Now() + shuffleChains(chains) + + for _, chain := range chains { + // have we filled the block + if gasLimit < minGas { + break + } + + // has it been merged or invalidated? + if chain.merged || !chain.valid { + continue + } + + // is it negative? + if !allowNegativeChains(curTs.Height()) && chain.gasPerf < 0 { + continue + } + + // compute the dependencies that must be merged and the gas limit including deps + chainGasLimit := chain.gasLimit + depGasLimit := int64(0) + var chainDeps []*msgChain + for curChain := chain.prev; curChain != nil && !curChain.merged; curChain = curChain.prev { + chainDeps = append(chainDeps, curChain) + chainGasLimit += curChain.gasLimit + depGasLimit += curChain.gasLimit + } + + // do the deps fit? if the deps won't fit, invalidate the chain + if depGasLimit > gasLimit { + chain.Invalidate() + continue + } + + // do they fit as is? if it doesn't, trim to make it fit if possible + if chainGasLimit > gasLimit { + chain.Trim(gasLimit-depGasLimit, mp, baseFee, allowNegativeChains(curTs.Height())) + + if !chain.valid { + continue + } + } + + // include it together with all dependencies + for i := len(chainDeps) - 1; i >= 0; i-- { + curChain := chainDeps[i] + curChain.merged = true + result = append(result, curChain.msgs...) + randomCount += len(curChain.msgs) + } + + chain.merged = true + result = append(result, chain.msgs...) + randomCount += len(chain.msgs) + gasLimit -= chainGasLimit + } + + if dt := time.Since(startRandom); dt > time.Millisecond { + log.Infow("pack random tail chains done", "took", dt) + } + + if randomCount > 0 { + log.Warnf("optimal selection failed to pack a block; picked %d messages with random selection", + randomCount) + } + } + return result, nil } @@ -349,9 +432,9 @@ func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.S return chains[i].Before(chains[j]) }) - if len(chains) != 0 && chains[0].gasPerf < 0 { + if !allowNegativeChains(curTs.Height()) && len(chains) != 0 && chains[0].gasPerf < 0 { log.Warnw("all messages in mpool have non-positive gas performance", "bestGasPerf", chains[0].gasPerf) - return nil, nil + return result, nil } // 3. Merge the head chains to produce the list of messages selected for inclusion, subject to @@ -360,7 +443,7 @@ func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.S last := len(chains) for i, chain := range chains { // did we run out of performing chains? - if chain.gasPerf < 0 { + if !allowNegativeChains(curTs.Height()) && chain.gasPerf < 0 { break } @@ -389,7 +472,7 @@ func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.S tailLoop: for gasLimit >= minGas && last < len(chains) { // trim - chains[last].Trim(gasLimit, mp, baseFee, ts) + chains[last].Trim(gasLimit, mp, baseFee, allowNegativeChains(curTs.Height())) // push down if it hasn't been invalidated if chains[last].valid { @@ -409,7 +492,7 @@ tailLoop: } // if gasPerf < 0 we have no more profitable chains - if chain.gasPerf < 0 { + if !allowNegativeChains(curTs.Height()) && chain.gasPerf < 0 { break tailLoop } @@ -471,7 +554,7 @@ func (mp *MessagePool) selectPriorityMessages(pending map[address.Address]map[ui return chains[i].Before(chains[j]) }) - if len(chains) != 0 && chains[0].gasPerf < 0 { + if !allowNegativeChains(ts.Height()) && len(chains) != 0 && chains[0].gasPerf < 0 { log.Warnw("all priority messages in mpool have negative gas performance", "bestGasPerf", chains[0].gasPerf) return nil, gasLimit } @@ -479,7 +562,7 @@ func (mp *MessagePool) selectPriorityMessages(pending map[address.Address]map[ui // 3. Merge chains until the block limit, as long as they have non-negative gas performance last := len(chains) for i, chain := range chains { - if chain.gasPerf < 0 { + if !allowNegativeChains(ts.Height()) && chain.gasPerf < 0 { break } @@ -497,7 +580,7 @@ func (mp *MessagePool) selectPriorityMessages(pending map[address.Address]map[ui tailLoop: for gasLimit >= minGas && last < len(chains) { // trim, discarding negative performing messages - chains[last].Trim(gasLimit, mp, baseFee, ts) + chains[last].Trim(gasLimit, mp, baseFee, allowNegativeChains(ts.Height())) // push down if it hasn't been invalidated if chains[last].valid { @@ -517,7 +600,7 @@ tailLoop: } // if gasPerf < 0 we have no more profitable chains - if chain.gasPerf < 0 { + if !allowNegativeChains(ts.Height()) && chain.gasPerf < 0 { break tailLoop } @@ -592,7 +675,7 @@ func (*MessagePool) getGasReward(msg *types.SignedMessage, baseFee types.BigInt) maxPremium = msg.Message.GasPremium } - gasReward := abig.Mul(maxPremium, types.NewInt(uint64(msg.Message.GasLimit))) + gasReward := tbig.Mul(maxPremium, types.NewInt(uint64(msg.Message.GasLimit))) return gasReward.Int } @@ -775,9 +858,9 @@ func (mc *msgChain) Before(other *msgChain) bool { (mc.gasPerf == other.gasPerf && mc.gasReward.Cmp(other.gasReward) > 0) } -func (mc *msgChain) Trim(gasLimit int64, mp *MessagePool, baseFee types.BigInt, ts *types.TipSet) { +func (mc *msgChain) Trim(gasLimit int64, mp *MessagePool, baseFee types.BigInt, allowNegative bool) { i := len(mc.msgs) - 1 - for i >= 0 && (mc.gasLimit > gasLimit || mc.gasPerf < 0) { + for i >= 0 && (mc.gasLimit > gasLimit || (!allowNegative && mc.gasPerf < 0)) { gasReward := mp.getGasReward(mc.msgs[i], baseFee) mc.gasReward = new(big.Int).Sub(mc.gasReward, gasReward) mc.gasLimit -= mc.msgs[i].Message.GasLimit @@ -841,7 +924,16 @@ func (mc *msgChain) SetNullEffectivePerf() { func (mc *msgChain) BeforeEffective(other *msgChain) bool { // move merged chains to the front so we can discard them earlier - return (mc.merged && !other.merged) || mc.effPerf > other.effPerf || + return (mc.merged && !other.merged) || + (mc.gasPerf >= 0 && other.gasPerf < 0) || + mc.effPerf > other.effPerf || (mc.effPerf == other.effPerf && mc.gasPerf > other.gasPerf) || (mc.effPerf == other.effPerf && mc.gasPerf == other.gasPerf && mc.gasReward.Cmp(other.gasReward) > 0) } + +func shuffleChains(lst []*msgChain) { + for i := range lst { + j := rand.Intn(i + 1) + lst[i], lst[j] = lst[j], lst[i] + } +} diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index a9ead3c0129..5e372fc85cd 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -1,21 +1,26 @@ package messagepool import ( + "compress/gzip" "context" + "encoding/json" "fmt" + "io" "math" "math/big" "math/rand" + "os" + "sort" "testing" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/messagepool/gasguess" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/mock" "github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" @@ -728,6 +733,102 @@ func TestPriorityMessageSelection2(t *testing.T) { } } +func TestPriorityMessageSelection3(t *testing.T) { + t.Skip("reenable after removing allow negative") + + mp, tma := makeTestMpool() + + // the actors + w1, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + if err != nil { + t.Fatal(err) + } + + w2, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + if err != nil { + t.Fatal(err) + } + + block := tma.nextBlock() + ts := mock.TipSet(block) + tma.applyBlock(t, block) + + gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin.StorageMarketActorCodeID, M: 2}] + + tma.setBalance(a1, 1) // in FIL + tma.setBalance(a2, 1) // in FIL + + mp.cfg.PriorityAddrs = []address.Address{a1} + + tma.baseFee = types.NewInt(1000) + nMessages := 10 + for i := 0; i < nMessages; i++ { + bias := (nMessages - i) / 3 + m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(1000+i%3+bias)) + mustAdd(t, mp, m) + // messages from a2 have negative performance + m = makeTestMessage(w2, a2, a1, uint64(i), gasLimit, 100) + mustAdd(t, mp, m) + } + + // test greedy selection + msgs, err := mp.SelectMessages(ts, 1.0) + if err != nil { + t.Fatal(err) + } + + expectedMsgs := 10 + if len(msgs) != expectedMsgs { + t.Fatalf("expected %d messages but got %d", expectedMsgs, len(msgs)) + } + + // all messages must be from a1 + nextNonce := uint64(0) + for _, m := range msgs { + if m.Message.From != a1 { + t.Fatal("expected messages from a1 before messages from a2") + } + if m.Message.Nonce != nextNonce { + t.Fatalf("expected nonce %d but got %d", nextNonce, m.Message.Nonce) + } + nextNonce++ + } + + // test optimal selection + msgs, err = mp.SelectMessages(ts, 0.1) + if err != nil { + t.Fatal(err) + } + + expectedMsgs = 10 + if len(msgs) != expectedMsgs { + t.Fatalf("expected %d messages but got %d", expectedMsgs, len(msgs)) + } + + // all messages must be from a1 + nextNonce = uint64(0) + for _, m := range msgs { + if m.Message.From != a1 { + t.Fatal("expected messages from a1 before messages from a2") + } + if m.Message.Nonce != nextNonce { + t.Fatalf("expected nonce %d but got %d", nextNonce, m.Message.Nonce) + } + nextNonce++ + } + +} + func TestOptimalMessageSelection1(t *testing.T) { // this test uses just a single actor sending messages with a low tq // the chain depenent merging algorithm should pick messages from the actor @@ -1185,3 +1286,177 @@ func TestGasReward(t *testing.T) { }) } } + +func TestRealWorldSelection(t *testing.T) { + // load test-messages.json.gz and rewrite the messages so that + // 1) we map each real actor to a test actor so that we can sign the messages + // 2) adjust the nonces so that they start from 0 + file, err := os.Open("test-messages.json.gz") + if err != nil { + t.Fatal(err) + } + + gzr, err := gzip.NewReader(file) + if err != nil { + t.Fatal(err) + } + + dec := json.NewDecoder(gzr) + + var msgs []*types.SignedMessage + baseNonces := make(map[address.Address]uint64) + +readLoop: + for { + m := new(types.SignedMessage) + err := dec.Decode(m) + switch err { + case nil: + msgs = append(msgs, m) + nonce, ok := baseNonces[m.Message.From] + if !ok || m.Message.Nonce < nonce { + baseNonces[m.Message.From] = m.Message.Nonce + } + + case io.EOF: + break readLoop + + default: + t.Fatal(err) + } + } + + actorMap := make(map[address.Address]address.Address) + actorWallets := make(map[address.Address]*wallet.Wallet) + + for _, m := range msgs { + baseNonce := baseNonces[m.Message.From] + + localActor, ok := actorMap[m.Message.From] + if !ok { + w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a, err := w.GenerateKey(crypto.SigTypeSecp256k1) + if err != nil { + t.Fatal(err) + } + + actorMap[m.Message.From] = a + actorWallets[a] = w + localActor = a + } + + w, ok := actorWallets[localActor] + if !ok { + t.Fatalf("failed to lookup wallet for actor %s", localActor) + } + + m.Message.From = localActor + m.Message.Nonce -= baseNonce + + sig, err := w.Sign(context.TODO(), localActor, m.Message.Cid().Bytes()) + if err != nil { + t.Fatal(err) + } + + m.Signature = *sig + } + + mp, tma := makeTestMpool() + + block := tma.nextBlockWithHeight(build.UpgradeBreezeHeight + 10) + ts := mock.TipSet(block) + tma.applyBlock(t, block) + + for _, a := range actorMap { + tma.setBalance(a, 1000000) + } + + tma.baseFee = types.NewInt(800_000_000) + + sort.Slice(msgs, func(i, j int) bool { + return msgs[i].Message.Nonce < msgs[j].Message.Nonce + }) + + // add the messages + for _, m := range msgs { + mustAdd(t, mp, m) + } + + // do message selection and check block packing + minGasLimit := int64(0.9 * float64(build.BlockGasLimit)) + + // greedy first + selected, err := mp.SelectMessages(ts, 1.0) + if err != nil { + t.Fatal(err) + } + + gasLimit := int64(0) + for _, m := range selected { + gasLimit += m.Message.GasLimit + } + if gasLimit < minGasLimit { + t.Fatalf("failed to pack with tq=1.0; packed %d, minimum packing: %d", gasLimit, minGasLimit) + } + + // high quality ticket + selected, err = mp.SelectMessages(ts, .8) + if err != nil { + t.Fatal(err) + } + + gasLimit = int64(0) + for _, m := range selected { + gasLimit += m.Message.GasLimit + } + if gasLimit < minGasLimit { + t.Fatalf("failed to pack with tq=0.8; packed %d, minimum packing: %d", gasLimit, minGasLimit) + } + + // mid quality ticket + selected, err = mp.SelectMessages(ts, .4) + if err != nil { + t.Fatal(err) + } + + gasLimit = int64(0) + for _, m := range selected { + gasLimit += m.Message.GasLimit + } + if gasLimit < minGasLimit { + t.Fatalf("failed to pack with tq=0.4; packed %d, minimum packing: %d", gasLimit, minGasLimit) + } + + // low quality ticket + selected, err = mp.SelectMessages(ts, .1) + if err != nil { + t.Fatal(err) + } + + gasLimit = int64(0) + for _, m := range selected { + gasLimit += m.Message.GasLimit + } + if gasLimit < minGasLimit { + t.Fatalf("failed to pack with tq=0.1; packed %d, minimum packing: %d", gasLimit, minGasLimit) + } + + // very low quality ticket + selected, err = mp.SelectMessages(ts, .01) + if err != nil { + t.Fatal(err) + } + + gasLimit = int64(0) + for _, m := range selected { + gasLimit += m.Message.GasLimit + } + if gasLimit < minGasLimit { + t.Fatalf("failed to pack with tq=0.01; packed %d, minimum packing: %d", gasLimit, minGasLimit) + } + +} diff --git a/chain/messagepool/test-messages.json.gz b/chain/messagepool/test-messages.json.gz new file mode 100644 index 00000000000..09481e1f88c Binary files /dev/null and b/chain/messagepool/test-messages.json.gz differ diff --git a/chain/metrics/consensus.go b/chain/metrics/consensus.go index 25e2992479d..c3c4a10d1b0 100644 --- a/chain/metrics/consensus.go +++ b/chain/metrics/consensus.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" pubsub "github.com/libp2p/go-libp2p-pubsub" diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index b21fb75f22e..4b83842b4d1 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -5,8 +5,8 @@ import ( "fmt" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/ipfs/go-cid" "go.opencensus.io/trace" "golang.org/x/xerrors" @@ -29,6 +29,7 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate Bstore: sm.cs.Blockstore(), Syscalls: sm.cs.VMSys(), CircSupplyCalc: sm.GetCirculatingSupply, + NtwkVersion: sm.GetNtwkVersion, BaseFee: types.NewInt(0), } @@ -130,6 +131,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri Bstore: sm.cs.Blockstore(), Syscalls: sm.cs.VMSys(), CircSupplyCalc: sm.GetCirculatingSupply, + NtwkVersion: sm.GetNtwkVersion, BaseFee: ts.Blocks()[0].ParentBaseFee, } vmi, err := vm.NewVM(vmopt) diff --git a/chain/stmgr/forks.go b/chain/stmgr/forks.go index c7c7526b33b..addaba90f92 100644 --- a/chain/stmgr/forks.go +++ b/chain/stmgr/forks.go @@ -3,16 +3,28 @@ package stmgr import ( "context" + "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/build" + "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/abi" + "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" ) -var ForksAtHeight = map[abi.ChainEpoch]func(context.Context, *StateManager, types.StateTree) error{} +var ForksAtHeight = map[abi.ChainEpoch]func(context.Context, *StateManager, types.StateTree, *types.TipSet) error{ + build.UpgradeBreezeHeight: UpgradeFaucetBurnRecovery, +} -func (sm *StateManager) handleStateForks(ctx context.Context, st types.StateTree, height abi.ChainEpoch) (err error) { +func (sm *StateManager) handleStateForks(ctx context.Context, st types.StateTree, height abi.ChainEpoch, ts *types.TipSet) (err error) { f, ok := ForksAtHeight[height] if ok { - err := f(ctx, sm, st) + err := f(ctx, sm, st, ts) if err != nil { return err } @@ -20,3 +32,291 @@ func (sm *StateManager) handleStateForks(ctx context.Context, st types.StateTree return nil } + +type forEachTree interface { + ForEach(func(address.Address, *types.Actor) error) error +} + +func doTransfer(tree types.StateTree, from, to address.Address, amt abi.TokenAmount) error { + fromAct, err := tree.GetActor(from) + if err != nil { + return xerrors.Errorf("failed to get 'from' actor for transfer: %w", err) + } + + fromAct.Balance = types.BigSub(fromAct.Balance, amt) + if fromAct.Balance.Sign() < 0 { + return xerrors.Errorf("(sanity) deducted more funds from target account than it had (%s, %s)", from, types.FIL(amt)) + } + + if err := tree.SetActor(from, fromAct); err != nil { + return xerrors.Errorf("failed to persist from actor: %w", err) + } + + toAct, err := tree.GetActor(to) + if err != nil { + return xerrors.Errorf("failed to get 'to' actor for transfer: %w", err) + } + + toAct.Balance = types.BigAdd(toAct.Balance, amt) + + if err := tree.SetActor(to, toAct); err != nil { + return xerrors.Errorf("failed to persist to actor: %w", err) + } + + return nil +} + +func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types.StateTree, ts *types.TipSet) error { + // Some initial parameters + FundsForMiners := types.FromFil(1_000_000) + LookbackEpoch := abi.ChainEpoch(32000) + AccountCap := types.FromFil(0) + BaseMinerBalance := types.FromFil(20) + DesiredReimbursementBalance := types.FromFil(5_000_000) + + isSystemAccount := func(addr address.Address) (bool, error) { + id, err := address.IDFromAddress(addr) + if err != nil { + return false, xerrors.Errorf("id address: %w", err) + } + + if id < 1000 { + return true, nil + } + return false, nil + } + + minerFundsAlloc := func(pow, tpow abi.StoragePower) abi.TokenAmount { + return types.BigDiv(types.BigMul(pow, FundsForMiners), tpow) + } + + // Grab lookback state for account checks + lbts, err := sm.ChainStore().GetTipsetByHeight(ctx, LookbackEpoch, ts, false) + if err != nil { + 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 { + return xerrors.Errorf("loading state tree failed: %w", err) + } + + ReserveAddress, err := address.NewFromString("t090") + if err != nil { + return xerrors.Errorf("failed to parse reserve address: %w", err) + } + + fetree, ok := tree.(forEachTree) + if !ok { + return xerrors.Errorf("fork transition state tree doesnt support ForEach (%T)", tree) + } + + type transfer struct { + From address.Address + To address.Address + Amt abi.TokenAmount + } + + var transfers []transfer + + // 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: + sysAcc, err := isSystemAccount(addr) + if err != nil { + return xerrors.Errorf("checking system account: %w", err) + } + + if !sysAcc { + transfers = append(transfers, transfer{ + From: addr, + To: ReserveAddress, + Amt: act.Balance, + }) + } + case builtin.StorageMinerActorCodeID: + var st miner.State + if err := sm.WithActorState(ctx, &st)(act); err != nil { + return xerrors.Errorf("failed to load miner state: %w", err) + } + + var available abi.TokenAmount + { + defer func() { + if err := recover(); err != nil { + log.Warnf("Get available balance failed (%s, %s, %s): %s", addr, act.Head, act.Balance, err) + } + available = abi.NewTokenAmount(0) + }() + // this panics if the miner doesnt have enough funds to cover their locked pledge + available = st.GetAvailableBalance(act.Balance) + } + + transfers = append(transfers, transfer{ + From: addr, + To: ReserveAddress, + Amt: available, + }) + } + return nil + }) + if err != nil { + return xerrors.Errorf("foreach over state tree failed: %w", err) + } + + // Execute transfers from previous step + for _, t := range transfers { + if err := doTransfer(tree, t.From, t.To, t.Amt); err != nil { + return xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err) + } + } + + // pull up power table to give miners back some funds proportional to their power + var ps power.State + powAct, err := tree.GetActor(builtin.StoragePowerActorAddr) + if err != nil { + return xerrors.Errorf("failed to load power actor: %w", err) + } + + cst := cbor.NewCborStore(sm.ChainStore().Blockstore()) + if err := cst.Get(ctx, powAct.Head, &ps); err != nil { + return xerrors.Errorf("failed to get power actor state: %w", err) + } + + totalPower := ps.TotalBytesCommitted + + var transfersBack []transfer + // Now, we return some funds to places where they are needed + err = fetree.ForEach(func(addr address.Address, act *types.Actor) error { + lbact, err := lbtree.GetActor(addr) + if err != nil { + if !xerrors.Is(err, types.ErrActorNotFound) { + return xerrors.Errorf("failed to get actor in lookback state") + } + } + + prevBalance := abi.NewTokenAmount(0) + if lbact != nil { + prevBalance = lbact.Balance + } + + switch act.Code { + case builtin.AccountActorCodeID, builtin.MultisigActorCodeID, builtin.PaymentChannelActorCodeID: + nbalance := big.Min(prevBalance, AccountCap) + if nbalance.Sign() != 0 { + transfersBack = append(transfersBack, transfer{ + From: ReserveAddress, + To: addr, + Amt: nbalance, + }) + } + case builtin.StorageMinerActorCodeID: + var st miner.State + if err := sm.WithActorState(ctx, &st)(act); err != nil { + return xerrors.Errorf("failed to load miner state: %w", err) + } + + var minfo miner.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) + if err != nil { + return xerrors.Errorf("failed to load sectors array: %w", err) + } + + slen := sectorsArr.Length() + + power := types.BigMul(types.NewInt(slen), types.NewInt(uint64(minfo.SectorSize))) + + mfunds := minerFundsAlloc(power, totalPower) + transfersBack = append(transfersBack, transfer{ + From: ReserveAddress, + To: minfo.Worker, + Amt: mfunds, + }) + + // 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 { + return xerrors.Errorf("failed to load miner state: %w", err) + } + + lbsectors, err := adt.AsArray(sm.ChainStore().Store(ctx), lbst.Sectors) + if err != nil { + return xerrors.Errorf("failed to load lb sectors array: %w", err) + } + + if lbsectors.Length() > 0 { + transfersBack = append(transfersBack, transfer{ + From: ReserveAddress, + To: minfo.Worker, + Amt: BaseMinerBalance, + }) + } + + } else { + log.Warnf("failed to get miner in lookback state: %s", err) + } + } + return nil + }) + if err != nil { + return xerrors.Errorf("foreach over state tree failed: %w", err) + } + + for _, t := range transfersBack { + if err := doTransfer(tree, t.From, t.To, t.Amt); err != nil { + return xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err) + } + } + + // transfer all burnt funds back to the reserve account + burntAct, err := tree.GetActor(builtin.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 { + return xerrors.Errorf("failed to unburn funds: %w", err) + } + + // Top up the reimbursement service + reimbAddr, err := address.NewFromString("t0111") + if err != nil { + return xerrors.Errorf("failed to parse reimbursement service address") + } + + reimb, err := tree.GetActor(reimbAddr) + if err != nil { + return xerrors.Errorf("failed to load reimbursement account actor: %w", err) + } + + difference := types.BigSub(DesiredReimbursementBalance, reimb.Balance) + if err := doTransfer(tree, ReserveAddress, reimbAddr, difference); err != nil { + return xerrors.Errorf("failed to top up reimbursement account: %w", err) + } + + // Now, a final sanity check to make sure the balances all check out + total := abi.NewTokenAmount(0) + err = fetree.ForEach(func(addr address.Address, act *types.Actor) error { + total = types.BigAdd(total, act.Balance) + return nil + }) + if err != nil { + return xerrors.Errorf("checking final state balance failed: %w", err) + } + + exp := types.FromFil(build.FilBase) + if !exp.Equals(total) { + return xerrors.Errorf("resultant state tree account balance was not correct: %s", total) + } + + return nil +} diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index caa63c879fb..e96d3f3161b 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -7,15 +7,14 @@ import ( "testing" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" - "github.com/filecoin-project/specs-actors/actors/util/adt" "golang.org/x/xerrors" "github.com/filecoin-project/lotus/chain/actors" @@ -73,15 +72,15 @@ func (ta *testActor) Exports() []interface{} { } } -func (ta *testActor) Constructor(rt runtime.Runtime, params *adt.EmptyValue) *adt.EmptyValue { +func (ta *testActor) Constructor(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue { rt.ValidateImmediateCallerAcceptAny() rt.State().Create(&testActorState{11}) fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Message().Receiver()) - return adt.Empty + return abi.Empty } -func (ta *testActor) TestMethod(rt runtime.Runtime, params *adt.EmptyValue) *adt.EmptyValue { +func (ta *testActor) TestMethod(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue { rt.ValidateImmediateCallerAcceptAny() var st testActorState rt.State().Readonly(&st) @@ -96,7 +95,7 @@ func (ta *testActor) TestMethod(rt runtime.Runtime, params *adt.EmptyValue) *adt } } - return adt.Empty + return abi.Empty } func TestForkHeightTriggers(t *testing.T) { @@ -119,7 +118,7 @@ func TestForkHeightTriggers(t *testing.T) { t.Fatal(err) } - stmgr.ForksAtHeight[testForkHeight] = func(ctx context.Context, sm *StateManager, st types.StateTree) error { + stmgr.ForksAtHeight[testForkHeight] = func(ctx context.Context, sm *StateManager, st types.StateTree, ts *types.TipSet) error { cst := cbor.NewCborStore(sm.ChainStore().Blockstore()) act, err := st.GetActor(taddr) diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index e041fe08894..e6103e2b3a3 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -5,6 +5,8 @@ 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" @@ -18,8 +20,8 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" @@ -145,7 +147,7 @@ func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (c type ExecCallback func(cid.Cid, *types.Message, *vm.ApplyRet) error -func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []store.BlockMessages, epoch abi.ChainEpoch, r vm.Rand, cb ExecCallback, baseFee abi.TokenAmount) (cid.Cid, cid.Cid, error) { +func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []store.BlockMessages, epoch abi.ChainEpoch, r vm.Rand, cb ExecCallback, baseFee abi.TokenAmount, ts *types.TipSet) (cid.Cid, cid.Cid, error) { vmopt := &vm.VMOpts{ StateBase: pstate, @@ -154,6 +156,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp Bstore: sm.cs.Blockstore(), Syscalls: sm.cs.VMSys(), CircSupplyCalc: sm.GetCirculatingSupply, + NtwkVersion: sm.GetNtwkVersion, BaseFee: baseFee, } @@ -198,7 +201,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp for i := parentEpoch; i < epoch; i++ { // handle state forks - err = sm.handleStateForks(ctx, vmi.StateTree(), i) + err = sm.handleStateForks(ctx, vmi.StateTree(), i, ts) if err != nil { return cid.Undef, cid.Undef, xerrors.Errorf("error handling state forks: %w", err) } @@ -347,7 +350,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, ts *types.TipSet baseFee := blks[0].ParentBaseFee - return sm.ApplyBlocks(ctx, parentEpoch, pstate, blkmsgs, blks[0].Height, r, cb, baseFee) + return sm.ApplyBlocks(ctx, parentEpoch, pstate, blkmsgs, blks[0].Height, r, cb, baseFee, ts) } func (sm *StateManager) parentState(ts *types.TipSet) cid.Cid { @@ -1120,3 +1123,19 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha return csi.FilCirculating, nil } + +func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) network.Version { + if build.UseNewestNetwork() { + return build.NewestNetworkVersion + } + + if height <= build.UpgradeBreezeHeight { + return network.Version0 + } + + if height <= build.UpgradeSmokeHeight { + return network.Version1 + } + + return build.NewestNetworkVersion +} diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index db6157b093f..f77ec20ffbd 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -3,8 +3,14 @@ package stmgr import ( "bytes" "context" + "fmt" "os" "reflect" + "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" @@ -13,8 +19,9 @@ import ( "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/crypto" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/abi" "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" @@ -26,7 +33,6 @@ import ( "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/crypto" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api" @@ -163,7 +169,7 @@ func MinerSectorInfo(ctx context.Context, sm *StateManager, maddr address.Addres return sectorInfo, nil } -func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address, filter *abi.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) { +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) if err != nil { @@ -173,8 +179,8 @@ func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, return LoadSectorsFromSet(ctx, sm.ChainStore().Blockstore(), mas.Sectors, filter, filterOut) } -func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]abi.SectorInfo, error) { - var partsProving []abi.BitField +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 @@ -261,7 +267,7 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S return nil, xerrors.Errorf("failed to load sectors amt: %w", err) } - out := make([]abi.SectorInfo, len(ids)) + out := make([]proof.SectorInfo, len(ids)) for i, n := range ids { sid := sectors[n] @@ -272,7 +278,7 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S return nil, xerrors.Errorf("failed to find sector %d", sid) } - out[i] = abi.SectorInfo{ + out[i] = proof.SectorInfo{ SealProof: spt, SectorNumber: sinfo.SectorNumber, SealedCID: sinfo.SealedCID, @@ -387,7 +393,7 @@ func ListMinerActors(ctx context.Context, sm *StateManager, ts *types.TipSet) ([ return miners, nil } -func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.Cid, filter *abi.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) { +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 @@ -440,6 +446,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, Bstore: sm.cs.Blockstore(), Syscalls: sm.cs.VMSys(), CircSupplyCalc: sm.GetCirculatingSupply, + NtwkVersion: sm.GetNtwkVersion, BaseFee: ts.Blocks()[0].ParentBaseFee, } vmi, err := vm.NewVM(vmopt) @@ -449,7 +456,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, for i := ts.Height(); i < height; i++ { // handle state forks - err = sm.handleStateForks(ctx, vmi.StateTree(), i) + err = sm.handleStateForks(ctx, vmi.StateTree(), i, ts) if err != nil { return cid.Undef, nil, xerrors.Errorf("error handling state forks: %w", err) } @@ -495,7 +502,7 @@ func GetLookbackTipSetForRound(ctx context.Context, sm *StateManager, ts *types. return lbts, nil } -func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBeacon, tsk types.TipSetKey, round abi.ChainEpoch, maddr address.Address, pv ffiwrapper.Verifier) (*api.MiningBaseInfo, error) { +func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule, tsk types.TipSetKey, round abi.ChainEpoch, maddr address.Address, pv ffiwrapper.Verifier) (*api.MiningBaseInfo, error) { ts, err := sm.ChainStore().LoadTipSet(tsk) if err != nil { return nil, xerrors.Errorf("failed to load tipset for mining base: %w", err) @@ -510,7 +517,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBe prev = &types.BeaconEntry{} } - entries, err := beacon.BeaconEntriesForBlock(ctx, bcn, round, *prev) + entries, err := beacon.BeaconEntriesForBlock(ctx, bcs, round, ts.Height(), *prev) if err != nil { return nil, err } @@ -586,14 +593,14 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBe }, nil } -type methodMeta struct { +type MethodMeta struct { Name string Params reflect.Type Ret reflect.Type } -var MethodsMap = map[cid.Cid][]methodMeta{} +var MethodsMap = map[cid.Cid]map[abi.MethodNum]MethodMeta{} func init() { cidToMethods := map[cid.Cid][2]interface{}{ @@ -611,25 +618,65 @@ func init() { } for c, m := range cidToMethods { - rt := reflect.TypeOf(m[0]) - nf := rt.NumField() + exports := m[1].(saruntime.Invokee).Exports() + methods := make(map[abi.MethodNum]MethodMeta, len(exports)) - MethodsMap[c] = append(MethodsMap[c], methodMeta{ + // Explicitly add send, it's special. + methods[builtin.MethodSend] = MethodMeta{ Name: "Send", - Params: reflect.TypeOf(new(adt.EmptyValue)), - Ret: reflect.TypeOf(new(adt.EmptyValue)), - }) + Params: reflect.TypeOf(new(abi.EmptyValue)), + Ret: reflect.TypeOf(new(abi.EmptyValue)), + } - exports := m[1].(abi.Invokee).Exports() + // Learn method names from the builtin.Methods* structs. + rv := reflect.ValueOf(m[0]) + rt := rv.Type() + nf := rt.NumField() + methodToName := make([]string, len(exports)) for i := 0; i < nf; i++ { - export := reflect.TypeOf(exports[i+1]) + name := rt.Field(i).Name + number := rv.Field(i).Interface().(abi.MethodNum) + methodToName[number] = name + } - MethodsMap[c] = append(MethodsMap[c], methodMeta{ - Name: rt.Field(i).Name, - Params: export.In(1), - Ret: export.Out(0), - }) + // Iterate over exported methods. Some of these _may_ be nil and + // must be skipped. + for number, export := range exports { + if export == nil { + continue + } + + ev := reflect.ValueOf(export) + et := ev.Type() + + // Make sure the method name is correct. + // This is just a nice sanity check. + fnName := runtime.FuncForPC(ev.Pointer()).Name() + fnName = strings.TrimSuffix(fnName[strings.LastIndexByte(fnName, '.')+1:], "-fm") + mName := methodToName[number] + if mName != fnName { + panic(fmt.Sprintf( + "actor method name is %s but exported method name is %s", + fnName, mName, + )) + } + + switch abi.MethodNum(number) { + case builtin.MethodSend: + panic("method 0 is reserved for Send") + case builtin.MethodConstructor: + if fnName != "Constructor" { + panic("method 1 is reserved for Constructor") + } + } + + methods[abi.MethodNum(number)] = MethodMeta{ + Name: fnName, + Params: et.In(1), + Ret: et.Out(0), + } } + MethodsMap[c] = methods } } @@ -639,7 +686,10 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me return nil, xerrors.Errorf("getting actor: %w", err) } - m := MethodsMap[act.Code][method] + m, found := MethodsMap[act.Code][method] + if !found { + return nil, fmt.Errorf("unknown method %d for actor %s", method, act.Code) + } return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil } diff --git a/chain/store/basefee.go b/chain/store/basefee.go index de3f90a8f60..45785240e5a 100644 --- a/chain/store/basefee.go +++ b/chain/store/basefee.go @@ -3,22 +3,28 @@ package store import ( "context" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/ipfs/go-cid" "golang.org/x/xerrors" ) -func computeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int) types.BigInt { - // deta := 1/PackingEfficiency * gasLimitUsed/noOfBlocks - build.BlockGasTarget - // change := baseFee * deta / BlockGasTarget / BaseFeeMaxChangeDenom +func ComputeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int, epoch abi.ChainEpoch) types.BigInt { + // deta := gasLimitUsed/noOfBlocks - build.BlockGasTarget + // change := baseFee * deta / BlockGasTarget // nextBaseFee = baseFee + change // nextBaseFee = max(nextBaseFee, build.MinimumBaseFee) - delta := build.PackingEfficiencyDenom * gasLimitUsed / (int64(noOfBlocks) * build.PackingEfficiencyNum) - delta -= build.BlockGasTarget + var delta int64 + if epoch > build.UpgradeSmokeHeight { + delta = gasLimitUsed / int64(noOfBlocks) + delta -= build.BlockGasTarget + } else { + delta = build.PackingEfficiencyDenom * gasLimitUsed / (int64(noOfBlocks) * build.PackingEfficiencyNum) + delta -= build.BlockGasTarget + } // cap change at 12.5% (BaseFeeMaxChangeDenom) by capping delta if delta > build.BlockGasTarget { @@ -40,6 +46,10 @@ func computeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int } func (cs *ChainStore) ComputeBaseFee(ctx context.Context, ts *types.TipSet) (abi.TokenAmount, error) { + if ts.Height() > build.UpgradeBreezeHeight && ts.Height() < build.UpgradeBreezeHeight+build.BreezeGasTampingDuration { + return abi.NewTokenAmount(100), nil + } + zero := abi.NewTokenAmount(0) // totalLimit is sum of GasLimits of unique messages in a tipset @@ -69,5 +79,5 @@ func (cs *ChainStore) ComputeBaseFee(ctx context.Context, ts *types.TipSet) (abi } parentBaseFee := ts.Blocks()[0].ParentBaseFee - return computeNextBaseFee(parentBaseFee, totalLimit, len(ts.Blocks())), nil + return ComputeNextBaseFee(parentBaseFee, totalLimit, len(ts.Blocks()), ts.Height()), nil } diff --git a/chain/store/basefee_test.go b/chain/store/basefee_test.go index 7a7cae91142..b4757f70e1c 100644 --- a/chain/store/basefee_test.go +++ b/chain/store/basefee_test.go @@ -27,7 +27,7 @@ func TestBaseFee(t *testing.T) { for _, test := range tests { test := test t.Run(fmt.Sprintf("%v", test), func(t *testing.T) { - output := computeNextBaseFee(types.NewInt(test.basefee), test.limitUsed, test.noOfBlocks) + output := ComputeNextBaseFee(types.NewInt(test.basefee), test.limitUsed, test.noOfBlocks, 0) assert.Equal(t, fmt.Sprintf("%d", test.output), output.String()) }) } diff --git a/chain/store/index.go b/chain/store/index.go index 8f3e8841765..a9da994af9d 100644 --- a/chain/store/index.go +++ b/chain/store/index.go @@ -5,8 +5,8 @@ import ( "os" "strconv" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/abi" lru "github.com/hashicorp/golang-lru" "golang.org/x/xerrors" ) diff --git a/chain/store/index_test.go b/chain/store/index_test.go index 5c49c679170..63e08070c91 100644 --- a/chain/store/index_test.go +++ b/chain/store/index_test.go @@ -5,11 +5,11 @@ import ( "context" "testing" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types/mock" "github.com/filecoin-project/lotus/lib/blockstore" - "github.com/filecoin-project/specs-actors/actors/abi" datastore "github.com/ipfs/go-datastore" syncds "github.com/ipfs/go-datastore/sync" "github.com/stretchr/testify/assert" diff --git a/chain/store/store.go b/chain/store/store.go index c608e76ed0b..20a7e30311e 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -10,11 +10,11 @@ import ( "strconv" "sync" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" "github.com/minio/blake2b-simd" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api" @@ -494,7 +494,7 @@ func (cs *ChainStore) IsAncestorOf(a, b *types.TipSet) (bool, error) { cur := b for !a.Equals(cur) && cur.Height() > a.Height() { - next, err := cs.LoadTipSet(b.Parents()) + next, err := cs.LoadTipSet(cur.Parents()) if err != nil { return false, err } @@ -1182,7 +1182,7 @@ func recurseLinks(bs bstore.Blockstore, walked *cid.Set, root cid.Cid, in []cid. return in, rerr } -func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, w io.Writer) error { +func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, skipOldMsgs bool, w io.Writer) error { if ts == nil { ts = cs.GetHeaviestTipSet() } @@ -1220,9 +1220,13 @@ func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRo return xerrors.Errorf("unmarshaling block header (cid=%s): %w", blk, err) } - cids, err := recurseLinks(cs.bs, walked, b.Messages, []cid.Cid{b.Messages}) - if err != nil { - return xerrors.Errorf("recursing messages failed: %w", err) + var cids []cid.Cid + if !skipOldMsgs || b.Height > ts.Height()-inclRecentRoots { + mcids, err := recurseLinks(cs.bs, walked, b.Messages, []cid.Cid{b.Messages}) + if err != nil { + return xerrors.Errorf("recursing messages failed: %w", err) + } + cids = mcids } if b.Height > 0 { diff --git a/chain/store/store_test.go b/chain/store/store_test.go index 42de4c19d4e..e56bab4c9f4 100644 --- a/chain/store/store_test.go +++ b/chain/store/store_test.go @@ -7,12 +7,12 @@ import ( datastore "github.com/ipfs/go-datastore" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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/specs-actors/actors/crypto" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/store" @@ -96,7 +96,7 @@ func TestChainExportImport(t *testing.T) { } buf := new(bytes.Buffer) - if err := cg.ChainStore().Export(context.TODO(), last, 0, buf); err != nil { + if err := cg.ChainStore().Export(context.TODO(), last, 0, false, buf); err != nil { t.Fatal(err) } diff --git a/chain/store/weight.go b/chain/store/weight.go index 2e8516f57f8..5249df0112b 100644 --- a/chain/store/weight.go +++ b/chain/store/weight.go @@ -4,10 +4,10 @@ import ( "context" "math/big" + 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" - big2 "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/power" cbor "github.com/ipfs/go-ipld-cbor" diff --git a/chain/sub/incoming.go b/chain/sub/incoming.go index 5c28aa83544..34dde227fa7 100644 --- a/chain/sub/incoming.go +++ b/chain/sub/incoming.go @@ -369,9 +369,8 @@ func (bv *BlockValidator) decodeAndCheckBlock(msg *pubsub.Message) (*types.Block func (bv *BlockValidator) isChainNearSynced() bool { ts := bv.chain.GetHeaviestTipSet() timestamp := ts.MinTimestamp() - now := build.Clock.Now().UnixNano() - cutoff := uint64(now) - uint64(6*time.Hour) - return timestamp > cutoff + timestampTime := time.Unix(int64(timestamp), 0) + return build.Clock.Since(timestampTime) < 6*time.Hour } func (bv *BlockValidator) validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error { diff --git a/chain/sync.go b/chain/sync.go index 1b1cbdde9ca..9864600dd4e 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -9,8 +9,13 @@ import ( "sort" "strconv" "strings" + "sync" "time" + "github.com/filecoin-project/lotus/node/modules/dtypes" + + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/Gurpartap/async" "github.com/hashicorp/go-multierror" "github.com/ipfs/go-cid" @@ -25,18 +30,18 @@ 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/crypto" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/crypto" "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/beacon" - "github.com/filecoin-project/lotus/chain/blocksync" + "github.com/filecoin-project/lotus/chain/exchange" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/stmgr" @@ -50,7 +55,7 @@ import ( ) // Blocks that are more than MaxHeightDrift epochs above -//the theoretical max height based on systime are quickly rejected +// the theoretical max height based on systime are quickly rejected const MaxHeightDrift = 5 var defaultMessageFetchWindowSize = 200 @@ -87,7 +92,7 @@ var LocalIncoming = "incoming" // The Syncer does not run workers itself. It's mainly concerned with // ensuring a consistent state of chain consensus. The reactive and network- // interfacing processes are part of other components, such as the SyncManager -// (which owns the sync scheduler and sync workers), BlockSync, the HELLO +// (which owns the sync scheduler and sync workers), ChainExchange, the HELLO // protocol, and the gossipsub block propagation layer. // // {hint/concept} The fork-choice rule as it currently stands is: "pick the @@ -98,7 +103,7 @@ type Syncer struct { store *store.ChainStore // handle to the random beacon for verification - beacon beacon.RandomBeacon + beacon beacon.Schedule // the state manager handles making state queries sm *stmgr.StateManager @@ -110,7 +115,7 @@ type Syncer struct { bad *BadBlockCache // handle to the block sync service - Bsync *blocksync.BlockSync + Exchange exchange.Client self peer.ID @@ -125,10 +130,18 @@ type Syncer struct { verifier ffiwrapper.Verifier windowSize int + + tickerCtxCancel context.CancelFunc + + checkptLk sync.Mutex + + checkpt types.TipSetKey + + ds dtypes.MetadataDS } // NewSyncer creates a new Syncer object. -func NewSyncer(sm *stmgr.StateManager, bsync *blocksync.BlockSync, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*Syncer, error) { +func NewSyncer(ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.Schedule, verifier ffiwrapper.Verifier) (*Syncer, error) { gen, err := sm.ChainStore().GetGenesis() if err != nil { return nil, xerrors.Errorf("getting genesis block: %w", err) @@ -139,11 +152,18 @@ func NewSyncer(sm *stmgr.StateManager, bsync *blocksync.BlockSync, connmgr connm return nil, err } + cp, err := loadCheckpoint(ds) + if err != nil { + return nil, xerrors.Errorf("error loading mpool config: %w", err) + } + s := &Syncer{ + ds: ds, + checkpt: cp, beacon: beacon, bad: NewBadBlockCache(), Genesis: gent, - Bsync: bsync, + Exchange: exchange, store: sm.ChainStore(), sm: sm, self: self, @@ -166,11 +186,35 @@ func NewSyncer(sm *stmgr.StateManager, bsync *blocksync.BlockSync, connmgr connm } func (syncer *Syncer) Start() { + tickerCtx, tickerCtxCancel := context.WithCancel(context.Background()) syncer.syncmgr.Start() + + syncer.tickerCtxCancel = tickerCtxCancel + + go syncer.runMetricsTricker(tickerCtx) +} + +func (syncer *Syncer) runMetricsTricker(tickerCtx context.Context) { + genesisTime := time.Unix(int64(syncer.Genesis.MinTimestamp()), 0) + ticker := build.Clock.Ticker(time.Duration(build.BlockDelaySecs) * time.Second) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + sinceGenesis := build.Clock.Now().Sub(genesisTime) + expectedHeight := int64(sinceGenesis.Seconds()) / int64(build.BlockDelaySecs) + + stats.Record(tickerCtx, metrics.ChainNodeHeightExpected.M(expectedHeight)) + case <-tickerCtx.Done(): + return + } + } } func (syncer *Syncer) Stop() { syncer.syncmgr.Stop() + syncer.tickerCtxCancel() } // InformNewHead informs the syncer about a new potential tipset @@ -220,7 +264,7 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool { return false } - syncer.Bsync.AddPeer(from) + syncer.Exchange.AddPeer(from) bestPweight := syncer.store.GetHeaviestTipSet().ParentWeight() targetWeight := fts.TipSet().ParentWeight() @@ -451,7 +495,7 @@ func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cid.Cid) (cid.Cid, e } // FetchTipSet tries to load the provided tipset from the store, and falls back -// to the network (BlockSync) by querying the supplied peer if not found +// to the network (client) by querying the supplied peer if not found // locally. // // {hint/usage} This is used from the HELLO protocol, to fetch the greeting @@ -462,7 +506,7 @@ func (syncer *Syncer) FetchTipSet(ctx context.Context, p peer.ID, tsk types.TipS } // fall back to the network. - return syncer.Bsync.GetFullTipSet(ctx, p, tsk) + return syncer.Exchange.GetFullTipSet(ctx, p, tsk) } // tryLoadFullTipSet queries the tipset in the ChainStore, and returns a full @@ -835,7 +879,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er return nil } - if err := beacon.ValidateBlockValues(syncer.beacon, h, *prevBeacon); err != nil { + if err := beacon.ValidateBlockValues(syncer.beacon, h, baseTs.Height(), *prevBeacon); err != nil { return xerrors.Errorf("failed to validate blocks random beacon values: %w", err) } return nil @@ -847,10 +891,12 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er return xerrors.Errorf("failed to marshal miner address to cbor: %w", err) } - beaconBase := *prevBeacon - if len(h.BeaconEntries) == 0 { + if h.Height > build.UpgradeSmokeHeight { buf.Write(baseTs.MinTicket().VRFProof) - } else { + } + + beaconBase := *prevBeacon + if len(h.BeaconEntries) != 0 { beaconBase = h.BeaconEntries[len(h.BeaconEntries)-1] } @@ -953,7 +999,7 @@ func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.Block return xerrors.Errorf("getting winning post sector set: %w", err) } - ok, err := ffiwrapper.ProofVerifier.VerifyWinningPoSt(ctx, abi.WinningPoStVerifyInfo{ + ok, err := ffiwrapper.ProofVerifier.VerifyWinningPoSt(ctx, proof.WinningPoStVerifyInfo{ Randomness: rand, Proofs: h.WinPoStProof, ChallengedSectors: sectors, @@ -1164,7 +1210,7 @@ func extractSyncState(ctx context.Context) *SyncerState { // total equality of the BeaconEntries in each block. // 3. Traverse the chain backwards, for each tipset: // 3a. Load it from the chainstore; if found, it move on to its parent. -// 3b. Query our peers via BlockSync in batches, requesting up to a +// 3b. Query our peers via client in batches, requesting up to a // maximum of 500 tipsets every time. // // Once we've concluded, if we find a mismatching tipset at the height where the @@ -1265,7 +1311,7 @@ loop: if gap := int(blockSet[len(blockSet)-1].Height() - untilHeight); gap < window { window = gap } - blks, err := syncer.Bsync.GetBlocks(ctx, at, window) + blks, err := syncer.Exchange.GetBlocks(ctx, at, window) if err != nil { // Most likely our peers aren't fully synced yet, but forwarded // new block message (ideally we'd find better peers) @@ -1283,7 +1329,7 @@ loop: // have. Since we fetch from the head backwards our reassembled chain // is sorted in reverse here: we have a child -> parent order, our last // tipset then should be child of the first tipset retrieved. - // FIXME: The reassembly logic should be part of the `BlockSync` + // FIXME: The reassembly logic should be part of the `client` // service, the consumer should not be concerned with the // `MaxRequestLength` limitation, it should just be able to request // an segment of arbitrary length. The same burden is put on @@ -1333,7 +1379,7 @@ loop: log.Warnf("(fork detected) synced header chain (%s - %d) does not link to our best block (%s - %d)", incoming.Cids(), incoming.Height(), known.Cids(), known.Height()) fork, err := syncer.syncFork(ctx, base, known) if err != nil { - if xerrors.Is(err, ErrForkTooLong) { + if xerrors.Is(err, ErrForkTooLong) || xerrors.Is(err, ErrForkCheckpoint) { // TODO: we're marking this block bad in the same way that we mark invalid blocks bad. Maybe distinguish? log.Warn("adding forked chain to our bad tipset cache") for _, b := range incoming.Blocks() { @@ -1349,15 +1395,24 @@ loop: } var ErrForkTooLong = fmt.Errorf("fork longer than threshold") +var ErrForkCheckpoint = fmt.Errorf("fork would require us to diverge from checkpointed block") // syncFork tries to obtain the chain fragment that links a fork into a common // ancestor in our view of the chain. // -// If the fork is too long (build.ForkLengthThreshold), we add the entire subchain to the -// denylist. Else, we find the common ancestor, and add the missing chain +// If the fork is too long (build.ForkLengthThreshold), or would cause us to diverge from the checkpoint (ErrForkCheckpoint), +// we add the entire subchain to the denylist. Else, we find the common ancestor, and add the missing chain // fragment until the fork point to the returned []TipSet. func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, known *types.TipSet) ([]*types.TipSet, error) { - tips, err := syncer.Bsync.GetBlocks(ctx, incoming.Parents(), int(build.ForkLengthThreshold)) + + chkpt := syncer.GetCheckpoint() + if known.Key() == chkpt { + return nil, ErrForkCheckpoint + } + + // TODO: Does this mean we always ask for ForkLengthThreshold blocks from the network, even if we just need, like, 2? + // Would it not be better to ask in smaller chunks, given that an ~ForkLengthThreshold is very rare? + tips, err := syncer.Exchange.GetBlocks(ctx, incoming.Parents(), int(build.ForkLengthThreshold)) if err != nil { return nil, err } @@ -1382,12 +1437,18 @@ func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, know if nts.Height() < tips[cur].Height() { cur++ } else { + // We will be forking away from nts, check that it isn't checkpointed + if nts.Key() == chkpt { + return nil, ErrForkCheckpoint + } + nts, err = syncer.store.LoadTipSet(nts.Parents()) if err != nil { return nil, xerrors.Errorf("loading next local tipset: %w", err) } } } + return nil, ErrForkTooLong } @@ -1411,6 +1472,7 @@ func (syncer *Syncer) syncMessagesAndCheckState(ctx context.Context, headers []* // fills out each of the given tipsets with messages and calls the callback with it func (syncer *Syncer) iterFullTipsets(ctx context.Context, headers []*types.TipSet, cb func(context.Context, *store.FullTipSet) error) error { + ss := extractSyncState(ctx) ctx, span := trace.StartSpan(ctx, "iterFullTipsets") defer span.End() @@ -1438,12 +1500,13 @@ mainLoop: 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 - var bstout []*blocksync.CompactedMessages + ss.SetStage(api.StageFetchingMessages) + var bstout []*exchange.CompactedMessages for len(bstout) < batchSize { next := headers[nextI] nreq := batchSize - len(bstout) - bstips, err := syncer.Bsync.GetChainMessages(ctx, next, uint64(nreq)) + bstips, err := syncer.Exchange.GetChainMessages(ctx, next, uint64(nreq)) if err != nil { // TODO check errors for temporary nature if windowSize > 1 { @@ -1457,6 +1520,7 @@ mainLoop: bstout = append(bstout, bstips...) nextI += len(bstips) } + ss.SetStage(api.StageMessages) for bsi := 0; bsi < len(bstout); bsi++ { // temp storage so we don't persist data we dont want to @@ -1488,8 +1552,8 @@ mainLoop: if i >= windowSize { newWindowSize := windowSize + 10 - if newWindowSize > int(blocksync.MaxRequestLength) { - newWindowSize = int(blocksync.MaxRequestLength) + if newWindowSize > int(exchange.MaxRequestLength) { + newWindowSize = int(exchange.MaxRequestLength) } if newWindowSize > windowSize { windowSize = newWindowSize @@ -1506,7 +1570,7 @@ mainLoop: return nil } -func persistMessages(bs bstore.Blockstore, bst *blocksync.CompactedMessages) error { +func persistMessages(bs bstore.Blockstore, bst *exchange.CompactedMessages) error { for _, m := range bst.Bls { //log.Infof("putting BLS message: %s", m.Cid()) if _, err := store.PutMessage(bs, m); err != nil { @@ -1613,6 +1677,11 @@ func (syncer *Syncer) MarkBad(blk cid.Cid) { syncer.bad.Add(blk, NewBadBlockReason([]cid.Cid{blk}, "manually marked bad")) } +// UnmarkBad manually adds a block to the "bad blocks" cache. +func (syncer *Syncer) UnmarkBad(blk cid.Cid) { + syncer.bad.Remove(blk) +} + func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) { bbr, ok := syncer.bad.Has(blk) return bbr.String(), ok diff --git a/chain/sync_test.go b/chain/sync_test.go index cf1385baa77..0b0d1ed0098 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -7,6 +7,8 @@ import ( "testing" "time" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" @@ -16,8 +18,8 @@ import ( "github.com/stretchr/testify/require" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" @@ -331,6 +333,36 @@ func (tu *syncTestUtil) compareSourceState(with int) { } } +func (tu *syncTestUtil) assertBad(node int, ts *types.TipSet) { + for _, blk := range ts.Cids() { + rsn, err := tu.nds[node].SyncCheckBad(context.TODO(), blk) + require.NoError(tu.t, err) + require.True(tu.t, len(rsn) != 0) + } +} + +func (tu *syncTestUtil) getHead(node int) *types.TipSet { + ts, err := tu.nds[node].ChainHead(context.TODO()) + require.NoError(tu.t, err) + return ts +} + +func (tu *syncTestUtil) checkpointTs(node int, tsk types.TipSetKey) { + require.NoError(tu.t, tu.nds[node].SyncCheckpoint(context.TODO(), tsk)) +} + +func (tu *syncTestUtil) waitUntilNodeHasTs(node int, tsk types.TipSetKey) { + for { + _, err := tu.nds[node].ChainGetTipSet(context.TODO(), tsk) + if err != nil { + break + } + } + + // Time to allow for syncing and validation + time.Sleep(2 * time.Second) +} + func (tu *syncTestUtil) waitUntilSync(from, to int) { target, err := tu.nds[from].ChainHead(tu.ctx) if err != nil { @@ -442,8 +474,8 @@ func (wpp badWpp) GenerateCandidates(context.Context, abi.PoStRandomness, uint64 return []uint64{1}, nil } -func (wpp badWpp) ComputeProof(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]abi.PoStProof, error) { - return []abi.PoStProof{ +func (wpp badWpp) ComputeProof(context.Context, []proof.SectorInfo, abi.PoStRandomness) ([]proof.PoStProof, error) { + return []proof.PoStProof{ { PoStProof: abi.RegisteredPoStProof_StackedDrgWinning2KiBV1, ProofBytes: []byte("evil"), @@ -676,3 +708,87 @@ func TestSyncInputs(t *testing.T) { t.Fatal("should error on block with nil election proof") } } + +func TestSyncCheckpointHead(t *testing.T) { + H := 10 + tu := prepSyncTest(t, H) + + p1 := tu.addClientNode() + p2 := tu.addClientNode() + + fmt.Println("GENESIS: ", tu.g.Genesis().Cid()) + tu.loadChainToNode(p1) + tu.loadChainToNode(p2) + + base := tu.g.CurTipset + fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height()) + + // The two nodes fork at this point into 'a' and 'b' + a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil) + a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil) + a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil) + + tu.waitUntilSyncTarget(p1, a.TipSet()) + tu.checkpointTs(p1, a.TipSet().Key()) + + require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet())) + // chain B will now be heaviest + b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil) + b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil) + b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil) + b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil) + + fmt.Println("A: ", a.Cids(), a.TipSet().Height()) + fmt.Println("B: ", b.Cids(), b.TipSet().Height()) + + // Now for the fun part!! p1 should mark p2's head as BAD. + + require.NoError(t, tu.mn.LinkAll()) + tu.connect(p1, p2) + tu.waitUntilNodeHasTs(p1, b.TipSet().Key()) + p1Head := tu.getHead(p1) + require.Equal(tu.t, p1Head, a.TipSet()) + tu.assertBad(p1, b.TipSet()) +} + +func TestSyncCheckpointEarlierThanHead(t *testing.T) { + H := 10 + tu := prepSyncTest(t, H) + + p1 := tu.addClientNode() + p2 := tu.addClientNode() + + fmt.Println("GENESIS: ", tu.g.Genesis().Cid()) + tu.loadChainToNode(p1) + tu.loadChainToNode(p2) + + base := tu.g.CurTipset + fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height()) + + // The two nodes fork at this point into 'a' and 'b' + a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil) + a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil) + a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil) + + tu.waitUntilSyncTarget(p1, a.TipSet()) + tu.checkpointTs(p1, a1.TipSet().Key()) + + require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet())) + // chain B will now be heaviest + b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil) + b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil) + b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil) + b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil) + + fmt.Println("A: ", a.Cids(), a.TipSet().Height()) + fmt.Println("B: ", b.Cids(), b.TipSet().Height()) + + // Now for the fun part!! p1 should mark p2's head as BAD. + + require.NoError(t, tu.mn.LinkAll()) + tu.connect(p1, p2) + tu.waitUntilNodeHasTs(p1, b.TipSet().Key()) + p1Head := tu.getHead(p1) + require.Equal(tu.t, p1Head, a.TipSet()) + tu.assertBad(p1, b.TipSet()) +} diff --git a/chain/syncstate.go b/chain/syncstate.go index aaca8830314..06cd5d91e06 100644 --- a/chain/syncstate.go +++ b/chain/syncstate.go @@ -1,34 +1,16 @@ package chain import ( - "fmt" "sync" "time" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" ) -func SyncStageString(v api.SyncStateStage) string { - switch v { - case api.StageHeaders: - return "header sync" - case api.StagePersistHeaders: - return "persisting headers" - case api.StageMessages: - return "message sync" - case api.StageSyncComplete: - return "complete" - case api.StageSyncErrored: - return "error" - default: - return fmt.Sprintf("", v) - } -} - type SyncerState struct { lk sync.Mutex Target *types.TipSet diff --git a/chain/types/bigint.go b/chain/types/bigint.go index 466b9c556cb..da4857d5b4d 100644 --- a/chain/types/bigint.go +++ b/chain/types/bigint.go @@ -4,7 +4,7 @@ import ( "fmt" "math/big" - big2 "github.com/filecoin-project/specs-actors/actors/abi/big" + big2 "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/build" ) diff --git a/chain/types/blockheader.go b/chain/types/blockheader.go index 36b43c0129e..0ec33fe4214 100644 --- a/chain/types/blockheader.go +++ b/chain/types/blockheader.go @@ -4,10 +4,12 @@ import ( "bytes" "math/big" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/minio/blake2b-simd" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" @@ -53,7 +55,7 @@ type BlockHeader struct { BeaconEntries []BeaconEntry // 3 - WinPoStProof []abi.PoStProof // 4 + WinPoStProof []proof.PoStProof // 4 Parents []cid.Cid // 5 diff --git a/chain/types/blockheader_test.go b/chain/types/blockheader_test.go index e4b545cca08..f5faac3b36c 100644 --- a/chain/types/blockheader_test.go +++ b/chain/types/blockheader_test.go @@ -7,12 +7,14 @@ import ( "reflect" "testing" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + cid "github.com/ipfs/go-cid" "github.com/stretchr/testify/require" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" ) func testBlockHeader(t testing.TB) *BlockHeader { @@ -80,7 +82,7 @@ func TestInteropBH(t *testing.T) { t.Fatal(err) } - posts := []abi.PoStProof{ + posts := []proof.PoStProof{ {PoStProof: abi.RegisteredPoStProof_StackedDrgWinning2KiBV1, ProofBytes: []byte{0x07}}, } diff --git a/chain/types/cbor_gen.go b/chain/types/cbor_gen.go index 35abf28289e..676ae7054c0 100644 --- a/chain/types/cbor_gen.go +++ b/chain/types/cbor_gen.go @@ -6,9 +6,10 @@ import ( "fmt" "io" - abi "github.com/filecoin-project/specs-actors/actors/abi" - crypto "github.com/filecoin-project/specs-actors/actors/crypto" - exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + abi "github.com/filecoin-project/go-state-types/abi" + crypto "github.com/filecoin-project/go-state-types/crypto" + exitcode "github.com/filecoin-project/go-state-types/exitcode" + proof "github.com/filecoin-project/specs-actors/actors/runtime/proof" cid "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" @@ -58,7 +59,7 @@ func (t *BlockHeader) MarshalCBOR(w io.Writer) error { } } - // t.WinPoStProof ([]abi.PoStProof) (slice) + // t.WinPoStProof ([]proof.PoStProof) (slice) if len(t.WinPoStProof) > cbg.MaxLength { return xerrors.Errorf("Slice value in field t.WinPoStProof was too long") } @@ -243,7 +244,7 @@ func (t *BlockHeader) UnmarshalCBOR(r io.Reader) error { t.BeaconEntries[i] = v } - // t.WinPoStProof ([]abi.PoStProof) (slice) + // t.WinPoStProof ([]proof.PoStProof) (slice) maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) if err != nil { @@ -259,12 +260,12 @@ func (t *BlockHeader) UnmarshalCBOR(r io.Reader) error { } if extra > 0 { - t.WinPoStProof = make([]abi.PoStProof, extra) + t.WinPoStProof = make([]proof.PoStProof, extra) } for i := 0; i < int(extra); i++ { - var v abi.PoStProof + var v proof.PoStProof if err := v.UnmarshalCBOR(br); err != nil { return err } diff --git a/chain/types/message.go b/chain/types/message.go index 288fcf6d947..4fead44bc7c 100644 --- a/chain/types/message.go +++ b/chain/types/message.go @@ -4,9 +4,9 @@ import ( "bytes" "fmt" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" xerrors "golang.org/x/xerrors" diff --git a/chain/types/message_receipt.go b/chain/types/message_receipt.go index 6671595ff01..57761680d20 100644 --- a/chain/types/message_receipt.go +++ b/chain/types/message_receipt.go @@ -3,7 +3,7 @@ package types import ( "bytes" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/filecoin-project/go-state-types/exitcode" ) type MessageReceipt struct { diff --git a/chain/types/message_test.go b/chain/types/message_test.go index a7b4927e5f2..f57385a0958 100644 --- a/chain/types/message_test.go +++ b/chain/types/message_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" ) diff --git a/chain/types/mock/chain.go b/chain/types/mock/chain.go index 33b13d4086a..559630619a3 100644 --- a/chain/types/mock/chain.go +++ b/chain/types/mock/chain.go @@ -5,10 +5,11 @@ import ( "fmt" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/ipfs/go-cid" + "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" ) @@ -80,6 +81,7 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types Height: height, ParentStateRoot: pstateRoot, BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("boo! im a signature")}, + ParentBaseFee: types.NewInt(uint64(build.MinimumBaseFee)), } } diff --git a/chain/types/signature_test.go b/chain/types/signature_test.go index 751f55252ee..9ade3c04645 100644 --- a/chain/types/signature_test.go +++ b/chain/types/signature_test.go @@ -4,7 +4,7 @@ import ( "bytes" "testing" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" ) func TestSignatureSerializeRoundTrip(t *testing.T) { diff --git a/chain/types/signedmessage.go b/chain/types/signedmessage.go index 47592feb1bb..17d2f5d9475 100644 --- a/chain/types/signedmessage.go +++ b/chain/types/signedmessage.go @@ -3,8 +3,8 @@ package types import ( "bytes" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ) diff --git a/chain/types/tipset.go b/chain/types/tipset.go index 4217d2a867c..44d41c29de2 100644 --- a/chain/types/tipset.go +++ b/chain/types/tipset.go @@ -7,7 +7,7 @@ import ( "io" "sort" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" "github.com/minio/blake2b-simd" diff --git a/chain/types/tipset_key.go b/chain/types/tipset_key.go index ee1994f5a22..e5bc7750de3 100644 --- a/chain/types/tipset_key.go +++ b/chain/types/tipset_key.go @@ -5,7 +5,7 @@ import ( "encoding/json" "strings" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" ) diff --git a/chain/validation/applier.go b/chain/validation/applier.go deleted file mode 100644 index ac2fccf8533..00000000000 --- a/chain/validation/applier.go +++ /dev/null @@ -1,215 +0,0 @@ -package validation - -import ( - "context" - - "golang.org/x/xerrors" - - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/crypto" - "github.com/filecoin-project/specs-actors/actors/puppet" - "github.com/ipfs/go-cid" - - vtypes "github.com/filecoin-project/chain-validation/chain/types" - vstate "github.com/filecoin-project/chain-validation/state" - - "github.com/filecoin-project/lotus/chain/stmgr" - "github.com/filecoin-project/lotus/chain/store" - "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/chain/vm" -) - -// Applier applies messages to state trees and storage. -type Applier struct { - stateWrapper *StateWrapper - syscalls vm.SyscallBuilder -} - -var _ vstate.Applier = &Applier{} - -func NewApplier(sw *StateWrapper, syscalls vm.SyscallBuilder) *Applier { - return &Applier{sw, syscalls} -} - -func (a *Applier) ApplyMessage(epoch abi.ChainEpoch, message *vtypes.Message) (vtypes.ApplyMessageResult, error) { - lm := toLotusMsg(message) - receipt, penalty, reward, err := a.applyMessage(epoch, lm) - return vtypes.ApplyMessageResult{ - Msg: *message, - Receipt: receipt, - Penalty: penalty, - Reward: reward, - Root: a.stateWrapper.Root().String(), - }, err -} - -func (a *Applier) ApplySignedMessage(epoch abi.ChainEpoch, msg *vtypes.SignedMessage) (vtypes.ApplyMessageResult, error) { - var lm types.ChainMsg - switch msg.Signature.Type { - case crypto.SigTypeSecp256k1: - lm = toLotusSignedMsg(msg) - case crypto.SigTypeBLS: - lm = toLotusMsg(&msg.Message) - default: - return vtypes.ApplyMessageResult{}, xerrors.New("Unknown signature type") - } - // TODO: Validate the sig first - receipt, penalty, reward, err := a.applyMessage(epoch, lm) - return vtypes.ApplyMessageResult{ - Msg: msg.Message, - Receipt: receipt, - Penalty: penalty, - Reward: reward, - Root: a.stateWrapper.Root().String(), - }, err - -} - -func (a *Applier) ApplyTipSetMessages(epoch abi.ChainEpoch, blocks []vtypes.BlockMessagesInfo, rnd vstate.RandomnessSource) (vtypes.ApplyTipSetResult, error) { - cs := store.NewChainStore(a.stateWrapper.bs, a.stateWrapper.ds, a.syscalls) - sm := stmgr.NewStateManager(cs) - - var bms []store.BlockMessages - for _, b := range blocks { - bm := store.BlockMessages{ - Miner: b.Miner, - WinCount: 1, - } - - for _, m := range b.BLSMessages { - bm.BlsMessages = append(bm.BlsMessages, toLotusMsg(m)) - } - - for _, m := range b.SECPMessages { - bm.SecpkMessages = append(bm.SecpkMessages, toLotusSignedMsg(m)) - } - - bms = append(bms, bm) - } - - var receipts []vtypes.MessageReceipt - // TODO: base fee - sroot, _, err := sm.ApplyBlocks(context.TODO(), epoch-1, a.stateWrapper.Root(), bms, epoch, &randWrapper{rnd}, func(c cid.Cid, msg *types.Message, ret *vm.ApplyRet) error { - if msg.From == builtin.SystemActorAddr { - return nil // ignore reward and cron calls - } - rval := ret.Return - if rval == nil { - rval = []byte{} // chain validation tests expect empty arrays to not be nil... - } - receipts = append(receipts, vtypes.MessageReceipt{ - ExitCode: ret.ExitCode, - ReturnValue: rval, - - GasUsed: vtypes.GasUnits(ret.GasUsed), - }) - return nil - }, abi.NewTokenAmount(100)) - if err != nil { - return vtypes.ApplyTipSetResult{}, err - } - - a.stateWrapper.stateRoot = sroot - - return vtypes.ApplyTipSetResult{ - Receipts: receipts, - Root: a.stateWrapper.Root().String(), - }, nil -} - -type randWrapper struct { - rand vstate.RandomnessSource -} - -// TODO: these should really be two different randomness sources -func (w *randWrapper) GetChainRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { - return w.rand.Randomness(ctx, pers, round, entropy) -} - -func (w *randWrapper) GetBeaconRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { - return w.rand.Randomness(ctx, pers, round, entropy) -} - -type vmRand struct { -} - -func (*vmRand) GetChainRandomness(ctx context.Context, dst crypto.DomainSeparationTag, h abi.ChainEpoch, input []byte) ([]byte, error) { - panic("implement me") -} - -func (*vmRand) GetBeaconRandomness(ctx context.Context, dst crypto.DomainSeparationTag, h abi.ChainEpoch, input []byte) ([]byte, error) { - panic("implement me") -} - -func (a *Applier) applyMessage(epoch abi.ChainEpoch, lm types.ChainMsg) (vtypes.MessageReceipt, abi.TokenAmount, abi.TokenAmount, error) { - ctx := context.TODO() - base := a.stateWrapper.Root() - - vmopt := &vm.VMOpts{ - StateBase: base, - Epoch: epoch, - Rand: &vmRand{}, - Bstore: a.stateWrapper.bs, - Syscalls: a.syscalls, - CircSupplyCalc: nil, - BaseFee: abi.NewTokenAmount(100), - } - - lotusVM, err := vm.NewVM(vmopt) - // need to modify the VM invoker to add the puppet actor - chainValInvoker := vm.NewInvoker() - chainValInvoker.Register(puppet.PuppetActorCodeID, puppet.Actor{}, puppet.State{}) - lotusVM.SetInvoker(chainValInvoker) - if err != nil { - return vtypes.MessageReceipt{}, big.Zero(), big.Zero(), err - } - - ret, err := lotusVM.ApplyMessage(ctx, lm) - if err != nil { - return vtypes.MessageReceipt{}, big.Zero(), big.Zero(), err - } - - rval := ret.Return - if rval == nil { - rval = []byte{} - } - - a.stateWrapper.stateRoot, err = lotusVM.Flush(ctx) - if err != nil { - return vtypes.MessageReceipt{}, big.Zero(), big.Zero(), err - } - - mr := vtypes.MessageReceipt{ - ExitCode: ret.ExitCode, - ReturnValue: rval, - GasUsed: vtypes.GasUnits(ret.GasUsed), - } - - return mr, ret.Penalty, abi.NewTokenAmount(ret.GasUsed), nil -} - -func toLotusMsg(msg *vtypes.Message) *types.Message { - return &types.Message{ - To: msg.To, - From: msg.From, - - Nonce: msg.CallSeqNum, - Method: msg.Method, - - Value: msg.Value, - GasLimit: msg.GasLimit, - GasFeeCap: msg.GasFeeCap, - GasPremium: msg.GasPremium, - - Params: msg.Params, - } -} - -func toLotusSignedMsg(msg *vtypes.SignedMessage) *types.SignedMessage { - return &types.SignedMessage{ - Message: *toLotusMsg(&msg.Message), - Signature: msg.Signature, - } -} diff --git a/chain/validation/config.go b/chain/validation/config.go deleted file mode 100644 index 1e593635051..00000000000 --- a/chain/validation/config.go +++ /dev/null @@ -1,37 +0,0 @@ -package validation - -// -// Config -// - -type Config struct { - trackGas bool - checkExitCode bool - checkReturnValue bool - checkState bool -} - -func NewConfig(gas, exit, ret, state bool) *Config { - return &Config{ - trackGas: gas, - checkExitCode: exit, - checkReturnValue: ret, - checkState: state, - } -} - -func (v Config) ValidateGas() bool { - return v.trackGas -} - -func (v Config) ValidateExitCode() bool { - return v.checkExitCode -} - -func (v Config) ValidateReturnValue() bool { - return v.checkReturnValue -} - -func (v Config) ValidateStateRoot() bool { - return v.checkState -} diff --git a/chain/validation/factories.go b/chain/validation/factories.go deleted file mode 100644 index b7781caccad..00000000000 --- a/chain/validation/factories.go +++ /dev/null @@ -1,40 +0,0 @@ -package validation - -import ( - "context" - - "github.com/filecoin-project/lotus/chain/state" - "github.com/filecoin-project/specs-actors/actors/runtime" - cbor "github.com/ipfs/go-ipld-cbor" - - vstate "github.com/filecoin-project/chain-validation/state" -) - -type Factories struct { - *Applier -} - -var _ vstate.Factories = &Factories{} - -func NewFactories() *Factories { - return &Factories{} -} - -func (f *Factories) NewStateAndApplier(syscalls runtime.Syscalls) (vstate.VMWrapper, vstate.Applier) { - st := NewState() - return st, NewApplier(st, func(ctx context.Context, cstate *state.StateTree, cst cbor.IpldStore) runtime.Syscalls { - return syscalls - }) -} - -func (f *Factories) NewKeyManager() vstate.KeyManager { - return newKeyManager() -} - -func (f *Factories) NewValidationConfig() vstate.ValidationConfig { - trackGas := true - checkExit := true - checkRet := true - checkState := true - return NewConfig(trackGas, checkExit, checkRet, checkState) -} diff --git a/chain/validation/keymanager.go b/chain/validation/keymanager.go deleted file mode 100644 index e93f169bf37..00000000000 --- a/chain/validation/keymanager.go +++ /dev/null @@ -1,104 +0,0 @@ -package validation - -import ( - "fmt" - "math/rand" - - "github.com/minio/blake2b-simd" - - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/go-crypto" - acrypto "github.com/filecoin-project/specs-actors/actors/crypto" - - "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/chain/wallet" -) - -type KeyManager struct { - // Private keys by address - keys map[address.Address]*wallet.Key - - // Seed for deterministic secp key generation. - secpSeed int64 - // Seed for deterministic bls key generation. - blsSeed int64 // nolint: structcheck -} - -func newKeyManager() *KeyManager { - return &KeyManager{ - keys: make(map[address.Address]*wallet.Key), - secpSeed: 0, - } -} - -func (k *KeyManager) NewSECP256k1AccountAddress() address.Address { - secpKey := k.newSecp256k1Key() - k.keys[secpKey.Address] = secpKey - return secpKey.Address -} - -func (k *KeyManager) NewBLSAccountAddress() address.Address { - blsKey := k.newBLSKey() - k.keys[blsKey.Address] = blsKey - return blsKey.Address -} - -func (k *KeyManager) Sign(addr address.Address, data []byte) (acrypto.Signature, error) { - ki, ok := k.keys[addr] - if !ok { - return acrypto.Signature{}, fmt.Errorf("unknown address %v", addr) - } - var sigType acrypto.SigType - if ki.Type == wallet.KTSecp256k1 { - sigType = acrypto.SigTypeBLS - hashed := blake2b.Sum256(data) - sig, err := crypto.Sign(ki.PrivateKey, hashed[:]) - if err != nil { - return acrypto.Signature{}, err - } - - return acrypto.Signature{ - Type: sigType, - Data: sig, - }, nil - } else if ki.Type == wallet.KTBLS { - panic("lotus validator cannot sign BLS messages") - } else { - panic("unknown signature type") - } - -} - -func (k *KeyManager) newSecp256k1Key() *wallet.Key { - randSrc := rand.New(rand.NewSource(k.secpSeed)) // nolint - prv, err := crypto.GenerateKeyFromSeed(randSrc) - if err != nil { - panic(err) - } - k.secpSeed++ - key, err := wallet.NewKey(types.KeyInfo{ - Type: wallet.KTSecp256k1, - PrivateKey: prv, - }) - if err != nil { - panic(err) - } - return key -} - -func (k *KeyManager) newBLSKey() *wallet.Key { - // FIXME: bls needs deterministic key generation - //sk := ffi.PrivateKeyGenerate(s.blsSeed) - // s.blsSeed++ - sk := [32]byte{} - sk[0] = uint8(k.blsSeed) // hack to keep gas values determinist - k.blsSeed++ - key, err := wallet.NewKey(types.KeyInfo{ - Type: wallet.KTBLS, - PrivateKey: sk[:], - }) - if err != nil { - panic(err) - } - return key -} diff --git a/chain/validation/state.go b/chain/validation/state.go deleted file mode 100644 index 2a10eb6afbf..00000000000 --- a/chain/validation/state.go +++ /dev/null @@ -1,217 +0,0 @@ -package validation - -import ( - "context" - - "github.com/ipfs/go-cid" - "github.com/ipfs/go-datastore" - cbor "github.com/ipfs/go-ipld-cbor" - "golang.org/x/xerrors" - - vstate "github.com/filecoin-project/chain-validation/state" - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" - "github.com/filecoin-project/specs-actors/actors/runtime" - - "github.com/filecoin-project/lotus/chain/state" - "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/lib/blockstore" -) - -var _ vstate.VMWrapper = &StateWrapper{} - -type StateWrapper struct { - // The blockstore underlying the state tree and storage. - bs blockstore.Blockstore - - ds datastore.Batching - // HAMT-CBOR store on top of the blockstore. - cst cbor.IpldStore - - // CID of the root of the state tree. - stateRoot cid.Cid -} - -func NewState() *StateWrapper { - bs := blockstore.NewTemporary() - cst := cbor.NewCborStore(bs) - // Put EmptyObjectCid value in the store. When an actor is initially created its Head is set to this value. - _, err := cst.Put(context.TODO(), map[string]string{}) - if err != nil { - panic(err) - } - - treeImpl, err := state.NewStateTree(cst) - if err != nil { - panic(err) // Never returns error, the error return should be removed. - } - root, err := treeImpl.Flush(context.TODO()) - if err != nil { - panic(err) - } - return &StateWrapper{ - bs: bs, - ds: datastore.NewMapDatastore(), - cst: cst, - stateRoot: root, - } -} - -func (s *StateWrapper) NewVM() { - return -} - -func (s *StateWrapper) Root() cid.Cid { - return s.stateRoot -} - -// StoreGet the value at key from vm store -func (s *StateWrapper) StoreGet(key cid.Cid, out runtime.CBORUnmarshaler) error { - tree, err := state.LoadStateTree(s.cst, s.stateRoot) - if err != nil { - return err - } - return tree.Store.Get(context.Background(), key, out) -} - -// StorePut `value` into vm store -func (s *StateWrapper) StorePut(value runtime.CBORMarshaler) (cid.Cid, error) { - tree, err := state.LoadStateTree(s.cst, s.stateRoot) - if err != nil { - return cid.Undef, err - } - return tree.Store.Put(context.Background(), value) -} - -func (s *StateWrapper) Actor(addr address.Address) (vstate.Actor, error) { - tree, err := state.LoadStateTree(s.cst, s.stateRoot) - if err != nil { - return nil, err - } - fcActor, err := tree.GetActor(addr) - if err != nil { - return nil, err - } - return &actorWrapper{*fcActor}, nil -} - -func (s *StateWrapper) SetActorState(addr address.Address, balance abi.TokenAmount, actorState runtime.CBORMarshaler) (vstate.Actor, error) { - tree, err := state.LoadStateTree(s.cst, s.stateRoot) - if err != nil { - return nil, err - } - // actor should exist - act, err := tree.GetActor(addr) - if err != nil { - return nil, err - } - // add the state to the store and get a new head cid - actHead, err := tree.Store.Put(context.Background(), actorState) - if err != nil { - return nil, err - } - // update the actor object with new head and balance parameter - actr := &actorWrapper{types.Actor{ - Code: act.Code, - Nonce: act.Nonce, - // updates - Head: actHead, - Balance: balance, - }} - if err := tree.SetActor(addr, &actr.Actor); err != nil { - return nil, err - } - return actr, s.flush(tree) -} - -func (s *StateWrapper) CreateActor(code cid.Cid, addr address.Address, balance abi.TokenAmount, actorState runtime.CBORMarshaler) (vstate.Actor, address.Address, error) { - idAddr := addr - tree, err := state.LoadStateTree(s.cst, s.stateRoot) - if err != nil { - return nil, address.Undef, err - } - if addr.Protocol() != address.ID { - - actHead, err := tree.Store.Put(context.Background(), actorState) - if err != nil { - return nil, address.Undef, err - } - actr := &actorWrapper{types.Actor{ - Code: code, - Head: actHead, - Balance: balance, - }} - - idAddr, err = tree.RegisterNewAddress(addr) - if err != nil { - return nil, address.Undef, xerrors.Errorf("register new address for actor: %w", err) - } - - if err := tree.SetActor(addr, &actr.Actor); err != nil { - return nil, address.Undef, xerrors.Errorf("setting new actor for actor: %w", err) - } - } - - // store newState - head, err := tree.Store.Put(context.Background(), actorState) - if err != nil { - return nil, address.Undef, err - } - - // create and store actor object - a := types.Actor{ - Code: code, - Head: head, - Balance: balance, - } - if err := tree.SetActor(idAddr, &a); err != nil { - return nil, address.Undef, err - } - - return &actorWrapper{a}, idAddr, s.flush(tree) -} - -// Flushes a state tree to storage and sets this state's root to that tree's root CID. -func (s *StateWrapper) flush(tree *state.StateTree) (err error) { - s.stateRoot, err = tree.Flush(context.TODO()) - return -} - -// -// Actor Wrapper -// - -type actorWrapper struct { - types.Actor -} - -func (a *actorWrapper) Code() cid.Cid { - return a.Actor.Code -} - -func (a *actorWrapper) Head() cid.Cid { - return a.Actor.Head -} - -func (a *actorWrapper) CallSeqNum() uint64 { - return a.Actor.Nonce -} - -func (a *actorWrapper) Balance() big.Int { - return a.Actor.Balance - -} - -// -// Storage -// - -type contextStore struct { - cbor.IpldStore - ctx context.Context -} - -func (s *contextStore) Context() context.Context { - return s.ctx -} diff --git a/chain/vectors/gen/main.go b/chain/vectors/gen/main.go index ce8d137e800..ecc2498b98e 100644 --- a/chain/vectors/gen/main.go +++ b/chain/vectors/gen/main.go @@ -6,19 +6,20 @@ import ( "math/rand" "os" + "github.com/filecoin-project/specs-actors/actors/builtin/power" + "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/big" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/types" "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/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" - "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/crypto" _ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/secp" diff --git a/chain/vectors/vector_types.go b/chain/vectors/vector_types.go index 73216a049e7..7e014fb77cc 100644 --- a/chain/vectors/vector_types.go +++ b/chain/vectors/vector_types.go @@ -1,8 +1,8 @@ package vectors import ( + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/crypto" ) type HeaderVector struct { diff --git a/chain/vm/burn.go b/chain/vm/burn.go index e9b6802c143..eb0611349e8 100644 --- a/chain/vm/burn.go +++ b/chain/vm/burn.go @@ -1,8 +1,8 @@ package vm import ( - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" ) const ( diff --git a/chain/vm/gas.go b/chain/vm/gas.go index 72a7df8fc8c..12acf6a2145 100644 --- a/chain/vm/gas.go +++ b/chain/vm/gas.go @@ -3,10 +3,12 @@ package vm import ( "fmt" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/filecoin-project/go-address" addr "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/runtime" vmr "github.com/filecoin-project/specs-actors/actors/runtime" "github.com/ipfs/go-cid" @@ -77,8 +79,8 @@ type Pricelist interface { OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error) OnHashing(dataSize int) GasCharge OnComputeUnsealedSectorCid(proofType abi.RegisteredSealProof, pieces []abi.PieceInfo) GasCharge - OnVerifySeal(info abi.SealVerifyInfo) GasCharge - OnVerifyPost(info abi.WindowPoStVerifyInfo) GasCharge + OnVerifySeal(info proof.SealVerifyInfo) GasCharge + OnVerifyPost(info proof.WindowPoStVerifyInfo) GasCharge OnVerifyConsensusFault() GasCharge } @@ -183,7 +185,7 @@ func (ps pricedSyscalls) ComputeUnsealedSectorCID(reg abi.RegisteredSealProof, p } // Verifies a sector seal proof. -func (ps pricedSyscalls) VerifySeal(vi abi.SealVerifyInfo) error { +func (ps pricedSyscalls) VerifySeal(vi proof.SealVerifyInfo) error { ps.chargeGas(ps.pl.OnVerifySeal(vi)) defer ps.chargeGas(gasOnActorExec) @@ -191,7 +193,7 @@ func (ps pricedSyscalls) VerifySeal(vi abi.SealVerifyInfo) error { } // Verifies a proof of spacetime. -func (ps pricedSyscalls) VerifyPoSt(vi abi.WindowPoStVerifyInfo) error { +func (ps pricedSyscalls) VerifyPoSt(vi proof.WindowPoStVerifyInfo) error { ps.chargeGas(ps.pl.OnVerifyPost(vi)) defer ps.chargeGas(gasOnActorExec) @@ -215,7 +217,7 @@ func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte return ps.under.VerifyConsensusFault(h1, h2, extra) } -func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) { +func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]proof.SealVerifyInfo) (map[address.Address][]bool, error) { count := int64(0) for _, svis := range inp { count += int64(len(svis)) diff --git a/chain/vm/gas_v0.go b/chain/vm/gas_v0.go index f13710a1be1..e5ded440e7e 100644 --- a/chain/vm/gas_v0.go +++ b/chain/vm/gas_v0.go @@ -3,10 +3,12 @@ package vm import ( "fmt" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/crypto" ) type scalingCost struct { @@ -173,14 +175,14 @@ func (pl *pricelistV0) OnComputeUnsealedSectorCid(proofType abi.RegisteredSealPr } // OnVerifySeal -func (pl *pricelistV0) OnVerifySeal(info abi.SealVerifyInfo) GasCharge { +func (pl *pricelistV0) OnVerifySeal(info proof.SealVerifyInfo) GasCharge { // TODO: this needs more cost tunning, check with @lotus // this is not used return newGasCharge("OnVerifySeal", pl.verifySealBase, 0) } // OnVerifyPost -func (pl *pricelistV0) OnVerifyPost(info abi.WindowPoStVerifyInfo) GasCharge { +func (pl *pricelistV0) OnVerifyPost(info proof.WindowPoStVerifyInfo) GasCharge { sectorSize := "unknown" var proofType abi.RegisteredPoStProof diff --git a/chain/vm/invoker.go b/chain/vm/invoker.go index 56f769da2e0..c9d22cd4cde 100644 --- a/chain/vm/invoker.go +++ b/chain/vm/invoker.go @@ -6,15 +6,16 @@ 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/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "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" @@ -27,9 +28,6 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin/system" "github.com/filecoin-project/specs-actors/actors/runtime" vmr "github.com/filecoin-project/specs-actors/actors/runtime" - "github.com/filecoin-project/specs-actors/actors/util/adt" - - "github.com/filecoin-project/lotus/chain/actors/aerrors" ) type Invoker struct { @@ -47,7 +45,7 @@ func NewInvoker() *Invoker { } // add builtInCode using: register(cid, singleton) - inv.Register(builtin.SystemActorCodeID, system.Actor{}, adt.EmptyValue{}) + 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{}) @@ -116,7 +114,7 @@ func (*Invoker) transform(instance Invokee) (nativeCode, error) { return nil, newErr("first arguemnt should be vmr.Runtime") } if t.In(1).Kind() != reflect.Ptr { - return nil, newErr("second argument should be Runtime") + return nil, newErr("second argument should be of kind reflect.Ptr") } if t.NumOut() != 1 { @@ -130,6 +128,9 @@ func (*Invoker) transform(instance Invokee) (nativeCode, error) { } code := make(nativeCode, len(exports)) for id, m := range exports { + if m == nil { + continue + } meth := reflect.ValueOf(m) code[id] = reflect.MakeFunc(reflect.TypeOf((invokeFunc)(nil)), func(in []reflect.Value) []reflect.Value { diff --git a/chain/vm/invoker_test.go b/chain/vm/invoker_test.go index 55b27642195..3744aa8d2d9 100644 --- a/chain/vm/invoker_test.go +++ b/chain/vm/invoker_test.go @@ -5,15 +5,16 @@ import ( "io" "testing" + "github.com/filecoin-project/go-state-types/abi" + cbor "github.com/ipfs/go-ipld-cbor" "github.com/stretchr/testify/assert" cbg "github.com/whyrusleeping/cbor-gen" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/aerrors" "github.com/filecoin-project/specs-actors/actors/runtime" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" - "github.com/filecoin-project/specs-actors/actors/util/adt" ) type basicContract struct{} @@ -60,17 +61,17 @@ func (b basicContract) Exports() []interface{} { } } -func (basicContract) InvokeSomething0(rt runtime.Runtime, params *basicParams) *adt.EmptyValue { +func (basicContract) InvokeSomething0(rt runtime.Runtime, params *basicParams) *abi.EmptyValue { rt.Abortf(exitcode.ExitCode(params.B), "params.B") return nil } -func (basicContract) BadParam(rt runtime.Runtime, params *basicParams) *adt.EmptyValue { +func (basicContract) BadParam(rt runtime.Runtime, params *basicParams) *abi.EmptyValue { rt.Abortf(255, "bad params") return nil } -func (basicContract) InvokeSomething10(rt runtime.Runtime, params *basicParams) *adt.EmptyValue { +func (basicContract) InvokeSomething10(rt runtime.Runtime, params *basicParams) *abi.EmptyValue { rt.Abortf(exitcode.ExitCode(params.B+10), "params.B") return nil } diff --git a/chain/vm/mkactor.go b/chain/vm/mkactor.go index ef4382df169..43d2f943111 100644 --- a/chain/vm/mkactor.go +++ b/chain/vm/mkactor.go @@ -3,10 +3,10 @@ package vm import ( "context" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/lotus/chain/actors" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 99333fc044c..7e9dd894beb 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -8,15 +8,16 @@ import ( gruntime "runtime" "time" + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/runtime" vmr "github.com/filecoin-project/specs-actors/actors/runtime" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" - "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" cbg "github.com/whyrusleeping/cbor-gen" @@ -56,6 +57,10 @@ type Runtime struct { lastGasCharge *types.GasTrace } +func (rt *Runtime) NetworkVersion() network.Version { + return rt.vm.GetNtwkVersion(rt.ctx, rt.CurrEpoch()) +} + func (rt *Runtime) TotalFilCircSupply() abi.TokenAmount { cs, err := rt.vm.GetCircSupply(rt.ctx) if err != nil { @@ -132,7 +137,7 @@ func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act switch ret := ret.(type) { case []byte: return ret, nil - case *adt.EmptyValue: + case *abi.EmptyValue: return nil, nil case cbg.CBORMarshaler: buf := new(bytes.Buffer) @@ -341,7 +346,7 @@ func (rt *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMars if m != nil { buf := new(bytes.Buffer) if err := m.MarshalCBOR(buf); err != nil { - rt.Abortf(exitcode.SysErrInvalidParameters, "failed to marshal input parameters: %s", err) + rt.Abortf(exitcode.ErrSerialization, "failed to marshal input parameters: %s", err) } params = buf.Bytes() } diff --git a/chain/vm/runtime_test.go b/chain/vm/runtime_test.go index b5c75c177f7..2f9704394d2 100644 --- a/chain/vm/runtime_test.go +++ b/chain/vm/runtime_test.go @@ -8,7 +8,7 @@ import ( cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/lotus/chain/actors/aerrors" ) diff --git a/chain/vm/syscalls.go b/chain/vm/syscalls.go index 41ed9c76293..3e221f61f79 100644 --- a/chain/vm/syscalls.go +++ b/chain/vm/syscalls.go @@ -7,6 +7,8 @@ import ( goruntime "runtime" "sync" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/filecoin-project/go-address" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" @@ -14,12 +16,12 @@ import ( mh "github.com/multiformats/go-multihash" "golang.org/x/xerrors" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/sigs" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/runtime" "github.com/filecoin-project/specs-actors/actors/util/adt" @@ -213,7 +215,7 @@ func (ss *syscallShim) VerifyBlockSig(blk *types.BlockHeader) error { return nil } -func (ss *syscallShim) VerifyPoSt(proof abi.WindowPoStVerifyInfo) error { +func (ss *syscallShim) VerifyPoSt(proof proof.WindowPoStVerifyInfo) error { ok, err := ss.verifier.VerifyWindowPoSt(context.TODO(), proof) if err != nil { return err @@ -224,7 +226,7 @@ func (ss *syscallShim) VerifyPoSt(proof abi.WindowPoStVerifyInfo) error { return nil } -func (ss *syscallShim) VerifySeal(info abi.SealVerifyInfo) error { +func (ss *syscallShim) VerifySeal(info proof.SealVerifyInfo) error { //_, span := trace.StartSpan(ctx, "ValidatePoRep") //defer span.End() @@ -264,7 +266,7 @@ func (ss *syscallShim) VerifySignature(sig crypto.Signature, addr address.Addres var BatchSealVerifyParallelism = goruntime.NumCPU() -func (ss *syscallShim) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) { +func (ss *syscallShim) BatchVerifySeals(inp map[address.Address][]proof.SealVerifyInfo) (map[address.Address][]bool, error) { out := make(map[address.Address][]bool) sema := make(chan struct{}, BatchSealVerifyParallelism) @@ -276,7 +278,7 @@ func (ss *syscallShim) BatchVerifySeals(inp map[address.Address][]abi.SealVerify for i, s := range seals { wg.Add(1) - go func(ma address.Address, ix int, svi abi.SealVerifyInfo, res []bool) { + go func(ma address.Address, ix int, svi proof.SealVerifyInfo, res []bool) { defer wg.Done() sema <- struct{}{} diff --git a/chain/vm/validation_test.go b/chain/vm/validation_test.go deleted file mode 100644 index 880b3340173..00000000000 --- a/chain/vm/validation_test.go +++ /dev/null @@ -1,71 +0,0 @@ -package vm_test - -import ( - "fmt" - "reflect" - "runtime" - "strings" - "testing" - - suites "github.com/filecoin-project/chain-validation/suites" - - factory "github.com/filecoin-project/lotus/chain/validation" -) - -// TestSkipper contains a list of test cases skipped by the implementation. -type TestSkipper struct { - testSkips []suites.TestCase -} - -// Skip return true if the sutire.TestCase should be skipped. -func (ts *TestSkipper) Skip(test suites.TestCase) bool { - for _, skip := range ts.testSkips { - if reflect.ValueOf(skip).Pointer() == reflect.ValueOf(test).Pointer() { - fmt.Printf("=== SKIP %v\n", runtime.FuncForPC(reflect.ValueOf(test).Pointer()).Name()) - return true - } - } - return false -} - -// TestSuiteSkips contains tests we wish to skip. -var TestSuiteSkipper TestSkipper - -func init() { - // initialize the test skipper with tests being skipped - TestSuiteSkipper = TestSkipper{testSkips: []suites.TestCase{ - // tests to skip go here - }} -} - -func TestChainValidationMessageSuite(t *testing.T) { - f := factory.NewFactories() - for _, testCase := range suites.MessageTestCases() { - testCase := testCase - if TestSuiteSkipper.Skip(testCase) { - continue - } - t.Run(caseName(testCase), func(t *testing.T) { - testCase(t, f) - }) - } -} - -func TestChainValidationTipSetSuite(t *testing.T) { - f := factory.NewFactories() - for _, testCase := range suites.TipSetTestCases() { - testCase := testCase - if TestSuiteSkipper.Skip(testCase) { - continue - } - t.Run(caseName(testCase), func(t *testing.T) { - testCase(t, f) - }) - } -} - -func caseName(testCase suites.TestCase) string { - fqName := runtime.FuncForPC(reflect.ValueOf(testCase).Pointer()).Name() - toks := strings.Split(fqName, ".") - return toks[len(toks)-1] -} diff --git a/chain/vm/vm.go b/chain/vm/vm.go index f51cbff2938..e389a3531c4 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -7,9 +7,11 @@ import ( "reflect" "time" + "github.com/filecoin-project/go-state-types/network" + bstore "github.com/filecoin-project/lotus/lib/blockstore" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" block "github.com/ipfs/go-block-format" @@ -22,10 +24,10 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "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/account" - "github.com/filecoin-project/specs-actors/actors/crypto" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/aerrors" @@ -40,23 +42,23 @@ var actorLog = logging.Logger("actors") var gasOnActorExec = newGasCharge("OnActorExec", 0, 0) // 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, aerrors.ActorError) { +func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Address) (address.Address, error) { if addr.Protocol() == address.BLS || addr.Protocol() == address.SECP256K1 { return addr, nil } act, err := state.GetActor(addr) if err != nil { - return address.Undef, aerrors.Newf(exitcode.SysErrInvalidParameters, "failed to find actor: %s", addr) + return address.Undef, xerrors.Errorf("failed to find actor: %s", addr) } if act.Code != builtin.AccountActorCodeID { - return address.Undef, aerrors.Newf(exitcode.SysErrInvalidParameters, "address %s was not for an account actor", addr) + 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 { - return address.Undef, aerrors.Absorb(err, exitcode.SysErrInvalidParameters, fmt.Sprintf("failed to get account actor state for %s", addr)) + return address.Undef, xerrors.Errorf("failed to get account actor state for %s: %w", addr, err) } return aast.Address, nil @@ -140,6 +142,7 @@ func (vm *UnsafeVM) MakeRuntime(ctx context.Context, msg *types.Message, origin } type CircSupplyCalculator func(context.Context, abi.ChainEpoch, *state.StateTree) (abi.TokenAmount, error) +type NtwkVersionGetter func(context.Context, abi.ChainEpoch) network.Version type VM struct { cstate *state.StateTree @@ -150,6 +153,7 @@ type VM struct { inv *Invoker rand Rand circSupplyCalc CircSupplyCalculator + ntwkVersion NtwkVersionGetter baseFee abi.TokenAmount Syscalls SyscallBuilder @@ -162,6 +166,7 @@ type VMOpts struct { Bstore bstore.Blockstore Syscalls SyscallBuilder CircSupplyCalc CircSupplyCalculator + NtwkVersion NtwkVersionGetter BaseFee abi.TokenAmount } @@ -182,6 +187,7 @@ func NewVM(opts *VMOpts) (*VM, error) { inv: NewInvoker(), rand: opts.Rand, // TODO: Probably should be a syscall circSupplyCalc: opts.CircSupplyCalc, + ntwkVersion: opts.NtwkVersion, Syscalls: opts.Syscalls, baseFee: opts.BaseFee, }, nil @@ -716,6 +722,10 @@ func (vm *VM) SetInvoker(i *Invoker) { vm.inv = i } +func (vm *VM) GetNtwkVersion(ctx context.Context, ce abi.ChainEpoch) network.Version { + return vm.ntwkVersion(ctx, ce) +} + func (vm *VM) GetCircSupply(ctx context.Context) (abi.TokenAmount, error) { return vm.circSupplyCalc(ctx, vm.blockHeight, vm.cstate) } diff --git a/chain/wallet/wallet.go b/chain/wallet/wallet.go index 9c069d8192e..7cdb1929e98 100644 --- a/chain/wallet/wallet.go +++ b/chain/wallet/wallet.go @@ -6,7 +6,7 @@ import ( "strings" "sync" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" logging "github.com/ipfs/go-log/v2" "golang.org/x/xerrors" diff --git a/cli/chain.go b/cli/chain.go index 1d203639a98..36288c7d787 100644 --- a/cli/chain.go +++ b/cli/chain.go @@ -14,8 +14,8 @@ import ( "github.com/filecoin-project/go-address" cborutil "github.com/filecoin-project/go-cbor-util" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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/account" "github.com/filecoin-project/specs-actors/actors/builtin/market" @@ -337,25 +337,6 @@ var chainSetHeadCmd = &cli.Command{ }, } -func parseTipSet(ctx context.Context, api api.FullNode, vals []string) (*types.TipSet, error) { - var headers []*types.BlockHeader - for _, c := range vals { - blkc, err := cid.Decode(c) - if err != nil { - return nil, err - } - - bh, err := api.ChainGetBlock(ctx, blkc) - if err != nil { - return nil, err - } - - headers = append(headers, bh) - } - - return types.NewTipSet(headers) -} - var chainListCmd = &cli.Command{ Name: "list", Usage: "View a segment of the chain", @@ -863,6 +844,9 @@ var chainExportCmd = &cli.Command{ Name: "recent-stateroots", Usage: "specify the number of recent state roots to include in the export", }, + &cli.BoolFlag{ + Name: "skip-old-msgs", + }, }, Action: func(cctx *cli.Context) error { api, closer, err := GetFullNodeAPI(cctx) @@ -897,7 +881,13 @@ var chainExportCmd = &cli.Command{ return err } - stream, err := api.ChainExport(ctx, rsrs, ts.Key()) + skipold := cctx.Bool("skip-old-msgs") + + if rsrs == 0 && skipold { + return fmt.Errorf("must pass recent stateroots along with skip-old-msgs") + } + + stream, err := api.ChainExport(ctx, rsrs, skipold, ts.Key()) if err != nil { return err } diff --git a/cli/client.go b/cli/client.go index 17b24ba6a4b..e68f98791f8 100644 --- a/cli/client.go +++ b/cli/client.go @@ -27,8 +27,8 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-multistore" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" diff --git a/cli/log.go b/cli/log.go index b551b564583..ed624eb8df8 100644 --- a/cli/log.go +++ b/cli/log.go @@ -49,7 +49,7 @@ var logSetLevel = &cli.Command{ The system flag can be specified multiple times. - eg) log set-level --system chain --system blocksync debug + eg) log set-level --system chain --system chainxchg debug Available Levels: debug diff --git a/cli/mpool.go b/cli/mpool.go index 587246b87f6..65f4ef942c0 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -3,6 +3,7 @@ package cli import ( "encoding/json" "fmt" + stdbig "math/big" "sort" "strconv" @@ -10,8 +11,12 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + lapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/types" ) @@ -26,6 +31,7 @@ var mpoolCmd = &cli.Command{ mpoolReplaceCmd, mpoolFindCmd, mpoolConfig, + mpoolGasPerfCmd, }, } @@ -293,6 +299,14 @@ var mpoolReplaceCmd = &cli.Command{ Name: "gas-limit", Usage: "gas price for new message", }, + &cli.BoolFlag{ + Name: "auto", + Usage: "automatically reprice the specified message", + }, + &cli.StringFlag{ + Name: "max-fee", + Usage: "Spend up to X FIL for this message (applicable for auto mode)", + }, }, ArgsUsage: "[from] [nonce]", Action: func(cctx *cli.Context) error { @@ -342,15 +356,42 @@ var mpoolReplaceCmd = &cli.Command{ msg := found.Message - msg.GasLimit = cctx.Int64("gas-limit") - msg.GasPremium, err = types.BigFromString(cctx.String("gas-premium")) - if err != nil { - return fmt.Errorf("parsing gas-premium: %w", err) - } - // TODO: estimate fee cap here - msg.GasFeeCap, err = types.BigFromString(cctx.String("gas-feecap")) - if err != nil { - return fmt.Errorf("parsing gas-feecap: %w", err) + if cctx.Bool("auto") { + minRBF := messagepool.ComputeMinRBF(msg.GasPremium) + + var mss *lapi.MessageSendSpec + if cctx.IsSet("max-fee") { + maxFee, err := types.BigFromString(cctx.String("max-fee")) + if err != nil { + return fmt.Errorf("parsing max-spend: %w", err) + } + mss = &lapi.MessageSendSpec{ + MaxFee: maxFee, + } + } + + // msg.GasLimit = 0 // TODO: need to fix the way we estimate gas limits to account for the messages already being in the mempool + msg.GasFeeCap = abi.NewTokenAmount(0) + msg.GasPremium = abi.NewTokenAmount(0) + retm, err := api.GasEstimateMessageGas(ctx, &msg, mss, types.EmptyTSK) + if err != nil { + return fmt.Errorf("failed to estimate gas values: %w", err) + } + + msg.GasPremium = big.Max(retm.GasPremium, minRBF) + msg.GasFeeCap = big.Max(retm.GasFeeCap, msg.GasPremium) + messagepool.CapGasFee(&msg, mss.Get().MaxFee) + } else { + msg.GasLimit = cctx.Int64("gas-limit") + msg.GasPremium, err = types.BigFromString(cctx.String("gas-premium")) + if err != nil { + return fmt.Errorf("parsing gas-premium: %w", err) + } + // TODO: estimate fee cap here + msg.GasFeeCap, err = types.BigFromString(cctx.String("gas-feecap")) + if err != nil { + return fmt.Errorf("parsing gas-feecap: %w", err) + } } smsg, err := api.WalletSignMessage(ctx, msg.From, &msg) @@ -495,3 +536,86 @@ var mpoolConfig = &cli.Command{ return nil }, } + +var mpoolGasPerfCmd = &cli.Command{ + Name: "gas-perf", + Usage: "Check gas performance of messages in mempool", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "all", + Usage: "print gas performance for all mempool messages (default only prints for local)", + }, + }, + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := ReqContext(cctx) + + msgs, err := api.MpoolPending(ctx, types.EmptyTSK) + if err != nil { + return err + } + + var filter map[address.Address]struct{} + if !cctx.Bool("all") { + filter = map[address.Address]struct{}{} + + addrss, err := api.WalletList(ctx) + if err != nil { + return xerrors.Errorf("getting local addresses: %w", err) + } + + for _, a := range addrss { + filter[a] = struct{}{} + } + + var filtered []*types.SignedMessage + for _, msg := range msgs { + if _, has := filter[msg.Message.From]; !has { + continue + } + filtered = append(filtered, msg) + } + msgs = filtered + } + + ts, err := api.ChainHead(ctx) + if err != nil { + return xerrors.Errorf("failed to get chain head: %w", err) + } + + baseFee := ts.Blocks()[0].ParentBaseFee + + bigBlockGasLimit := big.NewInt(build.BlockGasLimit) + + getGasReward := func(msg *types.SignedMessage) big.Int { + maxPremium := types.BigSub(msg.Message.GasFeeCap, baseFee) + if types.BigCmp(maxPremium, msg.Message.GasPremium) < 0 { + maxPremium = msg.Message.GasPremium + } + return types.BigMul(maxPremium, types.NewInt(uint64(msg.Message.GasLimit))) + } + + getGasPerf := func(gasReward big.Int, gasLimit int64) float64 { + // gasPerf = gasReward * build.BlockGasLimit / gasLimit + a := new(stdbig.Rat).SetInt(new(stdbig.Int).Mul(gasReward.Int, bigBlockGasLimit.Int)) + b := stdbig.NewRat(1, gasLimit) + c := new(stdbig.Rat).Mul(a, b) + r, _ := c.Float64() + return r + } + + for _, m := range msgs { + gasReward := getGasReward(m) + gasPerf := getGasPerf(gasReward, m.Message.GasLimit) + + fmt.Printf("%s\t%d\t%s\t%f\n", m.Message.From, m.Message.Nonce, gasReward, gasPerf) + } + + return nil + }, +} diff --git a/cli/multisig.go b/cli/multisig.go index 57f6c2c0393..4596628f4fb 100644 --- a/cli/multisig.go +++ b/cli/multisig.go @@ -11,7 +11,7 @@ import ( "strconv" "text/tabwriter" - "github.com/filecoin-project/specs-actors/actors/abi" + "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" @@ -37,9 +37,13 @@ var multisigCmd = &cli.Command{ msigInspectCmd, msigProposeCmd, msigApproveCmd, + msigAddProposeCmd, + msigAddApproveCmd, + msigAddCancelCmd, msigSwapProposeCmd, msigSwapApproveCmd, msigSwapCancelCmd, + msigVestedCmd, }, } @@ -506,6 +510,236 @@ var msigApproveCmd = &cli.Command{ }, } +var msigAddProposeCmd = &cli.Command{ + Name: "add-propose", + Usage: "Propose to add a signer", + ArgsUsage: "[multisigAddress signer]", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "increase-threshold", + Usage: "whether the number of required signers should be increased", + }, + &cli.StringFlag{ + Name: "from", + Usage: "account to send the propose message from", + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 2 { + return ShowHelp(cctx, fmt.Errorf("must pass multisig address and signer address")) + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + msig, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return err + } + + addr, err := address.NewFromString(cctx.Args().Get(1)) + if err != nil { + return err + } + + var from address.Address + if cctx.IsSet("from") { + f, err := address.NewFromString(cctx.String("from")) + if err != nil { + return err + } + from = f + } else { + defaddr, err := api.WalletDefaultAddress(ctx) + if err != nil { + return err + } + from = defaddr + } + + msgCid, err := api.MsigAddPropose(ctx, msig, from, addr, cctx.Bool("increase-threshold")) + if err != nil { + return err + } + + fmt.Println("sent add proposal in message: ", msgCid) + + wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence) + if err != nil { + return err + } + + if wait.Receipt.ExitCode != 0 { + return fmt.Errorf("add proposal returned exit %d", wait.Receipt.ExitCode) + } + + return nil + }, +} + +var msigAddApproveCmd = &cli.Command{ + Name: "add-approve", + Usage: "Approve a message to add a signer", + ArgsUsage: "[multisigAddress proposerAddress txId newAddress increaseThreshold]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "from", + Usage: "account to send the approve message from", + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 5 { + return ShowHelp(cctx, fmt.Errorf("must pass multisig address, proposer address, transaction id, new signer address, whether to increase threshold")) + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + msig, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return err + } + + prop, err := address.NewFromString(cctx.Args().Get(1)) + if err != nil { + return err + } + + txid, err := strconv.ParseUint(cctx.Args().Get(2), 10, 64) + if err != nil { + return err + } + + newAdd, err := address.NewFromString(cctx.Args().Get(3)) + if err != nil { + return err + } + + inc, err := strconv.ParseBool(cctx.Args().Get(4)) + if err != nil { + return err + } + + var from address.Address + if cctx.IsSet("from") { + f, err := address.NewFromString(cctx.String("from")) + if err != nil { + return err + } + from = f + } else { + defaddr, err := api.WalletDefaultAddress(ctx) + if err != nil { + return err + } + from = defaddr + } + + msgCid, err := api.MsigAddApprove(ctx, msig, from, txid, prop, newAdd, inc) + if err != nil { + return err + } + + fmt.Println("sent add approval in message: ", msgCid) + + wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence) + if err != nil { + return err + } + + if wait.Receipt.ExitCode != 0 { + return fmt.Errorf("add approval returned exit %d", wait.Receipt.ExitCode) + } + + return nil + }, +} + +var msigAddCancelCmd = &cli.Command{ + Name: "add-cancel", + Usage: "Cancel a message to add a signer", + ArgsUsage: "[multisigAddress txId newAddress increaseThreshold]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "from", + Usage: "account to send the approve message from", + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 4 { + return ShowHelp(cctx, fmt.Errorf("must pass multisig address, transaction id, new signer address, whether to increase threshold")) + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + msig, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return err + } + + txid, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64) + if err != nil { + return err + } + + newAdd, err := address.NewFromString(cctx.Args().Get(2)) + if err != nil { + return err + } + + inc, err := strconv.ParseBool(cctx.Args().Get(3)) + if err != nil { + return err + } + + var from address.Address + if cctx.IsSet("from") { + f, err := address.NewFromString(cctx.String("from")) + if err != nil { + return err + } + from = f + } else { + defaddr, err := api.WalletDefaultAddress(ctx) + if err != nil { + return err + } + from = defaddr + } + + msgCid, err := api.MsigAddCancel(ctx, msig, from, txid, newAdd, inc) + if err != nil { + return err + } + + fmt.Println("sent add cancellation in message: ", msgCid) + + wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence) + if err != nil { + return err + } + + if wait.Receipt.ExitCode != 0 { + return fmt.Errorf("add cancellation returned exit %d", wait.Receipt.ExitCode) + } + + return nil + }, +} + var msigSwapProposeCmd = &cli.Command{ Name: "swap-propose", Usage: "Propose to swap signers", @@ -722,7 +956,7 @@ var msigSwapCancelCmd = &cli.Command{ return err } - fmt.Println("sent swap approval in message: ", msgCid) + fmt.Println("sent swap cancellation in message: ", msgCid) wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence) if err != nil { @@ -730,9 +964,71 @@ var msigSwapCancelCmd = &cli.Command{ } if wait.Receipt.ExitCode != 0 { - return fmt.Errorf("swap approval returned exit %d", wait.Receipt.ExitCode) + return fmt.Errorf("swap cancellation returned exit %d", wait.Receipt.ExitCode) + } + + return nil + }, +} + +var msigVestedCmd = &cli.Command{ + Name: "vested", + Usage: "Gets the amount vested in an msig between two epochs", + ArgsUsage: "[multisigAddress]", + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "start-epoch", + Usage: "start epoch to measure vesting from", + Value: 0, + }, + &cli.Int64Flag{ + Name: "end-epoch", + Usage: "end epoch to stop measure vesting at", + Value: -1, + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 1 { + return ShowHelp(cctx, fmt.Errorf("must pass multisig address")) } + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + msig, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return err + } + + start, err := api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Int64("start-epoch")), types.EmptyTSK) + if err != nil { + return err + } + + var end *types.TipSet + if cctx.Int64("end-epoch") < 0 { + end, err = LoadTipSet(ctx, cctx, api) + if err != nil { + return err + } + } else { + end, err = api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Int64("end-epoch")), types.EmptyTSK) + if err != nil { + return err + } + } + + ret, err := api.MsigGetVested(ctx, msig, start.Key(), end.Key()) + if err != nil { + return err + } + + fmt.Printf("Vested: %s between %d and %d\n", types.FIL(ret), start.Height(), end.Height()) + return nil }, } diff --git a/cli/net.go b/cli/net.go index f3b5ae2e938..9c40c70c7d7 100644 --- a/cli/net.go +++ b/cli/net.go @@ -8,12 +8,17 @@ import ( "strings" "text/tabwriter" + "github.com/dustin/go-humanize" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + "github.com/libp2p/go-libp2p-core/peer" protocol "github.com/libp2p/go-libp2p-core/protocol" + "github.com/multiformats/go-multiaddr" - "github.com/dustin/go-humanize" - "github.com/urfave/cli/v2" + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/addrutil" ) @@ -141,7 +146,7 @@ var NetListen = &cli.Command{ var netConnect = &cli.Command{ Name: "connect", Usage: "Connect to a peer", - ArgsUsage: "[peerMultiaddr]", + ArgsUsage: "[peerMultiaddr|minerActorAddress]", Action: func(cctx *cli.Context) error { api, closer, err := GetAPI(cctx) if err != nil { @@ -152,7 +157,43 @@ var netConnect = &cli.Command{ pis, err := addrutil.ParseAddresses(ctx, cctx.Args().Slice()) if err != nil { - return err + a, perr := address.NewFromString(cctx.Args().First()) + if perr != nil { + return err + } + + na, fc, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer fc() + + mi, err := na.StateMinerInfo(ctx, a, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting miner info: %w", err) + } + + if mi.PeerId == nil { + return xerrors.Errorf("no PeerID for miner") + } + multiaddrs := make([]multiaddr.Multiaddr, 0, len(mi.Multiaddrs)) + for i, a := range mi.Multiaddrs { + maddr, err := multiaddr.NewMultiaddrBytes(a) + if err != nil { + log.Warnf("parsing multiaddr %d (%x): %s", i, a, err) + continue + } + multiaddrs = append(multiaddrs, maddr) + } + + pi := peer.AddrInfo{ + ID: *mi.PeerId, + Addrs: multiaddrs, + } + + fmt.Printf("%s -> %s\n", a, pi) + + pis = append(pis, pi) } for _, pi := range pis { diff --git a/cli/paych.go b/cli/paych.go index 11b550cc6ba..57fd1c142ae 100644 --- a/cli/paych.go +++ b/cli/paych.go @@ -8,6 +8,8 @@ import ( "sort" "strings" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/paychmgr" "github.com/filecoin-project/go-address" @@ -26,6 +28,7 @@ var paychCmd = &cli.Command{ paychListCmd, paychVoucherCmd, paychSettleCmd, + paychStatusCmd, paychCloseCmd, }, } @@ -34,6 +37,14 @@ var paychAddFundsCmd = &cli.Command{ Name: "add-funds", Usage: "Add funds to the payment channel between fromAddress and toAddress. Creates the payment channel if it doesn't already exist.", ArgsUsage: "[fromAddress toAddress amount]", + Flags: []cli.Flag{ + + &cli.BoolFlag{ + Name: "restart-retrievals", + Usage: "restart stalled retrieval deals on this payment channel", + Value: true, + }, + }, Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 3 { return ShowHelp(cctx, fmt.Errorf("must pass three arguments: ")) @@ -76,17 +87,21 @@ var paychAddFundsCmd = &cli.Command{ } fmt.Fprintln(cctx.App.Writer, chAddr) + restartRetrievals := cctx.Bool("restart-retrievals") + if restartRetrievals { + return api.ClientRetrieveTryRestartInsufficientFunds(ctx, chAddr) + } return nil }, } -var paychStatusCmd = &cli.Command{ - Name: "status", - Usage: "Show the status of an outbound payment channel between fromAddress and toAddress", +var paychStatusByFromToCmd = &cli.Command{ + Name: "status-by-from-to", + Usage: "Show the status of an active outbound payment channel by from/to addresses", ArgsUsage: "[fromAddress toAddress]", Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 2 { - return ShowHelp(cctx, fmt.Errorf("must pass two arguments: ")) + return ShowHelp(cctx, fmt.Errorf("must pass two arguments: ")) } from, err := address.NewFromString(cctx.Args().Get(0)) @@ -105,52 +120,86 @@ var paychStatusCmd = &cli.Command{ } defer closer() - avail, err := api.PaychAvailableFunds(from, to) + avail, err := api.PaychAvailableFundsByFromTo(from, to) if err != nil { return err } - if avail.Channel == nil { - if avail.PendingWaitSentinel != nil { - fmt.Fprint(cctx.App.Writer, "Creating channel\n") - fmt.Fprintf(cctx.App.Writer, " From: %s\n", from) - fmt.Fprintf(cctx.App.Writer, " To: %s\n", to) - fmt.Fprintf(cctx.App.Writer, " Pending Amt: %d\n", avail.PendingAmt) - fmt.Fprintf(cctx.App.Writer, " Wait Sentinel: %s\n", avail.PendingWaitSentinel) - return nil - } - fmt.Fprint(cctx.App.Writer, "Channel does not exist\n") - fmt.Fprintf(cctx.App.Writer, " From: %s\n", from) - fmt.Fprintf(cctx.App.Writer, " To: %s\n", to) - return nil + paychStatus(cctx.App.Writer, avail) + return nil + }, +} + +var paychStatusCmd = &cli.Command{ + Name: "status", + Usage: "Show the status of an outbound payment channel", + ArgsUsage: "[channelAddress]", + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 1 { + return ShowHelp(cctx, fmt.Errorf("must pass an argument: ")) } - if avail.PendingWaitSentinel != nil { - fmt.Fprint(cctx.App.Writer, "Adding Funds to channel\n") - } else { - fmt.Fprint(cctx.App.Writer, "Channel exists\n") + ch, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return ShowHelp(cctx, fmt.Errorf("failed to parse channel address: %s", err)) } - nameValues := [][]string{ - {"Channel", avail.Channel.String()}, - {"From", from.String()}, - {"To", to.String()}, - {"Confirmed Amt", fmt.Sprintf("%d", avail.ConfirmedAmt)}, - {"Pending Amt", fmt.Sprintf("%d", avail.PendingAmt)}, - {"Queued Amt", fmt.Sprintf("%d", avail.QueuedAmt)}, - {"Voucher Redeemed Amt", fmt.Sprintf("%d", avail.VoucherReedeemedAmt)}, + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err } - if avail.PendingWaitSentinel != nil { - nameValues = append(nameValues, []string{ - "Add Funds Wait Sentinel", - avail.PendingWaitSentinel.String(), - }) + defer closer() + + avail, err := api.PaychAvailableFunds(ch) + if err != nil { + return err } - fmt.Fprint(cctx.App.Writer, formatNameValues(nameValues)) + + paychStatus(cctx.App.Writer, avail) return nil }, } +func paychStatus(writer io.Writer, avail *api.ChannelAvailableFunds) { + if avail.Channel == nil { + if avail.PendingWaitSentinel != nil { + fmt.Fprint(writer, "Creating channel\n") + fmt.Fprintf(writer, " From: %s\n", avail.From) + fmt.Fprintf(writer, " To: %s\n", avail.To) + fmt.Fprintf(writer, " Pending Amt: %d\n", avail.PendingAmt) + fmt.Fprintf(writer, " Wait Sentinel: %s\n", avail.PendingWaitSentinel) + return + } + fmt.Fprint(writer, "Channel does not exist\n") + fmt.Fprintf(writer, " From: %s\n", avail.From) + fmt.Fprintf(writer, " To: %s\n", avail.To) + return + } + + if avail.PendingWaitSentinel != nil { + fmt.Fprint(writer, "Adding Funds to channel\n") + } else { + fmt.Fprint(writer, "Channel exists\n") + } + + nameValues := [][]string{ + {"Channel", avail.Channel.String()}, + {"From", avail.From.String()}, + {"To", avail.To.String()}, + {"Confirmed Amt", fmt.Sprintf("%d", avail.ConfirmedAmt)}, + {"Pending Amt", fmt.Sprintf("%d", avail.PendingAmt)}, + {"Queued Amt", fmt.Sprintf("%d", avail.QueuedAmt)}, + {"Voucher Redeemed Amt", fmt.Sprintf("%d", avail.VoucherReedeemedAmt)}, + } + if avail.PendingWaitSentinel != nil { + nameValues = append(nameValues, []string{ + "Add Funds Wait Sentinel", + avail.PendingWaitSentinel.String(), + }) + } + fmt.Fprint(writer, formatNameValues(nameValues)) +} + func formatNameValues(nameValues [][]string) string { maxLen := 0 for _, nv := range nameValues { diff --git a/cli/paych_test.go b/cli/paych_test.go index d4089c4abaf..cccc80ff420 100644 --- a/cli/paych_test.go +++ b/cli/paych_test.go @@ -14,7 +14,7 @@ import ( "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" @@ -30,10 +30,10 @@ import ( "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/filecoin-project/specs-actors/actors/abi" "github.com/stretchr/testify/require" "github.com/urfave/cli/v2" ) @@ -117,7 +117,7 @@ func TestPaymentChannelStatus(t *testing.T) { creatorCLI := mockCLI.client(paymentCreator.ListenAddr) cmd := []string{creatorAddr.String(), receiverAddr.String()} - out := creatorCLI.runCmd(paychStatusCmd, cmd) + out := creatorCLI.runCmd(paychStatusByFromToCmd, cmd) fmt.Println(out) noChannelState := "Channel does not exist" require.Regexp(t, regexp.MustCompile(noChannelState), out) @@ -133,7 +133,7 @@ func TestPaymentChannelStatus(t *testing.T) { // Wait for the output to stop being "Channel does not exist" for regexp.MustCompile(noChannelState).MatchString(out) { cmd = []string{creatorAddr.String(), receiverAddr.String()} - out = creatorCLI.runCmd(paychStatusCmd, cmd) + out = creatorCLI.runCmd(paychStatusByFromToCmd, cmd) } fmt.Println(out) @@ -153,7 +153,7 @@ func TestPaymentChannelStatus(t *testing.T) { // Wait for create channel to complete chstr := <-create - cmd = []string{creatorAddr.String(), receiverAddr.String()} + cmd = []string{chstr} out = creatorCLI.runCmd(paychStatusCmd, cmd) fmt.Println(out) // Output should have the channel address @@ -169,7 +169,7 @@ func TestPaymentChannelStatus(t *testing.T) { cmd = []string{chAddr.String(), fmt.Sprintf("%d", voucherAmt)} creatorCLI.runCmd(paychVoucherCreateCmd, cmd) - cmd = []string{creatorAddr.String(), receiverAddr.String()} + cmd = []string{chstr} out = creatorCLI.runCmd(paychStatusCmd, cmd) fmt.Println(out) voucherAmtAtto := types.BigMul(types.NewInt(voucherAmt), types.NewInt(build.FilecoinPrecision)) diff --git a/cli/send.go b/cli/send.go index ecec4219170..14c1b263b01 100644 --- a/cli/send.go +++ b/cli/send.go @@ -12,7 +12,7 @@ import ( cbg "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/stmgr" @@ -173,7 +173,12 @@ func decodeTypedParams(ctx context.Context, fapi api.FullNode, to address.Addres return nil, err } - p := reflect.New(stmgr.MethodsMap[act.Code][method].Params.Elem()).Interface().(cbg.CBORMarshaler) + methodMeta, found := stmgr.MethodsMap[act.Code][method] + if !found { + return nil, fmt.Errorf("method %d not found on actor %s", method, act.Code) + } + + p := reflect.New(methodMeta.Params.Elem()).Interface().(cbg.CBORMarshaler) if err := json.Unmarshal([]byte(paramstr), p); err != nil { return nil, fmt.Errorf("unmarshaling input into params type: %w", err) diff --git a/cli/state.go b/cli/state.go index a0256c2e364..1036e8fe53c 100644 --- a/cli/state.go +++ b/cli/state.go @@ -14,6 +14,8 @@ import ( "strings" "time" + "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/multiformats/go-multiaddr" "github.com/ipfs/go-cid" @@ -24,10 +26,11 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "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/exported" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" @@ -120,7 +123,7 @@ var stateMinerInfo = &cli.Command{ }, } -func parseTipSetString(ts string) ([]cid.Cid, error) { +func ParseTipSetString(ts string) ([]cid.Cid, error) { strs := strings.Split(ts, ",") var cids []cid.Cid @@ -158,7 +161,7 @@ func ParseTipSetRef(ctx context.Context, api api.FullNode, tss string) (*types.T return api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(h), types.EmptyTSK) } - cids, err := parseTipSetString(tss) + cids, err := ParseTipSetString(tss) if err != nil { return nil, err } @@ -1167,7 +1170,11 @@ func sumGas(changes []*types.GasTrace) types.GasTrace { } func jsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, error) { - re := reflect.New(stmgr.MethodsMap[code][method].Params.Elem()) + methodMeta, found := stmgr.MethodsMap[code][method] + if !found { + return "", fmt.Errorf("method %d not found on actor %s", method, code) + } + re := reflect.New(methodMeta.Params.Elem()) p := re.Interface().(cbg.CBORUnmarshaler) if err := p.UnmarshalCBOR(bytes.NewReader(params)); err != nil { return "", err @@ -1178,7 +1185,11 @@ func jsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, erro } func jsonReturn(code cid.Cid, method abi.MethodNum, ret []byte) (string, error) { - re := reflect.New(stmgr.MethodsMap[code][method].Ret.Elem()) + methodMeta, found := stmgr.MethodsMap[code][method] + if !found { + return "", fmt.Errorf("method %d not found on actor %s", method, code) + } + re := reflect.New(methodMeta.Ret.Elem()) p := re.Interface().(cbg.CBORUnmarshaler) if err := p.UnmarshalCBOR(bytes.NewReader(ret)); err != nil { return "", err @@ -1374,7 +1385,7 @@ var stateCallCmd = &cli.Command{ } if ret.MsgRct.ExitCode != 0 { - return fmt.Errorf("invocation failed (exit: %d): %s", ret.MsgRct.ExitCode, ret.Error) + return fmt.Errorf("invocation failed (exit: %d, gasUsed: %d): %s", ret.MsgRct.ExitCode, ret.MsgRct.GasUsed, ret.Error) } s, err := formatOutput(cctx.String("ret"), ret.MsgRct.Return) @@ -1382,6 +1393,7 @@ var stateCallCmd = &cli.Command{ return fmt.Errorf("failed to format output: %s", err) } + fmt.Printf("gas used: %d\n", ret.MsgRct.GasUsed) fmt.Printf("return: %s\n", s) return nil @@ -1438,7 +1450,7 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er return nil, nil } - var target abi.Invokee + var target runtime.Invokee for _, actor := range exported.BuiltinActors() { if actor.Code() == act { target = actor @@ -1455,11 +1467,11 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er f := methods[method] rf := reflect.TypeOf(f) - if rf.NumIn() != 3 { + if rf.NumIn() != 2 { return nil, fmt.Errorf("expected referenced method to have three arguments") } - paramObj := rf.In(2).Elem() + paramObj := rf.In(1).Elem() if paramObj.NumField() != len(args) { return nil, fmt.Errorf("not enough arguments given to call that method (expecting %d)", paramObj.NumField()) } @@ -1479,6 +1491,18 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er return nil, err } p.Elem().Field(i).Set(reflect.ValueOf(val)) + case reflect.TypeOf(abi.ChainEpoch(0)): + val, err := strconv.ParseInt(args[i], 10, 64) + if err != nil { + return nil, err + } + p.Elem().Field(i).Set(reflect.ValueOf(abi.ChainEpoch(val))) + case reflect.TypeOf(big.Int{}): + val, err := big.FromString(args[i]) + if err != nil { + return nil, err + } + p.Elem().Field(i).Set(reflect.ValueOf(val)) case reflect.TypeOf(peer.ID("")): pid, err := peer.Decode(args[i]) if err != nil { diff --git a/cli/sync.go b/cli/sync.go index 27957ac3525..bff34960e19 100644 --- a/cli/sync.go +++ b/cli/sync.go @@ -5,13 +5,14 @@ import ( "fmt" "time" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/lotus/chain/types" + + "github.com/filecoin-project/go-state-types/abi" cid "github.com/ipfs/go-cid" "github.com/urfave/cli/v2" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain" ) var syncCmd = &cli.Command{ @@ -21,7 +22,9 @@ var syncCmd = &cli.Command{ syncStatusCmd, syncWaitCmd, syncMarkBadCmd, + syncUnmarkBadCmd, syncCheckBadCmd, + syncCheckpointCmd, }, } @@ -61,7 +64,7 @@ var syncStatusCmd = &cli.Command{ fmt.Printf("\tBase:\t%s\n", base) fmt.Printf("\tTarget:\t%s (%d)\n", target, theight) fmt.Printf("\tHeight diff:\t%d\n", heightDiff) - fmt.Printf("\tStage: %s\n", chain.SyncStageString(ss.Stage)) + fmt.Printf("\tStage: %s\n", ss.Stage) fmt.Printf("\tHeight: %d\n", ss.Height) if ss.End.IsZero() { if !ss.Start.IsZero() { @@ -118,6 +121,31 @@ var syncMarkBadCmd = &cli.Command{ }, } +var syncUnmarkBadCmd = &cli.Command{ + Name: "unmark-bad", + Usage: "Unmark the given block as bad, makes it possible to sync to a chain containing it", + ArgsUsage: "[blockCid]", + Action: func(cctx *cli.Context) error { + napi, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + if !cctx.Args().Present() { + return fmt.Errorf("must specify block cid to unmark") + } + + bcid, err := cid.Decode(cctx.Args().First()) + if err != nil { + return fmt.Errorf("failed to decode input as a cid: %s", err) + } + + return napi.SyncUnmarkBad(ctx, bcid) + }, +} + var syncCheckBadCmd = &cli.Command{ Name: "check-bad", Usage: "check if the given block was marked bad, and for what reason", @@ -154,6 +182,48 @@ var syncCheckBadCmd = &cli.Command{ }, } +var syncCheckpointCmd = &cli.Command{ + Name: "checkpoint", + Usage: "mark a certain tipset as checkpointed; the node will never fork away from this tipset", + ArgsUsage: "[tipsetKey]", + Flags: []cli.Flag{ + &cli.Uint64Flag{ + Name: "epoch", + Usage: "checkpoint the tipset at the given epoch", + }, + }, + Action: func(cctx *cli.Context) error { + napi, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + var ts *types.TipSet + + if cctx.IsSet("epoch") { + ts, err = napi.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Uint64("epoch")), types.EmptyTSK) + } + if ts == nil { + ts, err = parseTipSet(ctx, napi, cctx.Args().Slice()) + } + if err != nil { + return err + } + + if ts == nil { + return fmt.Errorf("must pass cids for tipset to set as head, or specify epoch flag") + } + + if err := napi.SyncCheckpoint(ctx, ts.Key()); err != nil { + return err + } + + return nil + }, +} + func SyncWait(ctx context.Context, napi api.FullNode) error { for { state, err := napi.SyncState(ctx) @@ -186,7 +256,7 @@ func SyncWait(ctx context.Context, napi api.FullNode) error { theight = ss.Target.Height() } - fmt.Printf("\r\x1b[2KWorker %d: Target Height: %d\tTarget: %s\tState: %s\tHeight: %d", working, theight, target, chain.SyncStageString(ss.Stage), ss.Height) + fmt.Printf("\r\x1b[2KWorker %d: Target Height: %d\tTarget: %s\tState: %s\tHeight: %d", working, theight, target, ss.Stage, ss.Height) if time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs) { fmt.Println("\nDone!") diff --git a/cli/util.go b/cli/util.go new file mode 100644 index 00000000000..4371f8bbc6b --- /dev/null +++ b/cli/util.go @@ -0,0 +1,28 @@ +package cli + +import ( + "context" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" + "github.com/ipfs/go-cid" +) + +func parseTipSet(ctx context.Context, api api.FullNode, vals []string) (*types.TipSet, error) { + var headers []*types.BlockHeader + for _, c := range vals { + blkc, err := cid.Decode(c) + if err != nil { + return nil, err + } + + bh, err := api.ChainGetBlock(ctx, blkc) + if err != nil { + return nil, err + } + + headers = append(headers, bh) + } + + return types.NewTipSet(headers) +} diff --git a/cli/wallet.go b/cli/wallet.go index 025e3a7b62f..4339a1fb6a4 100644 --- a/cli/wallet.go +++ b/cli/wallet.go @@ -10,9 +10,9 @@ import ( "strings" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/crypto" types "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" - "github.com/filecoin-project/specs-actors/actors/crypto" "golang.org/x/xerrors" "github.com/urfave/cli/v2" diff --git a/cmd/chain-noise/main.go b/cmd/chain-noise/main.go index 9e9ac2e49fd..7b982401615 100644 --- a/cmd/chain-noise/main.go +++ b/cmd/chain-noise/main.go @@ -7,7 +7,7 @@ import ( "os" "time" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/api" diff --git a/cmd/lotus-bench/import.go b/cmd/lotus-bench/import.go index 7400cd92ed9..7fe63eae19f 100644 --- a/cmd/lotus-bench/import.go +++ b/cmd/lotus-bench/import.go @@ -25,8 +25,8 @@ import ( _ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/secp" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/ipfs/go-datastore" badger "github.com/ipfs/go-ds-badger2" diff --git a/cmd/lotus-bench/main.go b/cmd/lotus-bench/main.go index 694987f27bc..431bfdd4472 100644 --- a/cmd/lotus-bench/main.go +++ b/cmd/lotus-bench/main.go @@ -11,6 +11,8 @@ import ( "path/filepath" "time" + saproof "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/docker/go-units" logging "github.com/ipfs/go-log/v2" "github.com/minio/blake2b-simd" @@ -20,11 +22,11 @@ import ( "github.com/filecoin-project/go-address" paramfetch "github.com/filecoin-project/go-paramfetch" + "github.com/filecoin-project/go-state-types/abi" lcli "github.com/filecoin-project/lotus/cli" "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/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-storage/storage" @@ -235,7 +237,7 @@ var sealBenchCmd = &cli.Command{ } var sealTimings []SealingResult - var sealedSectors []abi.SectorInfo + var sealedSectors []saproof.SectorInfo if robench == "" { var err error @@ -278,7 +280,7 @@ var sealBenchCmd = &cli.Command{ } for _, s := range genm.Sectors { - sealedSectors = append(sealedSectors, abi.SectorInfo{ + sealedSectors = append(sealedSectors, saproof.SectorInfo{ SealedCID: s.CommR, SectorNumber: s.SectorID, SealProof: s.ProofType, @@ -303,7 +305,7 @@ var sealBenchCmd = &cli.Command{ return err } - candidates := make([]abi.SectorInfo, len(fcandidates)) + candidates := make([]saproof.SectorInfo, len(fcandidates)) for i, fcandidate := range fcandidates { candidates[i] = sealedSectors[fcandidate] } @@ -326,7 +328,7 @@ var sealBenchCmd = &cli.Command{ winnningpost2 := time.Now() - pvi1 := abi.WinningPoStVerifyInfo{ + pvi1 := saproof.WinningPoStVerifyInfo{ Randomness: abi.PoStRandomness(challenge[:]), Proofs: proof1, ChallengedSectors: candidates, @@ -342,7 +344,7 @@ var sealBenchCmd = &cli.Command{ verifyWinningPost1 := time.Now() - pvi2 := abi.WinningPoStVerifyInfo{ + pvi2 := saproof.WinningPoStVerifyInfo{ Randomness: abi.PoStRandomness(challenge[:]), Proofs: proof2, ChallengedSectors: candidates, @@ -374,7 +376,7 @@ var sealBenchCmd = &cli.Command{ windowpost2 := time.Now() - wpvi1 := abi.WindowPoStVerifyInfo{ + wpvi1 := saproof.WindowPoStVerifyInfo{ Randomness: challenge[:], Proofs: wproof1, ChallengedSectors: sealedSectors, @@ -390,7 +392,7 @@ var sealBenchCmd = &cli.Command{ verifyWindowpost1 := time.Now() - wpvi2 := abi.WindowPoStVerifyInfo{ + wpvi2 := saproof.WindowPoStVerifyInfo{ Randomness: challenge[:], Proofs: wproof2, ChallengedSectors: sealedSectors, @@ -462,10 +464,10 @@ type ParCfg struct { Commit int } -func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, par ParCfg, mid abi.ActorID, sectorSize abi.SectorSize, ticketPreimage []byte, saveC2inp string, skipc2, skipunseal bool) ([]SealingResult, []abi.SectorInfo, error) { +func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, par ParCfg, mid abi.ActorID, sectorSize abi.SectorSize, ticketPreimage []byte, saveC2inp string, skipc2, skipunseal bool) ([]SealingResult, []saproof.SectorInfo, error) { var pieces []abi.PieceInfo sealTimings := make([]SealingResult, numSectors) - sealedSectors := make([]abi.SectorInfo, numSectors) + sealedSectors := make([]saproof.SectorInfo, numSectors) preCommit2Sema := make(chan struct{}, par.PreCommit2) commitSema := make(chan struct{}, par.Commit) @@ -535,7 +537,7 @@ func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, par precommit2 := time.Now() <-preCommit2Sema - sealedSectors[ix] = abi.SectorInfo{ + sealedSectors[ix] = saproof.SectorInfo{ SealProof: sb.SealProofType(), SectorNumber: i, SealedCID: cids.Sealed, @@ -587,7 +589,7 @@ func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, par <-commitSema if !skipc2 { - svi := abi.SealVerifyInfo{ + svi := saproof.SealVerifyInfo{ SectorID: abi.SectorID{Miner: mid, Number: i}, SealedCID: cids.Sealed, SealProof: sb.SealProofType(), diff --git a/cmd/lotus-chainwatch/processor/miner.go b/cmd/lotus-chainwatch/processor/miner.go index 13f63723744..e063db19f3c 100644 --- a/cmd/lotus-chainwatch/processor/miner.go +++ b/cmd/lotus-chainwatch/processor/miner.go @@ -13,8 +13,8 @@ import ( "golang.org/x/sync/errgroup" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/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" @@ -168,11 +168,11 @@ type SectorDealEvent struct { } type PartitionStatus struct { - Terminated abi.BitField - Expired abi.BitField - Faulted abi.BitField - InRecovery abi.BitField - Recovered abi.BitField + Terminated bitfield.BitField + Expired bitfield.BitField + Faulted bitfield.BitField + InRecovery bitfield.BitField + Recovered bitfield.BitField } type minerActorInfo struct { @@ -694,7 +694,7 @@ func (p *Processor) getMinerSectorChanges(ctx context.Context, m minerActorInfo) } func (p *Processor) diffMinerPartitions(ctx context.Context, m minerActorInfo, events chan<- *MinerSectorsEvent) error { - prevMiner, err := p.getMinerStateAt(ctx, m.common.addr, m.common.tsKey) + prevMiner, err := p.getMinerStateAt(ctx, m.common.addr, m.common.parentTsKey) if err != nil { return err } @@ -819,7 +819,7 @@ func (p *Processor) diffPartition(prevPart, curPart miner.Partition) (*Partition } expired := bitfield.New() - var bf abi.BitField + var bf bitfield.BitField if err := terminatedEarlyArr.ForEach(&bf, func(i int64) error { // expired = all removals - termination expirations, err := bitfield.SubtractBitField(allRemovedSectors, bf) diff --git a/cmd/lotus-chainwatch/processor/power.go b/cmd/lotus-chainwatch/processor/power.go index 6fa03e9430e..dfd7eddd72d 100644 --- a/cmd/lotus-chainwatch/processor/power.go +++ b/cmd/lotus-chainwatch/processor/power.go @@ -7,7 +7,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" diff --git a/cmd/lotus-chainwatch/processor/processor.go b/cmd/lotus-chainwatch/processor/processor.go index e6c2ffb9443..bce2b9fb75a 100644 --- a/cmd/lotus-chainwatch/processor/processor.go +++ b/cmd/lotus-chainwatch/processor/processor.go @@ -14,7 +14,7 @@ import ( "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/lotus/api" diff --git a/cmd/lotus-chainwatch/processor/reward.go b/cmd/lotus-chainwatch/processor/reward.go index 7068c1a93c6..5bdb478dfc8 100644 --- a/cmd/lotus-chainwatch/processor/reward.go +++ b/cmd/lotus-chainwatch/processor/reward.go @@ -7,7 +7,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" diff --git a/cmd/lotus-keygen/main.go b/cmd/lotus-keygen/main.go index 33124107e3f..8e2881ae9cc 100644 --- a/cmd/lotus-keygen/main.go +++ b/cmd/lotus-keygen/main.go @@ -5,10 +5,10 @@ import ( "fmt" "os" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/wallet" _ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/secp" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/urfave/cli/v2" ) diff --git a/cmd/lotus-pcr/main.go b/cmd/lotus-pcr/main.go index 80732accf0e..dc12693cafe 100644 --- a/cmd/lotus-pcr/main.go +++ b/cmd/lotus-pcr/main.go @@ -20,11 +20,11 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/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/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/api" @@ -125,7 +125,13 @@ var runCmd = &cli.Command{ Name: "max-message-queue", EnvVars: []string{"LOTUS_PCR_MAX_MESSAGE_QUEUE"}, Usage: "set the maximum number of messages that can be queue in the mpool", - Value: 3000, + Value: 300, + }, + &cli.IntFlag{ + Name: "aggregate-tipsets", + EnvVars: []string{"LOTUS_PCR_AGGREGATE_TIPSETS"}, + Usage: "number of tipsets to process before sending messages", + Value: 1, }, &cli.BoolFlag{ Name: "dry-run", @@ -194,6 +200,7 @@ var runCmd = &cli.Command{ dryRun := cctx.Bool("dry-run") preCommitEnabled := cctx.Bool("pre-commit") proveCommitEnabled := cctx.Bool("prove-commit") + aggregateTipsets := cctx.Int("aggregate-tipsets") rf := &refunder{ api: api, @@ -204,16 +211,32 @@ var runCmd = &cli.Command{ proveCommitEnabled: proveCommitEnabled, } + var refunds *MinersRefund = NewMinersRefund() + var rounds int = 0 + for tipset := range tipsetsCh { - refunds, err := rf.ProcessTipset(ctx, tipset) + refunds, err = rf.ProcessTipset(ctx, tipset, refunds) if err != nil { return err } - if err := rf.Refund(ctx, tipset, refunds); err != nil { + rounds = rounds + 1 + if rounds < aggregateTipsets { + continue + } + + refundTipset, err := api.ChainHead(ctx) + if err != nil { return err } + if err := rf.Refund(ctx, refundTipset, refunds, rounds); err != nil { + return err + } + + rounds = 0 + refunds = NewMinersRefund() + if err := r.SetHeight(tipset.Height()); err != nil { return err } @@ -247,13 +270,15 @@ var runCmd = &cli.Command{ } type MinersRefund struct { - refunds map[address.Address]types.BigInt - count int + refunds map[address.Address]types.BigInt + count int + totalRefunds types.BigInt } func NewMinersRefund() *MinersRefund { return &MinersRefund{ - refunds: make(map[address.Address]types.BigInt), + refunds: make(map[address.Address]types.BigInt), + totalRefunds: types.NewInt(0), } } @@ -263,6 +288,7 @@ func (m *MinersRefund) Track(addr address.Address, value types.BigInt) { } m.count = m.count + 1 + m.totalRefunds = types.BigAdd(m.totalRefunds, value) m.refunds[addr] = types.BigAdd(m.refunds[addr], value) } @@ -271,6 +297,10 @@ func (m *MinersRefund) Count() int { return m.count } +func (m *MinersRefund) TotalRefunds() types.BigInt { + return m.totalRefunds +} + func (m *MinersRefund) Miners() []address.Address { miners := make([]address.Address, 0, len(m.refunds)) for addr := range m.refunds { @@ -305,7 +335,7 @@ type refunder struct { proveCommitEnabled bool } -func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet) (*MinersRefund, error) { +func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund) (*MinersRefund, error) { cids := tipset.Cids() if len(cids) == 0 { log.Errorw("no cids in tipset", "height", tipset.Height(), "key", tipset.Key()) @@ -329,9 +359,8 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet) (*Mi return nil, nil } - refunds := NewMinersRefund() - refundValue := types.NewInt(0) + tipsetRefunds := NewMinersRefund() for i, msg := range msgs { m := msg.Message @@ -427,12 +456,15 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet) (*Mi log.Debugw("processing message", "method", messageMethod, "cid", msg.Cid, "from", m.From, "to", m.To, "value", m.Value, "gas_fee_cap", m.GasFeeCap, "gas_premium", m.GasPremium, "gas_used", recps[i].GasUsed, "refund", refundValue) refunds.Track(m.From, refundValue) + tipsetRefunds.Track(m.From, refundValue) } + log.Infow("tipset stats", "height", tipset.Height(), "key", tipset.Key(), "total_refunds", tipsetRefunds.TotalRefunds(), "messages_processed", tipsetRefunds.Count()) + return refunds, nil } -func (r *refunder) Refund(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund) error { +func (r *refunder) Refund(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund, rounds int) error { if refunds.Count() == 0 { log.Debugw("no messages to refund in tipset", "height", tipset.Height(), "key", tipset.Key()) return nil @@ -490,7 +522,7 @@ func (r *refunder) Refund(ctx context.Context, tipset *types.TipSet, refunds *Mi refundSum = types.BigAdd(refundSum, msg.Value) } - log.Infow("tipset stats", "height", tipset.Height(), "key", tipset.Key(), "messages_sent", len(messages)-failures, "refund_sum", refundSum, "messages_failures", failures, "messages_processed", refunds.Count()) + log.Infow("refund stats", "tipsets_processed", rounds, "height", tipset.Height(), "key", tipset.Key(), "messages_sent", len(messages)-failures, "refund_sum", refundSum, "messages_failures", failures, "messages_processed", refunds.Count()) return nil } diff --git a/cmd/lotus-seal-worker/main.go b/cmd/lotus-seal-worker/main.go index e6361d3cf7e..e36514bb880 100644 --- a/cmd/lotus-seal-worker/main.go +++ b/cmd/lotus-seal-worker/main.go @@ -45,6 +45,8 @@ const FlagWorkerRepo = "worker-repo" const FlagWorkerRepoDeprecation = "workerrepo" func main() { + build.RunningNodeType = build.NodeWorker + lotuslog.SetupLogLevels() local := []*cli.Command{ @@ -187,8 +189,8 @@ var runCmd = &cli.Command{ if err != nil { return err } - if v.APIVersion != build.APIVersion { - return xerrors.Errorf("lotus-miner API version doesn't match: local: %s", api.Version{APIVersion: build.APIVersion}) + if v.APIVersion != build.MinerAPIVersion { + return xerrors.Errorf("lotus-miner API version doesn't match: expected: %s", api.Version{APIVersion: build.MinerAPIVersion}) } log.Infof("Remote version %s", v) diff --git a/cmd/lotus-seal-worker/rpc.go b/cmd/lotus-seal-worker/rpc.go index 5380fe43214..8aa9093c246 100644 --- a/cmd/lotus-seal-worker/rpc.go +++ b/cmd/lotus-seal-worker/rpc.go @@ -21,7 +21,7 @@ type worker struct { } func (w *worker) Version(context.Context) (build.Version, error) { - return build.APIVersion, nil + return build.WorkerAPIVersion, nil } func (w *worker) StorageAddLocal(ctx context.Context, path string) error { diff --git a/cmd/lotus-seed/genesis.go b/cmd/lotus-seed/genesis.go index f2bff4d6e9b..bbaea6969a9 100644 --- a/cmd/lotus-seed/genesis.go +++ b/cmd/lotus-seed/genesis.go @@ -15,8 +15,8 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/gen" diff --git a/cmd/lotus-seed/main.go b/cmd/lotus-seed/main.go index 48691d5ec85..d365f6493e1 100644 --- a/cmd/lotus-seed/main.go +++ b/cmd/lotus-seed/main.go @@ -15,8 +15,8 @@ import ( "github.com/urfave/cli/v2" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" diff --git a/cmd/lotus-seed/seed/seed.go b/cmd/lotus-seed/seed/seed.go index f892709f619..5e911991ded 100644 --- a/cmd/lotus-seed/seed/seed.go +++ b/cmd/lotus-seed/seed/seed.go @@ -19,11 +19,11 @@ import ( ffi "github.com/filecoin-project/filecoin-ffi" "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/lotus/extern/sector-storage/zerocomm" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" diff --git a/cmd/lotus-shed/balances.go b/cmd/lotus-shed/balances.go new file mode 100644 index 00000000000..aad3217834c --- /dev/null +++ b/cmd/lotus-shed/balances.go @@ -0,0 +1,245 @@ +package main + +import ( + "context" + "fmt" + + "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/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/lotus/chain/state" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" + lcli "github.com/filecoin-project/lotus/cli" + "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 { + Address address.Address + Balance types.FIL + Type string + Power abi.StoragePower + Worker address.Address + Owner address.Address + InitialPledge types.FIL + PreCommits types.FIL + LockedFunds types.FIL + Sectors uint64 +} + +var auditsCmd = &cli.Command{ + Name: "audits", + Description: "a collection of utilities for auditing the filecoin chain", + Subcommands: []*cli.Command{ + chainBalanceCmd, + chainBalanceStateCmd, + }, +} + +var chainBalanceCmd = &cli.Command{ + Name: "chain-balances", + Description: "Produces a csv file of all account balances", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "tipset", + Usage: "specify tipset to start from", + }, + }, + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + + defer closer() + ctx := lcli.ReqContext(cctx) + + ts, err := lcli.LoadTipSet(ctx, cctx, api) + if err != nil { + return err + } + + tsk := ts.Key() + actors, err := api.StateListActors(ctx, tsk) + if err != nil { + return err + } + + var infos []accountInfo + for _, addr := range actors { + act, err := api.StateGetActor(ctx, addr, tsk) + if err != nil { + return err + } + + ai := accountInfo{ + Address: addr, + Balance: types.FIL(act.Balance), + Type: string(act.Code.Hash()[2:]), + } + + if act.Code == builtin.StorageMinerActorCodeID { + pow, err := api.StateMinerPower(ctx, addr, tsk) + if err != nil { + return xerrors.Errorf("failed to get power: %w", err) + } + + ai.Power = pow.MinerPower.RawBytePower + info, err := api.StateMinerInfo(ctx, addr, tsk) + if err != nil { + return xerrors.Errorf("failed to get miner info: %w", err) + } + ai.Worker = info.Worker + ai.Owner = info.Owner + + } + infos = append(infos, ai) + } + + fmt.Printf("Address,Balance,Type,Power,Worker,Owner\n") + for _, acc := range infos { + fmt.Printf("%s,%s,%s,%s,%s,%s\n", acc.Address, acc.Balance, acc.Type, acc.Power, acc.Worker, acc.Owner) + } + return nil + }, +} + +var chainBalanceStateCmd = &cli.Command{ + Name: "stateroot-balances", + Description: "Produces a csv file of all account balances from a given stateroot", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + Value: "~/.lotus", + }, + &cli.BoolFlag{ + Name: "miner-info", + }, + }, + Action: func(cctx *cli.Context) error { + ctx := context.TODO() + + if !cctx.Args().Present() { + return fmt.Errorf("must pass state root") + } + + sroot, err := cid.Decode(cctx.Args().First()) + if err != nil { + return fmt.Errorf("failed to parse input: %w", err) + } + + fsrepo, err := repo.NewFS(cctx.String("repo")) + if err != nil { + return err + } + + lkrepo, err := fsrepo.Lock(repo.FullNode) + if err != nil { + return err + } + + defer lkrepo.Close() //nolint:errcheck + + ds, err := lkrepo.Datastore("/chain") + if err != nil { + return err + } + + mds, err := lkrepo.Datastore("/metadata") + if err != nil { + return err + } + + bs := blockstore.NewBlockstore(ds) + + cs := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier)) + + cst := cbor.NewCborStore(bs) + + sm := stmgr.NewStateManager(cs) + + tree, err := state.LoadStateTree(cst, sroot) + if err != nil { + return err + } + + minerInfo := cctx.Bool("miner-info") + + var infos []accountInfo + err = tree.ForEach(func(addr address.Address, act *types.Actor) error { + + ai := accountInfo{ + Address: addr, + Balance: types.FIL(act.Balance), + Type: string(act.Code.Hash()[2:]), + Power: big.NewInt(0), + LockedFunds: types.FIL(big.NewInt(0)), + InitialPledge: types.FIL(big.NewInt(0)), + PreCommits: types.FIL(big.NewInt(0)), + } + + if act.Code == builtin.StorageMinerActorCodeID && minerInfo { + 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 { + return xerrors.Errorf("failed to read miner state: %w", err) + } + + sectors, err := adt.AsArray(cs.Store(ctx), st.Sectors) + if err != nil { + return xerrors.Errorf("failed to load sector set: %w", err) + } + + ai.InitialPledge = types.FIL(st.InitialPledgeRequirement) + ai.LockedFunds = types.FIL(st.LockedFunds) + ai.PreCommits = types.FIL(st.PreCommitDeposits) + ai.Sectors = sectors.Length() + + 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.Worker = minfo.Worker + ai.Owner = minfo.Owner + } + infos = append(infos, ai) + return nil + }) + if err != nil { + return xerrors.Errorf("failed to loop over actors: %w", err) + } + + if minerInfo { + fmt.Printf("Address,Balance,Type,Sectors,Worker,Owner,InitialPledge,Locked,PreCommits\n") + for _, acc := range infos { + fmt.Printf("%s,%s,%s,%d,%s,%s,%s,%s,%s\n", acc.Address, acc.Balance, acc.Type, acc.Sectors, acc.Worker, acc.Owner, acc.InitialPledge, acc.LockedFunds, acc.PreCommits) + } + } else { + fmt.Printf("Address,Balance,Type\n") + for _, acc := range infos { + fmt.Printf("%s,%s,%s\n", acc.Address, acc.Balance, acc.Type) + } + } + + return nil + }, +} diff --git a/cmd/lotus-shed/export.go b/cmd/lotus-shed/export.go new file mode 100644 index 00000000000..c12cbd82d01 --- /dev/null +++ b/cmd/lotus-shed/export.go @@ -0,0 +1,123 @@ +package main + +import ( + "context" + "fmt" + "os" + + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/lib/blockstore" + "github.com/filecoin-project/lotus/node/repo" +) + +var exportChainCmd = &cli.Command{ + Name: "export", + Description: "Export chain from repo (requires node to be offline)", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + Value: "~/.lotus", + }, + &cli.StringFlag{ + Name: "tipset", + Usage: "tipset to export from", + }, + &cli.Int64Flag{ + Name: "recent-stateroots", + }, + &cli.BoolFlag{ + Name: "full-state", + }, + &cli.BoolFlag{ + Name: "skip-old-msgs", + }, + }, + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return lcli.ShowHelp(cctx, fmt.Errorf("must specify file name to write export to")) + } + + ctx := context.TODO() + + r, err := repo.NewFS(cctx.String("repo")) + if err != nil { + return xerrors.Errorf("opening fs repo: %w", err) + } + + exists, err := r.Exists() + if err != nil { + return err + } + if !exists { + return xerrors.Errorf("lotus repo doesn't exist") + } + + lr, err := r.Lock(repo.FullNode) + if err != nil { + return err + } + defer lr.Close() //nolint:errcheck + + fi, err := os.Create(cctx.Args().First()) + if err != nil { + return xerrors.Errorf("opening the output file: %w", err) + } + + defer fi.Close() //nolint:errcheck + + ds, err := lr.Datastore("/chain") + if err != nil { + return err + } + + mds, err := lr.Datastore("/metadata") + if err != nil { + return err + } + + bs := blockstore.NewBlockstore(ds) + + cs := store.NewChainStore(bs, mds, nil) + if err := cs.Load(); err != nil { + return err + } + + nroots := abi.ChainEpoch(cctx.Int64("recent-stateroots")) + fullstate := cctx.Bool("full-state") + skipoldmsgs := cctx.Bool("skip-old-msgs") + + var ts *types.TipSet + if tss := cctx.String("tipset"); tss != "" { + cids, err := lcli.ParseTipSetString(tss) + if err != nil { + return xerrors.Errorf("failed to parse tipset (%q): %w", tss, err) + } + + tsk := types.NewTipSetKey(cids...) + + selts, err := cs.LoadTipSet(tsk) + if err != nil { + return xerrors.Errorf("loading tipset: %w", err) + } + ts = selts + } else { + ts = cs.GetHeaviestTipSet() + } + + if fullstate { + nroots = ts.Height() + 1 + } + + if err := cs.Export(ctx, ts, nroots, skipoldmsgs, fi); err != nil { + return xerrors.Errorf("export failed: %w", err) + } + + return nil + }, +} diff --git a/cmd/lotus-shed/genesis-verify.go b/cmd/lotus-shed/genesis-verify.go index 4ab6458a9fb..043cb72bb8b 100644 --- a/cmd/lotus-shed/genesis-verify.go +++ b/cmd/lotus-shed/genesis-verify.go @@ -13,13 +13,13 @@ import ( "golang.org/x/xerrors" "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/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/abi/big" "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" diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index 5438a31ef6d..cff3059b679 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -23,6 +23,7 @@ func main() { noncefix, bigIntParseCmd, staterootCmd, + auditsCmd, importCarCmd, commpToCidCmd, fetchParamCmd, @@ -31,6 +32,9 @@ func main() { miscCmd, mpoolCmd, genesisVerifyCmd, + mathCmd, + mpoolStatsCmd, + exportChainCmd, } app := &cli.App{ diff --git a/cmd/lotus-shed/math.go b/cmd/lotus-shed/math.go new file mode 100644 index 00000000000..434559f09a0 --- /dev/null +++ b/cmd/lotus-shed/math.go @@ -0,0 +1,103 @@ +package main + +import ( + "bufio" + "fmt" + "io" + "os" + "strings" + + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/lotus/chain/types" +) + +var mathCmd = &cli.Command{ + Name: "math", + Usage: "utility commands around doing math on a list of numbers", + Subcommands: []*cli.Command{ + mathSumCmd, + }, +} + +func readLargeNumbers(i io.Reader) ([]types.BigInt, error) { + list := []types.BigInt{} + reader := bufio.NewReader(i) + + exit := false + for { + if exit { + break + } + + line, err := reader.ReadString('\n') + if err != nil && err != io.EOF { + break + } + if err == io.EOF { + exit = true + } + + line = strings.Trim(line, "\n") + + if len(line) == 0 { + continue + } + + value, err := types.BigFromString(line) + if err != nil { + return []types.BigInt{}, fmt.Errorf("failed to parse line: %s", line) + } + + list = append(list, value) + } + + return list, nil +} + +var mathSumCmd = &cli.Command{ + Name: "sum", + Usage: "Sum numbers", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "avg", + Value: false, + Usage: "Print the average instead of the sum", + }, + &cli.StringFlag{ + Name: "format", + Value: "raw", + Usage: "format the number in a more readable way [fil,bytes2,bytes10]", + }, + }, + Action: func(cctx *cli.Context) error { + list, err := readLargeNumbers(os.Stdin) + if err != nil { + return err + } + + val := types.NewInt(0) + for _, value := range list { + val = types.BigAdd(val, value) + } + + if cctx.Bool("avg") { + val = types.BigDiv(val, types.NewInt(uint64(len(list)))) + } + + switch cctx.String("format") { + case "byte2": + fmt.Printf("%s\n", types.SizeStr(val)) + case "byte10": + fmt.Printf("%s\n", types.DeciStr(val)) + case "fil": + fmt.Printf("%s\n", types.FIL(val)) + case "raw": + fmt.Printf("%s\n", val) + default: + return fmt.Errorf("Unknown format") + } + + return nil + }, +} diff --git a/cmd/lotus-shed/mempool-stats.go b/cmd/lotus-shed/mempool-stats.go new file mode 100644 index 00000000000..b81cf2704e8 --- /dev/null +++ b/cmd/lotus-shed/mempool-stats.go @@ -0,0 +1,273 @@ +package main + +import ( + "fmt" + "net/http" + "sort" + "time" + + "contrib.go.opencensus.io/exporter/prometheus" + "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log" + "github.com/urfave/cli/v2" + "go.opencensus.io/stats" + "go.opencensus.io/stats/view" + "go.opencensus.io/tag" + + "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 ( + MpoolAge = stats.Float64("mpoolage", "Age of messages in the mempool", stats.UnitSeconds) + MpoolSize = stats.Int64("mpoolsize", "Number of messages in mempool", stats.UnitDimensionless) + MpoolInboundRate = stats.Int64("inbound", "Counter for inbound messages", stats.UnitDimensionless) + BlockInclusionRate = stats.Int64("inclusion", "Counter for message included in blocks", stats.UnitDimensionless) + MsgWaitTime = stats.Float64("msg-wait-time", "Wait time of messages to make it into a block", stats.UnitSeconds) +) + +var ( + LeTag, _ = tag.NewKey("quantile") + MTTag, _ = tag.NewKey("msg_type") +) + +var ( + AgeView = &view.View{ + Name: "mpool-age", + Measure: MpoolAge, + TagKeys: []tag.Key{LeTag, MTTag}, + Aggregation: view.LastValue(), + } + SizeView = &view.View{ + Name: "mpool-size", + Measure: MpoolSize, + TagKeys: []tag.Key{MTTag}, + Aggregation: view.LastValue(), + } + InboundRate = &view.View{ + Name: "msg-inbound", + Measure: MpoolInboundRate, + TagKeys: []tag.Key{MTTag}, + Aggregation: view.Count(), + } + InclusionRate = &view.View{ + Name: "msg-inclusion", + Measure: BlockInclusionRate, + TagKeys: []tag.Key{MTTag}, + Aggregation: view.Count(), + } + MsgWait = &view.View{ + Name: "msg-wait", + Measure: MsgWaitTime, + TagKeys: []tag.Key{MTTag}, + Aggregation: view.Distribution(10, 30, 60, 120, 240, 600, 1800, 3600), + } +) + +type msgInfo struct { + msg *types.SignedMessage + seen time.Time +} + +var mpoolStatsCmd = &cli.Command{ + Name: "mpool-stats", + Action: func(cctx *cli.Context) error { + logging.SetLogLevel("rpc", "ERROR") + + if err := view.Register(AgeView, SizeView, InboundRate, InclusionRate, MsgWait); err != nil { + return err + } + + expo, err := prometheus.NewExporter(prometheus.Options{ + Namespace: "lotusmpool", + }) + if err != nil { + return err + } + + http.Handle("/debug/metrics", expo) + + go func() { + if err := http.ListenAndServe(":10555", nil); err != nil { + panic(err) + } + }() + + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + + defer closer() + ctx := lcli.ReqContext(cctx) + + updates, err := api.MpoolSub(ctx) + if err != nil { + return err + } + + mcache := make(map[address.Address]bool) + isMiner := func(addr address.Address) (bool, error) { + cache, ok := mcache[addr] + if ok { + return cache, nil + } + + act, err := api.StateGetActor(ctx, addr, types.EmptyTSK) + if err != nil { + return false, err + } + + ism := act.Code == builtin.StorageMinerActorCodeID + mcache[addr] = ism + return ism, nil + } + + wpostTracker := make(map[cid.Cid]*msgInfo) + tracker := make(map[cid.Cid]*msgInfo) + tick := time.Tick(time.Second) + for { + select { + case u, ok := <-updates: + if !ok { + return fmt.Errorf("connection with lotus node broke") + } + switch u.Type { + case lapi.MpoolAdd: + stats.Record(ctx, MpoolInboundRate.M(1)) + tracker[u.Message.Cid()] = &msgInfo{ + msg: u.Message, + seen: time.Now(), + } + + if u.Message.Message.Method == builtin.MethodsMiner.SubmitWindowedPoSt { + + miner, err := isMiner(u.Message.Message.To) + if err != nil { + log.Warnf("failed to determine if message target was to a miner: %s", err) + continue + } + + if miner { + wpostTracker[u.Message.Cid()] = &msgInfo{ + msg: u.Message, + seen: time.Now(), + } + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MpoolInboundRate.M(1)) + } + } + + case lapi.MpoolRemove: + mi, ok := tracker[u.Message.Cid()] + if ok { + fmt.Printf("%s was in the mempool for %s (feecap=%s, prem=%s)\n", u.Message.Cid(), time.Since(mi.seen), u.Message.Message.GasFeeCap, u.Message.Message.GasPremium) + stats.Record(ctx, BlockInclusionRate.M(1)) + stats.Record(ctx, MsgWaitTime.M(time.Since(mi.seen).Seconds())) + delete(tracker, u.Message.Cid()) + } + + wm, ok := wpostTracker[u.Message.Cid()] + if ok { + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, BlockInclusionRate.M(1)) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MsgWaitTime.M(time.Since(wm.seen).Seconds())) + delete(wpostTracker, u.Message.Cid()) + } + default: + return fmt.Errorf("unrecognized mpool update state: %d", u.Type) + } + case <-tick: + var ages []time.Duration + if len(tracker) > 0 { + for _, v := range tracker { + age := time.Since(v.seen) + ages = append(ages, age) + } + + st := ageStats(ages) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "40")}, MpoolAge.M(st.Perc40.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "50")}, MpoolAge.M(st.Perc50.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "60")}, MpoolAge.M(st.Perc60.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "70")}, MpoolAge.M(st.Perc70.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "80")}, MpoolAge.M(st.Perc80.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "90")}, MpoolAge.M(st.Perc90.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "95")}, MpoolAge.M(st.Perc95.Seconds())) + + stats.Record(ctx, MpoolSize.M(int64(len(tracker)))) + fmt.Printf("%d messages in mempool for average of %s, (%s / %s / %s)\n", st.Count, st.Average, st.Perc50, st.Perc80, st.Perc95) + } + + var wpages []time.Duration + if len(wpostTracker) > 0 { + for _, v := range wpostTracker { + age := time.Since(v.seen) + wpages = append(wpages, age) + } + + st := ageStats(wpages) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "40"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc40.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "50"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc50.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "60"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc60.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "70"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc70.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "80"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc80.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "90"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc90.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "95"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc95.Seconds())) + + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MpoolSize.M(int64(len(wpostTracker)))) + fmt.Printf("%d wpost messages in mempool for average of %s, (%s / %s / %s)\n", st.Count, st.Average, st.Perc50, st.Perc80, st.Perc95) + } + } + } + }, +} + +type ageStat struct { + Average time.Duration + Max time.Duration + Perc40 time.Duration + Perc50 time.Duration + Perc60 time.Duration + Perc70 time.Duration + Perc80 time.Duration + Perc90 time.Duration + Perc95 time.Duration + Count int +} + +func ageStats(ages []time.Duration) *ageStat { + sort.Slice(ages, func(i, j int) bool { + return ages[i] < ages[j] + }) + + st := ageStat{ + Count: len(ages), + } + var sum time.Duration + for _, a := range ages { + sum += a + if a > st.Max { + st.Max = a + } + } + st.Average = sum / time.Duration(len(ages)) + + p40 := (4 * len(ages)) / 10 + p50 := len(ages) / 2 + p60 := (6 * len(ages)) / 10 + p70 := (7 * len(ages)) / 10 + p80 := (4 * len(ages)) / 5 + p90 := (9 * len(ages)) / 10 + p95 := (19 * len(ages)) / 20 + + st.Perc40 = ages[p40] + st.Perc50 = ages[p50] + st.Perc60 = ages[p60] + st.Perc70 = ages[p70] + st.Perc80 = ages[p80] + st.Perc90 = ages[p90] + st.Perc95 = ages[p95] + + return &st +} diff --git a/cmd/lotus-shed/proofs.go b/cmd/lotus-shed/proofs.go index f18dc93fb12..2379d8599b7 100644 --- a/cmd/lotus-shed/proofs.go +++ b/cmd/lotus-shed/proofs.go @@ -4,11 +4,13 @@ import ( "encoding/hex" "fmt" + saproof "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/urfave/cli/v2" ffi "github.com/filecoin-project/filecoin-ffi" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" ) @@ -82,7 +84,7 @@ var verifySealProofCmd = &cli.Command{ snum := abi.SectorNumber(cctx.Uint64("sector-id")) - ok, err := ffi.VerifySeal(abi.SealVerifyInfo{ + ok, err := ffi.VerifySeal(saproof.SealVerifyInfo{ SectorID: abi.SectorID{ Miner: abi.ActorID(mid), Number: snum, diff --git a/cmd/lotus-storage-miner/actor.go b/cmd/lotus-storage-miner/actor.go index e69a338ab24..c84e006d7fb 100644 --- a/cmd/lotus-storage-miner/actor.go +++ b/cmd/lotus-storage-miner/actor.go @@ -12,8 +12,8 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" diff --git a/cmd/lotus-storage-miner/info.go b/cmd/lotus-storage-miner/info.go index dbb93c9726b..55ef024f30d 100644 --- a/cmd/lotus-storage-miner/info.go +++ b/cmd/lotus-storage-miner/info.go @@ -14,8 +14,8 @@ import ( cbor "github.com/ipfs/go-ipld-cbor" "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/abi" "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" diff --git a/cmd/lotus-storage-miner/init.go b/cmd/lotus-storage-miner/init.go index e33030e4eea..e2a2419f3eb 100644 --- a/cmd/lotus-storage-miner/init.go +++ b/cmd/lotus-storage-miner/init.go @@ -12,7 +12,7 @@ import ( "path/filepath" "strconv" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "github.com/docker/go-units" "github.com/google/uuid" @@ -26,15 +26,15 @@ import ( "github.com/filecoin-project/go-address" cborutil "github.com/filecoin-project/go-cbor-util" paramfetch "github.com/filecoin-project/go-paramfetch" + "github.com/filecoin-project/go-state-types/abi" + crypto2 "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/lotus/extern/sector-storage/stores" - "github.com/filecoin-project/specs-actors/actors/abi" "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" - crypto2 "github.com/filecoin-project/specs-actors/actors/crypto" lapi "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" @@ -180,8 +180,8 @@ var initCmd = &cli.Command{ return err } - if !v.APIVersion.EqMajorMinor(build.APIVersion) { - return xerrors.Errorf("Remote API version didn't match (local %s, remote %s)", build.APIVersion, v.APIVersion) + if !v.APIVersion.EqMajorMinor(build.FullAPIVersion) { + return xerrors.Errorf("Remote API version didn't match (expected %s, remote %s)", build.FullAPIVersion, v.APIVersion) } log.Info("Initializing repo") diff --git a/cmd/lotus-storage-miner/main.go b/cmd/lotus-storage-miner/main.go index cc704f89199..cee64f07798 100644 --- a/cmd/lotus-storage-miner/main.go +++ b/cmd/lotus-storage-miner/main.go @@ -26,6 +26,8 @@ const FlagMinerRepo = "miner-repo" const FlagMinerRepoDeprecation = "storagerepo" func main() { + build.RunningNodeType = build.NodeMiner + lotuslog.SetupLogLevels() local := []*cli.Command{ diff --git a/cmd/lotus-storage-miner/market.go b/cmd/lotus-storage-miner/market.go index 39671f74c95..1c9eac1b716 100644 --- a/cmd/lotus-storage-miner/market.go +++ b/cmd/lotus-storage-miner/market.go @@ -20,7 +20,7 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-fil-markets/storagemarket" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" diff --git a/cmd/lotus-storage-miner/proving.go b/cmd/lotus-storage-miner/proving.go index 502edb57bf7..b5087556db5 100644 --- a/cmd/lotus-storage-miner/proving.go +++ b/cmd/lotus-storage-miner/proving.go @@ -11,7 +11,7 @@ import ( "github.com/urfave/cli/v2" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/build" diff --git a/cmd/lotus-storage-miner/run.go b/cmd/lotus-storage-miner/run.go index 7c88b74c46b..83d78172ea8 100644 --- a/cmd/lotus-storage-miner/run.go +++ b/cmd/lotus-storage-miner/run.go @@ -77,8 +77,8 @@ var runCmd = &cli.Command{ } } - if v.APIVersion != build.APIVersion { - return xerrors.Errorf("lotus-daemon API version doesn't match: local: %s", api.Version{APIVersion: build.APIVersion}) + if v.APIVersion != build.FullAPIVersion { + return xerrors.Errorf("lotus-daemon API version doesn't match: expected: %s", api.Version{APIVersion: build.FullAPIVersion}) } log.Info("Checking full node sync status") diff --git a/cmd/lotus-storage-miner/sectors.go b/cmd/lotus-storage-miner/sectors.go index 8bd8ff6a5b9..06f09fe2078 100644 --- a/cmd/lotus-storage-miner/sectors.go +++ b/cmd/lotus-storage-miner/sectors.go @@ -13,7 +13,7 @@ import ( "github.com/urfave/cli/v2" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types" diff --git a/cmd/lotus-storage-miner/storage.go b/cmd/lotus-storage-miner/storage.go index 7fadcf83f32..71d88de6d78 100644 --- a/cmd/lotus-storage-miner/storage.go +++ b/cmd/lotus-storage-miner/storage.go @@ -18,9 +18,9 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/fsutil" "github.com/filecoin-project/lotus/extern/sector-storage/stores" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" diff --git a/cmd/lotus/debug_advance.go b/cmd/lotus/debug_advance.go index 699182472eb..4e74a995fac 100644 --- a/cmd/lotus/debug_advance.go +++ b/cmd/lotus/debug_advance.go @@ -7,12 +7,12 @@ import ( "time" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/crypto" lapi "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" - "github.com/filecoin-project/specs-actors/actors/crypto" "golang.org/x/xerrors" "github.com/urfave/cli/v2" @@ -46,6 +46,7 @@ func init() { return xerrors.Errorf("StateMinerWorker: %w", err) } + // XXX: This can't be right rand, err := api.ChainGetRandomnessFromTickets(ctx, head.Key(), crypto.DomainSeparationTag_TicketProduction, head.Height(), addr.Bytes()) if err != nil { return xerrors.Errorf("failed to get randomness: %w", err) diff --git a/cmd/lotus/main.go b/cmd/lotus/main.go index 1e2c7faec15..ee95ad64b44 100644 --- a/cmd/lotus/main.go +++ b/cmd/lotus/main.go @@ -16,6 +16,8 @@ import ( var AdvanceBlockCmd *cli.Command func main() { + build.RunningNodeType = build.NodeFull + lotuslog.SetupLogLevels() local := []*cli.Command{ diff --git a/conformance/chaos/actor.go b/conformance/chaos/actor.go new file mode 100644 index 00000000000..b9a181ba7ca --- /dev/null +++ b/conformance/chaos/actor.go @@ -0,0 +1,253 @@ +package chaos + +import ( + "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/actors/runtime" + "github.com/ipfs/go-cid" + + typegen "github.com/whyrusleeping/cbor-gen" +) + +//go:generate go run ./gen + +// Actor is a chaos actor. It implements a variety of illegal behaviours that +// trigger violations of VM invariants. These behaviours are not found in +// production code, but are important to test that the VM constraints are +// properly enforced. +// +// The chaos actor is being incubated and its behaviour and ABI be standardised +// shortly. Its CID is ChaosActorCodeCID, and its singleton address is 98 (Address). +// It cannot be instantiated via the init actor, and its constructor panics. +// +// Test vectors relying on the chaos actor being deployed will carry selector +// "chaos_actor:true". +type Actor struct{} + +// CallerValidationBranch is an enum used to select a branch in the +// CallerValidation method. +type CallerValidationBranch int64 + +const ( + CallerValidationBranchNone CallerValidationBranch = iota + CallerValidationBranchTwice + CallerValidationBranchAddrNilSet + CallerValidationBranchTypeNilSet +) + +// MutateStateBranch is an enum used to select the type of state mutation to attempt. +type MutateStateBranch int64 + +const ( + // MutateInTransaction legally mutates state within a transaction. + MutateInTransaction MutateStateBranch = iota + // MutateReadonly ILLEGALLY mutates readonly state. + MutateReadonly + // MutateAfterTransaction ILLEGALLY mutates state after a transaction. + MutateAfterTransaction +) + +const ( + _ = 0 // skip zero iota value; first usage of iota gets 1. + MethodCallerValidation = builtin.MethodConstructor + iota + MethodCreateActor + MethodResolveAddress + // MethodDeleteActor is the identifier for the method that deletes this actor. + MethodDeleteActor + // MethodSend is the identifier for the method that sends a message to another actor. + MethodSend + // MethodMutateState is the identifier for the method that attempts to mutate + // a state value in the actor. + MethodMutateState + // MethodAbortWith is the identifier for the method that panics optionally with + // a passed exit code. + MethodAbortWith +) + +// Exports defines the methods this actor exposes publicly. +func (a Actor) Exports() []interface{} { + return []interface{}{ + builtin.MethodConstructor: a.Constructor, + MethodCallerValidation: a.CallerValidation, + MethodCreateActor: a.CreateActor, + MethodResolveAddress: a.ResolveAddress, + MethodDeleteActor: a.DeleteActor, + MethodSend: a.Send, + MethodMutateState: a.MutateState, + MethodAbortWith: a.AbortWith, + } +} + +var _ runtime.Invokee = Actor{} + +// SendArgs are the arguments for the Send method. +type SendArgs struct { + To address.Address + Value abi.TokenAmount + Method abi.MethodNum + Params []byte +} + +// SendReturn is the return values for the Send method. +type SendReturn struct { + Return runtime.CBORBytes + Code exitcode.ExitCode +} + +// Send requests for this actor to send a message to an actor with the +// passed parameters. +func (a Actor) Send(rt runtime.Runtime, args *SendArgs) *SendReturn { + rt.ValidateImmediateCallerAcceptAny() + ret, code := rt.Send( + args.To, + args.Method, + runtime.CBORBytes(args.Params), + args.Value, + ) + var out runtime.CBORBytes + if ret != nil { + if err := ret.Into(&out); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to unmarshal send return: %v", err) + } + } + return &SendReturn{ + Return: out, + Code: code, + } +} + +// Constructor will panic because the Chaos actor is a singleton. +func (a Actor) Constructor(_ runtime.Runtime, _ *abi.EmptyValue) *abi.EmptyValue { + panic("constructor should not be called; the Chaos actor is a singleton actor") +} + +// 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) { + case CallerValidationBranchNone: + case CallerValidationBranchTwice: + rt.ValidateImmediateCallerAcceptAny() + rt.ValidateImmediateCallerAcceptAny() + case CallerValidationBranchAddrNilSet: + rt.ValidateImmediateCallerIs() + case CallerValidationBranchTypeNilSet: + rt.ValidateImmediateCallerType() + default: + panic("invalid branch passed to CallerValidation") + } + + return nil +} + +// CreateActorArgs are the arguments to CreateActor. +type CreateActorArgs struct { + // UndefActorCID instructs us to use cid.Undef; we can't pass cid.Undef + // in ActorCID because it doesn't serialize. + UndefActorCID bool + ActorCID cid.Cid + + // UndefAddress is the same as UndefActorCID but for Address. + UndefAddress bool + Address address.Address +} + +// CreateActor creates an actor with the supplied CID and Address. +func (a Actor) CreateActor(rt runtime.Runtime, args *CreateActorArgs) *abi.EmptyValue { + rt.ValidateImmediateCallerAcceptAny() + + var ( + acid = args.ActorCID + addr = args.Address + ) + + if args.UndefActorCID { + acid = cid.Undef + } + if args.UndefAddress { + addr = address.Undef + } + + rt.CreateActor(acid, addr) + return nil +} + +// ResolveAddressResponse holds the response of a call to runtime.ResolveAddress +type ResolveAddressResponse struct { + Address address.Address + Success bool +} + +func (a Actor) ResolveAddress(rt runtime.Runtime, args *address.Address) *ResolveAddressResponse { + rt.ValidateImmediateCallerAcceptAny() + + resolvedAddr, ok := rt.ResolveAddress(*args) + if !ok { + invalidAddr, _ := address.NewIDAddress(0) + resolvedAddr = invalidAddr + } + return &ResolveAddressResponse{resolvedAddr, ok} +} + +// DeleteActor deletes the executing actor from the state tree, transferring any +// balance to beneficiary. +func (a Actor) DeleteActor(rt runtime.Runtime, beneficiary *address.Address) *abi.EmptyValue { + rt.ValidateImmediateCallerAcceptAny() + rt.DeleteActor(*beneficiary) + return nil +} + +// MutateStateArgs specify the value to set on the state and the way in which +// it should be attempted to be set. +type MutateStateArgs struct { + Value string + Branch MutateStateBranch +} + +// MutateState attempts to mutate a state value in the actor. +func (a Actor) MutateState(rt runtime.Runtime, args *MutateStateArgs) *abi.EmptyValue { + rt.ValidateImmediateCallerAcceptAny() + var st State + switch args.Branch { + case MutateInTransaction: + rt.State().Transaction(&st, func() { + st.Value = args.Value + }) + case MutateReadonly: + rt.State().Readonly(&st) + st.Value = args.Value + case MutateAfterTransaction: + rt.State().Transaction(&st, func() { + st.Value = args.Value + "-in" + }) + st.Value = args.Value + default: + panic("unknown mutation type") + } + return nil +} + +// AbortWithArgs are the arguments to the Actor.AbortWith method, specifying the +// exit code to (optionally) abort with and the message. +type AbortWithArgs struct { + Code exitcode.ExitCode + Message string + Uncontrolled bool +} + +// AbortWith simply causes a panic with the passed exit code. +func (a Actor) AbortWith(rt runtime.Runtime, args *AbortWithArgs) *abi.EmptyValue { + if args.Uncontrolled { // uncontrolled abort: directly panic + panic(args.Message) + } else { + rt.Abortf(args.Code, args.Message) + } + return nil +} diff --git a/conformance/chaos/actor_test.go b/conformance/chaos/actor_test.go new file mode 100644 index 00000000000..a0826702281 --- /dev/null +++ b/conformance/chaos/actor_test.go @@ -0,0 +1,153 @@ +package chaos + +import ( + "context" + "testing" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/exitcode" + "github.com/filecoin-project/specs-actors/support/mock" + atesting "github.com/filecoin-project/specs-actors/support/testing" +) + +func TestSingleton(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + msg := "constructor should not be called; the Chaos actor is a singleton actor" + rt.ExpectAssertionFailure(msg, func() { + rt.Call(a.Constructor, abi.Empty) + }) + rt.Verify() +} + +func TestDeleteActor(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + beneficiary := atesting.NewIDAddr(t, 101) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + rt.ExpectValidateCallerAny() + rt.ExpectDeleteActor(beneficiary) + rt.Call(a.DeleteActor, &beneficiary) + rt.Verify() +} + +func TestMutateStateInTransaction(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + rt.ExpectValidateCallerAny() + rt.Create(&State{}) + + val := "__mutstat test" + rt.Call(a.MutateState, &MutateStateArgs{ + Value: val, + Branch: MutateInTransaction, + }) + + var st State + rt.GetState(&st) + + if st.Value != val { + t.Fatal("state was not updated") + } + + rt.Verify() +} + +func TestMutateStateAfterTransaction(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + rt.ExpectValidateCallerAny() + rt.Create(&State{}) + + val := "__mutstat test" + rt.Call(a.MutateState, &MutateStateArgs{ + Value: val, + Branch: MutateAfterTransaction, + }) + + var st State + rt.GetState(&st) + + // state should be updated successfully _in_ the transaction but not outside + if st.Value != val+"-in" { + t.Fatal("state was not updated") + } + + rt.Verify() +} + +func TestMutateStateReadonly(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + rt.ExpectValidateCallerAny() + rt.Create(&State{}) + + val := "__mutstat test" + rt.Call(a.MutateState, &MutateStateArgs{ + Value: val, + Branch: MutateReadonly, + }) + + var st State + rt.GetState(&st) + + if st.Value != "" { + t.Fatal("state was not expected to be updated") + } + + rt.Verify() +} + +func TestAbortWith(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + msg := "__test forbidden" + rt.ExpectAbortContainsMessage(exitcode.ErrForbidden, msg, func() { + rt.Call(a.AbortWith, &AbortWithArgs{ + Code: exitcode.ErrForbidden, + Message: msg, + Uncontrolled: false, + }) + }) + rt.Verify() +} + +func TestAbortWithUncontrolled(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + var a Actor + + msg := "__test uncontrolled panic" + rt.ExpectAssertionFailure(msg, func() { + rt.Call(a.AbortWith, &AbortWithArgs{ + Message: msg, + Uncontrolled: true, + }) + }) + rt.Verify() +} diff --git a/conformance/chaos/cbor_gen.go b/conformance/chaos/cbor_gen.go new file mode 100644 index 00000000000..710b84b9306 --- /dev/null +++ b/conformance/chaos/cbor_gen.go @@ -0,0 +1,732 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package chaos + +import ( + "fmt" + "io" + + abi "github.com/filecoin-project/go-state-types/abi" + exitcode "github.com/filecoin-project/go-state-types/exitcode" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +var lengthBufState = []byte{130} + +func (t *State) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufState); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Value (string) (string) + if len(t.Value) > cbg.MaxLength { + return xerrors.Errorf("Value in field t.Value was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len(t.Value))); err != nil { + return err + } + if _, err := io.WriteString(w, string(t.Value)); err != nil { + return err + } + + // t.Unmarshallable ([]*chaos.UnmarshallableCBOR) (slice) + if len(t.Unmarshallable) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Unmarshallable was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Unmarshallable))); err != nil { + return err + } + for _, v := range t.Unmarshallable { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + return nil +} + +func (t *State) UnmarshalCBOR(r io.Reader) error { + *t = State{} + + 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 != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Value (string) (string) + + { + sval, err := cbg.ReadStringBuf(br, scratch) + if err != nil { + return err + } + + t.Value = string(sval) + } + // t.Unmarshallable ([]*chaos.UnmarshallableCBOR) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Unmarshallable: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Unmarshallable = make([]*UnmarshallableCBOR, extra) + } + + for i := 0; i < int(extra); i++ { + + var v UnmarshallableCBOR + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Unmarshallable[i] = &v + } + + return nil +} + +var lengthBufCreateActorArgs = []byte{132} + +func (t *CreateActorArgs) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufCreateActorArgs); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.UndefActorCID (bool) (bool) + if err := cbg.WriteBool(w, t.UndefActorCID); err != nil { + return err + } + + // t.ActorCID (cid.Cid) (struct) + + if err := cbg.WriteCidBuf(scratch, w, t.ActorCID); err != nil { + return xerrors.Errorf("failed to write cid field t.ActorCID: %w", err) + } + + // t.UndefAddress (bool) (bool) + if err := cbg.WriteBool(w, t.UndefAddress); err != nil { + return err + } + + // t.Address (address.Address) (struct) + if err := t.Address.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *CreateActorArgs) UnmarshalCBOR(r io.Reader) error { + *t = CreateActorArgs{} + + 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 != 4 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.UndefActorCID (bool) (bool) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.UndefActorCID = false + case 21: + t.UndefActorCID = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + // t.ActorCID (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.ActorCID: %w", err) + } + + t.ActorCID = c + + } + // t.UndefAddress (bool) (bool) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.UndefAddress = false + case 21: + t.UndefAddress = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + // t.Address (address.Address) (struct) + + { + + if err := t.Address.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Address: %w", err) + } + + } + return nil +} + +var lengthBufResolveAddressResponse = []byte{130} + +func (t *ResolveAddressResponse) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufResolveAddressResponse); err != nil { + return err + } + + // t.Address (address.Address) (struct) + if err := t.Address.MarshalCBOR(w); err != nil { + return err + } + + // t.Success (bool) (bool) + if err := cbg.WriteBool(w, t.Success); err != nil { + return err + } + return nil +} + +func (t *ResolveAddressResponse) UnmarshalCBOR(r io.Reader) error { + *t = ResolveAddressResponse{} + + 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 != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Address (address.Address) (struct) + + { + + if err := t.Address.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Address: %w", err) + } + + } + // t.Success (bool) (bool) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.Success = false + case 21: + t.Success = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + return nil +} + +var lengthBufSendArgs = []byte{132} + +func (t *SendArgs) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufSendArgs); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.To (address.Address) (struct) + if err := t.To.MarshalCBOR(w); err != nil { + return err + } + + // t.Value (big.Int) (struct) + if err := t.Value.MarshalCBOR(w); err != nil { + return err + } + + // t.Method (abi.MethodNum) (uint64) + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Method)); err != nil { + return err + } + + // t.Params ([]uint8) (slice) + if len(t.Params) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Params was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(t.Params))); err != nil { + return err + } + + if _, err := w.Write(t.Params[:]); err != nil { + return err + } + return nil +} + +func (t *SendArgs) UnmarshalCBOR(r io.Reader) error { + *t = SendArgs{} + + 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 != 4 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.To (address.Address) (struct) + + { + + if err := t.To.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.To: %w", err) + } + + } + // t.Value (big.Int) (struct) + + { + + if err := t.Value.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Value: %w", err) + } + + } + // t.Method (abi.MethodNum) (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.Method = abi.MethodNum(extra) + + } + // t.Params ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Params: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + if extra > 0 { + t.Params = make([]uint8, extra) + } + + if _, err := io.ReadFull(br, t.Params[:]); err != nil { + return err + } + return nil +} + +var lengthBufSendReturn = []byte{130} + +func (t *SendReturn) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufSendReturn); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Return (runtime.CBORBytes) (slice) + if len(t.Return) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Return was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(t.Return))); err != nil { + return err + } + + if _, err := w.Write(t.Return[:]); err != nil { + return err + } + + // t.Code (exitcode.ExitCode) (int64) + if t.Code >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Code)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.Code-1)); err != nil { + return err + } + } + return nil +} + +func (t *SendReturn) UnmarshalCBOR(r io.Reader) error { + *t = SendReturn{} + + 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 != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Return (runtime.CBORBytes) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Return: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + if extra > 0 { + t.Return = make([]uint8, extra) + } + + if _, err := io.ReadFull(br, t.Return[:]); err != nil { + return err + } + // t.Code (exitcode.ExitCode) (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.Code = exitcode.ExitCode(extraI) + } + return nil +} + +var lengthBufMutateStateArgs = []byte{130} + +func (t *MutateStateArgs) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufMutateStateArgs); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Value (string) (string) + if len(t.Value) > cbg.MaxLength { + return xerrors.Errorf("Value in field t.Value was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len(t.Value))); err != nil { + return err + } + if _, err := io.WriteString(w, string(t.Value)); err != nil { + return err + } + + // t.Branch (chaos.MutateStateBranch) (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 + } + } + return nil +} + +func (t *MutateStateArgs) UnmarshalCBOR(r io.Reader) error { + *t = MutateStateArgs{} + + 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 != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Value (string) (string) + + { + sval, err := cbg.ReadStringBuf(br, scratch) + if err != nil { + return err + } + + t.Value = string(sval) + } + // t.Branch (chaos.MutateStateBranch) (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 = MutateStateBranch(extraI) + } + return nil +} + +var lengthBufAbortWithArgs = []byte{131} + +func (t *AbortWithArgs) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufAbortWithArgs); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Code (exitcode.ExitCode) (int64) + if t.Code >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Code)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.Code-1)); err != nil { + return err + } + } + + // t.Message (string) (string) + if len(t.Message) > cbg.MaxLength { + return xerrors.Errorf("Value in field t.Message was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len(t.Message))); err != nil { + return err + } + if _, err := io.WriteString(w, string(t.Message)); err != nil { + return err + } + + // t.Uncontrolled (bool) (bool) + if err := cbg.WriteBool(w, t.Uncontrolled); err != nil { + return err + } + return nil +} + +func (t *AbortWithArgs) UnmarshalCBOR(r io.Reader) error { + *t = AbortWithArgs{} + + 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.Code (exitcode.ExitCode) (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.Code = exitcode.ExitCode(extraI) + } + // t.Message (string) (string) + + { + sval, err := cbg.ReadStringBuf(br, scratch) + if err != nil { + return err + } + + t.Message = string(sval) + } + // t.Uncontrolled (bool) (bool) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.Uncontrolled = false + case 21: + t.Uncontrolled = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + return nil +} diff --git a/conformance/chaos/gen/gen.go b/conformance/chaos/gen/gen.go new file mode 100644 index 00000000000..97ea98dc8bb --- /dev/null +++ b/conformance/chaos/gen/gen.go @@ -0,0 +1,21 @@ +package main + +import ( + "github.com/filecoin-project/lotus/conformance/chaos" + + gen "github.com/whyrusleeping/cbor-gen" +) + +func main() { + if err := gen.WriteTupleEncodersToFile("../cbor_gen.go", "chaos", + chaos.State{}, + chaos.CreateActorArgs{}, + chaos.ResolveAddressResponse{}, + chaos.SendArgs{}, + chaos.SendReturn{}, + chaos.MutateStateArgs{}, + chaos.AbortWithArgs{}, + ); err != nil { + panic(err) + } +} diff --git a/conformance/chaos/ids.go b/conformance/chaos/ids.go new file mode 100644 index 00000000000..6b0ad86a743 --- /dev/null +++ b/conformance/chaos/ids.go @@ -0,0 +1,29 @@ +package chaos + +import ( + "github.com/filecoin-project/go-address" + "github.com/ipfs/go-cid" + "github.com/multiformats/go-multihash" +) + +// ChaosActorCodeCID is the CID by which this kind of actor will be identified. +var ChaosActorCodeCID = func() cid.Cid { + builder := cid.V1Builder{Codec: cid.Raw, MhType: multihash.IDENTITY} + c, err := builder.Sum([]byte("fil/1/chaos")) + if err != nil { + panic(err) + } + return c +}() + +// Address is the singleton address of this actor. Its value is 98 +// (builtin.FirstNonSingletonActorId - 2), as 99 is reserved for the burnt funds +// singleton. +var Address = func() address.Address { + // the address before the burnt funds address (99) + addr, err := address.NewIDAddress(98) + if err != nil { + panic(err) + } + return addr +}() diff --git a/conformance/chaos/state.go b/conformance/chaos/state.go new file mode 100644 index 00000000000..4a54ef61ca8 --- /dev/null +++ b/conformance/chaos/state.go @@ -0,0 +1,32 @@ +package chaos + +import ( + "fmt" + "io" +) + +// State is the state for the chaos actor used by some methods to invoke +// behaviours in the vm or runtime. +type State struct { + // Value can be updated by chaos actor methods to test illegal state + // mutations when the state is in readonly mode for example. + Value string + // Unmarshallable is a sentinel value. If the slice contains no values, the + // State struct will encode as CBOR without issue. If the slice is non-nil, + // CBOR encoding will fail. + Unmarshallable []*UnmarshallableCBOR +} + +// UnmarshallableCBOR is a type that cannot be marshalled or unmarshalled to +// CBOR despite implementing the CBORMarshaler and CBORUnmarshaler interface. +type UnmarshallableCBOR struct{} + +// UnmarshalCBOR will fail to unmarshal the value from CBOR. +func (t *UnmarshallableCBOR) UnmarshalCBOR(io.Reader) error { + return fmt.Errorf("failed to unmarshal cbor") +} + +// MarshalCBOR will fail to marshal the value to CBOR. +func (t *UnmarshallableCBOR) MarshalCBOR(io.Writer) error { + return fmt.Errorf("failed to marshal cbor") +} diff --git a/conformance/driver.go b/conformance/driver.go index 218198a05b2..a3363783713 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -3,18 +3,18 @@ package conformance import ( "context" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" + "github.com/filecoin-project/lotus/conformance/chaos" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" "github.com/filecoin-project/lotus/lib/blockstore" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/test-vectors/chaos" "github.com/filecoin-project/test-vectors/schema" "github.com/filecoin-project/go-address" @@ -96,13 +96,16 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, preroot var ( messages []*types.Message results []*vm.ApplyRet + + epoch = abi.ChainEpoch(tipset.Epoch) + basefee = abi.NewTokenAmount(tipset.BaseFee.Int64()) ) - postcid, receiptsroot, err := sm.ApplyBlocks(context.Background(), parentEpoch, preroot, blocks, tipset.Epoch, vmRand, func(_ cid.Cid, msg *types.Message, ret *vm.ApplyRet) error { + postcid, receiptsroot, err := sm.ApplyBlocks(context.Background(), parentEpoch, preroot, blocks, epoch, vmRand, func(_ cid.Cid, msg *types.Message, ret *vm.ApplyRet) error { messages = append(messages, msg) results = append(results, ret) return nil - }, tipset.BaseFee) + }, basefee, nil) if err != nil { return nil, err diff --git a/conformance/runner_test.go b/conformance/runner_test.go index 87317fc8d61..cc7ef6b3d9b 100644 --- a/conformance/runner_test.go +++ b/conformance/runner_test.go @@ -9,19 +9,25 @@ import ( "fmt" "io/ioutil" "os" + "os/exec" "path/filepath" "strconv" "strings" "testing" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/exitcode" + "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" + offline "github.com/ipfs/go-ipfs-exchange-offline" + format "github.com/ipfs/go-ipld-format" + "github.com/ipfs/go-merkledag" "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/statediff" "github.com/filecoin-project/test-vectors/schema" "github.com/fatih/color" @@ -177,7 +183,7 @@ func executeMessageVector(t *testing.T, vector *schema.TestVector) { // Execute the message. var ret *vm.ApplyRet - ret, root, err = driver.ExecuteMessage(bs, root, epoch, msg) + ret, root, err = driver.ExecuteMessage(bs, root, abi.ChainEpoch(epoch), msg) if err != nil { t.Fatalf("fatal failure when executing message: %s", err) } @@ -188,8 +194,10 @@ func executeMessageVector(t *testing.T, vector *schema.TestVector) { // Once all messages are applied, assert that the final state root matches // the expected postcondition root. - if root != vector.Post.StateTree.RootCID { + if expected, actual := vector.Post.StateTree.RootCID, root; expected != actual { + t.Logf("actual state root CID doesn't match expected one; expected: %s, actual: %s", expected, actual) dumpThreeWayStateDiff(t, vector, bs, root) + t.FailNow() } } @@ -212,7 +220,7 @@ func executeTipsetVector(t *testing.T, vector *schema.TestVector) { var receiptsIdx int for i, ts := range vector.ApplyTipsets { ts := ts // capture - ret, err := driver.ExecuteTipset(bs, tmpds, root, prevEpoch, &ts) + ret, err := driver.ExecuteTipset(bs, tmpds, root, abi.ChainEpoch(prevEpoch), &ts) if err != nil { t.Fatalf("failed to apply tipset %d message: %s", i, err) } @@ -233,8 +241,10 @@ func executeTipsetVector(t *testing.T, vector *schema.TestVector) { // Once all messages are applied, assert that the final state root matches // the expected postcondition root. - if root != vector.Post.StateTree.RootCID { + if expected, actual := vector.Post.StateTree.RootCID, root; expected != actual { + t.Logf("actual state root CID doesn't match expected one; expected: %s, actual: %s", expected, actual) dumpThreeWayStateDiff(t, vector, bs, root) + t.FailNow() } } @@ -244,7 +254,7 @@ func executeTipsetVector(t *testing.T, vector *schema.TestVector) { func assertMsgResult(t *testing.T, expected *schema.Receipt, actual *vm.ApplyRet, label string) { t.Helper() - if expected, actual := expected.ExitCode, actual.ExitCode; expected != actual { + if expected, actual := exitcode.ExitCode(expected.ExitCode), actual.ExitCode; expected != actual { t.Errorf("exit code of msg %s did not match; expected: %s, got: %s", label, expected, actual) } if expected, actual := expected.GasUsed, actual.GasUsed; expected != actual { @@ -256,6 +266,23 @@ func assertMsgResult(t *testing.T, expected *schema.Receipt, actual *vm.ApplyRet } func dumpThreeWayStateDiff(t *testing.T, vector *schema.TestVector, bs blockstore.Blockstore, actual cid.Cid) { + // check if statediff exists; if not, skip. + if err := exec.Command("statediff", "--help").Run(); err != nil { + t.Log("could not dump 3-way state tree diff upon test failure: statediff command not found") + t.Log("install statediff with:") + t.Log("$ git clone https://github.com/filecoin-project/statediff.git") + t.Log("$ cd statediff") + t.Log("$ go generate ./...") + t.Log("$ go install ./cmd/statediff") + return + } + + tmpCar := writeStateToTempCAR(t, bs, + vector.Pre.StateTree.RootCID, + vector.Post.StateTree.RootCID, + actual, + ) + color.NoColor = false // enable colouring. t.Errorf("wrong post root cid; expected %v, but got %v", vector.Post.StateTree.RootCID, actual) @@ -269,19 +296,64 @@ func dumpThreeWayStateDiff(t *testing.T, vector *schema.TestVector, bs blockstor d3 = color.New(color.FgGreen, color.Bold).Sprint("[Δ3]") ) + printDiff := func(left, right cid.Cid) { + cmd := exec.Command("statediff", "car", "--file", tmpCar, left.String(), right.String()) + b, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("statediff failed: %s", err) + } + t.Log(string(b)) + } + bold := color.New(color.Bold).SprintfFunc() // run state diffs. t.Log(bold("=== dumping 3-way diffs between %s, %s, %s ===", a, b, c)) t.Log(bold("--- %s left: %s; right: %s ---", d1, a, b)) - t.Log(statediff.Diff(context.Background(), bs, vector.Post.StateTree.RootCID, actual)) + printDiff(vector.Post.StateTree.RootCID, actual) t.Log(bold("--- %s left: %s; right: %s ---", d2, c, b)) - t.Log(statediff.Diff(context.Background(), bs, vector.Pre.StateTree.RootCID, actual)) + printDiff(vector.Pre.StateTree.RootCID, actual) t.Log(bold("--- %s left: %s; right: %s ---", d3, c, a)) - t.Log(statediff.Diff(context.Background(), bs, vector.Pre.StateTree.RootCID, vector.Post.StateTree.RootCID)) + printDiff(vector.Pre.StateTree.RootCID, vector.Post.StateTree.RootCID) +} + +// writeStateToTempCAR writes the provided roots to a temporary CAR that'll be +// cleaned up via t.Cleanup(). It returns the full path of the temp file. +func writeStateToTempCAR(t *testing.T, bs blockstore.Blockstore, roots ...cid.Cid) string { + tmp, err := ioutil.TempFile("", "lotus-tests-*.car") + if err != nil { + t.Fatalf("failed to create temp file to dump CAR for diffing: %s", err) + } + // register a cleanup function to delete the CAR. + t.Cleanup(func() { + _ = os.Remove(tmp.Name()) + }) + + carWalkFn := func(nd format.Node) (out []*format.Link, err error) { + for _, link := range nd.Links() { + if link.Cid.Prefix().Codec == cid.FilCommitmentSealed || link.Cid.Prefix().Codec == cid.FilCommitmentUnsealed { + continue + } + out = append(out, link) + } + return out, nil + } + + var ( + offl = offline.Exchange(bs) + blkserv = blockservice.New(bs, offl) + dserv = merkledag.NewDAGService(blkserv) + ) + + err = car.WriteCarWithWalker(context.Background(), dserv, roots, tmp, carWalkFn) + if err != nil { + t.Fatalf("failed to dump CAR for diffing: %s", err) + } + _ = tmp.Close() + return tmp.Name() } func loadCAR(t *testing.T, vectorCAR schema.Base64EncodedBytes) blockstore.Blockstore { diff --git a/conformance/stubs.go b/conformance/stubs.go index 2fd1e7b64df..a7100892f9c 100644 --- a/conformance/stubs.go +++ b/conformance/stubs.go @@ -3,12 +3,14 @@ package conformance import ( "context" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/vm" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/runtime" cbor "github.com/ipfs/go-ipld-cbor" @@ -36,12 +38,12 @@ func (fss *testSyscalls) VerifySignature(_ crypto.Signature, _ address.Address, } // TODO VerifySeal this will always succeed; but we want to be able to test failures too. -func (fss *testSyscalls) VerifySeal(_ abi.SealVerifyInfo) error { +func (fss *testSyscalls) VerifySeal(_ proof.SealVerifyInfo) error { return nil } // TODO VerifyPoSt this will always succeed; but we want to be able to test failures too. -func (fss *testSyscalls) VerifyPoSt(_ abi.WindowPoStVerifyInfo) error { +func (fss *testSyscalls) VerifyPoSt(_ proof.WindowPoStVerifyInfo) error { return nil } diff --git a/documentation/en/.glossary.json b/documentation/en/.glossary.json index 79d96664a98..e8a9e0846b4 100644 --- a/documentation/en/.glossary.json +++ b/documentation/en/.glossary.json @@ -95,7 +95,7 @@ "title": "Miner (Block Producer)", "value": "The Block Producer Miner's logic. It currently shares an interface and process with the Lotus Node. A Block Producer chooses which messages to include in a block and is rewarded according to each message’s gas price and consumption, forming a market." }, - "lotus-storage-miner": { + "lotus-miner": { "title": "Miner (lotus-miner)", "value": "The Miner's logic. It has its own dedicated process. Contributes to the network through Sector commitments and Proofs of Spacetime to prove that it is storing the sectors it has commited to." }, diff --git a/documentation/en/api-methods.md b/documentation/en/api-methods.md index bba212d45be..27875eca1af 100644 --- a/documentation/en/api-methods.md +++ b/documentation/en/api-methods.md @@ -46,6 +46,7 @@ * [ClientQueryAsk](#ClientQueryAsk) * [ClientRemoveImport](#ClientRemoveImport) * [ClientRetrieve](#ClientRetrieve) + * [ClientRetrieveTryRestartInsufficientFunds](#ClientRetrieveTryRestartInsufficientFunds) * [ClientRetrieveWithEvents](#ClientRetrieveWithEvents) * [ClientStartDeal](#ClientStartDeal) * [Gas](#Gas) @@ -74,10 +75,14 @@ * [MpoolSetConfig](#MpoolSetConfig) * [MpoolSub](#MpoolSub) * [Msig](#Msig) + * [MsigAddApprove](#MsigAddApprove) + * [MsigAddCancel](#MsigAddCancel) + * [MsigAddPropose](#MsigAddPropose) * [MsigApprove](#MsigApprove) * [MsigCancel](#MsigCancel) * [MsigCreate](#MsigCreate) * [MsigGetAvailableBalance](#MsigGetAvailableBalance) + * [MsigGetVested](#MsigGetVested) * [MsigPropose](#MsigPropose) * [MsigSwapApprove](#MsigSwapApprove) * [MsigSwapCancel](#MsigSwapCancel) @@ -98,6 +103,7 @@ * [Paych](#Paych) * [PaychAllocateLane](#PaychAllocateLane) * [PaychAvailableFunds](#PaychAvailableFunds) + * [PaychAvailableFundsByFromTo](#PaychAvailableFundsByFromTo) * [PaychCollect](#PaychCollect) * [PaychGet](#PaychGet) * [PaychGetWaitReady](#PaychGetWaitReady) @@ -154,10 +160,12 @@ * [StateWaitMsg](#StateWaitMsg) * [Sync](#Sync) * [SyncCheckBad](#SyncCheckBad) + * [SyncCheckpoint](#SyncCheckpoint) * [SyncIncomingBlocks](#SyncIncomingBlocks) * [SyncMarkBad](#SyncMarkBad) * [SyncState](#SyncState) * [SyncSubmitBlock](#SyncSubmitBlock) + * [SyncUnmarkBad](#SyncUnmarkBad) * [Wallet](#Wallet) * [WalletBalance](#WalletBalance) * [WalletDefaultAddress](#WalletDefaultAddress) @@ -276,6 +284,7 @@ ChainExport returns a stream of bytes with CAR dump of chain data. The exported chain data includes the header chain from the given tipset back to genesis, the entire genesis state, and the most recent 'nroots' state trees. +If oldmsgskip is set, messages from before the requested roots are also not included. Perms: read @@ -284,6 +293,7 @@ Inputs: ```json [ 10101, + true, [ { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" @@ -1158,6 +1168,22 @@ Inputs: Response: `{}` +### ClientRetrieveTryRestartInsufficientFunds +ClientRetrieveTryRestartInsufficientFunds attempts to restart stalled retrievals on a given payment channel +which are stuck due to insufficient funds + + +Perms: write + +Inputs: +```json +[ + "t01234" +] +``` + +Response: `{}` + ### ClientRetrieveWithEvents ClientRetrieveWithEvents initiates the retrieval of a file, as specified in the order, and provides a channel of status updates. @@ -1819,6 +1845,84 @@ The Msig methods are used to interact with multisig wallets on the filecoin network +### MsigAddApprove +MsigAddApprove approves a previously proposed AddSigner message +It takes the following params: , , , +, , + + +Perms: sign + +Inputs: +```json +[ + "t01234", + "t01234", + 42, + "t01234", + "t01234", + true +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +### MsigAddCancel +MsigAddCancel cancels a previously proposed AddSigner message +It takes the following params: , , , +, + + +Perms: sign + +Inputs: +```json +[ + "t01234", + "t01234", + 42, + "t01234", + true +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +### MsigAddPropose +MsigAddPropose proposes adding a signer in the multisig +It takes the following params: , , +, + + +Perms: sign + +Inputs: +```json +[ + "t01234", + "t01234", + "t01234", + true +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + ### MsigApprove MsigApprove approves a previously-proposed multisig message It takes the following params: , , , , , @@ -1926,6 +2030,38 @@ Inputs: Response: `"0"` +### MsigGetVested +MsigGetVested returns the amount of FIL that vested in a multisig in a certain period. +It takes the following params: , , + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `"0"` + ### MsigPropose MsigPropose proposes a multisig message It takes the following params: , , , @@ -1956,7 +2092,7 @@ Response: ### MsigSwapApprove MsigSwapApprove approves a previously proposed SwapSigner It takes the following params: , , , -, +, , Perms: sign @@ -1983,7 +2119,7 @@ Response: ### MsigSwapCancel MsigSwapCancel cancels a previously proposed SwapSigner message It takes the following params: , , , - +, Perms: sign @@ -2009,7 +2145,7 @@ Response: ### MsigSwapPropose MsigSwapPropose proposes swapping 2 signers in the multisig It takes the following params: , , - +, Perms: sign @@ -2239,6 +2375,27 @@ There are not yet any comments for this method. Perms: sign +Inputs: `null` + +Response: +```json +{ + "Channel": "\u003cempty\u003e", + "From": "t01234", + "To": "t01234", + "ConfirmedAmt": "0", + "PendingAmt": "0", + "PendingWaitSentinel": null, + "QueuedAmt": "0", + "VoucherReedeemedAmt": "0" +} +``` + +### PaychAvailableFundsByFromTo +There are not yet any comments for this method. + +Perms: sign + Inputs: ```json [ @@ -2250,6 +2407,8 @@ Response: ```json { "Channel": "\u003cempty\u003e", + "From": "t01234", + "To": "t01234", "ConfirmedAmt": "0", "PendingAmt": "0", "PendingWaitSentinel": null, @@ -3476,7 +3635,12 @@ Response: "Open": 10101, "Close": 10101, "Challenge": 10101, - "FaultCutoff": 10101 + "FaultCutoff": 10101, + "WPoStPeriodDeadlines": 42, + "WPoStProvingPeriod": 10101, + "WPoStChallengeWindow": 10101, + "WPoStChallengeLookback": 10101, + "FaultDeclarationCutoff": 10101 } ``` @@ -3954,6 +4118,28 @@ Inputs: Response: `"string value"` +### SyncCheckpoint +SyncCheckpoint marks a blocks as checkpointed, meaning that it won't ever fork away from it. + + +Perms: admin + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `{}` + ### SyncIncomingBlocks SyncIncomingBlocks returns a channel streaming incoming, potentially not yet synced block headers. @@ -4089,6 +4275,23 @@ Inputs: Response: `{}` +### SyncUnmarkBad +SyncUnmarkBad unmarks a blocks as bad, making it possible to be validated and synced again. + + +Perms: admin + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: `{}` + ## Wallet diff --git a/documentation/en/architecture.md b/documentation/en/architecture.md index 619e04f05a2..ca4789fa009 100644 --- a/documentation/en/architecture.md +++ b/documentation/en/architecture.md @@ -259,7 +259,7 @@ When we launch a Lotus node with the command `./lotus daemon` (see [here](https://github.com/filecoin-project/lotus/blob/master/cmd/lotus/daemon.go) for more), the node is created through [dependency injection](https://godoc.org/go.uber.org/fx). This relies on reflection, which makes some of the references hard to follow. -The node sets up all of the subsystems it needs to run, such as the repository, the network connections, thechain sync +The node sets up all of the subsystems it needs to run, such as the repository, the network connections, the chain sync service, etc. This setup is orchestrated through calls to the `node.Override` function. The structure of each call indicates the type of component it will set up diff --git a/documentation/en/dev/create-miner.md b/documentation/en/dev/create-miner.md index 9a1cf2d4e07..7b3b8176548 100644 --- a/documentation/en/dev/create-miner.md +++ b/documentation/en/dev/create-miner.md @@ -43,9 +43,9 @@ FIXME: Is there an easy way to visualize the message generated by the Faucet? ## Storage miner node -The `lotus-storage-miner` command provides a set of tools to manage the miners associated with the local storage miner node. At this point it is important to note the different [node types](https://github.com/filecoin-project/lotus/blob/master/node/repo/fsrepo.go), in the previous document we always referred to a *single* local node, `FullNode`, which handled the sync process and any other communication with the Filecoin network (the term *full* stands for full validation of the consensus protocol, there are no *light* clients at the moment that do not do the full validation). We now create a new node of type [`StorageMiner`](https://github.com/filecoin-project/lotus/blob/master/node/repo/fsrepo.go), with its own repo (each node is always associated to its own repo), by default in `~/.lotusstorage`. The difference between the two nodes lies in the services they run (see build options in the main architecture document). +The `lotus-miner` command provides a set of tools to manage the miners associated with the local storage miner node. At this point it is important to note the different [node types](https://github.com/filecoin-project/lotus/blob/master/node/repo/fsrepo.go), in the previous document we always referred to a *single* local node, `FullNode`, which handled the sync process and any other communication with the Filecoin network (the term *full* stands for full validation of the consensus protocol, there are no *light* clients at the moment that do not do the full validation). We now create a new node of type [`StorageMiner`](https://github.com/filecoin-project/lotus/blob/master/node/repo/fsrepo.go), with its own repo (each node is always associated to its own repo), by default in `~/.lotusstorage`. The difference between the two nodes lies in the services they run (see build options in the main architecture document). -The `lotus-storage-miner init` command option creates a new storage miner node. We will only be able to run the command once the chain has been synced by the full node (which needs to be running) and it will also require the download of the [proof parameters](https://filecoin.io/blog/filecoin-proof-system/) (of several GBs, so it may take some time). +The `lotus-miner init` command option creates a new storage miner node. We will only be able to run the command once the chain has been synced by the full node (which needs to be running) and it will also require the download of the [proof parameters](https://filecoin.io/blog/filecoin-proof-system/) (of several GBs, so it may take some time). The main options that define a miner are the owner and worker addresses associated to it (stored in [`MinerInfo`](https://github.com/filecoin-project/specs-actors/blob/master/actors/builtin/miner/miner_state.go), a substructure of the Miner Actor State) and its peer ID. We use default values for all of these options in the command and briefly described them here: @@ -55,7 +55,7 @@ The main options that define a miner are the owner and worker addresses associat * [Peer ID](https://docs.libp2p.io/reference/glossary/#peerid): a network ID (belonging to the `libp2p` stack) used to contact the miner directly off-chain (e.g., to make a storage deal). Note the difference with the rest of the communication in the Filecoin network that happens largely inside the chain itself: when we "send" messages to the different actors that is actually a VM abstraction meaning we execute the method in the VM itself run by logic of the targeted actor, physically (at the network TCP/IP level) we broadcast the message to all of our peers to be included in a Filecoin block. -With the miner information filled the command constructs a Filecoin message to broadcast to the network and be included in a Filecoin block by a miner (see [`createStorageMiner()`](https://github.com/filecoin-project/lotus/blob/master/cmd/lotus-storage-miner/init.go)). We will wait for that block to be synced to the chain (by the full node) before returning the miner ID address. The ID address is another way to refer to the miner through a unique ID in the chain, it has a type 0 and it is the address that is normally seen in chain visualization tools, e.g., `t01475` (since, in contrast with the public-key types of addresses, it is easily readable by humans). +With the miner information filled the command constructs a Filecoin message to broadcast to the network and be included in a Filecoin block by a miner (see [`createStorageMiner()`](https://github.com/filecoin-project/lotus/blob/master/cmd/lotus-miner/init.go)). We will wait for that block to be synced to the chain (by the full node) before returning the miner ID address. The ID address is another way to refer to the miner through a unique ID in the chain, it has a type 0 and it is the address that is normally seen in chain visualization tools, e.g., `t01475` (since, in contrast with the public-key types of addresses, it is easily readable by humans). The Filecoin message constructed will be targeted to the [Power Actor](https://filecoin-project.github.io/specs/#systems__filecoin_blockchain__storage_power_consensus__storage_power_actor) (`StoragePowerActorAddr`), which tracks the amount of power (storage capacity) every miner has, and it will have the method number of the [`CreateMiner`](https://github.com/filecoin-project/specs-actors/blob/master/actors/builtin/methods.go) constant. @@ -69,13 +69,13 @@ Back to the CLI command, the [`MpoolPushMessage`](https://github.com/filecoin-pr ## VM: message execution -We describe here the code flow inside the VM when it executes the `CreateMiner` method (of the message sent by the `lotus-storage-miner` command included by a miner in a block). This execution will be the same seen by all participants in the Filecoin protocol, the miner including the message in the block, the full node syncing to it, and any other peer receiving also this message. +We describe here the code flow inside the VM when it executes the `CreateMiner` method (of the message sent by the `lotus-miner` command included by a miner in a block). This execution will be the same seen by all participants in the Filecoin protocol, the miner including the message in the block, the full node syncing to it, and any other peer receiving also this message. There is a one-to-one mapping between the pair of actor and method number (`To:`/`Method:` fields) in a message in the VM, and the Go function in an actor's exported methods list that implement it. In this case, for the Power Actor list of method numbers defined in [`MethodsPower`](https://github.com/filecoin-project/specs-actors/blob/master/actors/builtin/methods.go), the `CreateMiner` method number 2 will correspond to the Go function with the same index in the list of methods returned by [`Exports()`](https://github.com/filecoin-project/specs-actors/blob/master/actors/builtin/power/power_actor.go) (and normally also the same name, here `(Actor).CreateMiner()`). The Power Actor in `CreateMiner()` will do two things: -1. Send *another* message, `Exec`, to the Init Actor to instruct it to create the miner actor with the information provided by `lotus-storage-miner` and receive its ID address (this ID is the one returned to the CLI command). +1. Send *another* message, `Exec`, to the Init Actor to instruct it to create the miner actor with the information provided by `lotus-miner` and receive its ID address (this ID is the one returned to the CLI command). 2. Generate an entry in its list of power claims ([`State.Claims`](https://github.com/filecoin-project/specs-actors/blob/master/actors/builtin/power/power_state.go)) for the newly created ID address of the miner. diff --git a/documentation/en/install-systemd-services.md b/documentation/en/install-systemd-services.md index fbde1feec0e..3ce52acdf7e 100644 --- a/documentation/en/install-systemd-services.md +++ b/documentation/en/install-systemd-services.md @@ -8,7 +8,7 @@ The services expect their binaries to be present in `/usr/local/bin/`. You can u $ sudo make install ``` -for `lotus` and `lotus-storage-miner` and +for `lotus` and `lotus-miner` and ```sh $ sudo make install-chainwatch diff --git a/documentation/en/mining-troubleshooting.md b/documentation/en/mining-troubleshooting.md index 5aaf9f6ef61..d2cc036a7ea 100644 --- a/documentation/en/mining-troubleshooting.md +++ b/documentation/en/mining-troubleshooting.md @@ -22,7 +22,7 @@ This bug occurs when the miner can't acquire the `bellman.lock`. To fix it you n ```sh lotus-miner info -# WARN main lotus-storage-miner/main.go:73 failed to get api endpoint: (/Users/myrmidon/.lotusminer) %!w(*errors.errorString=&{API not running (no endpoint)}): +# WARN main lotus-miner/main.go:73 failed to get api endpoint: (/Users/myrmidon/.lotusminer) %!w(*errors.errorString=&{API not running (no endpoint)}): ``` If you see this, that means your **Lotus Miner** isn't ready yet. You need to finish [syncing the chain](https://lotu.sh/en+join-testnet). diff --git a/documentation/en/payment-channels.md b/documentation/en/payment-channels.md index 7179da91678..afddcdc409e 100644 --- a/documentation/en/payment-channels.md +++ b/documentation/en/payment-channels.md @@ -84,3 +84,28 @@ Once the settlement period is over, either the client or provider can call colle ```sh $ lotus paych collect ``` + +Check the status of a channel that is still being created using `lotus paych status-by-from-to`. + +```sh +$ lotus paych status-by-from-to +Creating channel + From: t3sb6xzvs6rhlziatagevxpp3dwapdolurtkpn4kyh3kgoo4tn5o7lutjqlsnvpceztlhxu3lzzfe34rvpsjgq + To: t1zip4sblhyrn4oxygzsm6nafbsynp2avmk3xafea + Pending Amt: 10000 + Wait Sentinel: bafy2bzacedk2jidsyxcynusted35t5ipkhu2kpiodtwyjr3pimrhke6f5pqbm +``` + +Check the status of a channel that has been created using `lotus paych status`. + +```sh +$ lotus paych status +Channel exists + Channel: t2nydpzhmeqkmid5smtqnowlr2mr5az6rexpmyv6i + From: t3sb6xzvs6rhlziatagevxpp3dwapdolurtkpn4kyh3kgoo4tn5o7lutjqlsnvpceztlhxu3lzzfe34rvpsjgq + To: t1zip4sblhyrn4oxygzsm6nafbsynp2avmk3xafea + Confirmed Amt: 10000 + Pending Amt: 6000 + Queued Amt: 3000 + Voucher Redeemed Amt: 2000 +``` diff --git a/extern/fil-blst b/extern/fil-blst new file mode 160000 index 00000000000..5f93488fc0d --- /dev/null +++ b/extern/fil-blst @@ -0,0 +1 @@ +Subproject commit 5f93488fc0dbfb450f2355269f18fc67010d59bb diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index 777a6fbf444..f640612a1a1 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit 777a6fbf4446b1112adfd4fa5dd88e0c88974122 +Subproject commit f640612a1a1f7a2dd8b3a49e1531db0aa0f63447 diff --git a/extern/sector-storage/faults.go b/extern/sector-storage/faults.go index 06c823bb870..31a1a369083 100644 --- a/extern/sector-storage/faults.go +++ b/extern/sector-storage/faults.go @@ -8,8 +8,8 @@ import ( "golang.org/x/xerrors" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/stores" - "github.com/filecoin-project/specs-actors/actors/abi" ) // FaultTracker TODO: Track things more actively diff --git a/extern/sector-storage/ffiwrapper/basicfs/fs.go b/extern/sector-storage/ffiwrapper/basicfs/fs.go index ae17273e9f5..00aa49b9808 100644 --- a/extern/sector-storage/ffiwrapper/basicfs/fs.go +++ b/extern/sector-storage/ffiwrapper/basicfs/fs.go @@ -6,7 +6,7 @@ import ( "path/filepath" "sync" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/stores" "github.com/filecoin-project/lotus/extern/sector-storage/storiface" diff --git a/extern/sector-storage/ffiwrapper/config.go b/extern/sector-storage/ffiwrapper/config.go index 707fc6746b7..ca32b119186 100644 --- a/extern/sector-storage/ffiwrapper/config.go +++ b/extern/sector-storage/ffiwrapper/config.go @@ -3,7 +3,7 @@ package ffiwrapper import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) type Config struct { diff --git a/extern/sector-storage/ffiwrapper/partialfile.go b/extern/sector-storage/ffiwrapper/partialfile.go index 597e3310585..e19930ac1ca 100644 --- a/extern/sector-storage/ffiwrapper/partialfile.go +++ b/extern/sector-storage/ffiwrapper/partialfile.go @@ -10,7 +10,7 @@ import ( "golang.org/x/xerrors" rlepluslazy "github.com/filecoin-project/go-bitfield/rle" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/fsutil" "github.com/filecoin-project/lotus/extern/sector-storage/storiface" diff --git a/extern/sector-storage/ffiwrapper/sealer.go b/extern/sector-storage/ffiwrapper/sealer.go index c97557a3738..c1b558d9a30 100644 --- a/extern/sector-storage/ffiwrapper/sealer.go +++ b/extern/sector-storage/ffiwrapper/sealer.go @@ -1,7 +1,7 @@ package ffiwrapper import ( - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" logging "github.com/ipfs/go-log/v2" ) diff --git a/extern/sector-storage/ffiwrapper/sealer_cgo.go b/extern/sector-storage/ffiwrapper/sealer_cgo.go index d4f796dcb83..9bc2680edfa 100644 --- a/extern/sector-storage/ffiwrapper/sealer_cgo.go +++ b/extern/sector-storage/ffiwrapper/sealer_cgo.go @@ -17,7 +17,7 @@ import ( ffi "github.com/filecoin-project/filecoin-ffi" rlepluslazy "github.com/filecoin-project/go-bitfield/rle" commcid "github.com/filecoin-project/go-fil-commcid" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/extern/sector-storage/fr32" @@ -410,7 +410,7 @@ func (sb *Sealer) ReadPiece(ctx context.Context, writer io.Writer, sector abi.Se return false, xerrors.Errorf("closing partial file: %w", err) } - return false, nil + return true, nil } func (sb *Sealer) SealPreCommit1(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, pieces []abi.PieceInfo) (out storage.PreCommit1Out, err error) { diff --git a/extern/sector-storage/ffiwrapper/sealer_test.go b/extern/sector-storage/ffiwrapper/sealer_test.go index b484b391fee..d59de2cabc7 100644 --- a/extern/sector-storage/ffiwrapper/sealer_test.go +++ b/extern/sector-storage/ffiwrapper/sealer_test.go @@ -15,6 +15,8 @@ import ( "testing" "time" + saproof "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log" @@ -22,7 +24,7 @@ import ( "golang.org/x/xerrors" paramfetch "github.com/filecoin-project/go-paramfetch" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" ffi "github.com/filecoin-project/filecoin-ffi" @@ -91,7 +93,7 @@ func (s *seal) commit(t *testing.T, sb *Sealer, done func()) { t.Fatalf("%+v", err) } - ok, err := ProofVerifier.VerifySeal(abi.SealVerifyInfo{ + ok, err := ProofVerifier.VerifySeal(saproof.SealVerifyInfo{ SectorID: s.id, SealedCID: s.cids.Sealed, SealProof: sealProofType, @@ -166,50 +168,34 @@ func (s *seal) unseal(t *testing.T, sb *Sealer, sp *basicfs.Provider, si abi.Sec } } -func post(t *testing.T, sealer *Sealer, seals ...seal) time.Time { - /*randomness := abi.PoStRandomness{0, 9, 2, 7, 6, 5, 4, 3, 2, 1, 0, 9, 8, 7, 6, 45, 3, 2, 1, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 7} +func post(t *testing.T, sealer *Sealer, skipped []abi.SectorID, seals ...seal) { + randomness := abi.PoStRandomness{0, 9, 2, 7, 6, 5, 4, 3, 2, 1, 0, 9, 8, 7, 6, 45, 3, 2, 1, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 7} - sis := make([]abi.SectorInfo, len(seals)) + sis := make([]saproof.SectorInfo, len(seals)) for i, s := range seals { - sis[i] = abi.SectorInfo{ - RegisteredProof: sealProofType, - SectorNumber: s.id.Number, - SealedCID: s.cids.Sealed, + sis[i] = saproof.SectorInfo{ + SealProof: sealProofType, + SectorNumber: s.id.Number, + SealedCID: s.cids.Sealed, } } - candidates, err := sealer.GenerateEPostCandidates(context.TODO(), seals[0].id.Miner, sis, randomness, []abi.SectorNumber{}) - if err != nil { - t.Fatalf("%+v", err) - }*/ - - fmt.Println("skipping post") - - genCandidates := time.Now() - - /*if len(candidates) != 1 { - t.Fatal("expected 1 candidate") + proofs, skp, err := sealer.GenerateWindowPoSt(context.TODO(), seals[0].id.Miner, sis, randomness) + if len(skipped) > 0 { + require.Error(t, err) + require.EqualValues(t, skipped, skp) + return } - candidatesPrime := make([]abi.PoStCandidate, len(candidates)) - for idx := range candidatesPrime { - candidatesPrime[idx] = candidates[idx].Candidate - } - - proofs, err := sealer.ComputeElectionPoSt(context.TODO(), seals[0].id.Miner, sis, randomness, candidatesPrime) if err != nil { t.Fatalf("%+v", err) } - ePoStChallengeCount := ElectionPostChallengeCount(uint64(len(sis)), 0) - - ok, err := ProofVerifier.VerifyElectionPost(context.TODO(), abi.PoStVerifyInfo{ - Randomness: randomness, - Candidates: candidatesPrime, - Proofs: proofs, - EligibleSectors: sis, - Prover: seals[0].id.Miner, - ChallengeCount: ePoStChallengeCount, + ok, err := ProofVerifier.VerifyWindowPoSt(context.TODO(), saproof.WindowPoStVerifyInfo{ + Randomness: randomness, + Proofs: proofs, + ChallengedSectors: sis, + Prover: seals[0].id.Miner, }) if err != nil { t.Fatalf("%+v", err) @@ -217,8 +203,21 @@ func post(t *testing.T, sealer *Sealer, seals ...seal) time.Time { if !ok { t.Fatal("bad post") } - */ - return genCandidates +} + +func corrupt(t *testing.T, sealer *Sealer, id abi.SectorID) { + paths, done, err := sealer.sectors.AcquireSector(context.Background(), id, stores.FTSealed, 0, stores.PathStorage) + require.NoError(t, err) + defer done() + + log.Infof("corrupt %s", paths.Sealed) + f, err := os.OpenFile(paths.Sealed, os.O_RDWR, 0664) + require.NoError(t, err) + + _, err = f.WriteAt(bytes.Repeat([]byte{'d'}, 2048), 0) + require.NoError(t, err) + + require.NoError(t, f.Close()) } func getGrothParamFileAndVerifyingKeys(s abi.SectorSize) { @@ -297,11 +296,11 @@ func TestSealAndVerify(t *testing.T) { commit := time.Now() - genCandidiates := post(t, sb, s) + post(t, sb, nil, s) epost := time.Now() - post(t, sb, s) + post(t, sb, nil, s) if err := sb.FinalizeSector(context.TODO(), si, nil); err != nil { t.Fatalf("%+v", err) @@ -311,8 +310,7 @@ func TestSealAndVerify(t *testing.T) { fmt.Printf("PreCommit: %s\n", precommit.Sub(start).String()) fmt.Printf("Commit: %s\n", commit.Sub(precommit).String()) - fmt.Printf("GenCandidates: %s\n", genCandidiates.Sub(commit).String()) - fmt.Printf("EPoSt: %s\n", epost.Sub(genCandidiates).String()) + fmt.Printf("EPoSt: %s\n", epost.Sub(commit).String()) } func TestSealPoStNoCommit(t *testing.T) { @@ -368,16 +366,15 @@ func TestSealPoStNoCommit(t *testing.T) { t.Fatal(err) } - genCandidiates := post(t, sb, s) + post(t, sb, nil, s) epost := time.Now() fmt.Printf("PreCommit: %s\n", precommit.Sub(start).String()) - fmt.Printf("GenCandidates: %s\n", genCandidiates.Sub(precommit).String()) - fmt.Printf("EPoSt: %s\n", epost.Sub(genCandidiates).String()) + fmt.Printf("EPoSt: %s\n", epost.Sub(precommit).String()) } -func TestSealAndVerify2(t *testing.T) { +func TestSealAndVerify3(t *testing.T) { defer requireFDsClosed(t, openFDs(t)) if runtime.NumCPU() < 10 && os.Getenv("CI") == "" { // don't bother on slow hardware @@ -417,22 +414,32 @@ func TestSealAndVerify2(t *testing.T) { si1 := abi.SectorID{Miner: miner, Number: 1} si2 := abi.SectorID{Miner: miner, Number: 2} + si3 := abi.SectorID{Miner: miner, Number: 3} s1 := seal{id: si1} s2 := seal{id: si2} + s3 := seal{id: si3} - wg.Add(2) + wg.Add(3) go s1.precommit(t, sb, si1, wg.Done) //nolint: staticcheck time.Sleep(100 * time.Millisecond) go s2.precommit(t, sb, si2, wg.Done) //nolint: staticcheck + time.Sleep(100 * time.Millisecond) + go s3.precommit(t, sb, si3, wg.Done) //nolint: staticcheck wg.Wait() - wg.Add(2) + wg.Add(3) go s1.commit(t, sb, wg.Done) //nolint: staticcheck go s2.commit(t, sb, wg.Done) //nolint: staticcheck + go s3.commit(t, sb, wg.Done) //nolint: staticcheck wg.Wait() - post(t, sb, s1, s2) + post(t, sb, nil, s1, s2, s3) + + corrupt(t, sb, si1) + corrupt(t, sb, si2) + + post(t, sb, []abi.SectorID{si1, si2}, s1, s2, s3) } func BenchmarkWriteWithAlignment(b *testing.B) { diff --git a/extern/sector-storage/ffiwrapper/types.go b/extern/sector-storage/ffiwrapper/types.go index a634134eefe..318dbd2b0ea 100644 --- a/extern/sector-storage/ffiwrapper/types.go +++ b/extern/sector-storage/ffiwrapper/types.go @@ -4,9 +4,11 @@ import ( "context" "io" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/ipfs/go-cid" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper/basicfs" @@ -33,9 +35,9 @@ type Storage interface { } type Verifier interface { - VerifySeal(abi.SealVerifyInfo) (bool, error) - VerifyWinningPoSt(ctx context.Context, info abi.WinningPoStVerifyInfo) (bool, error) - VerifyWindowPoSt(ctx context.Context, info abi.WindowPoStVerifyInfo) (bool, error) + VerifySeal(proof.SealVerifyInfo) (bool, error) + VerifyWinningPoSt(ctx context.Context, info proof.WinningPoStVerifyInfo) (bool, error) + VerifyWindowPoSt(ctx context.Context, info proof.WindowPoStVerifyInfo) (bool, error) GenerateWinningPoStSectorChallenge(context.Context, abi.RegisteredPoStProof, abi.ActorID, abi.PoStRandomness, uint64) ([]uint64, error) } diff --git a/extern/sector-storage/ffiwrapper/unseal_ranges.go b/extern/sector-storage/ffiwrapper/unseal_ranges.go index 2e51199944a..4519fc21e6a 100644 --- a/extern/sector-storage/ffiwrapper/unseal_ranges.go +++ b/extern/sector-storage/ffiwrapper/unseal_ranges.go @@ -5,7 +5,7 @@ import ( rlepluslazy "github.com/filecoin-project/go-bitfield/rle" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/storiface" ) diff --git a/extern/sector-storage/ffiwrapper/verifier_cgo.go b/extern/sector-storage/ffiwrapper/verifier_cgo.go index de6fc08499a..d6c0ae35f1b 100644 --- a/extern/sector-storage/ffiwrapper/verifier_cgo.go +++ b/extern/sector-storage/ffiwrapper/verifier_cgo.go @@ -5,9 +5,11 @@ package ffiwrapper import ( "context" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ffi "github.com/filecoin-project/filecoin-ffi" @@ -16,7 +18,7 @@ import ( "go.opencensus.io/trace" ) -func (sb *Sealer) GenerateWinningPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []abi.SectorInfo, randomness abi.PoStRandomness) ([]abi.PoStProof, error) { +func (sb *Sealer) GenerateWinningPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []proof.SectorInfo, randomness abi.PoStRandomness) ([]proof.PoStProof, error) { randomness[31] &= 0x3f privsectors, skipped, done, err := sb.pubSectorToPriv(ctx, minerID, sectorInfo, nil, abi.RegisteredSealProof.RegisteredWinningPoStProof) // TODO: FAULTS? if err != nil { @@ -30,7 +32,7 @@ func (sb *Sealer) GenerateWinningPoSt(ctx context.Context, minerID abi.ActorID, return ffi.GenerateWinningPoSt(minerID, privsectors, randomness) } -func (sb *Sealer) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []abi.SectorInfo, randomness abi.PoStRandomness) ([]abi.PoStProof, []abi.SectorID, error) { +func (sb *Sealer) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []proof.SectorInfo, randomness abi.PoStRandomness) ([]proof.PoStProof, []abi.SectorID, error) { randomness[31] &= 0x3f privsectors, skipped, done, err := sb.pubSectorToPriv(ctx, minerID, sectorInfo, nil, abi.RegisteredSealProof.RegisteredWindowPoStProof) if err != nil { @@ -38,11 +40,24 @@ func (sb *Sealer) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, s } defer done() - proof, err := ffi.GenerateWindowPoSt(minerID, privsectors, randomness) - return proof, skipped, err + if len(skipped) > 0 { + return nil, skipped, xerrors.Errorf("pubSectorToPriv skipped some sectors") + } + + proof, faulty, err := ffi.GenerateWindowPoSt(minerID, privsectors, randomness) + + var faultyIDs []abi.SectorID + for _, f := range faulty { + faultyIDs = append(faultyIDs, abi.SectorID{ + Miner: minerID, + Number: f, + }) + } + + return proof, faultyIDs, err } -func (sb *Sealer) pubSectorToPriv(ctx context.Context, mid abi.ActorID, sectorInfo []abi.SectorInfo, faults []abi.SectorNumber, rpt func(abi.RegisteredSealProof) (abi.RegisteredPoStProof, error)) (ffi.SortedPrivateSectorInfo, []abi.SectorID, func(), error) { +func (sb *Sealer) pubSectorToPriv(ctx context.Context, mid abi.ActorID, sectorInfo []proof.SectorInfo, faults []abi.SectorNumber, rpt func(abi.RegisteredSealProof) (abi.RegisteredPoStProof, error)) (ffi.SortedPrivateSectorInfo, []abi.SectorID, func(), error) { fmap := map[abi.SectorNumber]struct{}{} for _, fault := range faults { fmap[fault] = struct{}{} @@ -95,11 +110,11 @@ type proofVerifier struct{} var ProofVerifier = proofVerifier{} -func (proofVerifier) VerifySeal(info abi.SealVerifyInfo) (bool, error) { +func (proofVerifier) VerifySeal(info proof.SealVerifyInfo) (bool, error) { return ffi.VerifySeal(info) } -func (proofVerifier) VerifyWinningPoSt(ctx context.Context, info abi.WinningPoStVerifyInfo) (bool, error) { +func (proofVerifier) VerifyWinningPoSt(ctx context.Context, info proof.WinningPoStVerifyInfo) (bool, error) { info.Randomness[31] &= 0x3f _, span := trace.StartSpan(ctx, "VerifyWinningPoSt") defer span.End() @@ -107,7 +122,7 @@ func (proofVerifier) VerifyWinningPoSt(ctx context.Context, info abi.WinningPoSt return ffi.VerifyWinningPoSt(info) } -func (proofVerifier) VerifyWindowPoSt(ctx context.Context, info abi.WindowPoStVerifyInfo) (bool, error) { +func (proofVerifier) VerifyWindowPoSt(ctx context.Context, info proof.WindowPoStVerifyInfo) (bool, error) { info.Randomness[31] &= 0x3f _, span := trace.StartSpan(ctx, "VerifyWindowPoSt") defer span.End() diff --git a/extern/sector-storage/fr32/fr32.go b/extern/sector-storage/fr32/fr32.go index b7248db7efc..17e6a114295 100644 --- a/extern/sector-storage/fr32/fr32.go +++ b/extern/sector-storage/fr32/fr32.go @@ -5,7 +5,7 @@ import ( "runtime" "sync" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) var MTTresh = uint64(32 << 20) diff --git a/extern/sector-storage/fr32/fr32_ffi_cmp_test.go b/extern/sector-storage/fr32/fr32_ffi_cmp_test.go index 2a602424a8b..3d567909555 100644 --- a/extern/sector-storage/fr32/fr32_ffi_cmp_test.go +++ b/extern/sector-storage/fr32/fr32_ffi_cmp_test.go @@ -12,7 +12,7 @@ import ( ffi "github.com/filecoin-project/filecoin-ffi" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/stretchr/testify/require" ) diff --git a/extern/sector-storage/fr32/fr32_test.go b/extern/sector-storage/fr32/fr32_test.go index e27e7b1e30f..415134272d0 100644 --- a/extern/sector-storage/fr32/fr32_test.go +++ b/extern/sector-storage/fr32/fr32_test.go @@ -9,7 +9,7 @@ import ( "testing" ffi "github.com/filecoin-project/filecoin-ffi" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/stretchr/testify/require" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" diff --git a/extern/sector-storage/fr32/readers.go b/extern/sector-storage/fr32/readers.go index 8a1bbe08724..20f3e9b3185 100644 --- a/extern/sector-storage/fr32/readers.go +++ b/extern/sector-storage/fr32/readers.go @@ -6,7 +6,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) type unpadReader struct { diff --git a/extern/sector-storage/fr32/readers_test.go b/extern/sector-storage/fr32/readers_test.go index e87a776efab..706af5fee79 100644 --- a/extern/sector-storage/fr32/readers_test.go +++ b/extern/sector-storage/fr32/readers_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/fr32" ) diff --git a/extern/sector-storage/fr32/utils.go b/extern/sector-storage/fr32/utils.go index 9f4093c40e3..26c348f4f9a 100644 --- a/extern/sector-storage/fr32/utils.go +++ b/extern/sector-storage/fr32/utils.go @@ -3,7 +3,7 @@ package fr32 import ( "math/bits" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) func subPieces(in abi.UnpaddedPieceSize) []abi.UnpaddedPieceSize { diff --git a/extern/sector-storage/localworker.go b/extern/sector-storage/localworker.go index 773ef2d3b68..2c3c350f765 100644 --- a/extern/sector-storage/localworker.go +++ b/extern/sector-storage/localworker.go @@ -12,7 +12,7 @@ import ( "golang.org/x/xerrors" ffi "github.com/filecoin-project/filecoin-ffi" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" storage2 "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" diff --git a/extern/sector-storage/manager.go b/extern/sector-storage/manager.go index 300958e397a..fe9bf5d4569 100644 --- a/extern/sector-storage/manager.go +++ b/extern/sector-storage/manager.go @@ -12,7 +12,7 @@ import ( "github.com/mitchellh/go-homedir" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" @@ -217,16 +217,11 @@ func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.Sect return xerrors.Errorf("read piece: checking for already existing unsealed sector: %w", err) } + var readOk bool var selector WorkerSelector if len(best) == 0 { // new selector = newAllocSelector(m.index, stores.FTUnsealed, stores.PathSealing) } else { // append to existing - selector = newExistingSelector(m.index, sector, stores.FTUnsealed, false) - } - - var readOk bool - - if len(best) > 0 { // There is unsealed sector, see if we can read from it selector = newExistingSelector(m.index, sector, stores.FTUnsealed, false) @@ -257,6 +252,9 @@ func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.Sect return nil } + if unsealed == cid.Undef { + return xerrors.Errorf("cannot unseal piece (sector: %d, offset: %d size: %d) - unsealed cid is undefined", sector, offset, size) + } err = m.sched.Schedule(ctx, sector, sealtasks.TTUnseal, selector, unsealFetch, func(ctx context.Context, w Worker) error { return w.UnsealPiece(ctx, sector, offset, size, ticket, unsealed) }) @@ -274,7 +272,7 @@ func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.Sect return xerrors.Errorf("reading piece from sealed sector: %w", err) } - if readOk { + if !readOk { return xerrors.Errorf("failed to read unsealed piece") } diff --git a/extern/sector-storage/manager_test.go b/extern/sector-storage/manager_test.go index 13ad9f8bf34..ee704cb5ae8 100644 --- a/extern/sector-storage/manager_test.go +++ b/extern/sector-storage/manager_test.go @@ -16,7 +16,7 @@ import ( "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" "github.com/filecoin-project/lotus/extern/sector-storage/stores" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/google/uuid" logging "github.com/ipfs/go-log" diff --git a/extern/sector-storage/mock/mock.go b/extern/sector-storage/mock/mock.go index 4afe5f0967c..64207e66d16 100644 --- a/extern/sector-storage/mock/mock.go +++ b/extern/sector-storage/mock/mock.go @@ -9,8 +9,10 @@ import ( "math/rand" "sync" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + commcid "github.com/filecoin-project/go-fil-commcid" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log" @@ -64,8 +66,9 @@ const ( ) type sectorState struct { - pieces []cid.Cid - failed bool + pieces []cid.Cid + failed bool + corrupted bool state int @@ -249,6 +252,18 @@ func (mgr *SectorMgr) MarkFailed(sid abi.SectorID, failed bool) error { return nil } +func (mgr *SectorMgr) MarkCorrupted(sid abi.SectorID, corrupted bool) error { + mgr.lk.Lock() + defer mgr.lk.Unlock() + ss, ok := mgr.sectors[sid] + if !ok { + return fmt.Errorf("no such sector in storage") + } + + ss.corrupted = corrupted + return nil +} + func opFinishWait(ctx context.Context) { val, ok := ctx.Value("opfinish").(chan struct{}) if !ok { @@ -265,14 +280,16 @@ func AddOpFinish(ctx context.Context) (context.Context, func()) { } } -func (mgr *SectorMgr) GenerateWinningPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []abi.SectorInfo, randomness abi.PoStRandomness) ([]abi.PoStProof, error) { +func (mgr *SectorMgr) GenerateWinningPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []proof.SectorInfo, randomness abi.PoStRandomness) ([]proof.PoStProof, error) { return generateFakePoSt(sectorInfo, abi.RegisteredSealProof.RegisteredWinningPoStProof, randomness), nil } -func (mgr *SectorMgr) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []abi.SectorInfo, randomness abi.PoStRandomness) ([]abi.PoStProof, []abi.SectorID, error) { - si := make([]abi.SectorInfo, 0, len(sectorInfo)) +func (mgr *SectorMgr) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []proof.SectorInfo, randomness abi.PoStRandomness) ([]proof.PoStProof, []abi.SectorID, error) { + si := make([]proof.SectorInfo, 0, len(sectorInfo)) var skipped []abi.SectorID + var err error + for _, info := range sectorInfo { sid := abi.SectorID{ Miner: minerID, @@ -281,17 +298,22 @@ func (mgr *SectorMgr) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorI _, found := mgr.sectors[sid] - if found && !mgr.sectors[sid].failed { + if found && !mgr.sectors[sid].failed && !mgr.sectors[sid].corrupted { si = append(si, info) } else { skipped = append(skipped, sid) + err = xerrors.Errorf("skipped some sectors") } } + if err != nil { + return nil, skipped, err + } + return generateFakePoSt(si, abi.RegisteredSealProof.RegisteredWindowPoStProof, randomness), skipped, nil } -func generateFakePoStProof(sectorInfo []abi.SectorInfo, randomness abi.PoStRandomness) []byte { +func generateFakePoStProof(sectorInfo []proof.SectorInfo, randomness abi.PoStRandomness) []byte { hasher := sha256.New() _, _ = hasher.Write(randomness) for _, info := range sectorInfo { @@ -304,13 +326,13 @@ func generateFakePoStProof(sectorInfo []abi.SectorInfo, randomness abi.PoStRando } -func generateFakePoSt(sectorInfo []abi.SectorInfo, rpt func(abi.RegisteredSealProof) (abi.RegisteredPoStProof, error), randomness abi.PoStRandomness) []abi.PoStProof { +func generateFakePoSt(sectorInfo []proof.SectorInfo, rpt func(abi.RegisteredSealProof) (abi.RegisteredPoStProof, error), randomness abi.PoStRandomness) []proof.PoStProof { wp, err := rpt(sectorInfo[0].SealProof) if err != nil { panic(err) } - return []abi.PoStProof{ + return []proof.PoStProof{ { PoStProof: wp, ProofBytes: generateFakePoStProof(sectorInfo, randomness), @@ -384,7 +406,7 @@ func (mgr *SectorMgr) CheckProvable(ctx context.Context, spt abi.RegisteredSealP return bad, nil } -func (m mockVerif) VerifySeal(svi abi.SealVerifyInfo) (bool, error) { +func (m mockVerif) VerifySeal(svi proof.SealVerifyInfo) (bool, error) { if len(svi.Proof) != 32 { // Real ones are longer, but this should be fine return false, nil } @@ -398,11 +420,11 @@ func (m mockVerif) VerifySeal(svi abi.SealVerifyInfo) (bool, error) { return true, nil } -func (m mockVerif) VerifyWinningPoSt(ctx context.Context, info abi.WinningPoStVerifyInfo) (bool, error) { +func (m mockVerif) VerifyWinningPoSt(ctx context.Context, info proof.WinningPoStVerifyInfo) (bool, error) { return true, nil } -func (m mockVerif) VerifyWindowPoSt(ctx context.Context, info abi.WindowPoStVerifyInfo) (bool, error) { +func (m mockVerif) VerifyWindowPoSt(ctx context.Context, info proof.WindowPoStVerifyInfo) (bool, error) { if len(info.Proofs) != 1 { return false, xerrors.Errorf("expected 1 proof entry") } diff --git a/extern/sector-storage/mock/mock_test.go b/extern/sector-storage/mock/mock_test.go index c7d43e8b9f2..47c060f667d 100644 --- a/extern/sector-storage/mock/mock_test.go +++ b/extern/sector-storage/mock/mock_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) func TestOpFinish(t *testing.T) { diff --git a/extern/sector-storage/resources.go b/extern/sector-storage/resources.go index 2fa7972673a..28ab47e6f71 100644 --- a/extern/sector-storage/resources.go +++ b/extern/sector-storage/resources.go @@ -1,7 +1,7 @@ package sectorstorage import ( - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" ) diff --git a/extern/sector-storage/roprov.go b/extern/sector-storage/roprov.go index fe58a84450f..2b009c63bc5 100644 --- a/extern/sector-storage/roprov.go +++ b/extern/sector-storage/roprov.go @@ -5,7 +5,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/stores" ) diff --git a/extern/sector-storage/sched.go b/extern/sector-storage/sched.go index 831a2615fed..8b8ef6d466c 100644 --- a/extern/sector-storage/sched.go +++ b/extern/sector-storage/sched.go @@ -10,7 +10,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" "github.com/filecoin-project/lotus/extern/sector-storage/storiface" diff --git a/extern/sector-storage/sched_test.go b/extern/sector-storage/sched_test.go index 4c39370a088..c560a58f600 100644 --- a/extern/sector-storage/sched_test.go +++ b/extern/sector-storage/sched_test.go @@ -14,7 +14,7 @@ import ( logging "github.com/ipfs/go-log/v2" "github.com/stretchr/testify/require" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/fsutil" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" diff --git a/extern/sector-storage/selector_alloc.go b/extern/sector-storage/selector_alloc.go index ca4b99bfc75..b891383fb3d 100644 --- a/extern/sector-storage/selector_alloc.go +++ b/extern/sector-storage/selector_alloc.go @@ -5,7 +5,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" "github.com/filecoin-project/lotus/extern/sector-storage/stores" diff --git a/extern/sector-storage/selector_existing.go b/extern/sector-storage/selector_existing.go index 1e97db539dd..fb161f085be 100644 --- a/extern/sector-storage/selector_existing.go +++ b/extern/sector-storage/selector_existing.go @@ -5,7 +5,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" "github.com/filecoin-project/lotus/extern/sector-storage/stores" diff --git a/extern/sector-storage/selector_task.go b/extern/sector-storage/selector_task.go index 5c0d65bb135..807b531038b 100644 --- a/extern/sector-storage/selector_task.go +++ b/extern/sector-storage/selector_task.go @@ -5,7 +5,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" "github.com/filecoin-project/lotus/extern/sector-storage/stores" diff --git a/extern/sector-storage/stores/filetype.go b/extern/sector-storage/stores/filetype.go index 50417d9683a..90cc1d160d1 100644 --- a/extern/sector-storage/stores/filetype.go +++ b/extern/sector-storage/stores/filetype.go @@ -5,7 +5,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) const ( diff --git a/extern/sector-storage/stores/index.go b/extern/sector-storage/stores/index.go index 256dc965174..e2bd7e4ee57 100644 --- a/extern/sector-storage/stores/index.go +++ b/extern/sector-storage/stores/index.go @@ -12,8 +12,8 @@ import ( "github.com/filecoin-project/lotus/extern/sector-storage/fsutil" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" ) var HeartbeatInterval = 10 * time.Second diff --git a/extern/sector-storage/stores/index_locks.go b/extern/sector-storage/stores/index_locks.go index 8bf15b95071..32c963a417d 100644 --- a/extern/sector-storage/stores/index_locks.go +++ b/extern/sector-storage/stores/index_locks.go @@ -6,7 +6,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) type sectorLock struct { diff --git a/extern/sector-storage/stores/index_locks_test.go b/extern/sector-storage/stores/index_locks_test.go index 5039f8815f4..1c550d3cae0 100644 --- a/extern/sector-storage/stores/index_locks_test.go +++ b/extern/sector-storage/stores/index_locks_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) var aSector = abi.SectorID{ diff --git a/extern/sector-storage/stores/interface.go b/extern/sector-storage/stores/interface.go index d94f28e839d..875754fc571 100644 --- a/extern/sector-storage/stores/interface.go +++ b/extern/sector-storage/stores/interface.go @@ -3,8 +3,8 @@ package stores import ( "context" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/fsutil" - "github.com/filecoin-project/specs-actors/actors/abi" ) type PathType string diff --git a/extern/sector-storage/stores/local.go b/extern/sector-storage/stores/local.go index b308f5d86da..75387acc87d 100644 --- a/extern/sector-storage/stores/local.go +++ b/extern/sector-storage/stores/local.go @@ -13,7 +13,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/fsutil" ) diff --git a/extern/sector-storage/stores/remote.go b/extern/sector-storage/stores/remote.go index a88e3b9470f..b9d241b5f2b 100644 --- a/extern/sector-storage/stores/remote.go +++ b/extern/sector-storage/stores/remote.go @@ -18,7 +18,7 @@ import ( "github.com/filecoin-project/lotus/extern/sector-storage/storiface" "github.com/filecoin-project/lotus/extern/sector-storage/tarutil" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/hashicorp/go-multierror" files "github.com/ipfs/go-ipfs-files" diff --git a/extern/sector-storage/storiface/ffi.go b/extern/sector-storage/storiface/ffi.go index 6e16018f0ec..95d400e5248 100644 --- a/extern/sector-storage/storiface/ffi.go +++ b/extern/sector-storage/storiface/ffi.go @@ -3,7 +3,7 @@ package storiface import ( "errors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) var ErrSectorNotFound = errors.New("sector not found") diff --git a/extern/sector-storage/storiface/worker.go b/extern/sector-storage/storiface/worker.go index 37e4aad1d02..25e3175bdf7 100644 --- a/extern/sector-storage/storiface/worker.go +++ b/extern/sector-storage/storiface/worker.go @@ -3,8 +3,8 @@ package storiface import ( "time" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" - "github.com/filecoin-project/specs-actors/actors/abi" ) type WorkerInfo struct { diff --git a/extern/sector-storage/testworker_test.go b/extern/sector-storage/testworker_test.go index 858b76f7ce7..8f27401f01e 100644 --- a/extern/sector-storage/testworker_test.go +++ b/extern/sector-storage/testworker_test.go @@ -6,7 +6,7 @@ import ( "github.com/ipfs/go-cid" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/extern/sector-storage/mock" diff --git a/extern/sector-storage/work_tracker.go b/extern/sector-storage/work_tracker.go index fe176a7f7af..5dc12802c32 100644 --- a/extern/sector-storage/work_tracker.go +++ b/extern/sector-storage/work_tracker.go @@ -8,7 +8,7 @@ import ( "github.com/ipfs/go-cid" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" diff --git a/extern/sector-storage/zerocomm/zerocomm.go b/extern/sector-storage/zerocomm/zerocomm.go index 9b59723a0b4..9855a582176 100644 --- a/extern/sector-storage/zerocomm/zerocomm.go +++ b/extern/sector-storage/zerocomm/zerocomm.go @@ -4,7 +4,7 @@ import ( "math/bits" commcid "github.com/filecoin-project/go-fil-commcid" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" ) diff --git a/extern/sector-storage/zerocomm/zerocomm_test.go b/extern/sector-storage/zerocomm/zerocomm_test.go index f5f508796ae..393f61d64f0 100644 --- a/extern/sector-storage/zerocomm/zerocomm_test.go +++ b/extern/sector-storage/zerocomm/zerocomm_test.go @@ -7,7 +7,7 @@ import ( "testing" commcid "github.com/filecoin-project/go-fil-commcid" - abi "github.com/filecoin-project/specs-actors/actors/abi" + abi "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" diff --git a/extern/storage-sealing/cbor_gen.go b/extern/storage-sealing/cbor_gen.go index b0762618768..78765d7b4ec 100644 --- a/extern/storage-sealing/cbor_gen.go +++ b/extern/storage-sealing/cbor_gen.go @@ -6,7 +6,7 @@ import ( "fmt" "io" - abi "github.com/filecoin-project/specs-actors/actors/abi" + abi "github.com/filecoin-project/go-state-types/abi" miner "github.com/filecoin-project/specs-actors/actors/builtin/miner" cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" diff --git a/extern/storage-sealing/checks.go b/extern/storage-sealing/checks.go index 3a59ea05948..906c9c106cf 100644 --- a/extern/storage-sealing/checks.go +++ b/extern/storage-sealing/checks.go @@ -4,14 +4,16 @@ import ( "bytes" "context" + saproof "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "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/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/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/crypto" ) // TODO: For now we handle this by halting state execution, when we get jsonrpc reconnecting @@ -168,7 +170,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(abi.SealVerifyInfo{ + ok, err := m.verif.VerifySeal(saproof.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 565a38c8ea8..ebb3d334762 100644 --- a/extern/storage-sealing/constants.go +++ b/extern/storage-sealing/constants.go @@ -1,7 +1,7 @@ package sealing import ( - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) diff --git a/extern/storage-sealing/events.go b/extern/storage-sealing/events.go index ba6d2a8609a..29806314755 100644 --- a/extern/storage-sealing/events.go +++ b/extern/storage-sealing/events.go @@ -3,7 +3,7 @@ package sealing import ( "context" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) // `curH`-`ts.Height` = `confidence` diff --git a/extern/storage-sealing/fsm.go b/extern/storage-sealing/fsm.go index 4b8d76cba1b..0d2e766fd42 100644 --- a/extern/storage-sealing/fsm.go +++ b/extern/storage-sealing/fsm.go @@ -12,8 +12,8 @@ import ( "golang.org/x/xerrors" + "github.com/filecoin-project/go-state-types/abi" statemachine "github.com/filecoin-project/go-statemachine" - "github.com/filecoin-project/specs-actors/actors/abi" ) func (m *Sealing) Plan(events []statemachine.Event, user interface{}) (interface{}, uint64, error) { diff --git a/extern/storage-sealing/fsm_events.go b/extern/storage-sealing/fsm_events.go index 8649e6c5ea5..ee95ab1c7f6 100644 --- a/extern/storage-sealing/fsm_events.go +++ b/extern/storage-sealing/fsm_events.go @@ -4,8 +4,8 @@ import ( "github.com/ipfs/go-cid" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/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/fsm_test.go b/extern/storage-sealing/fsm_test.go index 35797c5c9f9..51fd2a37bf9 100644 --- a/extern/storage-sealing/fsm_test.go +++ b/extern/storage-sealing/fsm_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" logging "github.com/ipfs/go-log/v2" "github.com/stretchr/testify/require" diff --git a/extern/storage-sealing/garbage.go b/extern/storage-sealing/garbage.go index 4b95c1b67ec..caf371806dd 100644 --- a/extern/storage-sealing/garbage.go +++ b/extern/storage-sealing/garbage.go @@ -5,7 +5,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) func (m *Sealing) pledgeSector(ctx context.Context, sectorID abi.SectorID, existingPieceSizes []abi.UnpaddedPieceSize, sizes ...abi.UnpaddedPieceSize) ([]abi.PieceInfo, error) { diff --git a/extern/storage-sealing/nullreader.go b/extern/storage-sealing/nullreader.go index ea6dfddb071..5987a4145e0 100644 --- a/extern/storage-sealing/nullreader.go +++ b/extern/storage-sealing/nullreader.go @@ -3,8 +3,8 @@ package sealing import ( "io" + "github.com/filecoin-project/go-state-types/abi" nr "github.com/filecoin-project/lotus/extern/storage-sealing/lib/nullreader" - "github.com/filecoin-project/specs-actors/actors/abi" ) type NullReader struct { diff --git a/extern/storage-sealing/precommit_policy.go b/extern/storage-sealing/precommit_policy.go index 1521dfb058c..93a96353546 100644 --- a/extern/storage-sealing/precommit_policy.go +++ b/extern/storage-sealing/precommit_policy.go @@ -3,7 +3,7 @@ package sealing import ( "context" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) diff --git a/extern/storage-sealing/precommit_policy_test.go b/extern/storage-sealing/precommit_policy_test.go index 9f9267d6554..b9c3ec49bb1 100644 --- a/extern/storage-sealing/precommit_policy_test.go +++ b/extern/storage-sealing/precommit_policy_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" commcid "github.com/filecoin-project/go-fil-commcid" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" ) diff --git a/extern/storage-sealing/sealing.go b/extern/storage-sealing/sealing.go index 835303889c1..cb73182d39c 100644 --- a/extern/storage-sealing/sealing.go +++ b/extern/storage-sealing/sealing.go @@ -16,18 +16,20 @@ import ( "github.com/filecoin-project/go-address" padreader "github.com/filecoin-project/go-padreader" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" statemachine "github.com/filecoin-project/go-statemachine" 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/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" "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/crypto" ) const SectorStorePrefix = "/sectors" +var ErrTooManySectorsSealing = xerrors.New("too many sectors sealing") + var log = logging.Logger("sectors") type SectorLocation struct { @@ -287,7 +289,7 @@ func (m *Sealing) newDealSector() (abi.SectorNumber, error) { if cfg.MaxSealingSectorsForDeals > 0 { if m.stats.curSealing() > cfg.MaxSealingSectorsForDeals { - return 0, xerrors.Errorf("too many sectors sealing") + return 0, ErrTooManySectorsSealing } } diff --git a/extern/storage-sealing/states_failed.go b/extern/storage-sealing/states_failed.go index e313fd712f9..4dd945a81ee 100644 --- a/extern/storage-sealing/states_failed.go +++ b/extern/storage-sealing/states_failed.go @@ -6,11 +6,11 @@ import ( "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/abi" "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/runtime/exitcode" "github.com/filecoin-project/lotus/extern/sector-storage/zerocomm" ) @@ -62,7 +62,7 @@ func (m *Sealing) handleSealPrecommit2Failed(ctx statemachine.Context, sector Se return err } - if sector.PreCommit2Fails > 1 { + if sector.PreCommit2Fails > 3 { return ctx.Send(SectorRetrySealPreCommit1{}) } diff --git a/extern/storage-sealing/states_sealing.go b/extern/storage-sealing/states_sealing.go index 7693f26ad7f..5e2b72ee12f 100644 --- a/extern/storage-sealing/states_sealing.go +++ b/extern/storage-sealing/states_sealing.go @@ -6,13 +6,13 @@ import ( "golang.org/x/xerrors" + "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/go-statemachine" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/crypto" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/specs-storage/storage" ) diff --git a/extern/storage-sealing/stats.go b/extern/storage-sealing/stats.go index 871c962c147..78630c216be 100644 --- a/extern/storage-sealing/stats.go +++ b/extern/storage-sealing/stats.go @@ -3,7 +3,7 @@ package sealing import ( "sync" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) type statSectorState int diff --git a/extern/storage-sealing/types.go b/extern/storage-sealing/types.go index 99cce77149e..c044defd3f8 100644 --- a/extern/storage-sealing/types.go +++ b/extern/storage-sealing/types.go @@ -6,10 +6,10 @@ import ( "github.com/ipfs/go-cid" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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/miner" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/specs-storage/storage" sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" diff --git a/extern/storage-sealing/types_test.go b/extern/storage-sealing/types_test.go index c11cc66b7f2..fc56620dcb1 100644 --- a/extern/storage-sealing/types_test.go +++ b/extern/storage-sealing/types_test.go @@ -7,7 +7,7 @@ import ( "gotest.tools/assert" cborutil "github.com/filecoin-project/go-cbor-util" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin" ) diff --git a/extern/storage-sealing/upgrade_queue.go b/extern/storage-sealing/upgrade_queue.go index 870f60dbb4b..650fdc83d10 100644 --- a/extern/storage-sealing/upgrade_queue.go +++ b/extern/storage-sealing/upgrade_queue.go @@ -5,8 +5,8 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) diff --git a/extern/storage-sealing/utils.go b/extern/storage-sealing/utils.go index b507907fb0c..dadef227d66 100644 --- a/extern/storage-sealing/utils.go +++ b/extern/storage-sealing/utils.go @@ -3,7 +3,7 @@ package sealing import ( "math/bits" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) func fillersFromRem(in abi.UnpaddedPieceSize) ([]abi.UnpaddedPieceSize, error) { diff --git a/extern/storage-sealing/utils_test.go b/extern/storage-sealing/utils_test.go index 1d6b6c515fe..e346b6dc95b 100644 --- a/extern/storage-sealing/utils_test.go +++ b/extern/storage-sealing/utils_test.go @@ -3,7 +3,7 @@ package sealing import ( "testing" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/stretchr/testify/assert" ) diff --git a/extern/test-vectors b/extern/test-vectors index 84da0a5ea12..7d3becbeb5b 160000 --- a/extern/test-vectors +++ b/extern/test-vectors @@ -1 +1 @@ -Subproject commit 84da0a5ea1256a6e66bcbf73542c93e4916d6356 +Subproject commit 7d3becbeb5b932baed419c43390595b5e5cece12 diff --git a/gen/main.go b/gen/main.go index e062f6a2e4a..e7586a92a89 100644 --- a/gen/main.go +++ b/gen/main.go @@ -7,7 +7,7 @@ import ( gen "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/chain/blocksync" + "github.com/filecoin-project/lotus/chain/exchange" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/hello" "github.com/filecoin-project/lotus/paychmgr" @@ -63,11 +63,11 @@ func main() { os.Exit(1) } - err = gen.WriteTupleEncodersToFile("./chain/blocksync/cbor_gen.go", "blocksync", - blocksync.Request{}, - blocksync.Response{}, - blocksync.CompactedMessages{}, - blocksync.BSTipSet{}, + err = gen.WriteTupleEncodersToFile("./chain/exchange/cbor_gen.go", "exchange", + exchange.Request{}, + exchange.Response{}, + exchange.CompactedMessages{}, + exchange.BSTipSet{}, ) if err != nil { fmt.Println(err) diff --git a/genesis/types.go b/genesis/types.go index 13349def29d..79656feac9d 100644 --- a/genesis/types.go +++ b/genesis/types.go @@ -4,7 +4,7 @@ import ( "encoding/json" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/ipfs/go-cid" "github.com/libp2p/go-libp2p-core/peer" diff --git a/go.mod b/go.mod index 109f8110b97..4cedea65f60 100644 --- a/go.mod +++ b/go.mod @@ -2,26 +2,24 @@ module github.com/filecoin-project/lotus go 1.14 -replace github.com/supranational/blst => github.com/supranational/blst v0.1.2-alpha.1 - require ( contrib.go.opencensus.io/exporter/jaeger v0.1.0 contrib.go.opencensus.io/exporter/prometheus v0.1.0 github.com/BurntSushi/toml v0.3.1 github.com/GeertJohan/go.rice v1.0.0 github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee + github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 github.com/coreos/go-systemd/v22 v22.0.0 github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e - github.com/dgraph-io/badger/v2 v2.0.3 + github.com/dgraph-io/badger/v2 v2.2007.2 github.com/docker/go-units v0.4.0 - github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4 - github.com/drand/kyber v1.1.1 + github.com/drand/drand v1.1.2-0.20200905144319-79c957281b32 + github.com/drand/kyber v1.1.2 github.com/dustin/go-humanize v1.0.0 github.com/elastic/go-sysinfo v1.3.0 github.com/fatih/color v1.8.0 - github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef github.com/filecoin-project/filecoin-ffi v0.30.4-0.20200716204036-cddc56607e1d github.com/filecoin-project/go-address v0.0.3 github.com/filecoin-project/go-bitfield v0.2.0 @@ -29,20 +27,21 @@ require ( 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-fil-commcid v0.0.0-20200716160307-8f644712406f - github.com/filecoin-project/go-fil-markets v0.5.9 + github.com/filecoin-project/go-fil-markets v0.6.1-0.20200911011457-2959ccca6a3c 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-20200210211231-548257017ca6 + github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 + github.com/filecoin-project/go-state-types v0.0.0-20200909080127-001afaca718c github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 github.com/filecoin-project/go-statestore v0.1.0 github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b - github.com/filecoin-project/specs-actors v0.9.3 - github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401 - github.com/filecoin-project/statediff v0.0.1 - github.com/filecoin-project/test-vectors v0.0.0-20200903223506-84da0a5ea125 + github.com/filecoin-project/specs-actors v0.9.8 + github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 + github.com/filecoin-project/test-vectors/schema v0.0.1 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 github.com/go-kit/kit v0.10.0 + github.com/go-ole/go-ole v1.2.4 // indirect github.com/google/uuid v1.1.1 github.com/gorilla/mux v1.7.4 github.com/gorilla/websocket v1.4.2 @@ -91,7 +90,7 @@ require ( github.com/libp2p/go-libp2p-mplex v0.2.4 github.com/libp2p/go-libp2p-noise v0.1.1 github.com/libp2p/go-libp2p-peerstore v0.2.6 - github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200901174250-06a12f17b7de + github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200910093904-f7f33e10cc18 github.com/libp2p/go-libp2p-quic-transport v0.8.0 github.com/libp2p/go-libp2p-record v0.1.3 github.com/libp2p/go-libp2p-routing-helpers v0.2.3 @@ -118,6 +117,7 @@ require ( github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 go.opencensus.io v0.22.4 + go.uber.org/dig v1.10.0 // indirect go.uber.org/fx v1.9.0 go.uber.org/multierr v1.5.0 go.uber.org/zap v1.15.0 @@ -126,12 +126,15 @@ require ( golang.org/x/time v0.0.0-20191024005414-555d28b269f0 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 gotest.tools v2.2.0+incompatible + launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect ) replace github.com/golangci/golangci-lint => github.com/golangci/golangci-lint v1.18.0 replace github.com/filecoin-project/filecoin-ffi => ./extern/filecoin-ffi -replace github.com/dgraph-io/badger/v2 => github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794 - replace github.com/filecoin-project/test-vectors => ./extern/test-vectors + +replace github.com/supranational/blst => ./extern/fil-blst/blst + +replace github.com/filecoin-project/fil-blst => ./extern/fil-blst diff --git a/go.sum b/go.sum index b483f8030e8..215eec43124 100644 --- a/go.sum +++ b/go.sum @@ -8,20 +8,14 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= contrib.go.opencensus.io/exporter/jaeger v0.1.0 h1:WNc9HbA38xEQmsI40Tjd/MNU/g8byN2Of7lwIjv0Jdc= contrib.go.opencensus.io/exporter/jaeger v0.1.0/go.mod h1:VYianECmuFPwU37O699Vc1GOcy+y8kOsfaxHRImmjbA= contrib.go.opencensus.io/exporter/prometheus v0.1.0 h1:SByaIoWwNgMdPSgl5sMqM2KDE5H/ukPWBRo314xiDvg= @@ -65,9 +59,11 @@ github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= @@ -156,7 +152,6 @@ github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY= github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= -github.com/dave/jennifer v1.4.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -171,8 +166,10 @@ github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhY github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger v1.6.1 h1:w9pSFNSdq/JPM1N12Fz/F/bzo993Is1W+Q7HjPzi7yg= github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= -github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794 h1:PIPH4SLjYXMMlX/cQqV7nIRatv7556yqUfWY+KBjrtQ= -github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= +github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM= +github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= +github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= +github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= @@ -184,12 +181,12 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/drand/bls12-381 v0.3.2 h1:RImU8Wckmx8XQx1tp1q04OV73J9Tj6mmpQLYDP7V1XE= github.com/drand/bls12-381 v0.3.2/go.mod h1:dtcLgPtYT38L3NO6mPDYH0nbpc5tjPassDqiniuAt4Y= -github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4 h1:+Rov3bfUriGWFR/lUVXnpimx+HMr9BXRC4by0BxuQ8k= -github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4/go.mod h1:SnqWL9jksIMK63UKkfmWI6f9PDN8ROoCgg+Z4zWk7hg= +github.com/drand/drand v1.1.2-0.20200905144319-79c957281b32 h1:sU+51aQRaDxg0KnjQg19KuYRIxDBEUHffBAICSnBys8= +github.com/drand/drand v1.1.2-0.20200905144319-79c957281b32/go.mod h1:0sQEVg+ngs1jaDPVIiEgY0lbENWJPaUlWxGHEaSmKVM= github.com/drand/kyber v1.0.1-0.20200110225416-8de27ed8c0e2/go.mod h1:UpXoA0Upd1N9l4TvRPHr1qAUBBERj6JQ/mnKI3BPEmw= github.com/drand/kyber v1.0.2/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw= -github.com/drand/kyber v1.1.1 h1:mwCY2XGRB+Qc1MPfrnRuVuXELkPhcq/r9yMoJIcDhHI= -github.com/drand/kyber v1.1.1/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw= +github.com/drand/kyber v1.1.2 h1:faemqlaFyLrbBSjZGRzzu5SG/do+uTYpHlnrJIHbAhQ= +github.com/drand/kyber v1.1.2/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw= github.com/drand/kyber-bls12381 v0.1.0 h1:/P4C65VnyEwxzR5ZYYVMNzY1If+aYBrdUU5ukwh7LQw= github.com/drand/kyber-bls12381 v0.1.0/go.mod h1:N1emiHpm+jj7kMlxEbu3MUyOiooTgNySln564cgD9mk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -215,51 +212,37 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.8.0 h1:5bzFgL+oy7JITMTxUPJ00n7VxmYd/PdMp5mHFX40/RY= github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8= github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E= -github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef h1:MtQRSnJLsQOOlmsd/Ua5KWXimpxcaa715h6FUh/eJPY= -github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef/go.mod h1:SMj5VK1pYgqC8FXVEtOBRTc+9AIrYu+C+K3tAXi2Rk8= -github.com/filecoin-project/go-address v0.0.0-20200107215422-da8eea2842b5/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0= -github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0= github.com/filecoin-project/go-address v0.0.3 h1:eVfbdjEbpbzIrbiSa+PiGUY+oDK9HnUn+M1R/ggoHf8= github.com/filecoin-project/go-address v0.0.3/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8= -github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200131012142-05d80eeccc5e/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= -github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= +github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 h1:t6qDiuGYYngDqaLc2ZUvdtAg4UNxPeOYaXhBWSNsVaM= github.com/filecoin-project/go-amt-ipld/v2 v2.1.0/go.mod h1:nfFPoGyX0CU9SkXX8EoCcSuHN1XcbN0c6KBh7yvP5fs= -github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161 h1:K6t4Hrs+rwUxBz2xg88Bdqeh4k5/rycQFdPseZhRyfE= -github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161/go.mod h1:vgmwKBkx+ca5OIeEvstiQgzAZnb7R6QaqE1oEDSqa6g= -github.com/filecoin-project/go-bitfield v0.0.0-20200416002808-b3ee67ec9060/go.mod h1:iodsLxOFZnqKtjj2zkgqzoGNrv6vUqj69AT/J8DKXEw= -github.com/filecoin-project/go-bitfield v0.0.1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= -github.com/filecoin-project/go-bitfield v0.0.3/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= -github.com/filecoin-project/go-bitfield v0.0.4-0.20200703174658-f4a5758051a1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= -github.com/filecoin-project/go-bitfield v0.1.2/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= github.com/filecoin-project/go-bitfield v0.2.0 h1:gCtLcjskIPtdg4NfN7gQZSQF9yrBQ7mkT0qCJxzGI2Q= github.com/filecoin-project/go-bitfield v0.2.0/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 h1:av5fw6wmm58FYMgJeoB/lK9XXrgdugYiTqkdxjTy9k8= github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2/go.mod h1:pqTiPHobNkOVM5thSRsHYjyQfq7O5QSCMhvuu9JoDlg= github.com/filecoin-project/go-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.1/go.mod h1:uRYBRKVBVM12CSusBtVrzDHkVw/3DKZpkxKJVP1Ydas= 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-fil-commcid v0.0.0-20200208005934-2b8bd03caca5/go.mod h1:JbkIgFF/Z9BDlvrJO1FuKkaWsH673/UdFaiVS6uIHlA= 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.5.6-0.20200814234959-80b1788108ac/go.mod h1:umicPCaN99ysHTiYOmwhuLxTFbOwcsI+mdw/t96vvM4= -github.com/filecoin-project/go-fil-markets v0.5.8 h1:uwl0QNUVmmSlUQfxshpj21Dmhh6WKTQNhnb1GMfdp18= -github.com/filecoin-project/go-fil-markets v0.5.8/go.mod h1:6ZX1vbZbnukbVQ8tCB/MmEizuW/bmRX7SpGAltU3KVg= -github.com/filecoin-project/go-fil-markets v0.5.9 h1:iIO17UfIjUCiB37TRwgiBwAyfJJwHb8e8uAfu7F37gc= -github.com/filecoin-project/go-fil-markets v0.5.9/go.mod h1:/cb1IoaiHhwFEWyIAPm9yN6Z+MiPujFZBT8BGH7LwB8= -github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= +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-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-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= github.com/filecoin-project/go-multistore v0.0.3 h1:vaRBY4YiA2UZFPK57RNuewypB8u0DzzQwqsL0XarpnI= github.com/filecoin-project/go-multistore v0.0.3/go.mod h1:kaNqCC4IhU4B1uyr7YWFHd23TL4KM32aChS0jNkyUvQ= -github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6 h1:92PET+sx1Hb4W/8CgFwGuxaKbttwY+UNspYZTvXY0vs= -github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6/go.mod h1:0HgYnrkeSU4lu1p+LEOeDpFsNBssa0OGGriWdA4hvaE= -github.com/filecoin-project/go-paramfetch v0.0.1/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= -github.com/filecoin-project/go-paramfetch v0.0.2-0.20200218225740-47c639bab663/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= +github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 h1:+/4aUeUoKr6AKfPE3mBhXA5spIV6UcKdTYDPNU2Tdmg= +github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20/go.mod h1:mPn+LRRd5gEKNAtc+r3ScpW2JRU/pj4NBKdADYWHiak= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 h1:A256QonvzRaknIIAuWhe/M2dpV2otzs3NBhi5TWa/UA= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= -github.com/filecoin-project/go-statemachine v0.0.0-20200226041606-2074af6d51d9/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= +github.com/filecoin-project/go-state-types v0.0.0-20200903145444-247639ffa6ad/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= +github.com/filecoin-project/go-state-types v0.0.0-20200904021452-1883f36ca2f4/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= +github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= +github.com/filecoin-project/go-state-types v0.0.0-20200909080127-001afaca718c h1:HHRMFpU8OrODDUja5NmGWNBAVGoSy4MRjxgZa+a0qIw= +github.com/filecoin-project/go-state-types v0.0.0-20200909080127-001afaca718c/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= github.com/filecoin-project/go-statemachine v0.0.0-20200714194326-a77c3ae20989/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 h1:Jbburj7Ih2iaJ/o5Q9A+EAeTabME6YII7FLi9SKUf5c= github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= @@ -267,27 +250,14 @@ github.com/filecoin-project/go-statestore v0.1.0 h1:t56reH59843TwXHkMcwyuayStBIi github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= -github.com/filecoin-project/lotus v0.4.3-0.20200820203717-d1718369a182/go.mod h1:biFZPQ/YyQGfkHUmHMiaNf2hnD6zm1+OAXPQYQ61Zkg= -github.com/filecoin-project/lotus v0.5.8-0.20200903221953-ada5e6ae68cf/go.mod h1:wxuzS4ozpCFThia18G+J5P0Jp/DSiq9ezzJF1yvZuP4= -github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15/go.mod h1:salgVdX7qeXFo/xaiEQE29J4pPkjn71T0kt0n+VDBzo= -github.com/filecoin-project/sector-storage v0.0.0-20200730050024-3ee28c3b6d9a/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= -github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0 h1:E1fZ27fhKK05bhZItfTwqr1i05vXnEZJznQFEYwEEUU= -github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= -github.com/filecoin-project/specs-actors v0.0.0-20200210130641-2d1fbd8672cf/go.mod h1:xtDZUB6pe4Pksa/bAJbJ693OilaC5Wbot9jMhLm3cZA= -github.com/filecoin-project/specs-actors v0.3.0/go.mod h1:nQYnFbQ7Y0bHZyq6HDEuVlCPR+U3z5Q3wMOQ+2aiV+Y= -github.com/filecoin-project/specs-actors v0.6.1/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= -github.com/filecoin-project/specs-actors v0.7.3-0.20200716231407-60a2ae96d2e6/go.mod h1:JOMUa7EijvpOO4ofD1yeHNmqohkmmnhTvz/IpB6so4c= -github.com/filecoin-project/specs-actors v0.8.2/go.mod h1:Q3ACV5kBLvqPaYbthc/J1lGMJ5OwogmD9pzdtPRMdCw= -github.com/filecoin-project/specs-actors v0.8.7-0.20200811203034-272d022c1923/go.mod h1:hukRu6vKQrrS7Nt+fC/ql4PqWLSfmAWNshD/VDtARZU= -github.com/filecoin-project/specs-actors v0.9.2/go.mod h1:YasnVUOUha0DN5wB+twl+V8LlDKVNknRG00kTJpsfFA= -github.com/filecoin-project/specs-actors v0.9.3 h1:Fi75G/UQ7R4eiIwnN+S6bBQ9LqKivyJdw62jJzTi6aE= -github.com/filecoin-project/specs-actors v0.9.3/go.mod h1:YasnVUOUha0DN5wB+twl+V8LlDKVNknRG00kTJpsfFA= -github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= -github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401 h1:jLzN1hwO5WpKPu8ASbW8fs1FUCsOWNvoBXzQhv+8/E8= -github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= -github.com/filecoin-project/statediff v0.0.1 h1:lym6d5wNnzr+5Uc/6RRWx1hgwb+tCKn2mFIK0Eb1Q18= -github.com/filecoin-project/statediff v0.0.1/go.mod h1:qNWauolLFEzOiA4LNWermBRVNbaZHfPcPevumZeh+hE= -github.com/filecoin-project/storage-fsm v0.0.0-20200805013058-9d9ea4e6331f/go.mod h1:1CGbd11KkHuyWPT+xwwCol1zl/jnlpiKD2L4fzKxaiI= +github.com/filecoin-project/specs-actors v0.9.4/go.mod h1:BStZQzx5x7TmCkLv0Bpa07U6cPKol6fd3w9KjMPZ6Z4= +github.com/filecoin-project/specs-actors v0.9.7/go.mod h1:wM2z+kwqYgXn5Z7scV1YHLyd1Q1cy0R8HfTIWQ0BFGU= +github.com/filecoin-project/specs-actors v0.9.8 h1:45fnx/BsseFL3CtvSoR6CszFY26TFtsh9AHwCW2vkg8= +github.com/filecoin-project/specs-actors v0.9.8/go.mod h1:xFObDoWPySBNTNBrGXVVrutmgSZH/mMo46Q1bec/0hw= +github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 h1:dJsTPWpG2pcTeojO2pyn0c6l+x/3MZYCBgo/9d11JEk= +github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= +github.com/filecoin-project/test-vectors/schema v0.0.1 h1:5fNF76nl4qolEvcIsjc0kUADlTMVHO73tW4kXXPnsus= +github.com/filecoin-project/test-vectors/schema v0.0.1/go.mod h1:iQ9QXLpYWL3m7warwvK1JC/pTri8mnfEmKygNDqqY6E= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as= github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= @@ -306,7 +276,6 @@ github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclK github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= @@ -350,7 +319,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -358,7 +326,6 @@ github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -386,9 +353,7 @@ github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8v github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= @@ -407,7 +372,6 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -480,7 +444,6 @@ github.com/ipfs/go-bitswap v0.0.9/go.mod h1:kAPf5qgn2W2DrgAcscZ3HrM9qh4pH+X8Fkk3 github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs= github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= -github.com/ipfs/go-bitswap v0.2.8/go.mod h1:2Yjog0GMdH8+AsxkE0DI9D2mANaUTxbVVav0pPoZoug= github.com/ipfs/go-bitswap v0.2.20 h1:Zfi5jDUoqxDThORUznqdeL77DdGniAzlccNJ4vr+Itc= github.com/ipfs/go-bitswap v0.2.20/go.mod h1:C7TwBgHnu89Q8sHsTJP7IhUqF9XYLe71P4tT5adgmYo= github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= @@ -535,16 +498,11 @@ github.com/ipfs/go-ds-measure v0.1.0 h1:vE4TyY4aeLeVgnnPBC5QzKIjKrqzha0NCujTfgvV github.com/ipfs/go-ds-measure v0.1.0/go.mod h1:1nDiFrhLlwArTME1Ees2XaBOl49OoCgd2A3f8EchMSY= github.com/ipfs/go-filestore v1.0.0 h1:QR7ekKH+q2AGiWDc7W2Q0qHuYSRZGUJqUn0GsegEPb0= github.com/ipfs/go-filestore v1.0.0/go.mod h1:/XOCuNtIe2f1YPbiXdYvD0BKLA0JR1MgPiFOdcuu9SM= -github.com/ipfs/go-fs-lock v0.0.1/go.mod h1:DNBekbboPKcxs1aukPSaOtFA3QfSdi5C855v0i9XJ8Y= 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.1/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-hamt-ipld v0.0.15-0.20200131012125-dd88a59d3f2e/go.mod h1:9aQJu/i/TaRDW6jqB5U217dLIDopn50wxLdHXM2CTfE= -github.com/ipfs/go-hamt-ipld v0.0.15-0.20200204200533-99b8553ef242/go.mod h1:kq3Pi+UP3oHhAdKexE+kHHYRKMoFNuGero0R7q3hWGg= -github.com/ipfs/go-hamt-ipld v0.1.1 h1:0IQdvwnAAUKmDE+PMJa5y1QiwOPHpI9+eAbQEEEYthk= 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= @@ -575,7 +533,6 @@ github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAz github.com/ipfs/go-ipfs-files v0.0.2/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= github.com/ipfs/go-ipfs-files v0.0.4/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= -github.com/ipfs/go-ipfs-files v0.0.7/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= github.com/ipfs/go-ipfs-files v0.0.8 h1:8o0oFJkJ8UkO/ABl8T6ac6tKF3+NIpj67aAB6ZpusRg= github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= github.com/ipfs/go-ipfs-flags v0.0.1/go.mod h1:RnXBb9WV53GSfTrSDVK61NLTFKvWc60n+K9EgCDh+rA= @@ -764,7 +721,6 @@ github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qD github.com/libp2p/go-libp2p v0.8.3/go.mod h1:EsH1A+8yoWK+L4iKcbPYu6MPluZ+CHWI9El8cTaefiM= github.com/libp2p/go-libp2p v0.9.2/go.mod h1:cunHNLDVus66Ct9iXXcjKRLdmHdFdHVe1TAnbubJQqQ= github.com/libp2p/go-libp2p v0.10.0/go.mod h1:yBJNpb+mGJdgrwbKAKrhPU0u3ogyNFTfjJ6bdM+Q/G8= -github.com/libp2p/go-libp2p v0.10.3/go.mod h1:0ER6iPSaPeQjryNgOnm9bLNpMJCYmuw54xJXsVR17eE= github.com/libp2p/go-libp2p v0.11.0 h1:jb5mqdqYEBAybTEhD8io43Cz5LzVKuWxOK7znSN69jE= github.com/libp2p/go-libp2p v0.11.0/go.mod h1:3/ogJDXsbbepEfqtZKBR/DedzxJXCeK17t2Z9RE9bEE= github.com/libp2p/go-libp2p-autonat v0.0.2/go.mod h1:fs71q5Xk+pdnKU014o2iq1RhMs9/PMaG5zXRFNnIIT4= @@ -826,7 +782,6 @@ github.com/libp2p/go-libp2p-core v0.6.1 h1:XS+Goh+QegCDojUZp00CaPMfiEADCrLjNZskW github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE= github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I= -github.com/libp2p/go-libp2p-crypto v0.1.0 h1:k9MFy+o2zGDNGsaoZl0MA3iZ75qXxr9OOoAZF+sD5OQ= github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= github.com/libp2p/go-libp2p-daemon v0.2.2/go.mod h1:kyrpsLB2JeNYR2rvXSVWyY0iZuRIMhqzWR3im9BV6NQ= github.com/libp2p/go-libp2p-discovery v0.0.1/go.mod h1:ZkkF9xIFRLA1xCc7bstYFkd80gBGK8Fc1JqGoU2i+zI= @@ -852,7 +807,6 @@ github.com/libp2p/go-libp2p-kbucket v0.4.2/go.mod h1:7sCeZx2GkNK1S6lQnGUW5JYZCFP github.com/libp2p/go-libp2p-loggables v0.0.1/go.mod h1:lDipDlBNYbpyqyPX/KcoO+eq0sJYEVR2JgOexcivchg= github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= -github.com/libp2p/go-libp2p-metrics v0.0.1 h1:yumdPC/P2VzINdmcKZd0pciSUCpou+s0lwYCjBbzQZU= github.com/libp2p/go-libp2p-metrics v0.0.1/go.mod h1:jQJ95SXXA/K1VZi13h52WZMa9ja78zjyy5rspMsC/08= github.com/libp2p/go-libp2p-mplex v0.1.1/go.mod h1:KUQWpGkCzfV7UIpi8SKsAVxyBgz1c9R5EvxgnwLsb/I= github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= @@ -875,7 +829,6 @@ github.com/libp2p/go-libp2p-noise v0.1.1 h1:vqYQWvnIcHpIoWJKC7Al4D6Hgj0H012TuXRh github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM= github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo= github.com/libp2p/go-libp2p-peer v0.1.1/go.mod h1:jkF12jGB4Gk/IOo+yomm+7oLWxF278F7UnrYUQ1Q8es= -github.com/libp2p/go-libp2p-peer v0.2.0 h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY= github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= github.com/libp2p/go-libp2p-peerstore v0.0.1/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= github.com/libp2p/go-libp2p-peerstore v0.0.6/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= @@ -892,16 +845,13 @@ github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuD github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= -github.com/libp2p/go-libp2p-protocol v0.1.0 h1:HdqhEyhg0ToCaxgMhnOmUO8snQtt/kQlcjVk3UoJU3c= github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk= github.com/libp2p/go-libp2p-pubsub v0.1.1/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q= github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato= -github.com/libp2p/go-libp2p-pubsub v0.3.5-0.20200820194335-bfc96c2cd081/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= -github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200901174250-06a12f17b7de h1:Dl0B0x6u+OSKXAa1DeB6xHFsUOBAhjrXJ10zykVSN6Q= -github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200901174250-06a12f17b7de/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= +github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200910093904-f7f33e10cc18 h1:+ae7vHSv/PJ4xGXwLV6LKGj32zjyB8ttJHtyV4TXal0= +github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200910093904-f7f33e10cc18/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU= github.com/libp2p/go-libp2p-quic-transport v0.5.0/go.mod h1:IEcuC5MLxvZ5KuHKjRu+dr3LjCT1Be3rcD/4d8JrX8M= -github.com/libp2p/go-libp2p-quic-transport v0.7.1/go.mod h1:TD31to4E5exogR/GWHClXCfkktigjAl5rXSt7HoxNvY= github.com/libp2p/go-libp2p-quic-transport v0.8.0 h1:mHA94K2+TD0e9XtjWx/P5jGGZn0GdQ4OFYwNllagv4E= github.com/libp2p/go-libp2p-quic-transport v0.8.0/go.mod h1:F2FG/6Bzz0U6essUVxDzE0s9CrY4XGLbl7QEmDNvU7A= github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= @@ -1036,7 +986,6 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= github.com/lucas-clemente/quic-go v0.16.0/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE= -github.com/lucas-clemente/quic-go v0.17.3/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE= github.com/lucas-clemente/quic-go v0.18.0 h1:JhQDdqxdwdmGdKsKgXi1+coHRoGhvU6z0rNzOJqZ/4o= github.com/lucas-clemente/quic-go v0.18.0/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg= github.com/lufia/iostat v1.1.0/go.mod h1:rEPNA0xXgjHQjuI5Cy05sLlS2oRcSlWHRLrvh/AQ+Pg= @@ -1061,10 +1010,8 @@ github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -1083,7 +1030,6 @@ github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= @@ -1366,9 +1312,8 @@ github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3 github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -1376,8 +1321,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/supranational/blst v0.1.2-alpha.1 h1:v0UqVlvbRNZIaSeMPr+T01kvTUq1h0EZuZ6gnDR1Mlg= -github.com/supranational/blst v0.1.2-alpha.1/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= @@ -1419,13 +1362,11 @@ github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba/go.mod h1:CH 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-20200206220010-03c9665e2a66/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= github.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= github.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg= github.com/whyrusleeping/cbor-gen v0.0.0-20200710004633-5379fc63235d/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200715143311-227fab5a2377/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= -github.com/whyrusleeping/cbor-gen v0.0.0-20200723185710-6a3894a6352b/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200810223238-211df3b9e24c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200812213548-958ddffe352c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200814224545-656e08ce49ee h1:U7zWWvvAjT76EiuWPSOiZlQDnaQYPxPoxugTtTAcJK0= @@ -1452,12 +1393,7 @@ github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d/go.mod h1:g7c github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow= github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= github.com/whyrusleeping/yamux v1.1.5/go.mod h1:E8LnQQ8HKx5KD29HZFUwM1PxCOdPRzGwur1mcYhXcD8= -github.com/willscott/go-cmp v0.5.2-0.20200812183318-8affb9542345 h1:IJVAwIctqDFOrO0C2qzksXmANviyHJzrklU27e1ltzE= -github.com/willscott/go-cmp v0.5.2-0.20200812183318-8affb9542345/go.mod h1:D7hA8H5pyQx7Y5Em7IWx1R4vNJzfon3gpG9nxjkITjQ= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/c-for-go v0.0.0-20200718154222-87b0065af829 h1:wb7xrDzfkLgPHsSEBm+VSx6aDdi64VtV0xvP0E6j8bk= github.com/xlab/c-for-go v0.0.0-20200718154222-87b0065af829/go.mod h1:h/1PEBwj7Ym/8kOuMWvO2ujZ6Lt+TMbySEXNhjjR87I= @@ -1467,7 +1403,6 @@ github.com/xorcare/golden v0.6.0/go.mod h1:7T39/ZMvaSEZlBPoYfVFmsBLmUl3uz9IuzWj/ github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 h1:oWgZJmC1DorFZDpfMfWg7xk29yEOZiXmo/wZl+utTI8= github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542/go.mod h1:7T39/ZMvaSEZlBPoYfVFmsBLmUl3uz9IuzWj/U6FtvQ= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw= @@ -1498,8 +1433,8 @@ go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/dig v1.8.0 h1:1rR6hnL/bu1EVcjnRDN5kx1vbIjEJDTGhSQ2B3ddpcI= -go.uber.org/dig v1.8.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= +go.uber.org/dig v1.10.0 h1:yLmDDj9/zuDjv3gz8GQGviXMs9TfysIUMUilCpgzUJY= +go.uber.org/dig v1.10.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= go.uber.org/fx v1.9.0 h1:7OAz8ucp35AU8eydejpYG7QrbE8rLKzGhHbZlJi5LYY= go.uber.org/fx v1.9.0/go.mod h1:mFdUyAUuJ3w4jAckiKSKbldsxy1ojpAMJ+dVZg5Y0Aw= go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo= @@ -1517,8 +1452,6 @@ go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= -go4.org v0.0.0-20190218023631-ce4c26f7be8e/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= -go4.org v0.0.0-20190313082347-94abd6928b1d/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU= go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= @@ -1543,13 +1476,10 @@ golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200427165652-729f1e841bcc/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= @@ -1561,10 +1491,8 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd h1:zkO/Lhoka23X63N9OSzpSeROEUQ5ODw47tM3YWjygbs= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1576,15 +1504,13 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367 h1:0IiAsCRByjO2QjX7ZPkw5oU9x+n1YqRL802rjC0c3Aw= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -1622,11 +1548,8 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200519113804-d87ec0cfa476/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -1684,13 +1607,11 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1700,20 +1621,14 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200427175716-29b57079015a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y= @@ -1757,22 +1672,14 @@ golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200108195415-316d2f248479/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200318150045-ba25ddc85566/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200711155855-7342f9734a7d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200827010519-17fd2f27a9e3 h1:r3P/5xOq/dK1991B65Oy6E1fRF/2d/fSYZJ/fXGVfJc= golang.org/x/tools v0.0.0-20200827010519-17fd2f27a9e3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -1793,11 +1700,8 @@ google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0 h1:0q95w+VuFtv4PAx4PZVQdBMmYbaCHbnfKaEiDIcVyag= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.25.0 h1:LodzhlzZEUfhXzNUMIfVlf9Gr6Ua5MMtoFWh7+f47qA= -google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1823,12 +1727,7 @@ google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482 h1:i+Aiej6cta/Frzp13/swvwz5O00kYcSe0A/C5Wd7zX8= @@ -1849,10 +1748,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200617041141-9a465503579e/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1863,6 +1760,7 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1900,9 +1798,8 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M= howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= diff --git a/lib/peermgr/peermgr.go b/lib/peermgr/peermgr.go index 80b05e8ce0a..2f9d3467499 100644 --- a/lib/peermgr/peermgr.go +++ b/lib/peermgr/peermgr.go @@ -10,7 +10,10 @@ import ( "github.com/filecoin-project/lotus/node/modules/dtypes" "go.opencensus.io/stats" "go.uber.org/fx" + "go.uber.org/multierr" + "golang.org/x/xerrors" + "github.com/libp2p/go-libp2p-core/event" host "github.com/libp2p/go-libp2p-core/host" net "github.com/libp2p/go-libp2p-core/network" peer "github.com/libp2p/go-libp2p-core/peer" @@ -50,12 +53,17 @@ type PeerMgr struct { h host.Host dht *dht.IpfsDHT - notifee *net.NotifyBundle + notifee *net.NotifyBundle + filPeerEmitter event.Emitter done chan struct{} } -func NewPeerMgr(lc fx.Lifecycle, h host.Host, dht *dht.IpfsDHT, bootstrap dtypes.BootstrapPeers) *PeerMgr { +type NewFilPeer struct { + Id peer.ID +} + +func NewPeerMgr(lc fx.Lifecycle, h host.Host, dht *dht.IpfsDHT, bootstrap dtypes.BootstrapPeers) (*PeerMgr, error) { pm := &PeerMgr{ h: h, dht: dht, @@ -69,10 +77,18 @@ func NewPeerMgr(lc fx.Lifecycle, h host.Host, dht *dht.IpfsDHT, bootstrap dtypes done: make(chan struct{}), } + emitter, err := h.EventBus().Emitter(new(NewFilPeer)) + if err != nil { + return nil, xerrors.Errorf("creating NewFilPeer emitter: %w", err) + } + pm.filPeerEmitter = emitter lc.Append(fx.Hook{ OnStop: func(ctx context.Context) error { - return pm.Stop(ctx) + return multierr.Combine( + pm.filPeerEmitter.Close(), + pm.Stop(ctx), + ) }, }) @@ -84,10 +100,11 @@ func NewPeerMgr(lc fx.Lifecycle, h host.Host, dht *dht.IpfsDHT, bootstrap dtypes h.Network().Notify(pm.notifee) - return pm + return pm, nil } func (pmgr *PeerMgr) AddFilecoinPeer(p peer.ID) { + _ = pmgr.filPeerEmitter.Emit(NewFilPeer{Id: p}) //nolint:errcheck pmgr.peersLk.Lock() defer pmgr.peersLk.Unlock() pmgr.peers[p] = time.Duration(0) diff --git a/lib/rpcenc/reader.go b/lib/rpcenc/reader.go index 3f4d5c60409..617c6495eec 100644 --- a/lib/rpcenc/reader.go +++ b/lib/rpcenc/reader.go @@ -19,8 +19,8 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/go-state-types/abi" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - "github.com/filecoin-project/specs-actors/actors/abi" ) var log = logging.Logger("rpcenc") diff --git a/lib/sigs/bls/init.go b/lib/sigs/bls/init.go index c63cf0b6571..42633eee88a 100644 --- a/lib/sigs/bls/init.go +++ b/lib/sigs/bls/init.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" blst "github.com/supranational/blst/bindings/go" diff --git a/lib/sigs/secp/init.go b/lib/sigs/secp/init.go index 1285b19b6f3..674bbbb28c1 100644 --- a/lib/sigs/secp/init.go +++ b/lib/sigs/secp/init.go @@ -5,7 +5,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-crypto" - crypto2 "github.com/filecoin-project/specs-actors/actors/crypto" + crypto2 "github.com/filecoin-project/go-state-types/crypto" "github.com/minio/blake2b-simd" "github.com/filecoin-project/lotus/lib/sigs" diff --git a/lib/sigs/sigs.go b/lib/sigs/sigs.go index 4a4fd7340a2..1f56846a82f 100644 --- a/lib/sigs/sigs.go +++ b/lib/sigs/sigs.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" "go.opencensus.io/trace" "golang.org/x/xerrors" diff --git a/lotuspond/spawn.go b/lotuspond/spawn.go index f4e8decee19..5fa82a86533 100644 --- a/lotuspond/spawn.go +++ b/lotuspond/spawn.go @@ -16,8 +16,8 @@ import ( "golang.org/x/xerrors" "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/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/gen" diff --git a/markets/loggers/loggers.go b/markets/loggers/loggers.go index 6f386dbba26..27a6b2c6331 100644 --- a/markets/loggers/loggers.go +++ b/markets/loggers/loggers.go @@ -3,7 +3,7 @@ package marketevents import ( "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/storagemarket" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" logging "github.com/ipfs/go-log/v2" ) diff --git a/markets/retrievaladapter/client.go b/markets/retrievaladapter/client.go index e57a11bd1de..17c56c167fb 100644 --- a/markets/retrievaladapter/client.go +++ b/markets/retrievaladapter/client.go @@ -3,34 +3,30 @@ package retrievaladapter import ( "context" - "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/shared" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" "github.com/multiformats/go-multiaddr" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/impl/full" payapi "github.com/filecoin-project/lotus/node/impl/paych" - "github.com/filecoin-project/lotus/paychmgr" ) type retrievalClientNode struct { chainAPI full.ChainAPI - pmgr *paychmgr.Manager payAPI payapi.PaychAPI stateAPI full.StateAPI } // NewRetrievalClientNode returns a new node adapter for a retrieval client that talks to the // Lotus Node -func NewRetrievalClientNode(pmgr *paychmgr.Manager, payAPI payapi.PaychAPI, chainAPI full.ChainAPI, stateAPI full.StateAPI) retrievalmarket.RetrievalClientNode { - return &retrievalClientNode{pmgr: pmgr, payAPI: payAPI, chainAPI: chainAPI, stateAPI: stateAPI} +func NewRetrievalClientNode(payAPI payapi.PaychAPI, chainAPI full.ChainAPI, stateAPI full.StateAPI) retrievalmarket.RetrievalClientNode { + return &retrievalClientNode{payAPI: payAPI, chainAPI: chainAPI, stateAPI: stateAPI} } // GetOrCreatePaymentChannel sets up a new payment channel if one does not exist @@ -39,14 +35,18 @@ func NewRetrievalClientNode(pmgr *paychmgr.Manager, payAPI payapi.PaychAPI, chai func (rcn *retrievalClientNode) GetOrCreatePaymentChannel(ctx context.Context, clientAddress address.Address, minerAddress address.Address, clientFundsAvailable abi.TokenAmount, tok shared.TipSetToken) (address.Address, cid.Cid, error) { // TODO: respect the provided TipSetToken (a serialized TipSetKey) when // querying the chain - return rcn.pmgr.GetPaych(ctx, clientAddress, minerAddress, clientFundsAvailable) + ci, err := rcn.payAPI.PaychGet(ctx, clientAddress, minerAddress, clientFundsAvailable) + if err != nil { + return address.Undef, cid.Undef, err + } + return ci.Channel, ci.WaitSentinel, nil } // Allocate late creates a lane within a payment channel so that calls to // CreatePaymentVoucher will automatically make vouchers only for the difference // in total -func (rcn *retrievalClientNode) AllocateLane(paymentChannel address.Address) (uint64, error) { - return rcn.pmgr.AllocateLane(paymentChannel) +func (rcn *retrievalClientNode) AllocateLane(ctx context.Context, paymentChannel address.Address) (uint64, error) { + return rcn.payAPI.PaychAllocateLane(ctx, paymentChannel) } // CreatePaymentVoucher creates a new payment voucher in the given lane for a @@ -60,7 +60,7 @@ func (rcn *retrievalClientNode) CreatePaymentVoucher(ctx context.Context, paymen return nil, err } if voucher.Voucher == nil { - return nil, xerrors.Errorf("Could not create voucher - shortfall: %d", voucher.Shortfall) + return nil, retrievalmarket.NewShortfallError(voucher.Shortfall) } return voucher.Voucher, nil } @@ -74,15 +74,23 @@ func (rcn *retrievalClientNode) GetChainHead(ctx context.Context) (shared.TipSet return head.Key().Bytes(), head.Height(), nil } -// WaitForPaymentChannelAddFunds waits messageCID to appear on chain. If it doesn't appear within -// defaultMsgWaitTimeout it returns error -func (rcn *retrievalClientNode) WaitForPaymentChannelAddFunds(messageCID cid.Cid) error { - _, err := rcn.payAPI.PaychMgr.GetPaychWaitReady(context.TODO(), messageCID) - return err +func (rcn *retrievalClientNode) WaitForPaymentChannelReady(ctx context.Context, messageCID cid.Cid) (address.Address, error) { + return rcn.payAPI.PaychGetWaitReady(ctx, messageCID) } -func (rcn *retrievalClientNode) WaitForPaymentChannelCreation(messageCID cid.Cid) (address.Address, error) { - return rcn.payAPI.PaychMgr.GetPaychWaitReady(context.TODO(), messageCID) +func (rcn *retrievalClientNode) CheckAvailableFunds(ctx context.Context, paymentChannel address.Address) (retrievalmarket.ChannelAvailableFunds, error) { + + channelAvailableFunds, err := rcn.payAPI.PaychAvailableFunds(paymentChannel) + if err != nil { + return retrievalmarket.ChannelAvailableFunds{}, err + } + return retrievalmarket.ChannelAvailableFunds{ + ConfirmedAmt: channelAvailableFunds.ConfirmedAmt, + PendingAmt: channelAvailableFunds.PendingAmt, + PendingWaitSentinel: channelAvailableFunds.PendingWaitSentinel, + QueuedAmt: channelAvailableFunds.QueuedAmt, + VoucherReedeemedAmt: channelAvailableFunds.VoucherReedeemedAmt, + }, nil } func (rcn *retrievalClientNode) GetKnownAddresses(ctx context.Context, p retrievalmarket.RetrievalPeer, encodedTs shared.TipSetToken) ([]multiaddr.Multiaddr, error) { diff --git a/markets/retrievaladapter/provider.go b/markets/retrievaladapter/provider.go index f22a31ccc92..443c4fb4ae0 100644 --- a/markets/retrievaladapter/provider.go +++ b/markets/retrievaladapter/provider.go @@ -13,7 +13,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/shared" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/ipfs/go-cid" diff --git a/markets/storageadapter/client.go b/markets/storageadapter/client.go index 73d50c1d87d..f66fd3ef9b7 100644 --- a/markets/storageadapter/client.go +++ b/markets/storageadapter/client.go @@ -6,7 +6,7 @@ import ( "bytes" "context" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "golang.org/x/xerrors" @@ -14,6 +14,9 @@ import ( cborutil "github.com/filecoin-project/go-cbor-util" "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/lotus/build" "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/events/state" @@ -25,12 +28,9 @@ 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/abi" "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/filecoin-project/specs-actors/actors/crypto" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/ipfs/go-cid" ) @@ -171,7 +171,7 @@ func (c *ClientNodeAdapter) ValidatePublishedDeal(ctx context.Context, deal stor pubmsg, err := c.cs.GetMessage(*deal.PublishMessage) if err != nil { - return 0, xerrors.Errorf("getting deal pubsish message: %w", err) + return 0, xerrors.Errorf("getting deal publish message: %w", err) } mi, err := stmgr.StateMinerInfo(ctx, c.sm, c.cs.GetHeaviestTipSet(), deal.Proposal.Provider) @@ -372,6 +372,11 @@ func (c *ClientNodeAdapter) OnDealExpiredOrSlashed(ctx context.Context, dealID a // Called immediately to check if the deal has already expired or been slashed checkFunc := func(ts *types.TipSet) (done bool, more bool, err error) { + if ts == nil { + // keep listening for events + return false, true, nil + } + // Check if the deal has already expired if sd.Proposal.EndEpoch <= ts.Height() { onDealExpired(nil) @@ -517,12 +522,12 @@ func (c *ClientNodeAdapter) GetChainHead(ctx context.Context) (shared.TipSetToke return head.Key().Bytes(), head.Height(), nil } -func (c *ClientNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, err error) error) error { +func (c *ClientNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, finalCid cid.Cid, err error) error) error { receipt, err := c.StateWaitMsg(ctx, mcid, build.MessageConfidence) if err != nil { - return cb(0, nil, err) + return cb(0, nil, cid.Undef, err) } - return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, nil) + return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, receipt.Message, nil) } func (c *ClientNodeAdapter) GetMinerInfo(ctx context.Context, addr address.Address, encodedTs shared.TipSetToken) (*storagemarket.StorageProviderInfo, error) { diff --git a/markets/storageadapter/journal_events.go b/markets/storageadapter/journal_events.go index 6192738df82..b74c5030125 100644 --- a/markets/storageadapter/journal_events.go +++ b/markets/storageadapter/journal_events.go @@ -2,7 +2,7 @@ package storageadapter import ( "github.com/filecoin-project/go-fil-markets/storagemarket" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/market" ) diff --git a/markets/storageadapter/provider.go b/markets/storageadapter/provider.go index ab3b4d56cca..5b8ead5be68 100644 --- a/markets/storageadapter/provider.go +++ b/markets/storageadapter/provider.go @@ -6,6 +6,7 @@ import ( "bytes" "context" "io" + "time" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" @@ -14,13 +15,13 @@ import ( "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/specs-actors/actors/abi" + "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/specs-actors/actors/crypto" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" @@ -36,6 +37,8 @@ import ( "github.com/filecoin-project/lotus/storage/sectorblocks" ) +var addPieceRetryWait = 5 * time.Minute +var addPieceRetryTimeout = 6 * time.Hour var log = logging.Logger("storageadapter") type ProviderNodeAdapter struct { @@ -101,7 +104,7 @@ func (n *ProviderNodeAdapter) OnDealComplete(ctx context.Context, deal storagema return nil, xerrors.Errorf("deal.PublishCid can't be nil") } - p, offset, err := n.secb.AddPiece(ctx, pieceSize, pieceData, sealing.DealInfo{ + sdInfo := sealing.DealInfo{ DealID: deal.DealID, PublishCid: deal.PublishCid, DealSchedule: sealing.DealSchedule{ @@ -109,7 +112,23 @@ func (n *ProviderNodeAdapter) OnDealComplete(ctx context.Context, deal storagema EndEpoch: deal.ClientDealProposal.Proposal.EndEpoch, }, KeepUnsealed: deal.FastRetrieval, - }) + } + + p, offset, err := n.secb.AddPiece(ctx, pieceSize, pieceData, sdInfo) + 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) + break + } + select { + case <-time.After(addPieceRetryWait): + p, offset, err = n.secb.AddPiece(ctx, pieceSize, pieceData, sdInfo) + case <-ctx.Done(): + return nil, xerrors.New("context expired while waiting to retry AddPiece") + } + } + if err != nil { return nil, xerrors.Errorf("AddPiece failed: %s", err) } @@ -376,12 +395,12 @@ func (n *ProviderNodeAdapter) GetChainHead(ctx context.Context) (shared.TipSetTo return head.Key().Bytes(), head.Height(), nil } -func (n *ProviderNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, err error) error) error { +func (n *ProviderNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, finalCid cid.Cid, err error) error) error { receipt, err := n.StateWaitMsg(ctx, mcid, 2*build.MessageConfidence) if err != nil { - return cb(0, nil, err) + return cb(0, nil, cid.Undef, err) } - return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, nil) + 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) { diff --git a/markets/utils/converters.go b/markets/utils/converters.go index e1089842e37..05472801d42 100644 --- a/markets/utils/converters.go +++ b/markets/utils/converters.go @@ -1,9 +1,9 @@ package utils 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/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin/market" peer "github.com/libp2p/go-libp2p-core/peer" "github.com/multiformats/go-multiaddr" diff --git a/metrics/metrics.go b/metrics/metrics.go index a6732e8ea08..5dd8652636f 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -30,6 +30,7 @@ var ( var ( LotusInfo = stats.Int64("info", "Arbitrary counter to tag lotus info to", stats.UnitDimensionless) ChainNodeHeight = stats.Int64("chain/node_height", "Current Height of the node", stats.UnitDimensionless) + ChainNodeHeightExpected = stats.Int64("chain/node_height_expected", "Expected Height of the node", stats.UnitDimensionless) ChainNodeWorkerHeight = stats.Int64("chain/node_worker_height", "Current Height of workers on the node", stats.UnitDimensionless) MessagePublished = stats.Int64("message/published", "Counter for total locally published messages", stats.UnitDimensionless) MessageReceived = stats.Int64("message/received", "Counter for total received messages", stats.UnitDimensionless) @@ -62,6 +63,10 @@ var ( Measure: ChainNodeHeight, Aggregation: view.LastValue(), } + ChainNodeHeightExpectedView = &view.View{ + Measure: ChainNodeHeightExpected, + Aggregation: view.LastValue(), + } ChainNodeWorkerHeightView = &view.View{ Measure: ChainNodeWorkerHeight, Aggregation: view.LastValue(), @@ -138,6 +143,7 @@ var ( var DefaultViews = append([]*view.View{ InfoView, ChainNodeHeightView, + ChainNodeHeightExpectedView, ChainNodeWorkerHeightView, BlockReceivedView, BlockValidationFailureView, diff --git a/miner/miner.go b/miner/miner.go index e8ba30eca76..bcfdb46c1d4 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -9,11 +9,13 @@ import ( "sync" "time" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/filecoin-project/lotus/chain/gen/slashfilter" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" lru "github.com/hashicorp/golang-lru" "github.com/filecoin-project/lotus/api" @@ -197,6 +199,7 @@ 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) continue } @@ -371,7 +374,7 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*types.BlockMsg, rbase = bvals[len(bvals)-1] } - ticket, err := m.computeTicket(ctx, &rbase, base, len(bvals) > 0) + ticket, err := m.computeTicket(ctx, &rbase, base) if err != nil { return nil, xerrors.Errorf("scratching ticket failed: %w", err) } @@ -441,7 +444,7 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*types.BlockMsg, return b, nil } -func (m *Miner) computeTicket(ctx context.Context, brand *types.BeaconEntry, base *MiningBase, haveNewEntries bool) (*types.Ticket, error) { +func (m *Miner) computeTicket(ctx context.Context, brand *types.BeaconEntry, base *MiningBase) (*types.Ticket, error) { mi, err := m.api.StateMinerInfo(ctx, m.address, types.EmptyTSK) if err != nil { return nil, err @@ -456,11 +459,12 @@ func (m *Miner) computeTicket(ctx context.Context, brand *types.BeaconEntry, bas return nil, xerrors.Errorf("failed to marshal address to cbor: %w", err) } - if !haveNewEntries { + round := base.TipSet.Height() + base.NullRounds + 1 + if round > build.UpgradeSmokeHeight { buf.Write(base.TipSet.MinTicket().VRFProof) } - input, err := store.DrawRandomness(brand.Data, crypto.DomainSeparationTag_TicketProduction, base.TipSet.Height()+base.NullRounds+1-build.TicketRandomnessLookback, buf.Bytes()) + input, err := store.DrawRandomness(brand.Data, crypto.DomainSeparationTag_TicketProduction, round-build.TicketRandomnessLookback, buf.Bytes()) if err != nil { return nil, err } @@ -476,7 +480,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 []abi.PoStProof, msgs []*types.SignedMessage) (*types.BlockMsg, error) { + eproof *types.ElectionProof, bvals []types.BeaconEntry, wpostProof []proof.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/miner/testminer.go b/miner/testminer.go index 0b1cbb12b23..64e3b3a6227 100644 --- a/miner/testminer.go +++ b/miner/testminer.go @@ -7,10 +7,10 @@ import ( ds "github.com/ipfs/go-datastore" "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/gen" "github.com/filecoin-project/lotus/chain/gen/slashfilter" - "github.com/filecoin-project/specs-actors/actors/abi" ) type MineReq struct { diff --git a/node/builder.go b/node/builder.go index 75639ec9754..08c48d4087f 100644 --- a/node/builder.go +++ b/node/builder.go @@ -29,7 +29,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain" "github.com/filecoin-project/lotus/chain/beacon" - "github.com/filecoin-project/lotus/chain/blocksync" + "github.com/filecoin-project/lotus/chain/exchange" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/gen/slashfilter" "github.com/filecoin-project/lotus/chain/market" @@ -109,7 +109,7 @@ const ( SetGenesisKey RunHelloKey - RunBlockSyncKey + RunChainExchangeKey RunChainGraphsync RunPeerMgrKey @@ -237,7 +237,7 @@ func Online() Option { Override(new(dtypes.BootstrapPeers), modules.BuiltinBootstrap), Override(new(dtypes.DrandBootstrap), modules.DrandBootstrap), - Override(new(dtypes.DrandConfig), modules.BuiltinDrandConfig), + Override(new(dtypes.DrandSchedule), modules.BuiltinDrandConfig), Override(HandleIncomingMessagesKey, modules.HandleIncomingMessages), @@ -249,12 +249,12 @@ func Online() Option { Override(new(dtypes.ChainGCLocker), blockstore.NewGCLocker), Override(new(dtypes.ChainGCBlockstore), modules.ChainGCBlockstore), - Override(new(dtypes.ChainExchange), modules.ChainExchange), - Override(new(dtypes.ChainBlockService), modules.ChainBlockservice), + Override(new(dtypes.ChainBitswap), modules.ChainBitswap), + Override(new(dtypes.ChainBlockService), modules.ChainBlockService), // Filecoin services Override(new(*chain.Syncer), modules.NewSyncer), - Override(new(*blocksync.BlockSync), blocksync.NewClient), + Override(new(exchange.Client), exchange.NewClient), Override(new(*messagepool.MessagePool), modules.MessagePool), Override(new(modules.Genesis), modules.ErrorGenesis), @@ -263,14 +263,14 @@ func Online() Option { Override(new(dtypes.NetworkName), modules.NetworkName), Override(new(*hello.Service), hello.NewHelloService), - Override(new(*blocksync.BlockSyncService), blocksync.NewBlockSyncService), + Override(new(exchange.Server), exchange.NewServer), Override(new(*peermgr.PeerMgr), peermgr.NewPeerMgr), Override(new(dtypes.Graphsync), modules.Graphsync), Override(new(*dtypes.MpoolLocker), new(dtypes.MpoolLocker)), Override(RunHelloKey, modules.RunHello), - Override(RunBlockSyncKey, modules.RunBlockSync), + Override(RunChainExchangeKey, modules.RunChainExchange), Override(RunPeerMgrKey, modules.RunPeerMgr), Override(HandleIncomingBlocksKey, modules.HandleIncomingBlocks), @@ -283,7 +283,7 @@ func Online() Option { Override(new(modules.ClientDealFunds), modules.NewClientDealFunds), Override(new(storagemarket.StorageClient), modules.StorageClient), Override(new(storagemarket.StorageClientNode), storageadapter.NewClientNodeAdapter), - Override(new(beacon.RandomBeacon), modules.RandomBeacon), + Override(new(beacon.Schedule), modules.RandomSchedule), Override(new(*paychmgr.Store), paychmgr.NewStore), Override(new(*paychmgr.Manager), paychmgr.NewManager), @@ -546,6 +546,6 @@ func Test() Option { return Options( Unset(RunPeerMgrKey), Unset(new(*peermgr.PeerMgr)), - Override(new(beacon.RandomBeacon), testing.RandomBeacon), + Override(new(beacon.Schedule), testing.RandomBeacon), ) } diff --git a/node/hello/cbor_gen.go b/node/hello/cbor_gen.go index 48d111c6b8e..3b85e3a7466 100644 --- a/node/hello/cbor_gen.go +++ b/node/hello/cbor_gen.go @@ -6,7 +6,7 @@ import ( "fmt" "io" - abi "github.com/filecoin-project/specs-actors/actors/abi" + abi "github.com/filecoin-project/go-state-types/abi" cid "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" diff --git a/node/hello/hello.go b/node/hello/hello.go index 78da9c7e34b..05d53de06af 100644 --- a/node/hello/hello.go +++ b/node/hello/hello.go @@ -4,10 +4,10 @@ import ( "context" "time" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" xerrors "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p-core/host" @@ -104,6 +104,10 @@ func (hs *Service) HandleStream(s inet.Stream) { build.Clock.Sleep(time.Millisecond * 300) } + if hs.pmgr != nil { + hs.pmgr.AddFilecoinPeer(s.Conn().RemotePeer()) + } + ts, err := hs.syncer.FetchTipSet(context.Background(), s.Conn().RemotePeer(), types.NewTipSetKey(hmsg.HeaviestTipSet...)) if err != nil { log.Errorf("failed to fetch tipset from peer during hello: %+v", err) @@ -117,9 +121,6 @@ func (hs *Service) HandleStream(s inet.Stream) { log.Infof("Got new tipset through Hello: %s from %s", ts.Cids(), s.Conn().RemotePeer()) hs.syncer.InformNewHead(s.Conn().RemotePeer(), ts) } - if hs.pmgr != nil { - hs.pmgr.AddFilecoinPeer(s.Conn().RemotePeer()) - } } diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 3a157318e5e..7a107c2fda0 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -6,8 +6,10 @@ import ( "io" "os" + "github.com/filecoin-project/go-state-types/dline" + datatransfer "github.com/filecoin-project/go-data-transfer" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "golang.org/x/xerrors" "github.com/ipfs/go-blockservice" @@ -38,7 +40,7 @@ import ( "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-multistore" "github.com/filecoin-project/go-padreader" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" @@ -80,7 +82,7 @@ type API struct { Host host.Host } -func calcDealExpiration(minDuration uint64, md *miner.DeadlineInfo, startEpoch abi.ChainEpoch) abi.ChainEpoch { +func calcDealExpiration(minDuration uint64, md *dline.Info, startEpoch abi.ChainEpoch) abi.ChainEpoch { // Make sure we give some time for the miner to seal minExp := startEpoch + abi.ChainEpoch(minDuration) @@ -847,3 +849,7 @@ func newDealInfo(v storagemarket.ClientDeal) api.DealInfo { CreationTime: v.CreationTime.Time(), } } + +func (a *API) ClientRetrieveTryRestartInsufficientFunds(ctx context.Context, paymentChannel address.Address) error { + return a.Retrieval.TryRestartInsufficientFunds(paymentChannel) +} diff --git a/node/impl/common/common.go b/node/impl/common/common.go index 6a69b2a7a4b..b07c1830520 100644 --- a/node/impl/common/common.go +++ b/node/impl/common/common.go @@ -170,9 +170,14 @@ func (a *CommonAPI) ID(context.Context) (peer.ID, error) { } func (a *CommonAPI) Version(context.Context) (api.Version, error) { + v, err := build.VersionForType(build.RunningNodeType) + if err != nil { + return api.Version{}, err + } + return api.Version{ Version: build.UserVersion(), - APIVersion: build.APIVersion, + APIVersion: v, BlockDelay: build.BlockDelaySecs, }, nil diff --git a/node/impl/full/beacon.go b/node/impl/full/beacon.go index 07037f6e12f..bc7232c272d 100644 --- a/node/impl/full/beacon.go +++ b/node/impl/full/beacon.go @@ -4,21 +4,22 @@ import ( "context" "fmt" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/beacon" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/abi" "go.uber.org/fx" ) type BeaconAPI struct { fx.In - Beacon beacon.RandomBeacon + Beacon beacon.Schedule } func (a *BeaconAPI) BeaconGetEntry(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) { - rr := a.Beacon.MaxBeaconRoundForEpoch(epoch, types.BeaconEntry{}) - e := a.Beacon.Entry(ctx, rr) + b := a.Beacon.BeaconForEpoch(epoch) + rr := b.MaxBeaconRoundForEpoch(epoch) + e := b.Entry(ctx, rr) select { case be, ok := <-e: diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index ce5e3822aa7..ad2c2944c47 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -26,8 +26,8 @@ import ( cbg "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api" @@ -495,7 +495,7 @@ func (a *ChainAPI) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Mess return cm.VMMessage(), nil } -func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk types.TipSetKey) (<-chan []byte, error) { +func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, skipoldmsgs bool, tsk types.TipSetKey) (<-chan []byte, error) { ts, err := a.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) @@ -508,7 +508,7 @@ func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk t bw := bufio.NewWriterSize(w, 1<<20) defer bw.Flush() //nolint:errcheck // it is a write to a pipe - if err := a.Chain.Export(ctx, ts, nroots, bw); err != nil { + if err := a.Chain.Export(ctx, ts, nroots, skipoldmsgs, bw); err != nil { log.Errorf("chain export call failed: %s", err) return } diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index 778c2c4ebbe..536bef360c4 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -6,21 +6,21 @@ import ( "math/rand" "sort" + "go.uber.org/fx" + "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/exitcode" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/messagepool" "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/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" - - "go.uber.org/fx" - "golang.org/x/xerrors" ) type GasAPI struct { @@ -50,6 +50,35 @@ func (a *GasAPI) GasEstimateFeeCap(ctx context.Context, msg *types.Message, maxq return out, nil } +type gasMeta struct { + price big.Int + limit int64 +} + +func medianGasPremium(prices []gasMeta, blocks int) abi.TokenAmount { + sort.Slice(prices, func(i, j int) bool { + // sort desc by price + return prices[i].price.GreaterThan(prices[j].price) + }) + + at := build.BlockGasTarget * int64(blocks) / 2 + prev1, prev2 := big.Zero(), big.Zero() + for _, price := range prices { + prev1, prev2 = price.price, prev1 + at -= price.limit + if at < 0 { + break + } + } + + premium := prev1 + if prev2.Sign() != 0 { + premium = big.Div(types.BigAdd(prev1, prev2), types.NewInt(2)) + } + + return premium +} + func (a *GasAPI) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, _ types.TipSetKey) (types.BigInt, error) { @@ -57,11 +86,6 @@ func (a *GasAPI) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, nblocksincl = 1 } - type gasMeta struct { - price big.Int - limit int64 - } - var prices []gasMeta var blocks int @@ -92,25 +116,7 @@ func (a *GasAPI) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, ts = pts } - sort.Slice(prices, func(i, j int) bool { - // sort desc by price - return prices[i].price.GreaterThan(prices[j].price) - }) - - at := build.BlockGasTarget * int64(blocks) / 2 - prev1, prev2 := big.Zero(), big.Zero() - for _, price := range prices { - prev1, prev2 = price.price, prev1 - at -= price.limit - if at > 0 { - continue - } - } - - premium := prev1 - if prev2.Sign() != 0 { - premium = big.Div(types.BigAdd(prev1, prev2), types.NewInt(2)) - } + premium := medianGasPremium(prices, blocks) if types.BigCmp(premium, types.NewInt(MinGasPremium)) < 0 { switch nblocksincl { @@ -198,30 +204,14 @@ func (a *GasAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, } if msg.GasFeeCap == types.EmptyInt || types.BigCmp(msg.GasFeeCap, types.NewInt(0)) == 0 { - feeCap, err := a.GasEstimateFeeCap(ctx, msg, 10, types.EmptyTSK) + feeCap, err := a.GasEstimateFeeCap(ctx, msg, 20, types.EmptyTSK) if err != nil { return nil, xerrors.Errorf("estimating fee cap: %w", err) } msg.GasFeeCap = feeCap } - capGasFee(msg, spec.Get().MaxFee) + messagepool.CapGasFee(msg, spec.Get().MaxFee) return msg, nil } - -func capGasFee(msg *types.Message, maxFee abi.TokenAmount) { - if maxFee.Equals(big.Zero()) { - maxFee = types.NewInt(build.FilecoinPrecision / 10) - } - - gl := types.NewInt(uint64(msg.GasLimit)) - totalFee := types.BigMul(msg.GasFeeCap, gl) - - if totalFee.LessThanEqual(maxFee) { - return - } - - msg.GasFeeCap = big.Div(maxFee, gl) - msg.GasPremium = big.Min(msg.GasFeeCap, msg.GasPremium) // cap premium at FeeCap -} diff --git a/node/impl/full/gas_test.go b/node/impl/full/gas_test.go new file mode 100644 index 00000000000..2452ab8077b --- /dev/null +++ b/node/impl/full/gas_test.go @@ -0,0 +1,40 @@ +package full + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-state-types/big" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" +) + +func TestMedian(t *testing.T) { + require.Equal(t, types.NewInt(5), medianGasPremium([]gasMeta{ + {big.NewInt(5), build.BlockGasTarget}, + }, 1)) + + require.Equal(t, types.NewInt(10), medianGasPremium([]gasMeta{ + {big.NewInt(5), build.BlockGasTarget}, + {big.NewInt(10), build.BlockGasTarget}, + }, 1)) + + require.Equal(t, types.NewInt(15), medianGasPremium([]gasMeta{ + {big.NewInt(10), build.BlockGasTarget / 2}, + {big.NewInt(20), build.BlockGasTarget / 2}, + }, 1)) + + require.Equal(t, types.NewInt(25), medianGasPremium([]gasMeta{ + {big.NewInt(10), build.BlockGasTarget / 2}, + {big.NewInt(20), build.BlockGasTarget / 2}, + {big.NewInt(30), build.BlockGasTarget / 2}, + }, 1)) + + require.Equal(t, types.NewInt(15), medianGasPremium([]gasMeta{ + {big.NewInt(10), build.BlockGasTarget / 2}, + {big.NewInt(20), build.BlockGasTarget / 2}, + {big.NewInt(30), build.BlockGasTarget / 2}, + }, 2)) +} diff --git a/node/impl/full/mpool.go b/node/impl/full/mpool.go index bfb7439bb9f..6acb179902a 100644 --- a/node/impl/full/mpool.go +++ b/node/impl/full/mpool.go @@ -2,6 +2,7 @@ package full import ( "context" + "encoding/json" "github.com/filecoin-project/go-address" "github.com/ipfs/go-cid" @@ -113,6 +114,7 @@ func (a *MpoolAPI) MpoolPush(ctx context.Context, smsg *types.SignedMessage) (ci } func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec) (*types.SignedMessage, error) { + inMsg := *msg { fromA, err := a.Stmgr.ResolveToKeyAddress(ctx, msg.From, nil) if err != nil { @@ -134,6 +136,13 @@ func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spe return nil, xerrors.Errorf("GasEstimateMessageGas error: %w", err) } + if msg.GasPremium.GreaterThan(msg.GasFeeCap) { + inJson, _ := json.Marshal(inMsg) + outJson, _ := json.Marshal(msg) + return nil, xerrors.Errorf("After estimation, GasPremium is greater than GasFeeCap, inmsg: %s, outmsg: %s", + inJson, outJson) + } + sign := func(from address.Address, nonce uint64) (*types.SignedMessage, error) { msg.Nonce = nonce if msg.From.Protocol() == address.ID { diff --git a/node/impl/full/multisig.go b/node/impl/full/multisig.go index f1e3c61fde1..2322d5a1e53 100644 --- a/node/impl/full/multisig.go +++ b/node/impl/full/multisig.go @@ -3,13 +3,13 @@ package full import ( "context" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "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/actors" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/abi" "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" @@ -130,6 +130,33 @@ func (a *MsigAPI) MsigPropose(ctx context.Context, msig address.Address, to addr return smsg.Cid(), nil } +func (a *MsigAPI) MsigAddPropose(ctx context.Context, msig address.Address, src address.Address, newAdd address.Address, inc bool) (cid.Cid, error) { + enc, actErr := serializeAddParams(newAdd, inc) + if actErr != nil { + return cid.Undef, actErr + } + + return a.MsigPropose(ctx, msig, msig, big.Zero(), src, uint64(builtin.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) { + enc, actErr := serializeAddParams(newAdd, inc) + if actErr != nil { + return cid.Undef, actErr + } + + return a.MsigApprove(ctx, msig, txID, proposer, msig, big.Zero(), src, uint64(builtin.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) { + enc, actErr := serializeAddParams(newAdd, inc) + if actErr != nil { + return cid.Undef, actErr + } + + return a.MsigCancel(ctx, msig, txID, msig, big.Zero(), src, uint64(builtin.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) { enc, actErr := serializeSwapParams(oldAdd, newAdd) if actErr != nil { @@ -244,6 +271,18 @@ func (a *MsigAPI) msigApproveOrCancel(ctx context.Context, operation api.MsigPro return smsg.Cid(), nil } +func serializeAddParams(new address.Address, inc bool) ([]byte, error) { + enc, actErr := actors.SerializeParams(&samsig.AddSignerParams{ + Signer: new, + Increase: inc, + }) + if actErr != nil { + return nil, actErr + } + + return enc, nil +} + func serializeSwapParams(old address.Address, new address.Address) ([]byte, error) { enc, actErr := actors.SerializeParams(&samsig.SwapSignerParams{ From: old, diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 36721a93dec..e183fafa415 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -7,6 +7,8 @@ import ( "fmt" "strconv" + "github.com/filecoin-project/go-state-types/dline" + cid "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" cbg "github.com/whyrusleeping/cbor-gen" @@ -15,9 +17,9 @@ import ( "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/big" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/miner" @@ -53,14 +55,14 @@ type StateAPI struct { ProofVerifier ffiwrapper.Verifier StateManager *stmgr.StateManager Chain *store.ChainStore - Beacon beacon.RandomBeacon + Beacon beacon.Schedule } func (a *StateAPI) StateNetworkName(ctx context.Context) (dtypes.NetworkName, error) { return stmgr.GetNetworkName(ctx, a.StateManager, a.Chain.GetHeaviestTipSet().ParentState()) } -func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address, filter *abi.BitField, filterOut bool, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) { +func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address, filter *bitfield.BitField, filterOut bool, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) { ts, err := a.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) @@ -74,7 +76,7 @@ func (a *StateAPI) StateMinerActiveSectors(ctx context.Context, maddr address.Ad err := a.StateManager.WithParentStateTsk(tsk, a.StateManager.WithActor(maddr, a.StateManager.WithActorState(ctx, func(store adt.Store, mas *miner.State) error { - var allActive []abi.BitField + var allActive []bitfield.BitField err := a.StateManager.WithDeadlines( a.StateManager.WithEachDeadline( @@ -145,7 +147,7 @@ func (a *StateAPI) StateMinerPartitions(ctx context.Context, m address.Address, })))))) } -func (a *StateAPI) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*miner.DeadlineInfo, error) { +func (a *StateAPI) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) { ts, err := a.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) @@ -160,7 +162,7 @@ func (a *StateAPI) StateMinerProvingDeadline(ctx context.Context, addr address.A return mas.DeadlineInfo(ts.Height()).NextNotElapsed(), nil } -func (a *StateAPI) StateMinerFaults(ctx context.Context, addr address.Address, tsk types.TipSetKey) (abi.BitField, error) { +func (a *StateAPI) StateMinerFaults(ctx context.Context, addr address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { out := bitfield.New() err := a.StateManager.WithParentStateTsk(tsk, @@ -222,7 +224,7 @@ func (a *StateAPI) StateAllMinerFaults(ctx context.Context, lookback abi.ChainEp return allFaults, nil*/ } -func (a *StateAPI) StateMinerRecoveries(ctx context.Context, addr address.Address, tsk types.TipSetKey) (abi.BitField, error) { +func (a *StateAPI) StateMinerRecoveries(ctx context.Context, addr address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { out := bitfield.New() err := a.StateManager.WithParentStateTsk(tsk, @@ -636,7 +638,7 @@ func (a *StateAPI) StateMinerSectorCount(ctx context.Context, addr address.Addre err := a.StateManager.WithParentStateTsk(tsk, a.StateManager.WithActor(addr, a.StateManager.WithActorState(ctx, func(store adt.Store, mas *miner.State) error { - var allActive []abi.BitField + var allActive []bitfield.BitField err := a.StateManager.WithDeadlines( a.StateManager.WithEachDeadline( @@ -886,6 +888,48 @@ func (a *StateAPI) MsigGetAvailableBalance(ctx context.Context, addr address.Add return types.BigSub(act.Balance, minBalance), nil } +func (a *StateAPI) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) { + startTs, err := a.Chain.GetTipSetFromKey(start) + if err != nil { + return types.EmptyInt, xerrors.Errorf("loading start tipset %s: %w", start, err) + } + + endTs, err := a.Chain.GetTipSetFromKey(end) + if err != nil { + return types.EmptyInt, xerrors.Errorf("loading end tipset %s: %w", end, err) + } + + if startTs.Height() > endTs.Height() { + return types.EmptyInt, xerrors.Errorf("start tipset %d is after end tipset %d", startTs.Height(), endTs.Height()) + } else if startTs.Height() == endTs.Height() { + return big.Zero(), nil + } + + var mst samsig.State + act, err := a.StateManager.LoadActorState(ctx, addr, &mst, endTs) + if err != nil { + return types.EmptyInt, xerrors.Errorf("failed to load multisig actor state at end epoch: %w", err) + } + + if act.Code != builtin.MultisigActorCodeID { + return types.EmptyInt, fmt.Errorf("given actor was not a multisig") + } + + if mst.UnlockDuration == 0 || + mst.InitialBalance.IsZero() || + mst.StartEpoch+mst.UnlockDuration <= startTs.Height() || + mst.StartEpoch >= endTs.Height() { + return big.Zero(), nil + } + + startLk := mst.InitialBalance + if startTs.Height() > mst.StartEpoch { + startLk = mst.AmountLocked(startTs.Height() - mst.StartEpoch) + } + + return big.Sub(startLk, mst.AmountLocked(endTs.Height()-mst.StartEpoch)), nil +} + var initialPledgeNum = types.NewInt(110) var initialPledgeDen = types.NewInt(100) @@ -1150,7 +1194,13 @@ 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, verified, powerState.ThisEpochQualityAdjPower, rewardState.ThisEpochBaselinePower, circ.FilCirculating) + min, max := market.DealProviderCollateralBounds(size, + verified, + powerState.TotalRawBytePower, + powerState.ThisEpochQualityAdjPower, + rewardState.ThisEpochBaselinePower, + circ.FilCirculating, + a.StateManager.GetNtwkVersion(ctx, ts.Height())) return api.DealCollateralBounds{ Min: types.BigDiv(types.BigMul(min, dealProviderCollateralNum), dealProviderCollateralDen), Max: max, diff --git a/node/impl/full/sync.go b/node/impl/full/sync.go index 9066df56f19..31a707b9075 100644 --- a/node/impl/full/sync.go +++ b/node/impl/full/sync.go @@ -97,12 +97,23 @@ func (a *SyncAPI) SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHe return a.Syncer.IncomingBlocks(ctx) } +func (a *SyncAPI) SyncCheckpoint(ctx context.Context, tsk types.TipSetKey) error { + log.Warnf("Marking tipset %s as checkpoint", tsk) + return a.Syncer.SetCheckpoint(tsk) +} + func (a *SyncAPI) SyncMarkBad(ctx context.Context, bcid cid.Cid) error { log.Warnf("Marking block %s as bad", bcid) a.Syncer.MarkBad(bcid) return nil } +func (a *SyncAPI) SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error { + log.Warnf("Unmarking block %s as bad", bcid) + a.Syncer.UnmarkBad(bcid) + return nil +} + func (a *SyncAPI) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) { reason, ok := a.Syncer.CheckBadBlockCache(bcid) if !ok { diff --git a/node/impl/full/wallet.go b/node/impl/full/wallet.go index 440f9642fb7..af786085baa 100644 --- a/node/impl/full/wallet.go +++ b/node/impl/full/wallet.go @@ -7,8 +7,8 @@ import ( "go.uber.org/fx" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi/big" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" diff --git a/node/impl/paych/paych.go b/node/impl/paych/paych.go index e998f969f90..84c2cc03040 100644 --- a/node/impl/paych/paych.go +++ b/node/impl/paych/paych.go @@ -39,8 +39,12 @@ func (a *PaychAPI) PaychGet(ctx context.Context, from, to address.Address, amt t }, nil } -func (a *PaychAPI) PaychAvailableFunds(from, to address.Address) (*api.ChannelAvailableFunds, error) { - return a.PaychMgr.AvailableFunds(from, to) +func (a *PaychAPI) PaychAvailableFunds(ch address.Address) (*api.ChannelAvailableFunds, error) { + return a.PaychMgr.AvailableFunds(ch) +} + +func (a *PaychAPI) PaychAvailableFundsByFromTo(from, to address.Address) (*api.ChannelAvailableFunds, error) { + return a.PaychMgr.AvailableFundsByFromTo(from, to) } func (a *PaychAPI) PaychGetWaitReady(ctx context.Context, sentinel cid.Cid) (address.Address, error) { diff --git a/node/impl/remoteworker.go b/node/impl/remoteworker.go index 8111413ba71..b6ef43c7c59 100644 --- a/node/impl/remoteworker.go +++ b/node/impl/remoteworker.go @@ -8,7 +8,7 @@ import ( "github.com/filecoin-project/go-jsonrpc" "github.com/filecoin-project/go-jsonrpc/auth" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/client" diff --git a/node/impl/storminer.go b/node/impl/storminer.go index c688ff6778d..6eedc9f544e 100644 --- a/node/impl/storminer.go +++ b/node/impl/storminer.go @@ -9,7 +9,7 @@ import ( "time" datatransfer "github.com/filecoin-project/go-data-transfer" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "github.com/ipfs/go-cid" "github.com/libp2p/go-libp2p-core/host" "golang.org/x/xerrors" @@ -19,7 +19,7 @@ import ( retrievalmarket "github.com/filecoin-project/go-fil-markets/retrievalmarket" storagemarket "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-jsonrpc/auth" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" diff --git a/node/modules/chain.go b/node/modules/chain.go index ea04945efa5..7b7e03e44b8 100644 --- a/node/modules/chain.go +++ b/node/modules/chain.go @@ -20,7 +20,7 @@ import ( "github.com/filecoin-project/lotus/chain" "github.com/filecoin-project/lotus/chain/beacon" - "github.com/filecoin-project/lotus/chain/blocksync" + "github.com/filecoin-project/lotus/chain/exchange" "github.com/filecoin-project/lotus/chain/gen/slashfilter" "github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/stmgr" @@ -33,7 +33,7 @@ import ( "github.com/filecoin-project/lotus/node/repo" ) -func ChainExchange(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, rt routing.Routing, bs dtypes.ChainGCBlockstore) dtypes.ChainExchange { +func ChainBitswap(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, rt routing.Routing, bs dtypes.ChainGCBlockstore) dtypes.ChainBitswap { // prefix protocol for chain bitswap // (so bitswap uses /chain/ipfs/bitswap/1.0.0 internally for chain sync stuff) bitswapNetwork := network.NewFromIpfsHost(host, rt, network.Prefix("/chain")) @@ -83,7 +83,7 @@ func ChainGCBlockstore(bs dtypes.ChainBlockstore, gcl dtypes.ChainGCLocker) dtyp return blockstore.NewGCBlockstore(bs, gcl) } -func ChainBlockservice(bs dtypes.ChainBlockstore, rem dtypes.ChainExchange) dtypes.ChainBlockService { +func ChainBlockService(bs dtypes.ChainBlockstore, rem dtypes.ChainBitswap) dtypes.ChainBlockService { return blockservice.New(bs, rem) } @@ -163,8 +163,8 @@ func NetworkName(mctx helpers.MetricsCtx, lc fx.Lifecycle, cs *store.ChainStore, return netName, err } -func NewSyncer(lc fx.Lifecycle, sm *stmgr.StateManager, bsync *blocksync.BlockSync, h host.Host, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*chain.Syncer, error) { - syncer, err := chain.NewSyncer(sm, bsync, h.ConnManager(), h.ID(), beacon, verifier) +func NewSyncer(lc fx.Lifecycle, ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, h host.Host, beacon beacon.Schedule, verifier ffiwrapper.Verifier) (*chain.Syncer, error) { + syncer, err := chain.NewSyncer(ds, sm, exchange, h.ConnManager(), h.ID(), beacon, verifier) if err != nil { return nil, err } diff --git a/node/modules/client.go b/node/modules/client.go index bf534350e1d..63633c0e3ea 100644 --- a/node/modules/client.go +++ b/node/modules/client.go @@ -35,7 +35,6 @@ import ( "github.com/filecoin-project/lotus/node/repo" "github.com/filecoin-project/lotus/node/repo/importmgr" "github.com/filecoin-project/lotus/node/repo/retrievalstoremgr" - "github.com/filecoin-project/lotus/paychmgr" ) func ClientMultiDatastore(lc fx.Lifecycle, r repo.LockedRepo) (dtypes.ClientMultiDstore, error) { @@ -130,8 +129,8 @@ func StorageClient(lc fx.Lifecycle, h host.Host, ibs dtypes.ClientBlockstore, md } // RetrievalClient creates a new retrieval client attached to the client blockstore -func RetrievalClient(lc fx.Lifecycle, h host.Host, mds dtypes.ClientMultiDstore, dt dtypes.ClientDataTransfer, pmgr *paychmgr.Manager, payAPI payapi.PaychAPI, resolver retrievalmarket.PeerResolver, ds dtypes.MetadataDS, chainAPI full.ChainAPI, stateAPI full.StateAPI) (retrievalmarket.RetrievalClient, error) { - adapter := retrievaladapter.NewRetrievalClientNode(pmgr, payAPI, chainAPI, stateAPI) +func RetrievalClient(lc fx.Lifecycle, h host.Host, mds dtypes.ClientMultiDstore, dt dtypes.ClientDataTransfer, payAPI payapi.PaychAPI, resolver retrievalmarket.PeerResolver, ds dtypes.MetadataDS, chainAPI full.ChainAPI, stateAPI full.StateAPI) (retrievalmarket.RetrievalClient, error) { + adapter := retrievaladapter.NewRetrievalClientNode(payAPI, chainAPI, stateAPI) network := rmnet.NewFromLibp2pHost(h) sc := storedcounter.New(ds, datastore.NewKey("/retr")) client, err := retrievalimpl.NewClient(network, mds, dt, adapter, resolver, namespace.Wrap(ds, datastore.NewKey("/retrievals/client")), sc) diff --git a/node/modules/core.go b/node/modules/core.go index 4d070e80e85..a695d865147 100644 --- a/node/modules/core.go +++ b/node/modules/core.go @@ -9,6 +9,7 @@ import ( "github.com/gbrlsnchs/jwt/v3" logging "github.com/ipfs/go-log/v2" + "github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peerstore" record "github.com/libp2p/go-libp2p-record" "golang.org/x/xerrors" @@ -91,12 +92,16 @@ func BuiltinBootstrap() (dtypes.BootstrapPeers, error) { return build.BuiltinBootstrap() } -func DrandBootstrap(d dtypes.DrandConfig) (dtypes.DrandBootstrap, error) { +func DrandBootstrap(ds dtypes.DrandSchedule) (dtypes.DrandBootstrap, error) { // TODO: retry resolving, don't fail if at least one resolve succeeds - addrs, err := addrutil.ParseAddresses(context.TODO(), d.Relays) - if err != nil { - log.Errorf("reoslving drand relays addresses: %+v", err) - return nil, nil + res := []peer.AddrInfo{} + for _, d := range ds { + addrs, err := addrutil.ParseAddresses(context.TODO(), d.Config.Relays) + if err != nil { + log.Errorf("reoslving drand relays addresses: %+v", err) + return res, nil + } + res = append(res, addrs...) } - return addrs, nil + return res, nil } diff --git a/node/modules/dtypes/beacon.go b/node/modules/dtypes/beacon.go index 2231f0e0842..28bbdf281d3 100644 --- a/node/modules/dtypes/beacon.go +++ b/node/modules/dtypes/beacon.go @@ -1,5 +1,14 @@ package dtypes +import "github.com/filecoin-project/go-state-types/abi" + +type DrandSchedule []DrandPoint + +type DrandPoint struct { + Start abi.ChainEpoch + Config DrandConfig +} + type DrandConfig struct { Servers []string Relays []string diff --git a/node/modules/dtypes/miner.go b/node/modules/dtypes/miner.go index d559a2de13a..5bb439b4d6d 100644 --- a/node/modules/dtypes/miner.go +++ b/node/modules/dtypes/miner.go @@ -8,7 +8,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-fil-markets/storagemarket" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/storage-sealing/sealiface" ) diff --git a/node/modules/dtypes/storage.go b/node/modules/dtypes/storage.go index b8c1c3081ff..13defda8dec 100644 --- a/node/modules/dtypes/storage.go +++ b/node/modules/dtypes/storage.go @@ -27,7 +27,7 @@ type ChainBlockstore blockstore.Blockstore type ChainGCLocker blockstore.GCLocker type ChainGCBlockstore blockstore.GCBlockstore -type ChainExchange exchange.Interface +type ChainBitswap exchange.Interface type ChainBlockService bserv.BlockService type ClientMultiDstore *multistore.MultiStore diff --git a/node/modules/lp2p/pubsub.go b/node/modules/lp2p/pubsub.go index d4464e4de8e..aefb06d89fd 100644 --- a/node/modules/lp2p/pubsub.go +++ b/node/modules/lp2p/pubsub.go @@ -33,6 +33,7 @@ func init() { pubsub.GossipSubDirectConnectInitialDelay = 30 * time.Second pubsub.GossipSubIWantFollowupTime = 5 * time.Second pubsub.GossipSubHistoryLength = 10 + pubsub.GossipSubGossipFactor = 0.1 } func ScoreKeeper() *dtypes.ScoreKeeper { return new(dtypes.ScoreKeeper) @@ -48,7 +49,7 @@ type GossipIn struct { Db dtypes.DrandBootstrap Cfg *config.Pubsub Sk *dtypes.ScoreKeeper - Dr dtypes.DrandConfig + Dr dtypes.DrandSchedule } func getDrandTopic(chainInfoJSON string) (string, error) { @@ -73,9 +74,126 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { } isBootstrapNode := in.Cfg.Bootstrapper - drandTopic, err := getDrandTopic(in.Dr.ChainInfoJSON) - if err != nil { - return nil, err + + drandTopicParams := &pubsub.TopicScoreParams{ + // expected 2 beaconsn/min + TopicWeight: 0.5, // 5x block topic; max cap is 62.5 + + // 1 tick per second, maxes at 1 after 1 hour + TimeInMeshWeight: 0.00027, // ~1/3600 + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 1, + + // deliveries decay after 1 hour, cap at 25 beacons + FirstMessageDeliveriesWeight: 5, // max value is 125 + FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + FirstMessageDeliveriesCap: 25, // the maximum expected in an hour is ~26, including the decay + + // Mesh Delivery Failure is currently turned off for beacons + // This is on purpose as + // - the traffic is very low for meaningful distribution of incoming edges. + // - the reaction time needs to be very slow -- in the order of 10 min at least + // so we might as well let opportunistic grafting repair the mesh on its own + // pace. + // - the network is too small, so large asymmetries can be expected between mesh + // edges. + // We should revisit this once the network grows. + + // invalid messages decay after 1 hour + InvalidMessageDeliveriesWeight: -1000, + InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + } + + topicParams := map[string]*pubsub.TopicScoreParams{ + build.BlocksTopic(in.Nn): { + // expected 10 blocks/min + TopicWeight: 0.1, // max cap is 50, max mesh penalty is -10, single invalid message is -100 + + // 1 tick per second, maxes at 1 after 1 hour + TimeInMeshWeight: 0.00027, // ~1/3600 + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 1, + + // deliveries decay after 1 hour, cap at 100 blocks + FirstMessageDeliveriesWeight: 5, // max value is 500 + FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + FirstMessageDeliveriesCap: 100, // 100 blocks in an hour + + // Mesh Delivery Failure is currently turned off for blocks + // This is on purpose as + // - the traffic is very low for meaningful distribution of incoming edges. + // - the reaction time needs to be very slow -- in the order of 10 min at least + // so we might as well let opportunistic grafting repair the mesh on its own + // pace. + // - the network is too small, so large asymmetries can be expected between mesh + // edges. + // We should revisit this once the network grows. + // + // // tracks deliveries in the last minute + // // penalty activates at 1 minute and expects ~0.4 blocks + // MeshMessageDeliveriesWeight: -576, // max penalty is -100 + // MeshMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Minute), + // MeshMessageDeliveriesCap: 10, // 10 blocks in a minute + // MeshMessageDeliveriesThreshold: 0.41666, // 10/12/2 blocks/min + // MeshMessageDeliveriesWindow: 10 * time.Millisecond, + // MeshMessageDeliveriesActivation: time.Minute, + // + // // decays after 15 min + // MeshFailurePenaltyWeight: -576, + // MeshFailurePenaltyDecay: pubsub.ScoreParameterDecay(15 * time.Minute), + + // invalid messages decay after 1 hour + InvalidMessageDeliveriesWeight: -1000, + InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + }, + build.MessagesTopic(in.Nn): { + // expected > 1 tx/second + TopicWeight: 0.1, // max cap is 5, single invalid message is -100 + + // 1 tick per second, maxes at 1 hour + TimeInMeshWeight: 0.0002778, // ~1/3600 + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 1, + + // deliveries decay after 10min, cap at 100 tx + FirstMessageDeliveriesWeight: 0.5, // max value is 50 + FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(10 * time.Minute), + FirstMessageDeliveriesCap: 100, // 100 messages in 10 minutes + + // Mesh Delivery Failure is currently turned off for messages + // This is on purpose as the network is still too small, which results in + // asymmetries and potential unmeshing from negative scores. + // // tracks deliveries in the last minute + // // penalty activates at 1 min and expects 2.5 txs + // MeshMessageDeliveriesWeight: -16, // max penalty is -100 + // MeshMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Minute), + // MeshMessageDeliveriesCap: 100, // 100 txs in a minute + // MeshMessageDeliveriesThreshold: 2.5, // 60/12/2 txs/minute + // MeshMessageDeliveriesWindow: 10 * time.Millisecond, + // MeshMessageDeliveriesActivation: time.Minute, + + // // decays after 5min + // MeshFailurePenaltyWeight: -16, + // MeshFailurePenaltyDecay: pubsub.ScoreParameterDecay(5 * time.Minute), + + // invalid messages decay after 1 hour + InvalidMessageDeliveriesWeight: -1000, + InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + }, + } + + pgTopicWeights := map[string]float64{ + build.BlocksTopic(in.Nn): 10, + build.MessagesTopic(in.Nn): 1, + } + + for _, d := range in.Dr { + topic, err := getDrandTopic(d.Config.ChainInfoJSON) + if err != nil { + return nil, err + } + topicParams[topic] = drandTopicParams + pgTopicWeights[topic] = 5 } options := []pubsub.Option{ @@ -123,111 +241,7 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { RetainScore: 6 * time.Hour, // topic parameters - Topics: map[string]*pubsub.TopicScoreParams{ - drandTopic: { - // expected 2 beaconsn/min - TopicWeight: 0.5, // 5x block topic; max cap is 62.5 - - // 1 tick per second, maxes at 1 after 1 hour - TimeInMeshWeight: 0.00027, // ~1/3600 - TimeInMeshQuantum: time.Second, - TimeInMeshCap: 1, - - // deliveries decay after 1 hour, cap at 25 beacons - FirstMessageDeliveriesWeight: 5, // max value is 125 - FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), - FirstMessageDeliveriesCap: 25, // the maximum expected in an hour is ~26, including the decay - - // Mesh Delivery Failure is currently turned off for beacons - // This is on purpose as - // - the traffic is very low for meaningful distribution of incoming edges. - // - the reaction time needs to be very slow -- in the order of 10 min at least - // so we might as well let opportunistic grafting repair the mesh on its own - // pace. - // - the network is too small, so large asymmetries can be expected between mesh - // edges. - // We should revisit this once the network grows. - - // invalid messages decay after 1 hour - InvalidMessageDeliveriesWeight: -1000, - InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), - }, - build.BlocksTopic(in.Nn): { - // expected 10 blocks/min - TopicWeight: 0.1, // max cap is 50, max mesh penalty is -10, single invalid message is -100 - - // 1 tick per second, maxes at 1 after 1 hour - TimeInMeshWeight: 0.00027, // ~1/3600 - TimeInMeshQuantum: time.Second, - TimeInMeshCap: 1, - - // deliveries decay after 1 hour, cap at 100 blocks - FirstMessageDeliveriesWeight: 5, // max value is 500 - FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), - FirstMessageDeliveriesCap: 100, // 100 blocks in an hour - - // Mesh Delivery Failure is currently turned off for blocks - // This is on purpose as - // - the traffic is very low for meaningful distribution of incoming edges. - // - the reaction time needs to be very slow -- in the order of 10 min at least - // so we might as well let opportunistic grafting repair the mesh on its own - // pace. - // - the network is too small, so large asymmetries can be expected between mesh - // edges. - // We should revisit this once the network grows. - // - // // tracks deliveries in the last minute - // // penalty activates at 1 minute and expects ~0.4 blocks - // MeshMessageDeliveriesWeight: -576, // max penalty is -100 - // MeshMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Minute), - // MeshMessageDeliveriesCap: 10, // 10 blocks in a minute - // MeshMessageDeliveriesThreshold: 0.41666, // 10/12/2 blocks/min - // MeshMessageDeliveriesWindow: 10 * time.Millisecond, - // MeshMessageDeliveriesActivation: time.Minute, - // - // // decays after 15 min - // MeshFailurePenaltyWeight: -576, - // MeshFailurePenaltyDecay: pubsub.ScoreParameterDecay(15 * time.Minute), - - // invalid messages decay after 1 hour - InvalidMessageDeliveriesWeight: -1000, - InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), - }, - build.MessagesTopic(in.Nn): { - // expected > 1 tx/second - TopicWeight: 0.1, // max cap is 5, single invalid message is -100 - - // 1 tick per second, maxes at 1 hour - TimeInMeshWeight: 0.0002778, // ~1/3600 - TimeInMeshQuantum: time.Second, - TimeInMeshCap: 1, - - // deliveries decay after 10min, cap at 100 tx - FirstMessageDeliveriesWeight: 0.5, // max value is 50 - FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(10 * time.Minute), - FirstMessageDeliveriesCap: 100, // 100 messages in 10 minutes - - // Mesh Delivery Failure is currently turned off for messages - // This is on purpose as the network is still too small, which results in - // asymmetries and potential unmeshing from negative scores. - // // tracks deliveries in the last minute - // // penalty activates at 1 min and expects 2.5 txs - // MeshMessageDeliveriesWeight: -16, // max penalty is -100 - // MeshMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Minute), - // MeshMessageDeliveriesCap: 100, // 100 txs in a minute - // MeshMessageDeliveriesThreshold: 2.5, // 60/12/2 txs/minute - // MeshMessageDeliveriesWindow: 10 * time.Millisecond, - // MeshMessageDeliveriesActivation: time.Minute, - - // // decays after 5min - // MeshFailurePenaltyWeight: -16, - // MeshFailurePenaltyDecay: pubsub.ScoreParameterDecay(5 * time.Minute), - - // invalid messages decay after 1 hour - InvalidMessageDeliveriesWeight: -1000, - InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), - }, - }, + Topics: topicParams, }, &pubsub.PeerScoreThresholds{ GossipThreshold: -500, @@ -248,8 +262,8 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { pubsub.GossipSubDlo = 0 pubsub.GossipSubDhi = 0 pubsub.GossipSubDout = 0 - pubsub.GossipSubDlazy = 1024 - pubsub.GossipSubGossipFactor = 0.5 + pubsub.GossipSubDlazy = 64 + pubsub.GossipSubGossipFactor = 0.25 pubsub.GossipSubPruneBackoff = 5 * time.Minute // turn on PX options = append(options, pubsub.WithPeerExchange(true)) @@ -276,6 +290,25 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { options = append(options, pubsub.WithDirectPeers(directPeerInfo)) } + // validation queue RED + var pgParams *pubsub.PeerGaterParams + + if isBootstrapNode { + pgParams = pubsub.NewPeerGaterParams( + 0.33, + pubsub.ScoreParameterDecay(2*time.Minute), + pubsub.ScoreParameterDecay(10*time.Minute), + ).WithTopicDeliveryWeights(pgTopicWeights) + } else { + pgParams = pubsub.NewPeerGaterParams( + 0.33, + pubsub.ScoreParameterDecay(2*time.Minute), + pubsub.ScoreParameterDecay(time.Hour), + ).WithTopicDeliveryWeights(pgTopicWeights) + } + + options = append(options, pubsub.WithPeerGater(pgParams)) + // tracer if in.Cfg.RemoteTracer != "" { a, err := ma.NewMultiaddr(in.Cfg.RemoteTracer) diff --git a/node/modules/services.go b/node/modules/services.go index fd45583da78..7bef434be6a 100644 --- a/node/modules/services.go +++ b/node/modules/services.go @@ -19,7 +19,7 @@ import ( "github.com/filecoin-project/lotus/chain" "github.com/filecoin-project/lotus/chain/beacon" "github.com/filecoin-project/lotus/chain/beacon/drand" - "github.com/filecoin-project/lotus/chain/blocksync" + "github.com/filecoin-project/lotus/chain/exchange" "github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/store" @@ -73,8 +73,9 @@ func RunPeerMgr(mctx helpers.MetricsCtx, lc fx.Lifecycle, pmgr *peermgr.PeerMgr) go pmgr.Run(helpers.LifecycleCtx(mctx, lc)) } -func RunBlockSync(h host.Host, svc *blocksync.BlockSyncService) { - h.SetStreamHandler(blocksync.BlockSyncProtocolID, svc.HandleStream) +func RunChainExchange(h host.Host, svc exchange.Server) { + h.SetStreamHandler(exchange.BlockSyncProtocolID, svc.HandleStream) // old + h.SetStreamHandler(exchange.ChainExchangeProtocolID, svc.HandleStream) // new } func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, s *chain.Syncer, bserv dtypes.ChainBlockService, chain *store.ChainStore, stmgr *stmgr.StateManager, h host.Host, nn dtypes.NetworkName) { @@ -129,21 +130,29 @@ type RandomBeaconParams struct { PubSub *pubsub.PubSub `optional:"true"` Cs *store.ChainStore - DrandConfig dtypes.DrandConfig + DrandConfig dtypes.DrandSchedule } -func BuiltinDrandConfig() dtypes.DrandConfig { - return build.DrandConfig() +func BuiltinDrandConfig() dtypes.DrandSchedule { + return build.DrandConfigSchedule() } -func RandomBeacon(p RandomBeaconParams, _ dtypes.AfterGenesisSet) (beacon.RandomBeacon, error) { +func RandomSchedule(p RandomBeaconParams, _ dtypes.AfterGenesisSet) (beacon.Schedule, error) { gen, err := p.Cs.GetGenesis() if err != nil { return nil, err } - //return beacon.NewMockBeacon(build.BlockDelaySecs * time.Second) - return drand.NewDrandBeacon(gen.Timestamp, build.BlockDelaySecs, p.PubSub, p.DrandConfig) + shd := beacon.Schedule{} + for _, dc := range p.DrandConfig { + bc, err := drand.NewDrandBeacon(gen.Timestamp, build.BlockDelaySecs, p.PubSub, dc.Config) + if err != nil { + return nil, xerrors.Errorf("creating drand beacon: %w", err) + } + shd = append(shd, beacon.BeaconPoint{Start: dc.Start, Beacon: bc}) + } + + return shd, nil } func OpenFilesystemJournal(lr repo.LockedRepo, lc fx.Lifecycle, disabled journal.DisabledEvents) (journal.Journal, error) { diff --git a/node/modules/storageminer.go b/node/modules/storageminer.go index bbd40c0c91a..5f00fffc093 100644 --- a/node/modules/storageminer.go +++ b/node/modules/storageminer.go @@ -41,8 +41,8 @@ import ( "github.com/filecoin-project/go-jsonrpc/auth" "github.com/filecoin-project/go-multistore" paramfetch "github.com/filecoin-project/go-paramfetch" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-storedcounter" - "github.com/filecoin-project/specs-actors/actors/abi" sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" diff --git a/node/modules/testing/beacon.go b/node/modules/testing/beacon.go index a4ef822fca3..7876e1d0528 100644 --- a/node/modules/testing/beacon.go +++ b/node/modules/testing/beacon.go @@ -7,6 +7,9 @@ import ( "github.com/filecoin-project/lotus/chain/beacon" ) -func RandomBeacon() (beacon.RandomBeacon, error) { - return beacon.NewMockBeacon(time.Duration(build.BlockDelaySecs) * time.Second), nil +func RandomBeacon() (beacon.Schedule, error) { + return beacon.Schedule{ + {Start: 0, + Beacon: beacon.NewMockBeacon(time.Duration(build.BlockDelaySecs) * time.Second), + }}, nil } diff --git a/node/node_test.go b/node/node_test.go index 31a14bc20b2..8cc51f62988 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -7,9 +7,9 @@ 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" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/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" diff --git a/node/repo/fsrepo.go b/node/repo/fsrepo.go index 14085d4ac2e..709d78d3aa9 100644 --- a/node/repo/fsrepo.go +++ b/node/repo/fsrepo.go @@ -101,7 +101,7 @@ func (fsr *FsRepo) Init(t RepoType) error { } log.Infof("Initializing repo at '%s'", fsr.path) - err = os.Mkdir(fsr.path, 0755) //nolint: gosec + err = os.MkdirAll(fsr.path, 0755) //nolint: gosec if err != nil && !os.IsExist(err) { return err } diff --git a/node/test/builder.go b/node/test/builder.go index 64e20e4f2d8..de2071e7a85 100644 --- a/node/test/builder.go +++ b/node/test/builder.go @@ -13,6 +13,8 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-storedcounter" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/client" @@ -34,8 +36,6 @@ import ( testing2 "github.com/filecoin-project/lotus/node/modules/testing" "github.com/filecoin-project/lotus/node/repo" "github.com/filecoin-project/lotus/storage/mockstorage" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/ipfs/go-datastore" diff --git a/paychmgr/manager.go b/paychmgr/manager.go index d1fd715ef6c..4b102f062f7 100644 --- a/paychmgr/manager.go +++ b/paychmgr/manager.go @@ -4,7 +4,7 @@ import ( "context" "sync" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/node/modules/helpers" @@ -141,13 +141,48 @@ func (pm *Manager) GetPaych(ctx context.Context, from, to address.Address, amt t return chanAccessor.getPaych(ctx, amt) } -func (pm *Manager) AvailableFunds(from address.Address, to address.Address) (*api.ChannelAvailableFunds, error) { - chanAccessor, err := pm.accessorByFromTo(from, to) +func (pm *Manager) AvailableFunds(ch address.Address) (*api.ChannelAvailableFunds, error) { + ca, err := pm.accessorByAddress(ch) + if err != nil { + return nil, err + } + + ci, err := ca.getChannelInfo(ch) + if err != nil { + return nil, err + } + + return ca.availableFunds(ci.ChannelID) +} + +func (pm *Manager) AvailableFundsByFromTo(from address.Address, to address.Address) (*api.ChannelAvailableFunds, error) { + ca, err := pm.accessorByFromTo(from, to) + if err != nil { + return nil, err + } + + ci, err := ca.outboundActiveByFromTo(from, to) + if err == ErrChannelNotTracked { + // If there is no active channel between from / to we still want to + // return an empty ChannelAvailableFunds, so that clients can check + // for the existence of a channel between from / to without getting + // an error. + return &api.ChannelAvailableFunds{ + Channel: nil, + From: from, + To: to, + ConfirmedAmt: types.NewInt(0), + PendingAmt: types.NewInt(0), + PendingWaitSentinel: nil, + QueuedAmt: types.NewInt(0), + VoucherReedeemedAmt: types.NewInt(0), + }, nil + } if err != nil { return nil, err } - return chanAccessor.availableFunds() + return ca.availableFunds(ci.ChannelID) } // GetPaychWaitReady waits until the create channel / add funds message with the diff --git a/paychmgr/mock_test.go b/paychmgr/mock_test.go index d2aa047eee2..bc19de2239c 100644 --- a/paychmgr/mock_test.go +++ b/paychmgr/mock_test.go @@ -7,7 +7,7 @@ import ( "github.com/filecoin-project/lotus/lib/sigs" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" cbornode "github.com/ipfs/go-ipld-cbor" diff --git a/paychmgr/paych.go b/paychmgr/paych.go index be43aaf9b56..20d76b7fd87 100644 --- a/paychmgr/paych.go +++ b/paychmgr/paych.go @@ -13,14 +13,14 @@ import ( "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/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/sigs" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/account" "github.com/filecoin-project/specs-actors/actors/builtin/paych" - xerrors "golang.org/x/xerrors" + "golang.org/x/xerrors" ) // insufficientFundsErr indicates that there are not enough funds in the @@ -81,6 +81,13 @@ func (ca *channelAccessor) getChannelInfo(addr address.Address) (*ChannelInfo, e return ca.store.ByAddress(addr) } +func (ca *channelAccessor) outboundActiveByFromTo(from, to address.Address) (*ChannelInfo, error) { + ca.lk.Lock() + defer ca.lk.Unlock() + + return ca.store.OutboundActiveByFromTo(from, to) +} + // createVoucher creates a voucher with the given specification, setting its // 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 diff --git a/paychmgr/paych_test.go b/paychmgr/paych_test.go index e1ae487e131..18c6655dadc 100644 --- a/paychmgr/paych_test.go +++ b/paychmgr/paych_test.go @@ -11,14 +11,14 @@ import ( "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/filecoin-project/specs-actors/actors/crypto" "github.com/stretchr/testify/require" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/abi" + "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" diff --git a/paychmgr/paychget_test.go b/paychmgr/paychget_test.go index 8eff08bdd02..1f3e4c3969b 100644 --- a/paychmgr/paychget_test.go +++ b/paychmgr/paychget_test.go @@ -9,7 +9,7 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin/account" "github.com/filecoin-project/specs-actors/actors/util/adt" - "github.com/filecoin-project/specs-actors/actors/abi" + "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" @@ -22,7 +22,7 @@ import ( "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" @@ -921,7 +921,7 @@ func TestPaychAvailableFunds(t *testing.T) { require.NoError(t, err) // No channel created yet so available funds should be all zeroes - av, err := mgr.AvailableFunds(from, to) + av, err := mgr.AvailableFundsByFromTo(from, to) require.NoError(t, err) require.Nil(t, av.Channel) require.Nil(t, av.PendingWaitSentinel) @@ -936,7 +936,7 @@ func TestPaychAvailableFunds(t *testing.T) { require.NoError(t, err) // Available funds should reflect create channel message sent - av, err = mgr.AvailableFunds(from, to) + av, err = mgr.AvailableFundsByFromTo(from, to) require.NoError(t, err) require.Nil(t, av.Channel) require.EqualValues(t, 0, av.ConfirmedAmt.Int64()) @@ -964,7 +964,7 @@ func TestPaychAvailableFunds(t *testing.T) { waitForQueueSize(t, mgr, from, to, 1) // Available funds should now include queued funds - av, err = mgr.AvailableFunds(from, to) + av, err = mgr.AvailableFundsByFromTo(from, to) require.NoError(t, err) require.Nil(t, av.Channel) require.NotNil(t, av.PendingWaitSentinel) @@ -1009,7 +1009,7 @@ func TestPaychAvailableFunds(t *testing.T) { // Available funds should now include the channel and also a wait sentinel // for the add funds message - av, err = mgr.AvailableFunds(from, to) + av, err = mgr.AvailableFunds(ch) require.NoError(t, err) require.NotNil(t, av.Channel) require.NotNil(t, av.PendingWaitSentinel) @@ -1031,7 +1031,7 @@ func TestPaychAvailableFunds(t *testing.T) { require.NoError(t, err) // Available funds should no longer have a wait sentinel - av, err = mgr.AvailableFunds(from, to) + av, err = mgr.AvailableFunds(ch) require.NoError(t, err) require.NotNil(t, av.Channel) require.Nil(t, av.PendingWaitSentinel) @@ -1052,7 +1052,7 @@ func TestPaychAvailableFunds(t *testing.T) { _, err = mgr.AddVoucherOutbound(ctx, ch, voucher, nil, types.NewInt(0)) require.NoError(t, err) - av, err = mgr.AvailableFunds(from, to) + av, err = mgr.AvailableFunds(ch) require.NoError(t, err) require.NotNil(t, av.Channel) require.Nil(t, av.PendingWaitSentinel) diff --git a/paychmgr/settle_test.go b/paychmgr/settle_test.go index f922dcccb16..f17f961e20f 100644 --- a/paychmgr/settle_test.go +++ b/paychmgr/settle_test.go @@ -6,7 +6,7 @@ import ( "github.com/ipfs/go-cid" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" tutils "github.com/filecoin-project/specs-actors/support/testing" ds "github.com/ipfs/go-datastore" ds_sync "github.com/ipfs/go-datastore/sync" diff --git a/paychmgr/settler/settler.go b/paychmgr/settler/settler.go index d5f8bf54e3c..45f24cdd988 100644 --- a/paychmgr/settler/settler.go +++ b/paychmgr/settler/settler.go @@ -12,7 +12,7 @@ import ( logging "github.com/ipfs/go-log/v2" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "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" diff --git a/paychmgr/simple.go b/paychmgr/simple.go index 88d94645e79..4cf579a4778 100644 --- a/paychmgr/simple.go +++ b/paychmgr/simple.go @@ -10,7 +10,7 @@ import ( "golang.org/x/sync/errgroup" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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" @@ -187,11 +187,11 @@ func (ca *channelAccessor) enqueue(task *fundsReq) { defer ca.lk.Unlock() ca.fundsReqQueue = append(ca.fundsReqQueue, task) - go ca.processQueue() // nolint: errcheck + go ca.processQueue("") // nolint: errcheck } // Run the operations in the queue -func (ca *channelAccessor) processQueue() (*api.ChannelAvailableFunds, error) { +func (ca *channelAccessor) processQueue(channelID string) (*api.ChannelAvailableFunds, error) { ca.lk.Lock() defer ca.lk.Unlock() @@ -200,7 +200,7 @@ func (ca *channelAccessor) processQueue() (*api.ChannelAvailableFunds, error) { // If there's nothing in the queue, bail out if len(ca.fundsReqQueue) == 0 { - return ca.currentAvailableFunds(types.NewInt(0)) + return ca.currentAvailableFunds(channelID, types.NewInt(0)) } // Merge all pending requests into one. @@ -211,7 +211,7 @@ func (ca *channelAccessor) processQueue() (*api.ChannelAvailableFunds, error) { if amt.IsZero() { // Note: The amount can be zero if requests are cancelled as we're // building the mergedFundsReq - return ca.currentAvailableFunds(amt) + return ca.currentAvailableFunds(channelID, amt) } res := ca.processTask(merged.ctx, amt) @@ -221,7 +221,7 @@ func (ca *channelAccessor) processQueue() (*api.ChannelAvailableFunds, error) { if res == nil { // Stop processing the fundsReqQueue and wait. When the event occurs it will // call processQueue() again - return ca.currentAvailableFunds(amt) + return ca.currentAvailableFunds(channelID, amt) } // Finished processing so clear the queue @@ -230,7 +230,7 @@ func (ca *channelAccessor) processQueue() (*api.ChannelAvailableFunds, error) { // Call the task callback with its results merged.onComplete(res) - return ca.currentAvailableFunds(types.NewInt(0)) + return ca.currentAvailableFunds(channelID, types.NewInt(0)) } // filterQueue filters cancelled requests out of the queue @@ -283,25 +283,16 @@ func (ca *channelAccessor) msgWaitComplete(mcid cid.Cid, err error) { // The queue may have been waiting for msg completion to proceed, so // process the next queue item if len(ca.fundsReqQueue) > 0 { - go ca.processQueue() // nolint: errcheck + go ca.processQueue("") // nolint: errcheck } } -func (ca *channelAccessor) currentAvailableFunds(queuedAmt types.BigInt) (*api.ChannelAvailableFunds, error) { - channelInfo, err := ca.store.OutboundActiveByFromTo(ca.from, ca.to) - if err == ErrChannelNotTracked { - // If the channel does not exist we still want to return an empty - // ChannelAvailableFunds, so that clients can check for the existence - // of a channel between from / to without getting an error. - return &api.ChannelAvailableFunds{ - Channel: nil, - ConfirmedAmt: types.NewInt(0), - PendingAmt: types.NewInt(0), - PendingWaitSentinel: nil, - QueuedAmt: queuedAmt, - VoucherReedeemedAmt: types.NewInt(0), - }, nil +func (ca *channelAccessor) currentAvailableFunds(channelID string, queuedAmt types.BigInt) (*api.ChannelAvailableFunds, error) { + if len(channelID) == 0 { + return nil, nil } + + channelInfo, err := ca.store.ByChannelID(channelID) if err != nil { return nil, err } @@ -335,6 +326,8 @@ func (ca *channelAccessor) currentAvailableFunds(queuedAmt types.BigInt) (*api.C return &api.ChannelAvailableFunds{ Channel: channelInfo.Channel, + From: channelInfo.from(), + To: channelInfo.to(), ConfirmedAmt: channelInfo.Amount, PendingAmt: channelInfo.PendingAmount, PendingWaitSentinel: waitSentinel, @@ -713,6 +706,6 @@ func (ca *channelAccessor) msgPromise(ctx context.Context, mcid cid.Cid) chan on return promise } -func (ca *channelAccessor) availableFunds() (*api.ChannelAvailableFunds, error) { - return ca.processQueue() +func (ca *channelAccessor) availableFunds(channelID string) (*api.ChannelAvailableFunds, error) { + return ca.processQueue(channelID) } diff --git a/paychmgr/store.go b/paychmgr/store.go index 4a5a4f49f12..46249fa361c 100644 --- a/paychmgr/store.go +++ b/paychmgr/store.go @@ -86,6 +86,20 @@ type ChannelInfo struct { Settling bool } +func (ci *ChannelInfo) from() address.Address { + if ci.Direction == DirOutbound { + return ci.Control + } + return ci.Target +} + +func (ci *ChannelInfo) to() address.Address { + if ci.Direction == DirOutbound { + return ci.Target + } + return ci.Control +} + // 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) { diff --git a/storage/adapter_events.go b/storage/adapter_events.go index 42622e8550c..ff69c1e5110 100644 --- a/storage/adapter_events.go +++ b/storage/adapter_events.go @@ -3,7 +3,7 @@ package storage import ( "context" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/types" diff --git a/storage/adapter_storage_miner.go b/storage/adapter_storage_miner.go index 0963b07e6d6..2869e48e5cb 100644 --- a/storage/adapter_storage_miner.go +++ b/storage/adapter_storage_miner.go @@ -4,17 +4,19 @@ import ( "bytes" "context" + "github.com/filecoin-project/go-bitfield" + "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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/crypto" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api" @@ -198,7 +200,7 @@ func (s SealingAPIAdapter) StateSectorPreCommitInfo(ctx context.Context, maddr a return nil, err } if !ok { - var allocated abi.BitField + var allocated bitfield.BitField if err := stor.Get(ctx, state.AllocatedSectors, &allocated); err != nil { return nil, xerrors.Errorf("loading allocated sector bitfield: %w", err) } diff --git a/storage/addresses.go b/storage/addresses.go index a1c05660fcb..bef84536733 100644 --- a/storage/addresses.go +++ b/storage/addresses.go @@ -6,7 +6,7 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types" diff --git a/storage/miner.go b/storage/miner.go index 686a02df0e8..bf026fc30e7 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -5,6 +5,11 @@ import ( "errors" "time" + "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" logging "github.com/ipfs/go-log/v2" @@ -12,11 +17,11 @@ 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/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/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/api" @@ -64,12 +69,12 @@ type storageMinerApi interface { 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, *abi.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) + StateMinerSectors(context.Context, address.Address, *bitfield.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, 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) - StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, 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) StateSearchMsg(context.Context, cid.Cid) (*api.MsgLookup, error) @@ -77,8 +82,8 @@ type storageMinerApi interface { StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) StateMarketStorageDeal(context.Context, abi.DealID, types.TipSetKey) (*api.MarketDeal, error) - StateMinerFaults(context.Context, address.Address, types.TipSetKey) (abi.BitField, error) - StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (abi.BitField, error) + 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) MpoolPushMessage(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error) @@ -224,9 +229,9 @@ func (wpp *StorageWpp) GenerateCandidates(ctx context.Context, randomness abi.Po return cds, nil } -func (wpp *StorageWpp) ComputeProof(ctx context.Context, ssi []abi.SectorInfo, rand abi.PoStRandomness) ([]abi.PoStProof, error) { +func (wpp *StorageWpp) ComputeProof(ctx context.Context, ssi []proof.SectorInfo, rand abi.PoStRandomness) ([]proof.PoStProof, error) { if build.InsecurePoStValidation { - return []abi.PoStProof{{ProofBytes: []byte("valid proof")}}, nil + return []proof.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 fd4d0d69b1e..da063020dbd 100644 --- a/storage/mockstorage/preseal.go +++ b/storage/mockstorage/preseal.go @@ -5,11 +5,11 @@ import ( "github.com/filecoin-project/go-address" commcid "github.com/filecoin-project/go-fil-commcid" + "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/lotus/extern/sector-storage/mock" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" diff --git a/storage/sealing.go b/storage/sealing.go index 7d7140b9818..2cd454e5b33 100644 --- a/storage/sealing.go +++ b/storage/sealing.go @@ -5,7 +5,7 @@ import ( "io" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" ) diff --git a/storage/sectorblocks/blocks.go b/storage/sectorblocks/blocks.go index b88ebcbae90..bc8456a1f28 100644 --- a/storage/sectorblocks/blocks.go +++ b/storage/sectorblocks/blocks.go @@ -15,8 +15,8 @@ import ( "golang.org/x/xerrors" cborutil "github.com/filecoin-project/go-cbor-util" + "github.com/filecoin-project/go-state-types/abi" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/node/modules/dtypes" diff --git a/storage/wdpost_journal.go b/storage/wdpost_journal.go index 04bca895c40..c1a4d4817ca 100644 --- a/storage/wdpost_journal.go +++ b/storage/wdpost_journal.go @@ -1,7 +1,8 @@ package storage import ( - "github.com/filecoin-project/specs-actors/actors/abi" + "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/ipfs/go-cid" @@ -36,7 +37,7 @@ const ( // evtCommon is a common set of attributes for Windowed PoSt journal events. type evtCommon struct { - Deadline *miner.DeadlineInfo + Deadline *dline.Info Height abi.ChainEpoch TipSet []cid.Cid Error error `json:",omitempty"` diff --git a/storage/wdpost_run.go b/storage/wdpost_run.go index 1702c546e00..8f15c47965f 100644 --- a/storage/wdpost_run.go +++ b/storage/wdpost_run.go @@ -6,15 +6,20 @@ import ( "errors" "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/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "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/specs-actors/actors/crypto" "github.com/ipfs/go-cid" + "go.opencensus.io/trace" "golang.org/x/xerrors" @@ -27,7 +32,7 @@ import ( var errNoPartitions = errors.New("no partitions") -func (s *WindowPoStScheduler) failPost(err error, deadline *miner.DeadlineInfo) { +func (s *WindowPoStScheduler) failPost(err error, deadline *dline.Info) { journal.J.RecordEvent(s.evtTypes[evtTypeWdPoStScheduler], func() interface{} { return WdPoStSchedulerEvt{ evtCommon: s.getEvtCommon(err), @@ -43,7 +48,7 @@ func (s *WindowPoStScheduler) failPost(err error, deadline *miner.DeadlineInfo) s.failLk.Unlock()*/ } -func (s *WindowPoStScheduler) doPost(ctx context.Context, deadline *miner.DeadlineInfo, ts *types.TipSet) { +func (s *WindowPoStScheduler) doPost(ctx context.Context, deadline *dline.Info, ts *types.TipSet) { ctx, abort := context.WithCancel(ctx) s.abort = abort @@ -102,7 +107,7 @@ func (s *WindowPoStScheduler) doPost(ctx context.Context, deadline *miner.Deadli }() } -func (s *WindowPoStScheduler) checkSectors(ctx context.Context, check abi.BitField) (abi.BitField, error) { +func (s *WindowPoStScheduler) checkSectors(ctx context.Context, check bitfield.BitField) (bitfield.BitField, error) { spt, err := s.proofType.RegisteredSealProof() if err != nil { return bitfield.BitField{}, xerrors.Errorf("getting seal proof type: %w", err) @@ -322,7 +327,7 @@ func (s *WindowPoStScheduler) checkNextFaults(ctx context.Context, dlIdx uint64, return faults, sm, nil } -func (s *WindowPoStScheduler) runPost(ctx context.Context, di miner.DeadlineInfo, ts *types.TipSet) (*miner.SubmitWindowedPoStParams, error) { +func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *types.TipSet) (*miner.SubmitWindowedPoStParams, error) { ctx, span := trace.StartSpan(ctx, "storage.runPost") defer span.End() @@ -405,94 +410,114 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di miner.DeadlineInfo Proofs: nil, } - var sinfos []abi.SectorInfo - sidToPart := map[abi.SectorNumber]uint64{} skipCount := uint64(0) + postSkipped := bitfield.New() + var postOut []proof.PoStProof - for partIdx, partition := range partitions { - // TODO: Can do this in parallel - toProve, err := partition.ActiveSectors() - if err != nil { - return nil, xerrors.Errorf("getting active sectors: %w", err) - } + for retries := 0; retries < 5; retries++ { + var sinfos []proof.SectorInfo + sidToPart := map[abi.SectorNumber]int{} - toProve, err = bitfield.MergeBitFields(toProve, partition.Recoveries) - if err != nil { - return nil, xerrors.Errorf("adding recoveries to set of sectors to prove: %w", err) - } + for partIdx, partition := range partitions { + // TODO: Can do this in parallel + toProve, err := partition.ActiveSectors() + if err != nil { + return nil, xerrors.Errorf("getting active sectors: %w", err) + } - good, err := s.checkSectors(ctx, toProve) - if err != nil { - return nil, xerrors.Errorf("checking sectors to skip: %w", err) - } + toProve, err = bitfield.MergeBitFields(toProve, partition.Recoveries) + if err != nil { + return nil, xerrors.Errorf("adding recoveries to set of sectors to prove: %w", err) + } - skipped, err := bitfield.SubtractBitField(toProve, good) - if err != nil { - return nil, xerrors.Errorf("toProve - good: %w", err) - } + toProve, err = bitfield.SubtractBitField(toProve, postSkipped) + if err != nil { + return nil, xerrors.Errorf("toProve - postSkipped: %w", err) + } - sc, err := skipped.Count() - if err != nil { - return nil, xerrors.Errorf("getting skipped sector count: %w", err) - } + good, err := s.checkSectors(ctx, toProve) + if err != nil { + return nil, xerrors.Errorf("checking sectors to skip: %w", err) + } - skipCount += sc + skipped, err := bitfield.SubtractBitField(toProve, good) + if err != nil { + return nil, xerrors.Errorf("toProve - good: %w", err) + } - ssi, err := s.sectorsForProof(ctx, good, partition.Sectors, ts) - if err != nil { - return nil, xerrors.Errorf("getting sorted sector info: %w", err) + sc, err := skipped.Count() + if err != nil { + return nil, xerrors.Errorf("getting skipped sector count: %w", err) + } + + skipCount += sc + + ssi, err := s.sectorsForProof(ctx, good, partition.Sectors, ts) + if err != nil { + return nil, xerrors.Errorf("getting sorted sector info: %w", err) + } + + if len(ssi) == 0 { + continue + } + + sinfos = append(sinfos, ssi...) + for _, si := range ssi { + sidToPart[si.SectorNumber] = partIdx + } + + params.Partitions = append(params.Partitions, miner.PoStPartition{ + Index: uint64(partIdx), + Skipped: skipped, + }) } - if len(ssi) == 0 { - continue + if len(sinfos) == 0 { + // nothing to prove.. + return nil, errNoPartitions } - sinfos = append(sinfos, ssi...) - for _, si := range ssi { - sidToPart[si.SectorNumber] = uint64(partIdx) + log.Infow("running windowPost", + "chain-random", rand, + "deadline", di, + "height", ts.Height(), + "skipped", skipCount) + + tsStart := build.Clock.Now() + + mid, err := address.IDFromAddress(s.actor) + if err != nil { + return nil, err } - params.Partitions = append(params.Partitions, miner.PoStPartition{ - Index: uint64(partIdx), - Skipped: skipped, - }) - } + var ps []abi.SectorID + postOut, ps, err = s.prover.GenerateWindowPoSt(ctx, abi.ActorID(mid), sinfos, abi.PoStRandomness(rand)) + elapsed := time.Since(tsStart) - if len(sinfos) == 0 { - // nothing to prove.. - return nil, errNoPartitions - } + log.Infow("computing window PoSt", "elapsed", elapsed) - log.Infow("running windowPost", - "chain-random", rand, - "deadline", di, - "height", ts.Height(), - "skipped", skipCount) + if err == nil { + break + } - tsStart := build.Clock.Now() + if len(ps) == 0 { + return nil, xerrors.Errorf("running post failed: %w", err) + } - mid, err := address.IDFromAddress(s.actor) - if err != nil { - return nil, err - } + log.Warnw("generate window PoSt skipped sectors", "sectors", ps, "error", err, "try", retries) - postOut, postSkipped, err := s.prover.GenerateWindowPoSt(ctx, abi.ActorID(mid), sinfos, abi.PoStRandomness(rand)) - if err != nil { - return nil, xerrors.Errorf("running post failed: %w", err) + skipCount += uint64(len(ps)) + for _, sector := range ps { + postSkipped.Set(uint64(sector.Number)) + } } if len(postOut) == 0 { - return nil, xerrors.Errorf("received proofs back from generate window post") + return nil, xerrors.Errorf("received no proofs back from generate window post") } params.Proofs = postOut - for _, sector := range postSkipped { - params.Partitions[sidToPart[sector.Number]].Skipped.Set(uint64(sector.Number)) - } - - elapsed := time.Since(tsStart) - commEpoch := di.Open commRand, err := s.api.ChainGetRandomnessFromTickets(ctx, ts.Key(), crypto.DomainSeparationTag_PoStChainCommit, commEpoch, nil) if err != nil { @@ -501,12 +526,12 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di miner.DeadlineInfo params.ChainCommitEpoch = commEpoch params.ChainCommitRand = commRand - log.Infow("submitting window PoSt", "elapsed", elapsed) + log.Infow("submitting window PoSt") return params, nil } -func (s *WindowPoStScheduler) sectorsForProof(ctx context.Context, goodSectors, allSectors abi.BitField, ts *types.TipSet) ([]abi.SectorInfo, error) { +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()) if err != nil { return nil, err @@ -516,22 +541,22 @@ func (s *WindowPoStScheduler) sectorsForProof(ctx context.Context, goodSectors, return nil, nil } - substitute := abi.SectorInfo{ + substitute := proof.SectorInfo{ SectorNumber: sset[0].ID, SealedCID: sset[0].Info.SealedCID, SealProof: sset[0].Info.SealProof, } - sectorByID := make(map[uint64]abi.SectorInfo, len(sset)) + sectorByID := make(map[uint64]proof.SectorInfo, len(sset)) for _, sector := range sset { - sectorByID[uint64(sector.ID)] = abi.SectorInfo{ + sectorByID[uint64(sector.ID)] = proof.SectorInfo{ SectorNumber: sector.ID, SealedCID: sector.Info.SealedCID, SealProof: sector.Info.SealProof, } } - proofSectors := make([]abi.SectorInfo, 0, len(sset)) + proofSectors := make([]proof.SectorInfo, 0, len(sset)) if err := allSectors.ForEach(func(sectorNo uint64) error { if info, found := sectorByID[sectorNo]; found { proofSectors = append(proofSectors, info) @@ -562,7 +587,7 @@ func (s *WindowPoStScheduler) submitPost(ctx context.Context, proof *miner.Submi From: s.worker, Method: builtin.MethodsMiner.SubmitWindowedPoSt, Params: enc, - Value: types.NewInt(1000), // currently hard-coded late fee in actor, returned if not late + Value: types.NewInt(0), } spec := &api.MessageSendSpec{MaxFee: abi.TokenAmount(s.feeCfg.MaxWindowPoStGasFee)} s.setSender(ctx, msg, spec) diff --git a/storage/wdpost_sched.go b/storage/wdpost_sched.go index d2b8279a06c..037f4e481f3 100644 --- a/storage/wdpost_sched.go +++ b/storage/wdpost_sched.go @@ -4,11 +4,12 @@ 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/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/api" @@ -38,7 +39,7 @@ type WindowPoStScheduler struct { cur *types.TipSet // if a post is in progress, this indicates for which ElectionPeriodStart - activeDeadline *miner.DeadlineInfo + activeDeadline *dline.Info abort context.CancelFunc evtTypes [4]journal.EventType @@ -77,7 +78,7 @@ func NewWindowedPoStScheduler(api storageMinerApi, fc config.MinerFeeConfig, sb }, nil } -func deadlineEquals(a, b *miner.DeadlineInfo) bool { +func deadlineEquals(a, b *dline.Info) bool { if a == nil || b == nil { return b == a } diff --git a/tools/stats/collect.go b/tools/stats/collect.go index 3d031a4156f..221dc37e2c9 100644 --- a/tools/stats/collect.go +++ b/tools/stats/collect.go @@ -4,8 +4,8 @@ import ( "context" "time" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/specs-actors/actors/abi" client "github.com/influxdata/influxdb1-client/v2" ) diff --git a/tools/stats/metrics.go b/tools/stats/metrics.go index 39fecf47b8e..ae79d927362 100644 --- a/tools/stats/metrics.go +++ b/tools/stats/metrics.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "fmt" + "math" "math/big" "strings" "time" @@ -12,6 +13,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/power" @@ -131,12 +133,6 @@ func RecordTipsetPoints(ctx context.Context, api api.FullNode, pl *PointList, ti p = NewPoint("chain.blocktime", tsTime.Unix()) pl.AddPoint(p) - baseFeeBig := tipset.Blocks()[0].ParentBaseFee.Copy() - baseFeeRat := new(big.Rat).SetFrac(baseFeeBig.Int, new(big.Int).SetUint64(build.FilecoinPrecision)) - baseFeeFloat, _ := baseFeeRat.Float64() - p = NewPoint("chain.basefee", baseFeeFloat) - pl.AddPoint(p) - totalGasLimit := int64(0) totalUniqGasLimit := int64(0) seen := make(map[cid.Cid]struct{}) @@ -178,6 +174,30 @@ func RecordTipsetPoints(ctx context.Context, api api.FullNode, pl *PointList, ti p = NewPoint("chain.gas_limit_uniq_total", totalUniqGasLimit) pl.AddPoint(p) + { + baseFeeIn := tipset.Blocks()[0].ParentBaseFee + newBaseFee := store.ComputeNextBaseFee(baseFeeIn, totalUniqGasLimit, len(tipset.Blocks()), tipset.Height()) + + baseFeeRat := new(big.Rat).SetFrac(newBaseFee.Int, new(big.Int).SetUint64(build.FilecoinPrecision)) + baseFeeFloat, _ := baseFeeRat.Float64() + p = NewPoint("chain.basefee", baseFeeFloat) + pl.AddPoint(p) + + baseFeeChange := new(big.Rat).SetFrac(newBaseFee.Int, baseFeeIn.Int) + baseFeeChangeF, _ := baseFeeChange.Float64() + p = NewPoint("chain.basefee_change_log", math.Log(baseFeeChangeF)/math.Log(1.125)) + pl.AddPoint(p) + } + { + blks := 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)) + pl.AddPoint(p) + p = NewPoint("chain.gas_waste_ratio", float64(totalGasLimit-totalUniqGasLimit)/float64(blks*build.BlockGasTarget)) + pl.AddPoint(p) + } + return nil } diff --git a/tools/stats/rpc.go b/tools/stats/rpc.go index 166769fedad..b01c07a3579 100644 --- a/tools/stats/rpc.go +++ b/tools/stats/rpc.go @@ -6,7 +6,7 @@ import ( "time" "github.com/filecoin-project/go-jsonrpc" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" manet "github.com/multiformats/go-multiaddr/net" "golang.org/x/xerrors" @@ -14,7 +14,6 @@ import ( "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" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/repo" @@ -72,7 +71,7 @@ sync_complete: "target_height", w.Target.Height(), "height", w.Height, "error", w.Message, - "stage", chain.SyncStageString(w.Stage), + "stage", w.Stage.String(), ) } else { log.Infow( @@ -82,7 +81,7 @@ sync_complete: "target", w.Target.Key(), "target_height", w.Target.Height(), "height", w.Height, - "stage", chain.SyncStageString(w.Stage), + "stage", w.Stage.String(), ) }