diff --git a/api/api_storage.go b/api/api_storage.go index 93bb1f869..4d05419d6 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -314,6 +314,11 @@ type StorageMiner interface { CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []storiface.SectorRef, expensive bool) (map[abi.SectorNumber]string, error) //perm:admin ComputeProof(ctx context.Context, ssi []builtin.ExtendedSectorInfo, rand abi.PoStRandomness, poStEpoch abi.ChainEpoch, nv abinetwork.Version) ([]builtin.PoStProof, error) //perm:read + + // RecoverFault can be used to declare recoveries manually. It sends messages + // to the miner actor with details of recovered sectors and returns the CID of messages. It honors the + // maxPartitionsPerRecoveryMessage from the config + RecoverFault(ctx context.Context, sectors []abi.SectorNumber) ([]cid.Cid, error) //perm:admin } var _ storiface.WorkerReturn = *new(StorageMiner) diff --git a/api/api_test.go b/api/api_test.go index 15f59a486..c03216365 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package api import ( diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 1ff3017cb..a63f5ee52 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -775,6 +775,8 @@ type StorageMinerStruct struct { PledgeSector func(p0 context.Context) (abi.SectorID, error) `perm:"write"` + RecoverFault func(p0 context.Context, p1 []abi.SectorNumber) ([]cid.Cid, error) `perm:"admin"` + ReturnAddPiece func(p0 context.Context, p1 storiface.CallID, p2 abi.PieceInfo, p3 *storiface.CallError) error `perm:"admin"` ReturnDataCid func(p0 context.Context, p1 storiface.CallID, p2 abi.PieceInfo, p3 *storiface.CallError) error `perm:"admin"` @@ -4644,6 +4646,17 @@ func (s *StorageMinerStub) PledgeSector(p0 context.Context) (abi.SectorID, error return *new(abi.SectorID), ErrNotSupported } +func (s *StorageMinerStruct) RecoverFault(p0 context.Context, p1 []abi.SectorNumber) ([]cid.Cid, error) { + if s.Internal.RecoverFault == nil { + return *new([]cid.Cid), ErrNotSupported + } + return s.Internal.RecoverFault(p0, p1) +} + +func (s *StorageMinerStub) RecoverFault(p0 context.Context, p1 []abi.SectorNumber) ([]cid.Cid, error) { + return *new([]cid.Cid), ErrNotSupported +} + func (s *StorageMinerStruct) ReturnAddPiece(p0 context.Context, p1 storiface.CallID, p2 abi.PieceInfo, p3 *storiface.CallError) error { if s.Internal.ReturnAddPiece == nil { return ErrNotSupported diff --git a/api/proxy_util_test.go b/api/proxy_util_test.go index 57162acd8..adc78a7d1 100644 --- a/api/proxy_util_test.go +++ b/api/proxy_util_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package api import ( diff --git a/blockstore/badger/blockstore_test.go b/blockstore/badger/blockstore_test.go index 8d1465a79..a14515796 100644 --- a/blockstore/badger/blockstore_test.go +++ b/blockstore/badger/blockstore_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package badgerbs import ( diff --git a/blockstore/badger/blockstore_test_suite.go b/blockstore/badger/blockstore_test_suite.go index 8ca2a76cc..7db155901 100644 --- a/blockstore/badger/blockstore_test_suite.go +++ b/blockstore/badger/blockstore_test_suite.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package badgerbs import ( diff --git a/blockstore/splitstore/markset_test.go b/blockstore/splitstore/markset_test.go index bcfb9454b..6cc481852 100644 --- a/blockstore/splitstore/markset_test.go +++ b/blockstore/splitstore/markset_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package splitstore import ( diff --git a/blockstore/splitstore/splitstore_compact.go b/blockstore/splitstore/splitstore_compact.go index 0301f90d7..272d0afab 100644 --- a/blockstore/splitstore/splitstore_compact.go +++ b/blockstore/splitstore/splitstore_compact.go @@ -519,6 +519,7 @@ func (s *SplitStore) applyProtectors() error { // - At this point we are ready to begin purging: // - We sort cold objects heaviest first, so as to never delete the consituents of a DAG before the DAG itself (which would leave dangling references) // - We delete in small batches taking a lock; each batch is checked again for marks, from the concurrent transactional mark, so as to never delete anything live +// // - We then end the transaction and compact/gc the hotstore. func (s *SplitStore) compact(curTs *types.TipSet) { log.Info("waiting for active views to complete") diff --git a/blockstore/splitstore/splitstore_test.go b/blockstore/splitstore/splitstore_test.go index bb8db193a..d23a78cf0 100644 --- a/blockstore/splitstore/splitstore_test.go +++ b/blockstore/splitstore/splitstore_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package splitstore import ( diff --git a/blockstore/timed_test.go b/blockstore/timed_test.go index bfd6e8140..931f14507 100644 --- a/blockstore/timed_test.go +++ b/blockstore/timed_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package blockstore import ( diff --git a/blockstore/union.go b/blockstore/union.go index c0ad91262..71e785f1a 100644 --- a/blockstore/union.go +++ b/blockstore/union.go @@ -12,10 +12,9 @@ type unionBlockstore []Blockstore // Union returns an unioned blockstore. // -// * Reads return from the first blockstore that has the value, querying in the -// supplied order. -// * Writes (puts and deletes) are broadcast to all stores. -// +// - Reads return from the first blockstore that has the value, querying in the +// supplied order. +// - Writes (puts and deletes) are broadcast to all stores. func Union(stores ...Blockstore) Blockstore { return unionBlockstore(stores) } diff --git a/blockstore/union_test.go b/blockstore/union_test.go index 46433979a..a3ca117b2 100644 --- a/blockstore/union_test.go +++ b/blockstore/union_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package blockstore import ( diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index dde2df620..639e7c1c5 100644 Binary files a/build/openrpc/full.json.gz and b/build/openrpc/full.json.gz differ diff --git a/build/openrpc/gateway.json.gz b/build/openrpc/gateway.json.gz index 69358abf8..1f4e500da 100644 Binary files a/build/openrpc/gateway.json.gz and b/build/openrpc/gateway.json.gz differ diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index 7db37b5fa..71815de9b 100644 Binary files a/build/openrpc/miner.json.gz and b/build/openrpc/miner.json.gz differ diff --git a/build/openrpc/worker.json.gz b/build/openrpc/worker.json.gz index 3fe04f662..e5c7aa3de 100644 Binary files a/build/openrpc/worker.json.gz and b/build/openrpc/worker.json.gz differ diff --git a/build/openrpc_test.go b/build/openrpc_test.go index a06a44f3d..05119fd5d 100644 --- a/build/openrpc_test.go +++ b/build/openrpc_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package build import ( diff --git a/build/params_testground.go b/build/params_testground.go index 3cadf41ab..9d708781d 100644 --- a/build/params_testground.go +++ b/build/params_testground.go @@ -5,7 +5,6 @@ // // Its purpose is to unlock various degrees of flexibility and parametrization // when writing Testground plans for Lotus. -// package build import ( diff --git a/chain/actors/adt/diff_adt.go b/chain/actors/adt/diff_adt.go index 7f2f35eab..1d1e02ea1 100644 --- a/chain/actors/adt/diff_adt.go +++ b/chain/actors/adt/diff_adt.go @@ -26,7 +26,7 @@ type AdtArrayDiff interface { // - All values that exist in preArr and not in curArr are passed to AdtArrayDiff.Remove() // - All values that exist in curArr nnd not in prevArr are passed to adtArrayDiff.Add() // - All values that exist in preArr and in curArr are passed to AdtArrayDiff.Modify() -// - It is the responsibility of AdtArrayDiff.Modify() to determine if the values it was passed have been modified. +// - It is the responsibility of AdtArrayDiff.Modify() to determine if the values it was passed have been modified. func DiffAdtArray(preArr, curArr Array, out AdtArrayDiff) error { notNew := make(map[int64]struct{}, curArr.Length()) prevVal := new(typegen.Deferred) diff --git a/chain/actors/adt/diff_adt_test.go b/chain/actors/adt/diff_adt_test.go index 41abaeaad..7ea3c53e5 100644 --- a/chain/actors/adt/diff_adt_test.go +++ b/chain/actors/adt/diff_adt_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package adt import ( diff --git a/chain/actors/aerrors/error_test.go b/chain/actors/aerrors/error_test.go index 189b992a8..8c3738c88 100644 --- a/chain/actors/aerrors/error_test.go +++ b/chain/actors/aerrors/error_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package aerrors_test import ( diff --git a/chain/actors/policy/policy_test.go b/chain/actors/policy/policy_test.go index 92a9f6965..726fca95a 100644 --- a/chain/actors/policy/policy_test.go +++ b/chain/actors/policy/policy_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package policy import ( diff --git a/chain/beacon/drand/drand_test.go b/chain/beacon/drand/drand_test.go index e9267f8fc..e2819f4e9 100644 --- a/chain/beacon/drand/drand_test.go +++ b/chain/beacon/drand/drand_test.go @@ -1,5 +1,5 @@ -//stm: ignore -//Only tests external library behavior, therefore it should not be annotated +// stm: ignore +// Only tests external library behavior, therefore it should not be annotated package drand import ( diff --git a/chain/events/events_called.go b/chain/events/events_called.go index d9aa34161..7fc92e6a9 100644 --- a/chain/events/events_called.go +++ b/chain/events/events_called.go @@ -23,7 +23,8 @@ type triggerID = uint64 type msgH = abi.ChainEpoch // triggerH is the block height at which the listener will be notified about the -// message (msgH+confidence) +// +// message (msgH+confidence) type triggerH = abi.ChainEpoch type eventData interface{} @@ -39,7 +40,8 @@ type EventHandler func(ctx context.Context, data eventData, prevTs, ts *types.Ti // // If `done` is true, timeout won't be triggered // If `more` is false, no messages will be sent to EventHandler (RevertHandler -// may still be called) +// +// may still be called) type CheckFunc func(ctx context.Context, ts *types.TipSet) (done bool, more bool, err error) // Keep track of information for an event handler @@ -375,31 +377,31 @@ type StateMatchFunc func(oldTs, newTs *types.TipSet) (bool, StateChange, error) // StateChanged registers a callback which is triggered when a specified state // change occurs or a timeout is reached. // -// * `CheckFunc` callback is invoked immediately with a recent tipset, it -// returns two booleans - `done`, and `more`. +// - `CheckFunc` callback is invoked immediately with a recent tipset, it +// returns two booleans - `done`, and `more`. // -// * `done` should be true when some on-chain state change we are waiting +// - `done` should be true when some on-chain state change we are waiting // for has happened. When `done` is set to true, timeout trigger is disabled. // -// * `more` should be false when we don't want to receive new notifications +// - `more` should be false when we don't want to receive new notifications // through StateChangeHandler. Note that notifications may still be delivered to // RevertHandler // -// * `StateChangeHandler` is called when the specified state change was observed -// on-chain, and a confidence threshold was reached, or the specified `timeout` -// height was reached with no state change observed. When this callback is -// invoked on a timeout, `oldTs` and `states are set to nil. -// This callback returns a boolean specifying whether further notifications -// should be sent, like `more` return param from `CheckFunc` above. +// - `StateChangeHandler` is called when the specified state change was observed +// on-chain, and a confidence threshold was reached, or the specified `timeout` +// height was reached with no state change observed. When this callback is +// invoked on a timeout, `oldTs` and `states are set to nil. +// This callback returns a boolean specifying whether further notifications +// should be sent, like `more` return param from `CheckFunc` above. // -// * `RevertHandler` is called after apply handler, when we drop the tipset -// containing the message. The tipset passed as the argument is the tipset -// that is being dropped. Note that the event dropped may be re-applied -// in a different tipset in small amount of time. +// - `RevertHandler` is called after apply handler, when we drop the tipset +// containing the message. The tipset passed as the argument is the tipset +// that is being dropped. Note that the event dropped may be re-applied +// in a different tipset in small amount of time. // -// * `StateMatchFunc` is called against each tipset state. If there is a match, -// the state change is queued up until the confidence interval has elapsed (and -// `StateChangeHandler` is called) +// - `StateMatchFunc` is called against each tipset state. If there is a match, +// the state change is queued up until the confidence interval has elapsed (and +// `StateChangeHandler` is called) func (we *watcherEvents) StateChanged(check CheckFunc, scHnd StateChangeHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, mf StateMatchFunc) error { hnd := func(ctx context.Context, data eventData, prevTs, ts *types.TipSet, height abi.ChainEpoch) (bool, error) { states, ok := data.(StateChange) @@ -503,33 +505,34 @@ type MsgHandler func(msg *types.Message, rec *types.MessageReceipt, ts *types.Ti type MsgMatchFunc func(msg *types.Message) (matched bool, err error) // Called registers a callback which is triggered when a specified method is -// called on an actor, or a timeout is reached. // -// * `CheckFunc` callback is invoked immediately with a recent tipset, it -// returns two booleans - `done`, and `more`. +// called on an actor, or a timeout is reached. // -// * `done` should be true when some on-chain action we are waiting for has -// happened. When `done` is set to true, timeout trigger is disabled. +// - `CheckFunc` callback is invoked immediately with a recent tipset, it +// returns two booleans - `done`, and `more`. // -// * `more` should be false when we don't want to receive new notifications -// through MsgHandler. Note that notifications may still be delivered to -// RevertHandler +// - `done` should be true when some on-chain action we are waiting for has +// happened. When `done` is set to true, timeout trigger is disabled. // -// * `MsgHandler` is called when the specified event was observed on-chain, -// and a confidence threshold was reached, or the specified `timeout` height -// was reached with no events observed. When this callback is invoked on a -// timeout, `msg` is set to nil. This callback returns a boolean specifying -// whether further notifications should be sent, like `more` return param -// from `CheckFunc` above. +// - `more` should be false when we don't want to receive new notifications +// through MsgHandler. Note that notifications may still be delivered to +// RevertHandler // -// * `RevertHandler` is called after apply handler, when we drop the tipset -// containing the message. The tipset passed as the argument is the tipset -// that is being dropped. Note that the message dropped may be re-applied -// in a different tipset in small amount of time. +// - `MsgHandler` is called when the specified event was observed on-chain, +// and a confidence threshold was reached, or the specified `timeout` height +// was reached with no events observed. When this callback is invoked on a +// timeout, `msg` is set to nil. This callback returns a boolean specifying +// whether further notifications should be sent, like `more` return param +// from `CheckFunc` above. // -// * `MsgMatchFunc` is called against each message. If there is a match, the -// message is queued up until the confidence interval has elapsed (and -// `MsgHandler` is called) +// - `RevertHandler` is called after apply handler, when we drop the tipset +// containing the message. The tipset passed as the argument is the tipset +// that is being dropped. Note that the message dropped may be re-applied +// in a different tipset in small amount of time. +// +// - `MsgMatchFunc` is called against each message. If there is a match, the +// message is queued up until the confidence interval has elapsed (and +// `MsgHandler` is called) func (me *messageEvents) Called(ctx context.Context, check CheckFunc, msgHnd MsgHandler, rev RevertHandler, confidence int, timeout abi.ChainEpoch, mf MsgMatchFunc) error { hnd := func(ctx context.Context, data eventData, prevTs, ts *types.TipSet, height abi.ChainEpoch) (bool, error) { msg, ok := data.(*types.Message) diff --git a/chain/events/events_test.go b/chain/events/events_test.go index 8c07a9eb3..ad2dc8e71 100644 --- a/chain/events/events_test.go +++ b/chain/events/events_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package events import ( diff --git a/chain/events/state/predicates_test.go b/chain/events/state/predicates_test.go index 37f2e478c..52fc2668a 100644 --- a/chain/events/state/predicates_test.go +++ b/chain/events/state/predicates_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package state import ( diff --git a/chain/events/tscache_test.go b/chain/events/tscache_test.go index 74fa8656a..ec312740b 100644 --- a/chain/events/tscache_test.go +++ b/chain/events/tscache_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package events import ( diff --git a/chain/exchange/doc.go b/chain/exchange/doc.go index b20ee0c1f..21abc38c4 100644 --- a/chain/exchange/doc.go +++ b/chain/exchange/doc.go @@ -10,8 +10,8 @@ // 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 +// - 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 diff --git a/chain/exchange/protocol.go b/chain/exchange/protocol.go index 48080173c..5e12d31cc 100644 --- a/chain/exchange/protocol.go +++ b/chain/exchange/protocol.go @@ -21,11 +21,12 @@ const ( ) // FIXME: Bumped from original 800 to this to accommodate `syncFork()` -// use of `GetBlocks()`. It seems the expectation of that API is to -// fetch any amount of blocks leaving it to the internal logic here -// to partition and reassemble the requests if they go above the maximum. -// (Also as a consequence of this temporarily removing the `const` -// qualifier to avoid "const initializer [...] is not a constant" error.) +// +// use of `GetBlocks()`. It seems the expectation of that API is to +// fetch any amount of blocks leaving it to the internal logic here +// to partition and reassemble the requests if they go above the maximum. +// (Also as a consequence of this temporarily removing the `const` +// qualifier to avoid "const initializer [...] is not a constant" error.) var MaxRequestLength = uint64(build.ForkLengthThreshold) const ( @@ -147,11 +148,12 @@ type BSTipSet struct { // `BlsIncludes`/`SecpkIncludes` matches `Bls`/`Secpk` messages // to blocks in the tipsets with the format: // `BlsIncludes[BI][MI]` -// * BI: block index in the tipset. -// * MI: message index in `Bls` list +// - BI: block index in the tipset. +// - MI: message index in `Bls` list // // FIXME: The logic to decompress this structure should belong -// to itself, not to the consumer. +// +// to itself, not to the consumer. type CompactedMessages struct { Bls []*types.Message BlsIncludes [][]uint64 diff --git a/chain/gen/gen_test.go b/chain/gen/gen_test.go index e0637fbd8..d04e55a26 100644 --- a/chain/gen/gen_test.go +++ b/chain/gen/gen_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package gen import ( diff --git a/chain/market/fundmanager_test.go b/chain/market/fundmanager_test.go index 17d36325a..89063ec58 100644 --- a/chain/market/fundmanager_test.go +++ b/chain/market/fundmanager_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package market import ( diff --git a/chain/messagepool/block_proba_test.go b/chain/messagepool/block_proba_test.go index c33691e2b..6d121d222 100644 --- a/chain/messagepool/block_proba_test.go +++ b/chain/messagepool/block_proba_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package messagepool import ( diff --git a/chain/messagepool/check_test.go b/chain/messagepool/check_test.go index ffcac74e5..8458bdb0f 100644 --- a/chain/messagepool/check_test.go +++ b/chain/messagepool/check_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package messagepool import ( diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 3bc2babfd..def161171 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -1056,9 +1056,9 @@ func (mp *MessagePool) getStateBalance(ctx context.Context, addr address.Address // this method is provided for the gateway to push messages. // differences from Push: -// - strict checks are enabled -// - extra strict add checks are used when adding the messages to the msgSet -// that means: no nonce gaps, at most 10 pending messages for the actor +// - strict checks are enabled +// - extra strict add checks are used when adding the messages to the msgSet +// that means: no nonce gaps, at most 10 pending messages for the actor func (mp *MessagePool) PushUntrusted(ctx context.Context, m *types.SignedMessage) (cid.Cid, error) { err := mp.checkMessage(m) if err != nil { diff --git a/chain/messagepool/messagepool_test.go b/chain/messagepool/messagepool_test.go index 015ca69aa..7751f7978 100644 --- a/chain/messagepool/messagepool_test.go +++ b/chain/messagepool/messagepool_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package messagepool import ( diff --git a/chain/messagepool/repub_test.go b/chain/messagepool/repub_test.go index 18a75d881..f6130282c 100644 --- a/chain/messagepool/repub_test.go +++ b/chain/messagepool/repub_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package messagepool import ( diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 7c4e21913..a5b2f3266 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package messagepool import ( diff --git a/chain/messagesigner/messagesigner_test.go b/chain/messagesigner/messagesigner_test.go index dfae237bf..87a5e8615 100644 --- a/chain/messagesigner/messagesigner_test.go +++ b/chain/messagesigner/messagesigner_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package messagesigner import ( diff --git a/chain/rand/rand_test.go b/chain/rand/rand_test.go index e85d15444..acd928854 100644 --- a/chain/rand/rand_test.go +++ b/chain/rand/rand_test.go @@ -1,4 +1,4 @@ -//stm:#unit +// stm:#unit package rand_test import ( diff --git a/chain/state/statetree_test.go b/chain/state/statetree_test.go index 981842255..e15fed489 100644 --- a/chain/state/statetree_test.go +++ b/chain/state/statetree_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package state import ( diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index 57d453730..2d0d8f047 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -30,9 +30,9 @@ var ErrExpensiveFork = errors.New("refusing explicit call due to state fork at e // tipset's parent. In the presence of null blocks, the height at which the message is invoked may // be less than the specified tipset. // -// - If no tipset is specified, the first tipset without an expensive migration is used. -// - If executing a message at a given tipset would trigger an expensive migration, the call will -// fail with ErrExpensiveFork. +// - If no tipset is specified, the first tipset without an expensive migration is used. +// - If executing a message at a given tipset would trigger an expensive migration, the call will +// fail with ErrExpensiveFork. func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) { ctx, span := trace.StartSpan(ctx, "statemanager.Call") defer span.End() diff --git a/chain/stmgr/forks.go b/chain/stmgr/forks.go index 3c9493820..514f78f76 100644 --- a/chain/stmgr/forks.go +++ b/chain/stmgr/forks.go @@ -36,12 +36,12 @@ type MigrationCache interface { // MigrationFunc is a migration function run at every upgrade. // -// - The cache is a per-upgrade cache, pre-populated by pre-migrations. -// - The oldState is the state produced by the upgrade epoch. -// - The returned newState is the new state that will be used by the next epoch. -// - The height is the upgrade epoch height (already executed). -// - The tipset is the first non-null tipset after the upgrade height (the tipset in -// which the upgrade is executed). Do not assume that ts.Height() is the upgrade height. +// - The cache is a per-upgrade cache, pre-populated by pre-migrations. +// - The oldState is the state produced by the upgrade epoch. +// - The returned newState is the new state that will be used by the next epoch. +// - The height is the upgrade epoch height (already executed). +// - The tipset is the first non-null tipset after the upgrade height (the tipset in +// which the upgrade is executed). Do not assume that ts.Height() is the upgrade height. // // NOTE: In StateCompute and CallWithGas, the passed tipset is actually the tipset _before_ the // upgrade. The tipset should really only be used for referencing the "current chain". diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index 56c236d74..7eb63566c 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package stmgr_test import ( diff --git a/chain/stmgr/searchwait_test.go b/chain/stmgr/searchwait_test.go index 73635cdea..b23b22376 100644 --- a/chain/stmgr/searchwait_test.go +++ b/chain/stmgr/searchwait_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package stmgr_test import ( diff --git a/chain/store/checkpoint_test.go b/chain/store/checkpoint_test.go index acf61298d..bc2cb5e73 100644 --- a/chain/store/checkpoint_test.go +++ b/chain/store/checkpoint_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package store_test import ( diff --git a/chain/store/coalescer.go b/chain/store/coalescer.go index a6d066bca..db4cbdadc 100644 --- a/chain/store/coalescer.go +++ b/chain/store/coalescer.go @@ -9,12 +9,17 @@ import ( // WrapHeadChangeCoalescer wraps a ReorgNotifee with a head change coalescer. // minDelay is the minimum coalesce delay; when a head change is first received, the coalescer will -// wait for that long to coalesce more head changes. +// +// wait for that long to coalesce more head changes. +// // maxDelay is the maximum coalesce delay; the coalescer will not delay delivery of a head change -// more than that. +// +// more than that. +// // mergeInterval is the interval that triggers additional coalesce delay; if the last head change was -// within the merge interval when the coalesce timer fires, then the coalesce time is extended -// by min delay and up to max delay total. +// +// within the merge interval when the coalesce timer fires, then the coalesce time is extended +// by min delay and up to max delay total. func WrapHeadChangeCoalescer(fn ReorgNotifee, minDelay, maxDelay, mergeInterval time.Duration) ReorgNotifee { c := NewHeadChangeCoalescer(fn, minDelay, maxDelay, mergeInterval) return c.HeadChange diff --git a/chain/store/coalescer_test.go b/chain/store/coalescer_test.go index 463eb5c79..278e6b181 100644 --- a/chain/store/coalescer_test.go +++ b/chain/store/coalescer_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package store import ( diff --git a/chain/store/index_test.go b/chain/store/index_test.go index 86aa84cb8..63a1abad0 100644 --- a/chain/store/index_test.go +++ b/chain/store/index_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package store_test import ( diff --git a/chain/store/store.go b/chain/store/store.go index ff4a7201c..6313492a7 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -93,8 +93,8 @@ type WeightFunc func(ctx context.Context, stateBs bstore.Blockstore, ts *types.T // store). // // To alleviate disk access, the ChainStore has two ARC caches: -// 1. a tipset cache -// 2. a block => messages references cache. +// 1. a tipset cache +// 2. a block => messages references cache. type ChainStore struct { chainBlockstore bstore.Blockstore stateBlockstore bstore.Blockstore @@ -453,8 +453,9 @@ func (cs *ChainStore) MaybeTakeHeavierTipSet(ctx context.Context, ts *types.TipS // The "fast forward" case is covered in this logic as a valid fork of length 0. // // FIXME: We may want to replace some of the logic in `syncFork()` with this. -// `syncFork()` counts the length on both sides of the fork at the moment (we -// need to settle on that) but here we just enforce it on the `synced` side. +// +// `syncFork()` counts the length on both sides of the fork at the moment (we +// need to settle on that) but here we just enforce it on the `synced` side. func (cs *ChainStore) exceedsForkLength(ctx context.Context, synced, external *types.TipSet) (bool, error) { if synced == nil || external == nil { // FIXME: If `cs.heaviest` is nil we should just bypass the entire diff --git a/chain/store/store_test.go b/chain/store/store_test.go index 95de8401b..af78e3dc0 100644 --- a/chain/store/store_test.go +++ b/chain/store/store_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package store_test import ( diff --git a/chain/sub/incoming.go b/chain/sub/incoming.go index bd073e789..b8427e036 100644 --- a/chain/sub/incoming.go +++ b/chain/sub/incoming.go @@ -159,9 +159,12 @@ func FetchSignedMessagesByCids( } // Fetch `cids` from the block service, apply `cb` on each of them. Used -// by the fetch message functions above. +// +// by the fetch message functions above. +// // We check that each block is received only once and we do not received -// blocks we did not request. +// +// blocks we did not request. func fetchCids( ctx context.Context, bserv bserv.BlockGetter, diff --git a/chain/sub/incoming_test.go b/chain/sub/incoming_test.go index fbe73d460..8566391b9 100644 --- a/chain/sub/incoming_test.go +++ b/chain/sub/incoming_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package sub import ( diff --git a/chain/sync.go b/chain/sync.go index 41775705e..634313855 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -60,16 +60,16 @@ var ( // Syncer is in charge of running the chain synchronization logic. As such, it // is tasked with these functions, amongst others: // -// * Fast-forwards the chain as it learns of new TipSets from the network via -// the SyncManager. -// * Applies the fork choice rule to select the correct side when confronted -// with a fork in the network. -// * Requests block headers and messages from other peers when not available -// in our BlockStore. -// * Tracks blocks marked as bad in a cache. -// * Keeps the BlockStore and ChainStore consistent with our view of the world, -// the latter of which in turn informs other components when a reorg has been -// committed. +// - Fast-forwards the chain as it learns of new TipSets from the network via +// the SyncManager. +// - Applies the fork choice rule to select the correct side when confronted +// with a fork in the network. +// - Requests block headers and messages from other peers when not available +// in our BlockStore. +// - Tracks blocks marked as bad in a cache. +// - Keeps the BlockStore and ChainStore consistent with our view of the world, +// the latter of which in turn informs other components when a reorg has been +// committed. // // The Syncer does not run workers itself. It's mainly concerned with // ensuring a consistent state of chain consensus. The reactive and network- @@ -671,9 +671,9 @@ func extractSyncState(ctx context.Context) *SyncerState { // 2. Check the consistency of beacon entries in the from tipset. We check // 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 client in batches, requesting up to a -// maximum of 500 tipsets every time. +// 3a. Load it from the chainstore; if found, it move on to its parent. +// 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 // anchor tipset should be, we are facing a fork, and we invoke Syncer#syncFork @@ -1171,7 +1171,7 @@ func persistMessages(ctx context.Context, bs bstore.Blockstore, bst *exchange.Co // else we must drop part of our chain to connect to the peer's head // (referred to as "forking"). // -// 2. StagePersistHeaders: now that we've collected the missing headers, +// 2. StagePersistHeaders: now that we've collected the missing headers, // augmented by those on the other side of a fork, we persist them to the // BlockStore. // diff --git a/chain/sync_manager_test.go b/chain/sync_manager_test.go index b3069c3fb..737845ae2 100644 --- a/chain/sync_manager_test.go +++ b/chain/sync_manager_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package chain import ( diff --git a/chain/sync_test.go b/chain/sync_test.go index ee1fd91ec..b1be0b590 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package chain_test import ( diff --git a/chain/types/bigint_test.go b/chain/types/bigint_test.go index 595bb8e0b..348724953 100644 --- a/chain/types/bigint_test.go +++ b/chain/types/bigint_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package types import ( diff --git a/chain/types/blockheader_test.go b/chain/types/blockheader_test.go index 248016b28..b7af86d3c 100644 --- a/chain/types/blockheader_test.go +++ b/chain/types/blockheader_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package types import ( diff --git a/chain/types/electionproof_test.go b/chain/types/electionproof_test.go index 1eba21138..3a06460fe 100644 --- a/chain/types/electionproof_test.go +++ b/chain/types/electionproof_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package types import ( diff --git a/chain/types/fil_test.go b/chain/types/fil_test.go index 5cbe22904..85054ed98 100644 --- a/chain/types/fil_test.go +++ b/chain/types/fil_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package types import ( diff --git a/chain/types/message_test.go b/chain/types/message_test.go index 637288374..abb9c946e 100644 --- a/chain/types/message_test.go +++ b/chain/types/message_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package types import ( diff --git a/chain/types/signature_test.go b/chain/types/signature_test.go index 85b27fea9..abc7a369b 100644 --- a/chain/types/signature_test.go +++ b/chain/types/signature_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package types import ( diff --git a/chain/types/tipset.go b/chain/types/tipset.go index 9c2fc4d79..cb981e0f0 100644 --- a/chain/types/tipset.go +++ b/chain/types/tipset.go @@ -99,11 +99,11 @@ func tipsetSortFunc(blks []*BlockHeader) func(i, j int) bool { } // Checks: -// * A tipset is composed of at least one block. (Because of our variable -// number of blocks per tipset, determined by randomness, we do not impose -// an upper limit.) -// * All blocks have the same height. -// * All blocks have the same parents (same number of them and matching CIDs). +// - A tipset is composed of at least one block. (Because of our variable +// number of blocks per tipset, determined by randomness, we do not impose +// an upper limit.) +// - All blocks have the same height. +// - All blocks have the same parents (same number of them and matching CIDs). func NewTipSet(blks []*BlockHeader) (*TipSet, error) { if len(blks) == 0 { return nil, xerrors.Errorf("NewTipSet called with zero length array of blocks") diff --git a/chain/types/tipset_key_test.go b/chain/types/tipset_key_test.go index d809b7cb6..5fbecb3ea 100644 --- a/chain/types/tipset_key_test.go +++ b/chain/types/tipset_key_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package types import ( diff --git a/chain/types/types_test.go b/chain/types/types_test.go index 1083cdc38..4e08a0d88 100644 --- a/chain/types/types_test.go +++ b/chain/types/types_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package types import ( diff --git a/chain/types_test.go b/chain/types_test.go index 53210e180..0fb399214 100644 --- a/chain/types_test.go +++ b/chain/types_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package chain import ( diff --git a/chain/vectors/vectors_test.go b/chain/vectors/vectors_test.go index 248950787..8e73ec012 100644 --- a/chain/vectors/vectors_test.go +++ b/chain/vectors/vectors_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package vectors import ( diff --git a/chain/vm/burn_test.go b/chain/vm/burn_test.go index a9042ca14..46bc7f5de 100644 --- a/chain/vm/burn_test.go +++ b/chain/vm/burn_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package vm import ( diff --git a/chain/vm/gas_v0_test.go b/chain/vm/gas_v0_test.go index 0e657cb2c..bd527a779 100644 --- a/chain/vm/gas_v0_test.go +++ b/chain/vm/gas_v0_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package vm import ( diff --git a/chain/vm/invoker_test.go b/chain/vm/invoker_test.go index 8357da8af..5a4e1b402 100644 --- a/chain/vm/invoker_test.go +++ b/chain/vm/invoker_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package vm import ( diff --git a/chain/vm/runtime_test.go b/chain/vm/runtime_test.go index 0c75cb1dd..88b7366de 100644 --- a/chain/vm/runtime_test.go +++ b/chain/vm/runtime_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package vm import ( diff --git a/chain/wallet/multi_test.go b/chain/wallet/multi_test.go index d6fdf6656..5256ebde9 100644 --- a/chain/wallet/multi_test.go +++ b/chain/wallet/multi_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package wallet import ( diff --git a/chain/wallet/wallet_test.go b/chain/wallet/wallet_test.go index d9dac3356..8937c5eb8 100644 --- a/chain/wallet/wallet_test.go +++ b/chain/wallet/wallet_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package wallet import ( diff --git a/cli/chain_test.go b/cli/chain_test.go index dfef27b11..9fd46724e 100644 --- a/cli/chain_test.go +++ b/cli/chain_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package cli import ( diff --git a/cli/cmd.go b/cli/cmd.go index 71524d787..79023917b 100644 --- a/cli/cmd.go +++ b/cli/cmd.go @@ -69,6 +69,7 @@ var CommonCommands = []*cli.Command{ var Commands = []*cli.Command{ WithCategory("basic", sendCmd), WithCategory("basic", walletCmd), + WithCategory("basic", infoCmd), WithCategory("basic", clientCmd), WithCategory("basic", multisigCmd), WithCategory("basic", filplusCmd), diff --git a/cli/info.go b/cli/info.go new file mode 100644 index 000000000..0d036875a --- /dev/null +++ b/cli/info.go @@ -0,0 +1,230 @@ +package cli + +import ( + "context" + "fmt" + "math" + "os" + "sort" + "strings" + "text/tabwriter" + "time" + + "github.com/dustin/go-humanize" + "github.com/fatih/color" + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/go-state-types/big" + + "github.com/filecoin-project/lotus/api/v1api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" +) + +var infoCmd = &cli.Command{ + Name: "info", + Usage: "Print node info", + Action: infoCmdAct, +} + +func infoCmdAct(cctx *cli.Context) error { + fullapi, acloser, err := GetFullNodeAPIV1(cctx) + if err != nil { + return err + } + defer acloser() + ctx := ReqContext(cctx) + + network, err := fullapi.StateGetNetworkParams(ctx) + if err != nil { + return err + } + + fmt.Printf("Network: %s\n", network.NetworkName) + fmt.Print("Chain: ") + err = SyncBasefeeCheck(ctx, fullapi) + if err != nil { + return err + } + + status, err := fullapi.NodeStatus(ctx, true) + if err != nil { + return err + } + + fmt.Printf(" [epoch %s]\n", color.MagentaString(("%d"), status.SyncStatus.Epoch)) + fmt.Printf("Peers to: [publish messages %d] [publish blocks %d]\n", status.PeerStatus.PeersToPublishMsgs, status.PeerStatus.PeersToPublishBlocks) + + //Chain health calculated as percentage: amount of blocks in last finality / very healthy amount of blocks in a finality (900 epochs * 5 blocks per tipset) + health := (100 * (900 * status.ChainStatus.BlocksPerTipsetLastFinality) / (900 * 5)) + switch { + case health > 85: + fmt.Printf("Chain health: %.f%% [%s]\n", health, color.GreenString("healthy")) + case health < 85: + fmt.Printf("Chain health: %.f%% [%s]\n", health, color.RedString("unhealthy")) + } + + fmt.Println() + + addr, err := fullapi.WalletDefaultAddress(ctx) + if err == nil { + fmt.Printf("Default address: \n") + balance, err := fullapi.WalletBalance(ctx, addr) + if err != nil { + return err + } + fmt.Printf(" %s [%s]\n", addr.String(), types.FIL(balance).Short()) + } else { + fmt.Printf("Default address: address not set\n") + } + fmt.Println() + + addrs, err := fullapi.WalletList(ctx) + if err != nil { + return err + } + + totalBalance := big.Zero() + for _, addr := range addrs { + totbal, err := fullapi.WalletBalance(ctx, addr) + if err != nil { + return err + } + totalBalance = big.Add(totalBalance, totbal) + } + + switch { + case len(addrs) <= 1: + fmt.Printf("Wallet: %v address\n", len(addrs)) + case len(addrs) > 1: + fmt.Printf("Wallet: %v addresses\n", len(addrs)) + } + fmt.Printf(" Total balance: %s\n", types.FIL(totalBalance).Short()) + + mbLockedSum := big.Zero() + mbAvailableSum := big.Zero() + for _, addr := range addrs { + mbal, err := fullapi.StateMarketBalance(ctx, addr, types.EmptyTSK) + if err != nil { + if strings.Contains(err.Error(), "actor not found") { + continue + } else { + return err + } + } + mbLockedSum = big.Add(mbLockedSum, mbal.Locked) + mbAvailableSum = big.Add(mbAvailableSum, mbal.Escrow) + } + + fmt.Printf(" Market locked: %s\n", types.FIL(mbLockedSum).Short()) + fmt.Printf(" Market available: %s\n", types.FIL(mbAvailableSum).Short()) + + fmt.Println() + + chs, err := fullapi.PaychList(ctx) + if err != nil { + return err + } + + switch { + case len(chs) <= 1: + fmt.Printf("Payment Channels: %v channel\n", len(chs)) + case len(chs) > 1: + fmt.Printf("Payment Channels: %v channels\n", len(chs)) + } + fmt.Println() + + localDeals, err := fullapi.ClientListDeals(ctx) + if err != nil { + return err + } + + var totalSize uint64 + byState := map[storagemarket.StorageDealStatus][]uint64{} + for _, deal := range localDeals { + totalSize += deal.Size + byState[deal.State] = append(byState[deal.State], deal.Size) + } + + fmt.Printf("Deals: %d, %s\n", len(localDeals), types.SizeStr(types.NewInt(totalSize))) + + type stateStat struct { + state storagemarket.StorageDealStatus + count int + bytes uint64 + } + + stateStats := make([]stateStat, 0, len(byState)) + for state, deals := range byState { + if state == storagemarket.StorageDealActive { + state = math.MaxUint64 // for sort + } + + st := stateStat{ + state: state, + count: len(deals), + } + for _, b := range deals { + st.bytes += b + } + + stateStats = append(stateStats, st) + } + + sort.Slice(stateStats, func(i, j int) bool { + return int64(stateStats[i].state) < int64(stateStats[j].state) + }) + + for _, st := range stateStats { + if st.state == math.MaxUint64 { + st.state = storagemarket.StorageDealActive + } + fmt.Printf(" %s: %d deals, %s\n", storagemarket.DealStates[st.state], st.count, types.SizeStr(types.NewInt(st.bytes))) + } + + fmt.Println() + + tw := tabwriter.NewWriter(os.Stdout, 6, 6, 2, ' ', 0) + + s, err := fullapi.NetBandwidthStats(ctx) + if err != nil { + return err + } + + fmt.Printf("Bandwidth:\n") + fmt.Fprintf(tw, "\tTotalIn\tTotalOut\tRateIn\tRateOut\n") + fmt.Fprintf(tw, "\t%s\t%s\t%s/s\t%s/s\n", humanize.Bytes(uint64(s.TotalIn)), humanize.Bytes(uint64(s.TotalOut)), humanize.Bytes(uint64(s.RateIn)), humanize.Bytes(uint64(s.RateOut))) + return tw.Flush() + +} + +func SyncBasefeeCheck(ctx context.Context, fullapi v1api.FullNode) error { + head, err := fullapi.ChainHead(ctx) + if err != nil { + return err + } + + switch { + case time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs*3/2): // within 1.5 epochs + fmt.Printf("[%s]", color.GreenString("sync ok")) + case time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs*5): // within 5 epochs + fmt.Printf("[%s]", color.YellowString("sync slow (%s behind)", time.Now().Sub(time.Unix(int64(head.MinTimestamp()), 0)).Truncate(time.Second))) + default: + fmt.Printf("[%s]", color.RedString("sync behind! (%s behind)", time.Now().Sub(time.Unix(int64(head.MinTimestamp()), 0)).Truncate(time.Second))) + } + basefee := head.MinTicketBlock().ParentBaseFee + gasCol := []color.Attribute{color.FgBlue} + switch { + case basefee.GreaterThan(big.NewInt(7000_000_000)): // 7 nFIL + gasCol = []color.Attribute{color.BgRed, color.FgBlack} + case basefee.GreaterThan(big.NewInt(3000_000_000)): // 3 nFIL + gasCol = []color.Attribute{color.FgRed} + case basefee.GreaterThan(big.NewInt(750_000_000)): // 750 uFIL + gasCol = []color.Attribute{color.FgYellow} + case basefee.GreaterThan(big.NewInt(100_000_000)): // 100 uFIL + gasCol = []color.Attribute{color.FgGreen} + } + fmt.Printf(" [basefee %s]", color.New(gasCol...).Sprint(types.FIL(basefee).Short())) + return nil +} diff --git a/cli/mpool_test.go b/cli/mpool_test.go index 1533ef9e2..01b49d4b3 100644 --- a/cli/mpool_test.go +++ b/cli/mpool_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package cli import ( diff --git a/cli/send.go b/cli/send.go index a5200d3b8..b5bfd3eb0 100644 --- a/cli/send.go +++ b/cli/send.go @@ -3,6 +3,7 @@ package cli import ( "encoding/hex" "fmt" + "strings" "github.com/urfave/cli/v2" "golang.org/x/xerrors" @@ -152,6 +153,9 @@ var sendCmd = &cli.Command{ sm, err := InteractiveSend(ctx, cctx, srv, proto) if err != nil { + if strings.Contains(err.Error(), "no current EF") { + return xerrors.Errorf("transaction rejected on ledger: %w", err) + } return err } diff --git a/cli/send_test.go b/cli/send_test.go index 3ee6ad992..ec858774c 100644 --- a/cli/send_test.go +++ b/cli/send_test.go @@ -1,5 +1,5 @@ -//stm: ignore -//stm: #unit +// stm: ignore +// stm: #unit package cli import ( diff --git a/cli/services_send_test.go b/cli/services_send_test.go index fe9bb0e89..a524abe8c 100644 --- a/cli/services_send_test.go +++ b/cli/services_send_test.go @@ -1,5 +1,5 @@ -//stm: ignore -//stm: #unit +// stm: ignore +// stm: #unit package cli import ( diff --git a/cli/sync_test.go b/cli/sync_test.go index 345338f75..456d165f2 100644 --- a/cli/sync_test.go +++ b/cli/sync_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package cli import ( diff --git a/cli/wallet_test.go b/cli/wallet_test.go index 01aa0dd7c..dee26018b 100644 --- a/cli/wallet_test.go +++ b/cli/wallet_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package cli import ( diff --git a/cmd/lotus-bench/stats_test.go b/cmd/lotus-bench/stats_test.go index ff2e3dce8..0ccadb4d4 100644 --- a/cmd/lotus-bench/stats_test.go +++ b/cmd/lotus-bench/stats_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package main import ( diff --git a/cmd/lotus-fountain/rate_limiter_test.go b/cmd/lotus-fountain/rate_limiter_test.go index eefb07c8a..b7af23ebd 100644 --- a/cmd/lotus-fountain/rate_limiter_test.go +++ b/cmd/lotus-fountain/rate_limiter_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package main import ( diff --git a/cmd/lotus-health/main_test.go b/cmd/lotus-health/main_test.go index 40ca9d409..f0107380f 100644 --- a/cmd/lotus-health/main_test.go +++ b/cmd/lotus-health/main_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package main import ( diff --git a/cmd/lotus-miner/actor.go b/cmd/lotus-miner/actor.go index ba7c944d7..b3e7df4dc 100644 --- a/cmd/lotus-miner/actor.go +++ b/cmd/lotus-miner/actor.go @@ -55,6 +55,10 @@ var actorSetAddrsCmd = &cli.Command{ Aliases: []string{"set-addrs"}, Usage: "set addresses that your miner can be publicly dialed on", Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "from", + Usage: "optionally specify the account to send the message from", + }, &cli.Int64Flag{ Name: "gas-limit", Usage: "set gas limit", @@ -117,6 +121,25 @@ var actorSetAddrsCmd = &cli.Command{ return err } + fromAddr := minfo.Worker + if from := cctx.String("from"); from != "" { + addr, err := address.NewFromString(from) + if err != nil { + return err + } + + fromAddr = addr + } + + fromId, err := api.StateLookupID(ctx, fromAddr, types.EmptyTSK) + if err != nil { + return err + } + + if !isController(minfo, fromId) { + return xerrors.Errorf("sender isn't a controller of miner: %s", fromId) + } + params, err := actors.SerializeParams(&miner.ChangeMultiaddrsParams{NewMultiaddrs: addrs}) if err != nil { return err @@ -126,7 +149,7 @@ var actorSetAddrsCmd = &cli.Command{ smsg, err := api.MpoolPushMessage(ctx, &types.Message{ To: maddr, - From: minfo.Worker, + From: fromId, Value: types.NewInt(0), GasLimit: gasLimit, Method: builtin.MethodsMiner.ChangeMultiaddrs, diff --git a/cmd/lotus-miner/actor_test.go b/cmd/lotus-miner/actor_test.go index 2a6700e73..791298ffa 100644 --- a/cmd/lotus-miner/actor_test.go +++ b/cmd/lotus-miner/actor_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package main import ( diff --git a/cmd/lotus-miner/allinfo_test.go b/cmd/lotus-miner/allinfo_test.go index 6d439869a..144bdff70 100644 --- a/cmd/lotus-miner/allinfo_test.go +++ b/cmd/lotus-miner/allinfo_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package main import ( diff --git a/cmd/lotus-miner/info.go b/cmd/lotus-miner/info.go index 398d030a5..408482a89 100644 --- a/cmd/lotus-miner/info.go +++ b/cmd/lotus-miner/info.go @@ -25,7 +25,7 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/api/v0api" + "github.com/filecoin-project/lotus/api/v1api" "github.com/filecoin-project/lotus/blockstore" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/adt" @@ -70,7 +70,7 @@ func infoCmdAct(cctx *cli.Context) error { } defer closer() - fullapi, acloser, err := lcli.GetFullNodeAPI(cctx) + fullapi, acloser, err := lcli.GetFullNodeAPIV1(cctx) if err != nil { return err } @@ -94,34 +94,11 @@ func infoCmdAct(cctx *cli.Context) error { fmt.Print("Chain: ") - head, err := fullapi.ChainHead(ctx) + err = lcli.SyncBasefeeCheck(ctx, fullapi) if err != nil { return err } - switch { - case time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs*3/2): // within 1.5 epochs - fmt.Printf("[%s]", color.GreenString("sync ok")) - case time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs*5): // within 5 epochs - fmt.Printf("[%s]", color.YellowString("sync slow (%s behind)", time.Now().Sub(time.Unix(int64(head.MinTimestamp()), 0)).Truncate(time.Second))) - default: - fmt.Printf("[%s]", color.RedString("sync behind! (%s behind)", time.Now().Sub(time.Unix(int64(head.MinTimestamp()), 0)).Truncate(time.Second))) - } - - basefee := head.MinTicketBlock().ParentBaseFee - gasCol := []color.Attribute{color.FgBlue} - switch { - case basefee.GreaterThan(big.NewInt(7000_000_000)): // 7 nFIL - gasCol = []color.Attribute{color.BgRed, color.FgBlack} - case basefee.GreaterThan(big.NewInt(3000_000_000)): // 3 nFIL - gasCol = []color.Attribute{color.FgRed} - case basefee.GreaterThan(big.NewInt(750_000_000)): // 750 uFIL - gasCol = []color.Attribute{color.FgYellow} - case basefee.GreaterThan(big.NewInt(100_000_000)): // 100 uFIL - gasCol = []color.Attribute{color.FgGreen} - } - fmt.Printf(" [basefee %s]", color.New(gasCol...).Sprint(types.FIL(basefee).Short())) - fmt.Println() alerts, err := minerApi.LogAlerts(ctx) @@ -152,7 +129,7 @@ func infoCmdAct(cctx *cli.Context) error { return nil } -func handleMiningInfo(ctx context.Context, cctx *cli.Context, fullapi v0api.FullNode, nodeApi api.StorageMiner) error { +func handleMiningInfo(ctx context.Context, cctx *cli.Context, fullapi v1api.FullNode, nodeApi api.StorageMiner) error { maddr, err := getActorAddress(ctx, cctx) if err != nil { return err @@ -615,7 +592,7 @@ func colorTokenAmount(format string, amount abi.TokenAmount) { } } -func producedBlocks(ctx context.Context, count int, maddr address.Address, napi v0api.FullNode) error { +func producedBlocks(ctx context.Context, count int, maddr address.Address, napi v1api.FullNode) error { var err error head, err := napi.ChainHead(ctx) if err != nil { diff --git a/cmd/lotus-miner/proving.go b/cmd/lotus-miner/proving.go index 5ff49c25f..85bc48e78 100644 --- a/cmd/lotus-miner/proving.go +++ b/cmd/lotus-miner/proving.go @@ -7,10 +7,12 @@ import ( "os" "strconv" "strings" + "sync" "text/tabwriter" "time" "github.com/fatih/color" + "github.com/ipfs/go-cid" "github.com/urfave/cli/v2" "golang.org/x/xerrors" @@ -19,6 +21,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/blockstore" + "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" @@ -37,6 +40,7 @@ var provingCmd = &cli.Command{ provingCheckProvableCmd, workersCmd(false), provingComputeCmd, + provingRecoverFaultsCmd, }, } @@ -644,3 +648,82 @@ It will not send any messages to the chain.`, return nil }, } + +var provingRecoverFaultsCmd = &cli.Command{ + Name: "recover-faults", + Usage: "Manually recovers faulty sectors on chain", + ArgsUsage: "", + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "confidence", + Usage: "number of block confirmations to wait for", + Value: int(build.MessageConfidence), + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() < 1 { + return xerrors.Errorf("must pass at least 1 sector number") + } + + arglist := cctx.Args().Slice() + var sectors []abi.SectorNumber + for _, v := range arglist { + s, err := strconv.ParseUint(v, 10, 64) + if err != nil { + return xerrors.Errorf("failed to convert sectors, please check the arguments: %w", err) + } + sectors = append(sectors, abi.SectorNumber(s)) + } + + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + msgs, err := nodeApi.RecoverFault(ctx, sectors) + if err != nil { + return err + } + + // wait for msgs to get mined into a block + var wg sync.WaitGroup + wg.Add(len(msgs)) + results := make(chan error, len(msgs)) + for _, msg := range msgs { + go func(m cid.Cid) { + defer wg.Done() + wait, err := api.StateWaitMsg(ctx, m, uint64(cctx.Int("confidence"))) + if err != nil { + results <- xerrors.Errorf("Timeout waiting for message to land on chain %s", wait.Message) + return + } + + if wait.Receipt.ExitCode != 0 { + results <- xerrors.Errorf("Failed to execute message %s: %w", wait.Message, wait.Receipt.ExitCode.Error()) + return + } + results <- nil + return + }(msg) + } + + wg.Wait() + close(results) + + for v := range results { + if v != nil { + fmt.Println("Failed to execute the message %w", v) + } + } + return nil + }, +} diff --git a/cmd/lotus-sim/simulation/stages/commit_queue_test.go b/cmd/lotus-sim/simulation/stages/commit_queue_test.go index 1b7f79978..df0de9757 100644 --- a/cmd/lotus-sim/simulation/stages/commit_queue_test.go +++ b/cmd/lotus-sim/simulation/stages/commit_queue_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package stages import ( diff --git a/cmd/lotus-sim/simulation/stages/funding_stage.go b/cmd/lotus-sim/simulation/stages/funding_stage.go index faec6a504..f75a9910d 100644 --- a/cmd/lotus-sim/simulation/stages/funding_stage.go +++ b/cmd/lotus-sim/simulation/stages/funding_stage.go @@ -55,10 +55,10 @@ func (fs *FundingStage) Fund(bb *blockbuilder.BlockBuilder, target address.Addre // sendAndFund "packs" the given message, funding the actor if necessary. It: // -// 1. Tries to send the given message. -// 2. If that fails, it checks to see if the exit code was ErrInsufficientFunds. -// 3. If so, it sends 1K FIL from the "burnt funds actor" (because we need to send it from -// somewhere) and re-tries the message.0 +// 1. Tries to send the given message. +// 2. If that fails, it checks to see if the exit code was ErrInsufficientFunds. +// 3. If so, it sends 1K FIL from the "burnt funds actor" (because we need to send it from +// somewhere) and re-tries the message.0 func (fs *FundingStage) SendAndFund(bb *blockbuilder.BlockBuilder, msg *types.Message) (res *types.MessageReceipt, err error) { for i := 0; i < 10; i++ { res, err = bb.PushMessage(msg) diff --git a/cmd/lotus-sim/simulation/step.go b/cmd/lotus-sim/simulation/step.go index f9d58529e..5226c89b4 100644 --- a/cmd/lotus-sim/simulation/step.go +++ b/cmd/lotus-sim/simulation/step.go @@ -28,10 +28,10 @@ func (sim *Simulation) Step(ctx context.Context) (*types.TipSet, error) { // popNextMessages generates/picks a set of messages to be included in the next block. // -// - This function is destructive and should only be called once per epoch. -// - This function does not store anything in the repo. -// - This function handles all gas estimation. The returned messages should all fit in a single -// block. +// - This function is destructive and should only be called once per epoch. +// - This function does not store anything in the repo. +// - This function handles all gas estimation. The returned messages should all fit in a single +// block. func (sim *Simulation) popNextMessages(ctx context.Context) ([]*types.Message, error) { parentTs := sim.head diff --git a/cmd/tvx/codenames_test.go b/cmd/tvx/codenames_test.go index 9fd6870cb..46d8466ec 100644 --- a/cmd/tvx/codenames_test.go +++ b/cmd/tvx/codenames_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package main import ( diff --git a/conformance/chaos/actor.go b/conformance/chaos/actor.go index 7b28a058d..3a8b2b50a 100644 --- a/conformance/chaos/actor.go +++ b/conformance/chaos/actor.go @@ -146,10 +146,10 @@ type CallerValidationArgs struct { // CallerValidation violates VM call validation constraints. // -// CallerValidationBranchNone performs no validation. -// CallerValidationBranchTwice validates twice. -// CallerValidationBranchIsAddress validates caller against CallerValidationArgs.Addrs. -// CallerValidationBranchIsType validates caller against CallerValidationArgs.Types. +// CallerValidationBranchNone performs no validation. +// CallerValidationBranchTwice validates twice. +// CallerValidationBranchIsAddress validates caller against CallerValidationArgs.Addrs. +// CallerValidationBranchIsType validates caller against CallerValidationArgs.Types. func (a Actor) CallerValidation(rt runtime2.Runtime, args *CallerValidationArgs) *abi.EmptyValue { switch args.Branch { case CallerValidationBranchNone: diff --git a/conformance/chaos/actor_test.go b/conformance/chaos/actor_test.go index 0764463fc..fd45504d2 100644 --- a/conformance/chaos/actor_test.go +++ b/conformance/chaos/actor_test.go @@ -1,4 +1,4 @@ -//stm: #chaos +// stm: #chaos package chaos import ( diff --git a/conformance/corpus_test.go b/conformance/corpus_test.go index 55c1cf08e..adbebbcc7 100644 --- a/conformance/corpus_test.go +++ b/conformance/corpus_test.go @@ -1,4 +1,4 @@ -//stm: ignore +// stm: ignore // This file does not test any behaviors by itself; rather, it runs other test files // Therefore, this file should not be annotated. package conformance diff --git a/conformance/driver.go b/conformance/driver.go index 342d9e9a3..0bb51800e 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -276,7 +276,8 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP // messages that originate from secp256k senders, leaving all // others untouched. // TODO: generate a signature in the DSL so that it's encoded in -// the test vector. +// +// the test vector. func toChainMsg(msg *types.Message) (ret types.ChainMsg) { ret = msg if msg.From.Protocol() == address.SECP256K1 { diff --git a/documentation/en/api-v0-methods-miner.md b/documentation/en/api-v0-methods-miner.md index 379fa22dd..e5147340d 100644 --- a/documentation/en/api-v0-methods-miner.md +++ b/documentation/en/api-v0-methods-miner.md @@ -106,6 +106,8 @@ * [PiecesListPieces](#PiecesListPieces) * [Pledge](#Pledge) * [PledgeSector](#PledgeSector) +* [Recover](#Recover) + * [RecoverFault](#RecoverFault) * [Return](#Return) * [ReturnAddPiece](#ReturnAddPiece) * [ReturnDataCid](#ReturnDataCid) @@ -2265,6 +2267,36 @@ Response: } ``` +## Recover + + +### RecoverFault +RecoverFault can be used to declare recoveries manually. It sends messages +to the miner actor with details of recovered sectors and returns the CID of messages. It honors the +maxPartitionsPerRecoveryMessage from the config + + +Perms: admin + +Inputs: +```json +[ + [ + 123, + 124 + ] +] +``` + +Response: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + ## Return @@ -4397,26 +4429,26 @@ Response: }, "seal/v0/datacid": { "0": { - "MinMemory": 2048, - "MaxMemory": 2048, + "MinMemory": 4294967296, + "MaxMemory": 4294967296, "GPUUtilization": 0, "MaxParallelism": 1, "MaxParallelismGPU": 0, - "BaseMinMemory": 2048, + "BaseMinMemory": 1073741824, "MaxConcurrent": 0 }, "1": { - "MinMemory": 8388608, - "MaxMemory": 8388608, + "MinMemory": 4294967296, + "MaxMemory": 4294967296, "GPUUtilization": 0, "MaxParallelism": 1, "MaxParallelismGPU": 0, - "BaseMinMemory": 8388608, + "BaseMinMemory": 1073741824, "MaxConcurrent": 0 }, "2": { - "MinMemory": 1073741824, - "MaxMemory": 1073741824, + "MinMemory": 4294967296, + "MaxMemory": 4294967296, "GPUUtilization": 0, "MaxParallelism": 1, "MaxParallelismGPU": 0, @@ -4433,8 +4465,8 @@ Response: "MaxConcurrent": 0 }, "4": { - "MinMemory": 8589934592, - "MaxMemory": 8589934592, + "MinMemory": 4294967296, + "MaxMemory": 4294967296, "GPUUtilization": 0, "MaxParallelism": 1, "MaxParallelismGPU": 0, @@ -4442,26 +4474,26 @@ Response: "MaxConcurrent": 0 }, "5": { - "MinMemory": 2048, - "MaxMemory": 2048, + "MinMemory": 4294967296, + "MaxMemory": 4294967296, "GPUUtilization": 0, "MaxParallelism": 1, "MaxParallelismGPU": 0, - "BaseMinMemory": 2048, + "BaseMinMemory": 1073741824, "MaxConcurrent": 0 }, "6": { - "MinMemory": 8388608, - "MaxMemory": 8388608, + "MinMemory": 4294967296, + "MaxMemory": 4294967296, "GPUUtilization": 0, "MaxParallelism": 1, "MaxParallelismGPU": 0, - "BaseMinMemory": 8388608, + "BaseMinMemory": 1073741824, "MaxConcurrent": 0 }, "7": { - "MinMemory": 1073741824, - "MaxMemory": 1073741824, + "MinMemory": 4294967296, + "MaxMemory": 4294967296, "GPUUtilization": 0, "MaxParallelism": 1, "MaxParallelismGPU": 0, @@ -4478,8 +4510,8 @@ Response: "MaxConcurrent": 0 }, "9": { - "MinMemory": 8589934592, - "MaxMemory": 8589934592, + "MinMemory": 4294967296, + "MaxMemory": 4294967296, "GPUUtilization": 0, "MaxParallelism": 1, "MaxParallelismGPU": 0, diff --git a/documentation/en/api-v0-methods-worker.md b/documentation/en/api-v0-methods-worker.md index 0889a9b3c..554f8666d 100644 --- a/documentation/en/api-v0-methods-worker.md +++ b/documentation/en/api-v0-methods-worker.md @@ -579,26 +579,26 @@ Response: }, "seal/v0/datacid": { "0": { - "MinMemory": 2048, - "MaxMemory": 2048, + "MinMemory": 4294967296, + "MaxMemory": 4294967296, "GPUUtilization": 0, "MaxParallelism": 1, "MaxParallelismGPU": 0, - "BaseMinMemory": 2048, + "BaseMinMemory": 1073741824, "MaxConcurrent": 0 }, "1": { - "MinMemory": 8388608, - "MaxMemory": 8388608, + "MinMemory": 4294967296, + "MaxMemory": 4294967296, "GPUUtilization": 0, "MaxParallelism": 1, "MaxParallelismGPU": 0, - "BaseMinMemory": 8388608, + "BaseMinMemory": 1073741824, "MaxConcurrent": 0 }, "2": { - "MinMemory": 1073741824, - "MaxMemory": 1073741824, + "MinMemory": 4294967296, + "MaxMemory": 4294967296, "GPUUtilization": 0, "MaxParallelism": 1, "MaxParallelismGPU": 0, @@ -615,8 +615,8 @@ Response: "MaxConcurrent": 0 }, "4": { - "MinMemory": 8589934592, - "MaxMemory": 8589934592, + "MinMemory": 4294967296, + "MaxMemory": 4294967296, "GPUUtilization": 0, "MaxParallelism": 1, "MaxParallelismGPU": 0, @@ -624,26 +624,26 @@ Response: "MaxConcurrent": 0 }, "5": { - "MinMemory": 2048, - "MaxMemory": 2048, + "MinMemory": 4294967296, + "MaxMemory": 4294967296, "GPUUtilization": 0, "MaxParallelism": 1, "MaxParallelismGPU": 0, - "BaseMinMemory": 2048, + "BaseMinMemory": 1073741824, "MaxConcurrent": 0 }, "6": { - "MinMemory": 8388608, - "MaxMemory": 8388608, + "MinMemory": 4294967296, + "MaxMemory": 4294967296, "GPUUtilization": 0, "MaxParallelism": 1, "MaxParallelismGPU": 0, - "BaseMinMemory": 8388608, + "BaseMinMemory": 1073741824, "MaxConcurrent": 0 }, "7": { - "MinMemory": 1073741824, - "MaxMemory": 1073741824, + "MinMemory": 4294967296, + "MaxMemory": 4294967296, "GPUUtilization": 0, "MaxParallelism": 1, "MaxParallelismGPU": 0, @@ -660,8 +660,8 @@ Response: "MaxConcurrent": 0 }, "9": { - "MinMemory": 8589934592, - "MaxMemory": 8589934592, + "MinMemory": 4294967296, + "MaxMemory": 4294967296, "GPUUtilization": 0, "MaxParallelism": 1, "MaxParallelismGPU": 0, diff --git a/documentation/en/cli-lotus-miner.md b/documentation/en/cli-lotus-miner.md index 88c4d4141..ec266311b 100644 --- a/documentation/en/cli-lotus-miner.md +++ b/documentation/en/cli-lotus-miner.md @@ -2093,14 +2093,15 @@ USAGE: lotus-miner proving command [command options] [arguments...] COMMANDS: - info View current state information - deadlines View the current proving period deadlines information - deadline View the current proving period deadline information by its index - faults View the currently known proving faulty sectors information - check Check sectors provable - workers list workers - compute Compute simulated proving tasks - help, h Shows a list of commands or help for one command + info View current state information + deadlines View the current proving period deadlines information + deadline View the current proving period deadline information by its index + faults View the currently known proving faulty sectors information + check Check sectors provable + workers list workers + compute Compute simulated proving tasks + recover-faults Manually recovers faulty sectors on chain + help, h Shows a list of commands or help for one command OPTIONS: --help, -h show help (default: false) @@ -2210,6 +2211,19 @@ OPTIONS: ``` ``` +### lotus-miner proving recover-faults +``` +NAME: + lotus-miner proving recover-faults - Manually recovers faulty sectors on chain + +USAGE: + lotus-miner proving recover-faults [command options] + +OPTIONS: + --confidence value number of block confirmations to wait for (default: 5) + +``` + ## lotus-miner storage ``` NAME: diff --git a/documentation/en/cli-lotus.md b/documentation/en/cli-lotus.md index 5cb6b42aa..15178d8e0 100644 --- a/documentation/en/cli-lotus.md +++ b/documentation/en/cli-lotus.md @@ -18,6 +18,7 @@ COMMANDS: BASIC: send Send funds between accounts wallet Manage wallet + info Print node info client Make deals, store data, retrieve data msig Interact with a multisig wallet filplus Interact with the verified registry actor used by Filplus @@ -398,6 +399,22 @@ OPTIONS: ``` +## lotus info +``` +NAME: + lotus info - Print node info + +USAGE: + lotus info [command options] [arguments...] + +CATEGORY: + BASIC + +OPTIONS: + --help, -h show help (default: false) + +``` + ## lotus client ``` NAME: diff --git a/gateway/node_test.go b/gateway/node_test.go index b077d514a..805767dc6 100644 --- a/gateway/node_test.go +++ b/gateway/node_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package gateway import ( diff --git a/itests/api_test.go b/itests/api_test.go index ac204dc1b..7eac4e8a3 100644 --- a/itests/api_test.go +++ b/itests/api_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/batch_deal_test.go b/itests/batch_deal_test.go index 329a6b3bb..d1bb40531 100644 --- a/itests/batch_deal_test.go +++ b/itests/batch_deal_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/ccupgrade_test.go b/itests/ccupgrade_test.go index aae99c6ba..909b5691e 100644 --- a/itests/ccupgrade_test.go +++ b/itests/ccupgrade_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/cli_test.go b/itests/cli_test.go index ac7e4d488..a323c0863 100644 --- a/itests/cli_test.go +++ b/itests/cli_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/deadlines_test.go b/itests/deadlines_test.go index e76d4dafd..a2b0bde88 100644 --- a/itests/deadlines_test.go +++ b/itests/deadlines_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/deals_512mb_test.go b/itests/deals_512mb_test.go index e3817fae1..7b55204d9 100644 --- a/itests/deals_512mb_test.go +++ b/itests/deals_512mb_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/deals_concurrent_test.go b/itests/deals_concurrent_test.go index 3248a1d20..e36bde773 100644 --- a/itests/deals_concurrent_test.go +++ b/itests/deals_concurrent_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/deals_max_staging_deals_test.go b/itests/deals_max_staging_deals_test.go index 7b71d09be..738a1e2fe 100644 --- a/itests/deals_max_staging_deals_test.go +++ b/itests/deals_max_staging_deals_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/deals_offline_test.go b/itests/deals_offline_test.go index ccd86dff9..9b8354d36 100644 --- a/itests/deals_offline_test.go +++ b/itests/deals_offline_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/deals_padding_test.go b/itests/deals_padding_test.go index 93da33210..3535a1227 100644 --- a/itests/deals_padding_test.go +++ b/itests/deals_padding_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/deals_partial_retrieval_dm-level_test.go b/itests/deals_partial_retrieval_dm-level_test.go index 48fb8d516..f56d64026 100644 --- a/itests/deals_partial_retrieval_dm-level_test.go +++ b/itests/deals_partial_retrieval_dm-level_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/deals_partial_retrieval_test.go b/itests/deals_partial_retrieval_test.go index 604f3cfcb..0bbf23da0 100644 --- a/itests/deals_partial_retrieval_test.go +++ b/itests/deals_partial_retrieval_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/deals_power_test.go b/itests/deals_power_test.go index 27b196109..1ca28c6fd 100644 --- a/itests/deals_power_test.go +++ b/itests/deals_power_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/deals_pricing_test.go b/itests/deals_pricing_test.go index 15482f62b..f2301eee8 100644 --- a/itests/deals_pricing_test.go +++ b/itests/deals_pricing_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/deals_publish_test.go b/itests/deals_publish_test.go index b12fe31b7..43f4eeb05 100644 --- a/itests/deals_publish_test.go +++ b/itests/deals_publish_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/deals_retry_deal_no_funds_test.go b/itests/deals_retry_deal_no_funds_test.go index 98f99a4a2..8d5a02172 100644 --- a/itests/deals_retry_deal_no_funds_test.go +++ b/itests/deals_retry_deal_no_funds_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/deals_test.go b/itests/deals_test.go index 9810d417a..e8296ea87 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/gateway_test.go b/itests/gateway_test.go index 934b88fd2..a7d9d353b 100644 --- a/itests/gateway_test.go +++ b/itests/gateway_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/get_messages_in_ts_test.go b/itests/get_messages_in_ts_test.go index f5efa1bb8..ecc13e3aa 100644 --- a/itests/get_messages_in_ts_test.go +++ b/itests/get_messages_in_ts_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/kit/circuit.go b/itests/kit/circuit.go index d2857010e..50a10fa1c 100644 --- a/itests/kit/circuit.go +++ b/itests/kit/circuit.go @@ -10,9 +10,9 @@ import ( CircuitBreaker implements a simple time-based circuit breaker used for waiting for async operations to finish. This is how it works: - - It runs the `cb` function until it returns true, - - waiting for `throttle` duration between each iteration, - - or at most `timeout` duration until it breaks test execution. + - It runs the `cb` function until it returns true, + - waiting for `throttle` duration between each iteration, + - or at most `timeout` duration until it breaks test execution. You can use it if t.Deadline() is not "granular" enough, and you want to know which specific piece of code timed out, or you need to set different deadlines in the same test. diff --git a/itests/kit/ensemble.go b/itests/kit/ensemble.go index 668042b83..78d10423d 100644 --- a/itests/kit/ensemble.go +++ b/itests/kit/ensemble.go @@ -75,14 +75,14 @@ func init() { // // Create a new ensemble with: // -// ens := kit.NewEnsemble() +// ens := kit.NewEnsemble() // // Create full nodes and miners: // -// var full TestFullNode -// var miner TestMiner -// ens.FullNode(&full, opts...) // populates a full node -// ens.Miner(&miner, &full, opts...) // populates a miner, using the full node as its chain daemon +// var full TestFullNode +// var miner TestMiner +// ens.FullNode(&full, opts...) // populates a full node +// ens.Miner(&miner, &full, opts...) // populates a miner, using the full node as its chain daemon // // It is possible to pass functional options to set initial balances, // presealed sectors, owner keys, etc. @@ -94,22 +94,21 @@ func init() { // Nodes also need to be connected with one another, either via `ens.Connect()` // or `ens.InterconnectAll()`. A common inchantation for simple tests is to do: // -// ens.InterconnectAll().BeginMining(blocktime) +// ens.InterconnectAll().BeginMining(blocktime) // // You can continue to add more nodes, but you must always follow with // `ens.Start()` to activate the new nodes. // // The API is chainable, so it's possible to do a lot in a very succinct way: // -// kit.NewEnsemble().FullNode(&full).Miner(&miner, &full).Start().InterconnectAll().BeginMining() +// kit.NewEnsemble().FullNode(&full).Miner(&miner, &full).Start().InterconnectAll().BeginMining() // // You can also find convenient fullnode:miner presets, such as 1:1, 1:2, // and 2:1, e.g.: // -// kit.EnsembleMinimal() -// kit.EnsembleOneTwo() -// kit.EnsembleTwoOne() -// +// kit.EnsembleMinimal() +// kit.EnsembleOneTwo() +// kit.EnsembleTwoOne() type Ensemble struct { t *testing.T bootstrapped bool diff --git a/itests/mempool_test.go b/itests/mempool_test.go index 2a9905e2d..f07b46a73 100644 --- a/itests/mempool_test.go +++ b/itests/mempool_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/multisig_test.go b/itests/multisig_test.go index 8c23a9033..63cc2f511 100644 --- a/itests/multisig_test.go +++ b/itests/multisig_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/net_test.go b/itests/net_test.go index e29911aa5..43524a51b 100644 --- a/itests/net_test.go +++ b/itests/net_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/nonce_test.go b/itests/nonce_test.go index 87ea487ec..cac2413f7 100644 --- a/itests/nonce_test.go +++ b/itests/nonce_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/paych_api_test.go b/itests/paych_api_test.go index 5144221a1..353e22294 100644 --- a/itests/paych_api_test.go +++ b/itests/paych_api_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/paych_cli_test.go b/itests/paych_cli_test.go index 8892d6819..d73f96905 100644 --- a/itests/paych_cli_test.go +++ b/itests/paych_cli_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/sdr_upgrade_test.go b/itests/sdr_upgrade_test.go index 493dc1224..d92d4edc9 100644 --- a/itests/sdr_upgrade_test.go +++ b/itests/sdr_upgrade_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/sector_finalize_early_test.go b/itests/sector_finalize_early_test.go index e0b2cd815..8678e6a28 100644 --- a/itests/sector_finalize_early_test.go +++ b/itests/sector_finalize_early_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/sector_miner_collateral_test.go b/itests/sector_miner_collateral_test.go index b722dae65..8d7abacee 100644 --- a/itests/sector_miner_collateral_test.go +++ b/itests/sector_miner_collateral_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/sector_pledge_test.go b/itests/sector_pledge_test.go index 6f966430d..2ac1298d0 100644 --- a/itests/sector_pledge_test.go +++ b/itests/sector_pledge_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/sector_terminate_test.go b/itests/sector_terminate_test.go index b7004b312..34b325f2a 100644 --- a/itests/sector_terminate_test.go +++ b/itests/sector_terminate_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/self_sent_txn_test.go b/itests/self_sent_txn_test.go index 978778a8b..00ca0e5ae 100644 --- a/itests/self_sent_txn_test.go +++ b/itests/self_sent_txn_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/splitstore_test.go b/itests/splitstore_test.go index 6c57e26a7..db74e86a9 100644 --- a/itests/splitstore_test.go +++ b/itests/splitstore_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/tape_test.go b/itests/tape_test.go index d179951ed..e0db4882c 100644 --- a/itests/tape_test.go +++ b/itests/tape_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/verifreg_test.go b/itests/verifreg_test.go index 7afcd3a3b..9132cf28b 100644 --- a/itests/verifreg_test.go +++ b/itests/verifreg_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/wdpost_config_test.go b/itests/wdpost_config_test.go index 61b64387d..984650ae6 100644 --- a/itests/wdpost_config_test.go +++ b/itests/wdpost_config_test.go @@ -300,3 +300,170 @@ func TestWindowPostMaxSectorsRecoveryConfig(t *testing.T) { sectors = p.MinerPower.RawBytePower.Uint64() / uint64(ssz) require.Equal(t, nSectors+kit.DefaultPresealsPerBootstrapMiner-1, int(sectors)) // -1 not recovered sector } + +func TestWindowPostManualSectorsRecovery(t *testing.T) { + oldVal := wdpost.RecoveringSectorLimit + defer func() { + wdpost.RecoveringSectorLimit = oldVal + }() + wdpost.RecoveringSectorLimit = 1 + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + client, miner, ens := kit.EnsembleMinimal(t, + kit.LatestActorsAt(-1), + kit.MockProofs()) + ens.InterconnectAll().BeginMining(2 * time.Millisecond) + + nSectors := 10 + + miner.PledgeSectors(ctx, nSectors, 0, nil) + + maddr, err := miner.ActorAddress(ctx) + require.NoError(t, err) + di, err := client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) + require.NoError(t, err) + + mid, err := address.IDFromAddress(maddr) + require.NoError(t, err) + + t.Log("Running one proving period") + waitUntil := di.Open + di.WPoStProvingPeriod + t.Logf("End for head.Height > %d", waitUntil) + + ts := client.WaitTillChain(ctx, kit.HeightAtLeast(waitUntil)) + t.Logf("Now head.Height = %d", ts.Height()) + + p, err := client.StateMinerPower(ctx, maddr, types.EmptyTSK) + require.NoError(t, err) + + ssz, err := miner.ActorSectorSize(ctx, maddr) + require.NoError(t, err) + + require.Equal(t, p.MinerPower, p.TotalPower) + require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*uint64(nSectors+kit.DefaultPresealsPerBootstrapMiner))) + + failed, err := client.StateMinerFaults(ctx, maddr, types.TipSetKey{}) + require.NoError(t, err) + failedCount, err := failed.Count() + require.NoError(t, err) + + require.Equal(t, failedCount, uint64(0)) + + t.Log("Drop some sectors") + + // Drop 2 sectors from deadline 2 partition 0 (full partition / deadline) + parts, err := client.StateMinerPartitions(ctx, maddr, 2, types.EmptyTSK) + require.NoError(t, err) + require.Greater(t, len(parts), 0) + + secs := parts[0].AllSectors + n, err := secs.Count() + require.NoError(t, err) + require.Equal(t, uint64(2), n) + + var failedSectors []abi.SectorNumber + + // Drop the partition + err = secs.ForEach(func(sid uint64) error { + failedSectors = append(failedSectors, abi.SectorNumber(sid)) + return miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkFailed(storiface.SectorRef{ + ID: abi.SectorID{ + Miner: abi.ActorID(mid), + Number: abi.SectorNumber(sid), + }, + }, true) + }) + require.NoError(t, err) + + di, err = client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) + require.NoError(t, err) + + t.Log("Go through another PP, wait for sectors to become faulty") + waitUntil = di.Open + di.WPoStProvingPeriod + t.Logf("End for head.Height > %d", waitUntil) + + ts = client.WaitTillChain(ctx, kit.HeightAtLeast(waitUntil)) + t.Logf("Now head.Height = %d", ts.Height()) + + failed, err = client.StateMinerFaults(ctx, maddr, types.TipSetKey{}) + require.NoError(t, err) + failedCount, err = failed.Count() + require.NoError(t, err) + + require.Equal(t, failedCount, uint64(2)) + + recovered, err := client.StateMinerRecoveries(ctx, maddr, types.TipSetKey{}) + require.NoError(t, err) + recoveredCount, err := recovered.Count() + require.NoError(t, err) + + require.Equal(t, recoveredCount, uint64(0)) + + p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK) + require.NoError(t, err) + + require.Equal(t, p.MinerPower, p.TotalPower) + + t.Log("Make the sectors recoverable") + + err = secs.ForEach(func(sid uint64) error { + return miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkFailed(storiface.SectorRef{ + ID: abi.SectorID{ + Miner: abi.ActorID(mid), + Number: abi.SectorNumber(sid), + }, + }, false) + }) + require.NoError(t, err) + + // Try to manually recover the sector + t.Log("Send recovery message") + _, err = miner.RecoverFault(ctx, failedSectors) + require.NoError(t, err) + + currentHeight, err := client.ChainHead(ctx) + require.NoError(t, err) + + ts = client.WaitTillChain(ctx, kit.HeightAtLeast(currentHeight.Height()+abi.ChainEpoch(10))) + t.Logf("Now head.Height = %d", ts.Height()) + + failed, err = client.StateMinerFaults(ctx, maddr, types.TipSetKey{}) + require.NoError(t, err) + failedCount, err = failed.Count() + require.NoError(t, err) + + require.Equal(t, failedCount, uint64(2)) + + recovered, err = client.StateMinerRecoveries(ctx, maddr, types.TipSetKey{}) + require.NoError(t, err) + recoveredCount, err = recovered.Count() + require.NoError(t, err) + + require.Equal(t, recoveredCount, uint64(2)) + + di, err = client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) + require.NoError(t, err) + + t.Log("Go through another PP, wait for sectors to become faulty") + waitUntil = di.Open + di.WPoStProvingPeriod + t.Logf("End for head.Height > %d", waitUntil) + + ts = client.WaitTillChain(ctx, kit.HeightAtLeast(waitUntil)) + t.Logf("Now head.Height = %d", ts.Height()) + + failed, err = client.StateMinerFaults(ctx, maddr, types.TipSetKey{}) + require.NoError(t, err) + failedCount, err = failed.Count() + require.NoError(t, err) + + require.Equal(t, failedCount, uint64(0)) + + recovered, err = client.StateMinerRecoveries(ctx, maddr, types.TipSetKey{}) + require.NoError(t, err) + recoveredCount, err = recovered.Count() + require.NoError(t, err) + + require.Equal(t, recoveredCount, uint64(0)) +} diff --git a/itests/wdpost_dispute_test.go b/itests/wdpost_dispute_test.go index 0982f44c8..eedb3e8f6 100644 --- a/itests/wdpost_dispute_test.go +++ b/itests/wdpost_dispute_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/itests/wdpost_test.go b/itests/wdpost_test.go index 63a599094..a3d157ef0 100644 --- a/itests/wdpost_test.go +++ b/itests/wdpost_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package itests import ( diff --git a/journal/alerting/alerts_test.go b/journal/alerting/alerts_test.go index 8147ac5e8..5f8c26929 100644 --- a/journal/alerting/alerts_test.go +++ b/journal/alerting/alerts_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package alerting import ( diff --git a/journal/registry_test.go b/journal/registry_test.go index cb83be6e9..65956daf7 100644 --- a/journal/registry_test.go +++ b/journal/registry_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package journal import ( diff --git a/lib/backupds/backupds_test.go b/lib/backupds/backupds_test.go index bbbbdcd2a..48b2a8d25 100644 --- a/lib/backupds/backupds_test.go +++ b/lib/backupds/backupds_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package backupds import ( diff --git a/lib/oldpath/oldresolver/resolver.go b/lib/oldpath/oldresolver/resolver.go index 7c598c66e..1fab6c3d0 100644 --- a/lib/oldpath/oldresolver/resolver.go +++ b/lib/oldpath/oldresolver/resolver.go @@ -39,7 +39,8 @@ type ResolveOnce func(ctx context.Context, ds ipld.NodeGetter, nd ipld.Node, nam // Resolver provides path resolution to IPFS // It has a pointer to a DAGService, which is uses to resolve nodes. // TODO: now that this is more modular, try to unify this code with the -// the resolvers in namesys +// +// the resolvers in namesys type Resolver struct { DAG ipld.NodeGetter diff --git a/lib/oldpath/path.go b/lib/oldpath/path.go index 9cc99ce5c..70303b428 100644 --- a/lib/oldpath/path.go +++ b/lib/oldpath/path.go @@ -27,10 +27,10 @@ func (e *pathError) Path() string { } // A Path represents an ipfs content path: -// * //path/to/file -// * /ipfs/ -// * /ipns//path/to/folder -// * etc +// - //path/to/file +// - /ipfs/ +// - /ipns//path/to/folder +// - etc type Path string // ^^^ diff --git a/lib/rpcenc/reader_test.go b/lib/rpcenc/reader_test.go index ac78d1109..455cc8fcc 100644 --- a/lib/rpcenc/reader_test.go +++ b/lib/rpcenc/reader_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package rpcenc import ( diff --git a/lib/sigs/bls/bls_bench_test.go b/lib/sigs/bls/bls_bench_test.go index 2f1f6ee6f..70e2a45ca 100644 --- a/lib/sigs/bls/bls_bench_test.go +++ b/lib/sigs/bls/bls_bench_test.go @@ -1,4 +1,4 @@ -//stm: ignore +// stm: ignore // Ignored because implementation relies on external (ffi) lib package bls diff --git a/lib/sigs/bls/bls_test.go b/lib/sigs/bls/bls_test.go index 3187fea67..7a290b8b7 100644 --- a/lib/sigs/bls/bls_test.go +++ b/lib/sigs/bls/bls_test.go @@ -1,4 +1,4 @@ -//stm: ignore +// stm: ignore // Ignored because implementation relies on external (ffi) lib package bls_test diff --git a/lib/stati/stats_test.go b/lib/stati/stats_test.go index b6aa7a0a5..c1a7ff66a 100644 --- a/lib/stati/stats_test.go +++ b/lib/stati/stats_test.go @@ -1,4 +1,4 @@ -//stm: ignore +// stm: ignore package stati import ( diff --git a/lib/tablewriter/tablewiter_test.go b/lib/tablewriter/tablewiter_test.go index ce676abdf..8ce8d3253 100644 --- a/lib/tablewriter/tablewiter_test.go +++ b/lib/tablewriter/tablewiter_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package tablewriter import ( diff --git a/lib/tablewriter/tablewriter.go b/lib/tablewriter/tablewriter.go index cd045710e..62fdd469f 100644 --- a/lib/tablewriter/tablewriter.go +++ b/lib/tablewriter/tablewriter.go @@ -35,7 +35,8 @@ func NewLineCol(name string) Column { } // Unlike text/tabwriter, this works with CLI escape codes, and allows for info -// in separate lines +// +// in separate lines func New(cols ...Column) *TableWriter { return &TableWriter{ cols: cols, diff --git a/lib/unixfs/filestore_test.go b/lib/unixfs/filestore_test.go index 3aee5cb24..9fe6c228a 100644 --- a/lib/unixfs/filestore_test.go +++ b/lib/unixfs/filestore_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package unixfs import ( diff --git a/markets/dagstore/miner_api_test.go b/markets/dagstore/miner_api_test.go index b30783c5d..c2618e8a7 100644 --- a/markets/dagstore/miner_api_test.go +++ b/markets/dagstore/miner_api_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package dagstore import ( diff --git a/markets/dagstore/mount_test.go b/markets/dagstore/mount_test.go index bc55f449d..e044603d4 100644 --- a/markets/dagstore/mount_test.go +++ b/markets/dagstore/mount_test.go @@ -1,4 +1,4 @@ -//stm: @unit +// stm: @unit package dagstore import ( diff --git a/markets/dagstore/wrapper_migration_test.go b/markets/dagstore/wrapper_migration_test.go index ce208cc82..9c8e08a8c 100644 --- a/markets/dagstore/wrapper_migration_test.go +++ b/markets/dagstore/wrapper_migration_test.go @@ -1,4 +1,4 @@ -//stm: #integration +// stm: #integration package dagstore import ( diff --git a/markets/dagstore/wrapper_test.go b/markets/dagstore/wrapper_test.go index 1240ce0a3..f3b5e1b52 100644 --- a/markets/dagstore/wrapper_test.go +++ b/markets/dagstore/wrapper_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package dagstore import ( diff --git a/markets/retrievaladapter/provider_test.go b/markets/retrievaladapter/provider_test.go index 0a50a10ac..b7b5039d6 100644 --- a/markets/retrievaladapter/provider_test.go +++ b/markets/retrievaladapter/provider_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package retrievaladapter import ( diff --git a/markets/storageadapter/dealpublisher_test.go b/markets/storageadapter/dealpublisher_test.go index b73c3e2a6..b7280842c 100644 --- a/markets/storageadapter/dealpublisher_test.go +++ b/markets/storageadapter/dealpublisher_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package storageadapter import ( diff --git a/markets/storageadapter/dealstatematcher_test.go b/markets/storageadapter/dealstatematcher_test.go index 6ff000a2a..9a46e4af9 100644 --- a/markets/storageadapter/dealstatematcher_test.go +++ b/markets/storageadapter/dealstatematcher_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package storageadapter import ( diff --git a/markets/storageadapter/ondealsectorcommitted_test.go b/markets/storageadapter/ondealsectorcommitted_test.go index 402b9b922..624cf84ae 100644 --- a/markets/storageadapter/ondealsectorcommitted_test.go +++ b/markets/storageadapter/ondealsectorcommitted_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package storageadapter import ( diff --git a/miner/miner.go b/miner/miner.go index 8f341166e..4952f95fb 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -179,26 +179,26 @@ func (m *Miner) niceSleep(d time.Duration) bool { // mine runs the mining loop. It performs the following: // -// 1. Queries our current best currently-known mining candidate (tipset to -// build upon). -// 2. Waits until the propagation delay of the network has elapsed (currently -// 6 seconds). The waiting is done relative to the timestamp of the best -// candidate, which means that if it's way in the past, we won't wait at -// all (e.g. in catch-up or rush mining). -// 3. After the wait, we query our best mining candidate. This will be the one -// we'll work with. -// 4. Sanity check that we _actually_ have a new mining base to mine on. If -// not, wait one epoch + propagation delay, and go back to the top. -// 5. We attempt to mine a block, by calling mineOne (refer to godocs). This -// method will either return a block if we were eligible to mine, or nil -// if we weren't. -// 6a. If we mined a block, we update our state and push it out to the network -// via gossipsub. -// 6b. If we didn't mine a block, we consider this to be a nil round on top of -// the mining base we selected. If other miner or miners on the network -// were eligible to mine, we will receive their blocks via gossipsub and -// we will select that tipset on the next iteration of the loop, thus -// discarding our null round. +// 1. Queries our current best currently-known mining candidate (tipset to +// build upon). +// 2. Waits until the propagation delay of the network has elapsed (currently +// 6 seconds). The waiting is done relative to the timestamp of the best +// candidate, which means that if it's way in the past, we won't wait at +// all (e.g. in catch-up or rush mining). +// 3. After the wait, we query our best mining candidate. This will be the one +// we'll work with. +// 4. Sanity check that we _actually_ have a new mining base to mine on. If +// not, wait one epoch + propagation delay, and go back to the top. +// 5. We attempt to mine a block, by calling mineOne (refer to godocs). This +// method will either return a block if we were eligible to mine, or nil +// if we weren't. +// 6a. If we mined a block, we update our state and push it out to the network +// via gossipsub. +// 6b. If we didn't mine a block, we consider this to be a nil round on top of +// the mining base we selected. If other miner or miners on the network +// were eligible to mine, we will receive their blocks via gossipsub and +// we will select that tipset on the next iteration of the loop, thus +// discarding our null round. func (m *Miner) mine(ctx context.Context) { ctx, span := trace.StartSpan(ctx, "/mine") defer span.End() @@ -416,7 +416,7 @@ func (m *Miner) GetBestMiningCandidate(ctx context.Context) (*MiningBase, error) // // This method does the following: // -// 1. +// 1. func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (minedBlock *types.BlockMsg, err error) { log.Debugw("attempting to mine a block", "tipset", types.LogCids(base.TipSet.Cids())) tStart := build.Clock.Now() diff --git a/node/builder.go b/node/builder.go index 5bc2d3ea3..bb0cb8645 100644 --- a/node/builder.go +++ b/node/builder.go @@ -49,7 +49,8 @@ import ( var log = logging.Logger("builder") // special is a type used to give keys to modules which -// can't really be identified by the returned type +// +// can't really be identified by the returned type type special struct{ id int } //nolint:golint @@ -73,6 +74,7 @@ var ( type invoke int // Invokes are called in the order they are defined. +// //nolint:golint const ( // InitJournal at position 0 initializes the journal global var as soon as diff --git a/node/config/def_test.go b/node/config/def_test.go index d644ae336..1739339a2 100644 --- a/node/config/def_test.go +++ b/node/config/def_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package config import ( diff --git a/node/config/load_test.go b/node/config/load_test.go index ccc227eb8..17e185be2 100644 --- a/node/config/load_test.go +++ b/node/config/load_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package config import ( diff --git a/node/impl/client/client_test.go b/node/impl/client/client_test.go index 0b3f1c98f..7c96897c5 100644 --- a/node/impl/client/client_test.go +++ b/node/impl/client/client_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package client import ( diff --git a/node/impl/full/gas_test.go b/node/impl/full/gas_test.go index 3b4084d43..8fc585bd5 100644 --- a/node/impl/full/gas_test.go +++ b/node/impl/full/gas_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package full import ( diff --git a/node/impl/storminer.go b/node/impl/storminer.go index bab72d631..f054f627e 100644 --- a/node/impl/storminer.go +++ b/node/impl/storminer.go @@ -1323,6 +1323,27 @@ func (sm *StorageMinerAPI) ComputeProof(ctx context.Context, ssi []builtin.Exten return sm.Epp.ComputeProof(ctx, ssi, rand, poStEpoch, nv) } +func (sm *StorageMinerAPI) RecoverFault(ctx context.Context, sectors []abi.SectorNumber) ([]cid.Cid, error) { + allsectors, err := sm.Miner.ListSectors() + if err != nil { + return nil, xerrors.Errorf("could not get a list of all sectors from the miner: %w", err) + } + var found bool + for _, v := range sectors { + found = false + for _, s := range allsectors { + if v == s.SectorNumber { + found = true + break + } + } + if !found { + return nil, xerrors.Errorf("sectors %d not found in the sector list for miner", v) + } + } + return sm.WdPoSt.ManualFaultRecovery(ctx, sm.Miner.Address(), sectors) +} + func (sm *StorageMinerAPI) RuntimeSubsystems(context.Context) (res api.MinerSubsystems, err error) { return sm.EnabledSubsystems, nil } diff --git a/node/repo/fsrepo_test.go b/node/repo/fsrepo_test.go index 9342258c3..943acc582 100644 --- a/node/repo/fsrepo_test.go +++ b/node/repo/fsrepo_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package repo import ( diff --git a/node/repo/memrepo_test.go b/node/repo/memrepo_test.go index 6fc0669da..6b3fc158b 100644 --- a/node/repo/memrepo_test.go +++ b/node/repo/memrepo_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package repo import ( diff --git a/node/repo/repo_test.go b/node/repo/repo_test.go index f2b83ce8e..16c101d44 100644 --- a/node/repo/repo_test.go +++ b/node/repo/repo_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package repo import ( diff --git a/node/shutdown_test.go b/node/shutdown_test.go index b831c6180..6a5088efd 100644 --- a/node/shutdown_test.go +++ b/node/shutdown_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package node import ( diff --git a/paychmgr/paych_test.go b/paychmgr/paych_test.go index 6787e3e0d..7de584784 100644 --- a/paychmgr/paych_test.go +++ b/paychmgr/paych_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package paychmgr import ( diff --git a/paychmgr/paychget_test.go b/paychmgr/paychget_test.go index 5f1876664..fca0022c6 100644 --- a/paychmgr/paychget_test.go +++ b/paychmgr/paychget_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package paychmgr import ( diff --git a/paychmgr/settle_test.go b/paychmgr/settle_test.go index e51c2de47..db1d35da3 100644 --- a/paychmgr/settle_test.go +++ b/paychmgr/settle_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package paychmgr import ( diff --git a/paychmgr/store_test.go b/paychmgr/store_test.go index c5a1875ae..f600b6537 100644 --- a/paychmgr/store_test.go +++ b/paychmgr/store_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package paychmgr import ( diff --git a/storage/paths/remote_test.go b/storage/paths/remote_test.go index ec58fb84d..a7bd6bf40 100644 --- a/storage/paths/remote_test.go +++ b/storage/paths/remote_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package paths_test import ( diff --git a/storage/pipeline/checks.go b/storage/pipeline/checks.go index 757714f1e..2192db5cf 100644 --- a/storage/pipeline/checks.go +++ b/storage/pipeline/checks.go @@ -18,7 +18,8 @@ import ( ) // TODO: For now we handle this by halting state execution, when we get jsonrpc reconnecting -// We should implement some wait-for-api logic +// +// We should implement some wait-for-api logic type ErrApi struct{ error } type ErrNoDeals struct{ error } @@ -91,7 +92,8 @@ func checkPieces(ctx context.Context, maddr address.Address, si SectorInfo, api } // checkPrecommit checks that data commitment generated in the sealing process -// matches pieces, and that the seal ticket isn't expired +// +// matches pieces, and that the seal ticket isn't expired func checkPrecommit(ctx context.Context, maddr address.Address, si SectorInfo, tsk types.TipSetKey, height abi.ChainEpoch, api SealingAPI) (err error) { if err := checkPieces(ctx, maddr, si, api, false); err != nil { return err diff --git a/storage/pipeline/commit_batch_test.go b/storage/pipeline/commit_batch_test.go index b25b78438..cece591d3 100644 --- a/storage/pipeline/commit_batch_test.go +++ b/storage/pipeline/commit_batch_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package sealing_test import ( diff --git a/storage/pipeline/precommit_batch_test.go b/storage/pipeline/precommit_batch_test.go index d380acbeb..735474f07 100644 --- a/storage/pipeline/precommit_batch_test.go +++ b/storage/pipeline/precommit_batch_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package sealing_test import ( diff --git a/storage/pipeline/states_failed_test.go b/storage/pipeline/states_failed_test.go index a313aedbb..0243af126 100644 --- a/storage/pipeline/states_failed_test.go +++ b/storage/pipeline/states_failed_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package sealing_test import ( diff --git a/storage/sealer/ffiwrapper/sealer_test.go b/storage/sealer/ffiwrapper/sealer_test.go index 829190015..fb6a2249c 100644 --- a/storage/sealer/ffiwrapper/sealer_test.go +++ b/storage/sealer/ffiwrapper/sealer_test.go @@ -261,7 +261,6 @@ func getGrothParamFileAndVerifyingKeys(s abi.SectorSize) { // those parameters and keys. To do this, run the following command: // // go test -run=^TestDownloadParams -// func TestDownloadParams(t *testing.T) { // defer requireFDsClosed(t, openFDs(t)) flaky likely cause of how go-embed works with param files diff --git a/storage/sealer/ffiwrapper/unseal_ranges.go b/storage/sealer/ffiwrapper/unseal_ranges.go index 22b41659c..37107aeb0 100644 --- a/storage/sealer/ffiwrapper/unseal_ranges.go +++ b/storage/sealer/ffiwrapper/unseal_ranges.go @@ -11,7 +11,8 @@ import ( ) // merge gaps between ranges which are close to each other -// TODO: more benchmarking to come up with more optimal number +// +// TODO: more benchmarking to come up with more optimal number const mergeGaps = 32 << 20 // TODO const expandRuns = 16 << 20 // unseal more than requested for future requests diff --git a/storage/sealer/manager_test.go b/storage/sealer/manager_test.go index d287462e0..739cfdd24 100644 --- a/storage/sealer/manager_test.go +++ b/storage/sealer/manager_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package sealer import ( diff --git a/storage/sealer/sched_test.go b/storage/sealer/sched_test.go index bca8ace6e..a30a4d261 100644 --- a/storage/sealer/sched_test.go +++ b/storage/sealer/sched_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package sealer import ( diff --git a/storage/sealer/sealtasks/task.go b/storage/sealer/sealtasks/task.go index 061e84c7f..53aa1cbc7 100644 --- a/storage/sealer/sealtasks/task.go +++ b/storage/sealer/sealtasks/task.go @@ -96,6 +96,11 @@ func (a TaskType) WorkerType() string { } } +// SectorSized returns true if the task operates on a specific sector size +func (a TaskType) SectorSized() bool { + return a != TTDataCid +} + func (a TaskType) MuchLess(b TaskType) (bool, bool) { oa, ob := order[a], order[b] oneNegative := oa^ob < 0 diff --git a/storage/sealer/storiface/index.go b/storage/sealer/storiface/index.go index a8f1f2f4a..653bd2fba 100644 --- a/storage/sealer/storiface/index.go +++ b/storage/sealer/storiface/index.go @@ -9,7 +9,8 @@ import ( ) // ID identifies sector storage by UUID. One sector storage should map to one -// filesystem, local or networked / shared by multiple machines +// +// filesystem, local or networked / shared by multiple machines type ID string const IDSep = "." diff --git a/storage/sealer/storiface/resources.go b/storage/sealer/storiface/resources.go index f3a658e34..be5c34d0f 100644 --- a/storage/sealer/storiface/resources.go +++ b/storage/sealer/storiface/resources.go @@ -6,6 +6,7 @@ import ( "strconv" "strings" + logging "github.com/ipfs/go-log/v2" "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/abi" @@ -13,6 +14,8 @@ import ( "github.com/filecoin-project/lotus/storage/sealer/sealtasks" ) +var log = logging.Logger("resources") + type Resources struct { MinMemory uint64 `envname:"MIN_MEMORY"` // What Must be in RAM for decent perf MaxMemory uint64 `envname:"MAX_MEMORY"` // Memory required (swap + ram; peak memory usage during task execution) @@ -32,16 +35,14 @@ type Resources struct { } /* +Percent of threads to allocate to parallel tasks - Percent of threads to allocate to parallel tasks - - 12 * 0.92 = 11 - 16 * 0.92 = 14 - 24 * 0.92 = 22 - 32 * 0.92 = 29 - 64 * 0.92 = 58 - 128 * 0.92 = 117 - +12 * 0.92 = 11 +16 * 0.92 = 14 +24 * 0.92 = 22 +32 * 0.92 = 29 +64 * 0.92 = 58 +128 * 0.92 = 117 */ var ParallelNum uint64 = 92 var ParallelDenom uint64 = 100 @@ -572,7 +573,12 @@ var ResourceTable = map[sealtasks.TaskType]map[abi.RegisteredSealProof]Resources func init() { ResourceTable[sealtasks.TTUnseal] = ResourceTable[sealtasks.TTPreCommit1] // TODO: measure accurately ResourceTable[sealtasks.TTRegenSectorKey] = ResourceTable[sealtasks.TTReplicaUpdate] - ResourceTable[sealtasks.TTDataCid] = ResourceTable[sealtasks.TTAddPiece] + + // DataCid doesn't care about sector proof type; Use 32G AddPiece resource definition + ResourceTable[sealtasks.TTDataCid] = map[abi.RegisteredSealProof]Resources{} + for proof := range ResourceTable[sealtasks.TTAddPiece] { + ResourceTable[sealtasks.TTDataCid][proof] = ResourceTable[sealtasks.TTAddPiece][abi.RegisteredSealProof_StackedDrg32GiBV1] + } // V1_1 is the same as V1 for _, m := range ResourceTable { @@ -610,20 +616,29 @@ func ParseResourceEnv(lookup func(key, def string) (string, bool)) (map[sealtask envval, found := lookup(taskType.Short()+"_"+shortSize+"_"+envname, fmt.Sprint(rr.Elem().Field(i).Interface())) if !found { - // special multicore SDR handling - if (taskType == sealtasks.TTPreCommit1 || taskType == sealtasks.TTUnseal) && envname == "MAX_PARALLELISM" { - v, ok := rr.Elem().Field(i).Addr().Interface().(*int) - if !ok { - // can't happen, but let's not panic - return nil, xerrors.Errorf("res.MAX_PARALLELISM is not int (!?): %w", err) - } - *v, err = getSDRThreads(lookup) - if err != nil { - return nil, err + // see if a non-size-specific envvar is set + envval, found = lookup(taskType.Short()+"_"+envname, fmt.Sprint(rr.Elem().Field(i).Interface())) + if !found { + // special multicore SDR handling + if (taskType == sealtasks.TTPreCommit1 || taskType == sealtasks.TTUnseal) && envname == "MAX_PARALLELISM" { + v, ok := rr.Elem().Field(i).Addr().Interface().(*int) + if !ok { + // can't happen, but let's not panic + return nil, xerrors.Errorf("res.MAX_PARALLELISM is not int (!?): %w", err) + } + *v, err = getSDRThreads(lookup) + if err != nil { + return nil, err + } } + + continue } - continue + } else { + if !taskType.SectorSized() { + log.Errorw("sector-size independent task resource var specified with sector-sized envvar", "env", taskType.Short()+"_"+shortSize+"_"+envname, "use", taskType.Short()+"_"+envname) + } } v := rr.Elem().Field(i).Addr().Interface() diff --git a/storage/sealer/storiface/resources_test.go b/storage/sealer/storiface/resources_test.go index 1040ef96e..e360b8d14 100644 --- a/storage/sealer/storiface/resources_test.go +++ b/storage/sealer/storiface/resources_test.go @@ -12,9 +12,12 @@ import ( ) func TestListResourceVars(t *testing.T) { + seen := map[string]struct{}{} _, err := ParseResourceEnv(func(key, def string) (string, bool) { - if def != "" { + _, s := seen[key] + if !s && def != "" { fmt.Printf("%s=%s\n", key, def) + seen[key] = struct{}{} } return "", false @@ -75,3 +78,44 @@ func TestListResourceSDRMulticoreOverride(t *testing.T) { require.Equal(t, 9001, rt[sealtasks.TTPreCommit1][stabi.RegisteredSealProof_StackedDrg2KiBV1_1].MaxParallelism) require.Equal(t, 9001, rt[sealtasks.TTUnseal][stabi.RegisteredSealProof_StackedDrg2KiBV1_1].MaxParallelism) } + +func TestUnsizedSetAll(t *testing.T) { + rt, err := ParseResourceEnv(func(key, def string) (string, bool) { + if key == "UNS_MAX_PARALLELISM" { + return "2", true + } + + return "", false + }) + + require.NoError(t, err) + require.Equal(t, 2, rt[sealtasks.TTUnseal][stabi.RegisteredSealProof_StackedDrg2KiBV1_1].MaxParallelism) + require.Equal(t, 2, rt[sealtasks.TTUnseal][stabi.RegisteredSealProof_StackedDrg32GiBV1].MaxParallelism) + require.Equal(t, 2, rt[sealtasks.TTUnseal][stabi.RegisteredSealProof_StackedDrg8MiBV1].MaxParallelism) + + // check that defaults don't get mutated + require.Equal(t, 1, ResourceTable[sealtasks.TTUnseal][stabi.RegisteredSealProof_StackedDrg2KiBV1_1].MaxParallelism) +} + +func TestUnsizedNotPreferred(t *testing.T) { + rt, err := ParseResourceEnv(func(key, def string) (string, bool) { + if key == "DC_MAX_PARALLELISM" { + return "2", true + } + + // test should also print a warning for DataCid as it's not sector-size dependent + if key == "DC_64G_MAX_PARALLELISM" { + return "1", true + } + + return "", false + }) + + require.NoError(t, err) + require.Equal(t, 2, rt[sealtasks.TTDataCid][stabi.RegisteredSealProof_StackedDrg2KiBV1_1].MaxParallelism) + require.Equal(t, 2, rt[sealtasks.TTDataCid][stabi.RegisteredSealProof_StackedDrg32GiBV1].MaxParallelism) + require.Equal(t, 1, rt[sealtasks.TTDataCid][stabi.RegisteredSealProof_StackedDrg64GiBV1_1].MaxParallelism) + + // check that defaults don't get mutated + require.Equal(t, 1, ResourceTable[sealtasks.TTUnseal][stabi.RegisteredSealProof_StackedDrg2KiBV1_1].MaxParallelism) +} diff --git a/storage/wdpost/wdpost_changehandler_test.go b/storage/wdpost/wdpost_changehandler_test.go index fc44091ee..3e7ca3f49 100644 --- a/storage/wdpost/wdpost_changehandler_test.go +++ b/storage/wdpost/wdpost_changehandler_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package wdpost import ( diff --git a/storage/wdpost/wdpost_nextdl_test.go b/storage/wdpost/wdpost_nextdl_test.go index 2902cb4fc..d591c1e88 100644 --- a/storage/wdpost/wdpost_nextdl_test.go +++ b/storage/wdpost/wdpost_nextdl_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package wdpost import ( diff --git a/storage/wdpost/wdpost_run.go b/storage/wdpost/wdpost_run.go index 0e715f101..0501923b0 100644 --- a/storage/wdpost/wdpost_run.go +++ b/storage/wdpost/wdpost_run.go @@ -717,3 +717,7 @@ func (s *WindowPoStScheduler) ComputePoSt(ctx context.Context, dlIdx uint64, ts return s.runPoStCycle(ctx, true, *dl, ts) } + +func (s *WindowPoStScheduler) ManualFaultRecovery(ctx context.Context, maddr address.Address, sectors []abi.SectorNumber) ([]cid.Cid, error) { + return s.declareManualRecoveries(ctx, maddr, sectors, types.TipSetKey{}) +} diff --git a/storage/wdpost/wdpost_run_faults.go b/storage/wdpost/wdpost_run_faults.go index 22186b551..9e9854a7c 100644 --- a/storage/wdpost/wdpost_run_faults.go +++ b/storage/wdpost/wdpost_run_faults.go @@ -10,6 +10,7 @@ import ( "go.opencensus.io/trace" "golang.org/x/xerrors" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/builtin" @@ -49,8 +50,9 @@ func init() { // on chain before returning. // // TODO: the waiting should happen in the background. Right now this -// is blocking/delaying the actual generation and submission of WindowPoSts in -// this deadline! +// +// is blocking/delaying the actual generation and submission of WindowPoSts in +// this deadline! func (s *WindowPoStScheduler) declareRecoveries(ctx context.Context, dlIdx uint64, partitions []api.Partition, tsk types.TipSetKey) ([][]miner.RecoveryDeclaration, []*types.SignedMessage, error) { ctx, span := trace.StartSpan(ctx, "storage.declareRecoveries") defer span.End() @@ -205,8 +207,9 @@ func (s *WindowPoStScheduler) declareRecoveries(ctx context.Context, dlIdx uint6 // on chain before returning. // // TODO: the waiting should happen in the background. Right now this -// is blocking/delaying the actual generation and submission of WindowPoSts in -// this deadline! +// +// is blocking/delaying the actual generation and submission of WindowPoSts in +// this deadline! func (s *WindowPoStScheduler) declareFaults(ctx context.Context, dlIdx uint64, partitions []api.Partition, tsk types.TipSetKey) ([]miner.FaultDeclaration, *types.SignedMessage, error) { ctx, span := trace.StartSpan(ctx, "storage.declareFaults") defer span.End() @@ -343,3 +346,111 @@ func (s *WindowPoStScheduler) asyncFaultRecover(di dline.Info, ts *types.TipSet) } }() } + +// declareRecoveries identifies sectors that were previously marked as faulty +// for our miner, but are now recovered (i.e. are now provable again) and +// still not reported as such. +// +// It then reports the recovery on chain via a `DeclareFaultsRecovered` +// message to our miner actor. +// +// This is always invoked ahead of time, before the deadline for the evaluated +// sectors arrives. That way, recoveries are declared in preparation for those +// sectors to be proven. +// +// If a declaration is made, it awaits for build.MessageConfidence confirmations +// on chain before returning. +func (s *WindowPoStScheduler) declareManualRecoveries(ctx context.Context, maddr address.Address, sectors []abi.SectorNumber, tsk types.TipSetKey) ([]cid.Cid, error) { + + var RecoveryDecls []miner.RecoveryDeclaration + var RecoveryBatches [][]miner.RecoveryDeclaration + + type ptx struct { + deadline uint64 + partition uint64 + } + + smap := make(map[ptx][]uint64) + + var mcids []cid.Cid + + for _, sector := range sectors { + ptxID, err := s.api.StateSectorPartition(ctx, maddr, sector, types.TipSetKey{}) + if err != nil { + return nil, xerrors.Errorf("failed to fetch partition and deadline details for sector %d: %w", sector, err) + } + ptxinfo := ptx{ + deadline: ptxID.Deadline, + partition: ptxID.Partition, + } + + slist := smap[ptxinfo] + sn := uint64(sector) + slist = append(slist, sn) + smap[ptxinfo] = slist + } + + for i, v := range smap { + sectorinbit := bitfield.NewFromSet(v) + RecoveryDecls = append(RecoveryDecls, miner.RecoveryDeclaration{ + Deadline: i.deadline, + Partition: i.partition, + Sectors: sectorinbit, + }) + } + + // Batch if maxPartitionsPerRecoveryMessage is set + if s.maxPartitionsPerRecoveryMessage > 0 { + + // Create batched + for len(RecoveryDecls) > s.maxPartitionsPerPostMessage { + Batch := RecoveryDecls[len(RecoveryDecls)-s.maxPartitionsPerRecoveryMessage:] + RecoveryDecls = RecoveryDecls[:len(RecoveryDecls)-s.maxPartitionsPerPostMessage] + RecoveryBatches = append(RecoveryBatches, Batch) + } + + // Add remaining as new batch + RecoveryBatches = append(RecoveryBatches, RecoveryDecls) + } else { + RecoveryBatches = append(RecoveryBatches, RecoveryDecls) + } + + for _, Batch := range RecoveryBatches { + msg, err := s.manualRecoveryMsg(ctx, Batch) + if err != nil { + return nil, err + } + + mcids = append(mcids, msg) + } + + return mcids, nil +} + +func (s *WindowPoStScheduler) manualRecoveryMsg(ctx context.Context, Recovery []miner.RecoveryDeclaration) (cid.Cid, error) { + params := &miner.DeclareFaultsRecoveredParams{ + Recoveries: Recovery, + } + + enc, aerr := actors.SerializeParams(params) + if aerr != nil { + return cid.Undef, xerrors.Errorf("could not serialize declare recoveries parameters: %w", aerr) + } + + msg := &types.Message{ + To: s.actor, + Method: builtin.MethodsMiner.DeclareFaultsRecovered, + Params: enc, + Value: types.NewInt(0), + } + spec := &api.MessageSendSpec{MaxFee: abi.TokenAmount(s.feeCfg.MaxWindowPoStGasFee)} + if err := s.prepareMessage(ctx, msg, spec); err != nil { + return cid.Undef, err + } + sm, err := s.api.MpoolPushMessage(ctx, msg, &api.MessageSendSpec{MaxFee: abi.TokenAmount(s.feeCfg.MaxWindowPoStGasFee)}) + if err != nil { + return cid.Undef, xerrors.Errorf("pushing message to mpool: %w", err) + } + + return sm.Cid(), nil +} diff --git a/storage/wdpost/wdpost_run_test.go b/storage/wdpost/wdpost_run_test.go index 233e40472..466fd6905 100644 --- a/storage/wdpost/wdpost_run_test.go +++ b/storage/wdpost/wdpost_run_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package wdpost import ( diff --git a/storage/wdpost/wdpost_sched.go b/storage/wdpost/wdpost_sched.go index 2739bc386..66722e283 100644 --- a/storage/wdpost/wdpost_sched.go +++ b/storage/wdpost/wdpost_sched.go @@ -19,6 +19,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/journal" @@ -44,6 +45,7 @@ type NodeAPI interface { StateMinerPartitions(context.Context, address.Address, uint64, types.TipSetKey) ([]api.Partition, error) StateLookupID(context.Context, address.Address, types.TipSetKey) (address.Address, error) StateAccountKey(context.Context, address.Address, types.TipSetKey) (address.Address, error) + StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*lminer.SectorLocation, error) MpoolPushMessage(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error) diff --git a/testplans/lotus-soup/paych/stress.go b/testplans/lotus-soup/paych/stress.go index 06c89d4d1..8f0097edf 100644 --- a/testplans/lotus-soup/paych/stress.go +++ b/testplans/lotus-soup/paych/stress.go @@ -44,7 +44,8 @@ func getClientMode(groupSeq int64) ClientMode { } // TODO Stress is currently WIP. We found blockers in Lotus that prevent us from -// making progress. See https://github.com/filecoin-project/lotus/issues/2297. +// +// making progress. See https://github.com/filecoin-project/lotus/issues/2297. func Stress(t *testkit.TestEnvironment) error { // Dispatch/forward non-client roles to defaults. if t.Role != "client" { diff --git a/tools/stats/headbuffer/head_buffer_test.go b/tools/stats/headbuffer/head_buffer_test.go index d68ba8fbc..f9c0385c0 100644 --- a/tools/stats/headbuffer/head_buffer_test.go +++ b/tools/stats/headbuffer/head_buffer_test.go @@ -1,4 +1,4 @@ -//stm: #unit +// stm: #unit package headbuffer import (