diff --git a/api/api_full.go b/api/api_full.go index 68b99638e..1403ce295 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -457,10 +457,15 @@ type FullNode interface { StateMinerInitialPledgeCollateral(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error) //perm:read // StateMinerAvailableBalance returns the portion of a miner's balance that can be withdrawn or spent StateMinerAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) //perm:read - // StateMinerSectorAllocated checks if a sector is allocated + // StateMinerSectorAllocated checks if a sector number is marked as allocated. StateMinerSectorAllocated(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (bool, error) //perm:read - // StateSectorPreCommitInfo returns the PreCommit info for the specified miner's sector - StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) //perm:read + // StateSectorPreCommitInfo returns the PreCommit info for the specified miner's sector. + // Returns nil and no error if the sector isn't precommitted. + // + // Note that the sector number may be allocated while PreCommitInfo is nil. This means that either allocated sector + // numbers were compacted, and the sector number was marked as allocated in order to reduce size of the allocated + // sectors bitfield, or that the sector was precommitted, but the precommit has expired. + StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorPreCommitOnChainInfo, error) //perm:read // StateSectorGetInfo returns the on-chain info for the specified miner's sector. Returns null in case the sector info isn't found // NOTE: returned info.Expiration may not be accurate in some cases, use StateSectorExpiration to get accurate // expiration epoch diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index bb50694b3..0cdd6c229 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -2949,10 +2949,10 @@ func (mr *MockFullNodeMockRecorder) StateSectorPartition(arg0, arg1, arg2, arg3 } // StateSectorPreCommitInfo mocks base method. -func (m *MockFullNode) StateSectorPreCommitInfo(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) { +func (m *MockFullNode) StateSectorPreCommitInfo(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (*miner.SectorPreCommitOnChainInfo, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateSectorPreCommitInfo", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].(miner.SectorPreCommitOnChainInfo) + ret0, _ := ret[0].(*miner.SectorPreCommitOnChainInfo) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/api/proxy_gen.go b/api/proxy_gen.go index fff68ec3c..731c8b445 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -430,7 +430,7 @@ type FullNodeStruct struct { StateSectorPartition func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*lminer.SectorLocation, error) `perm:"read"` - StateSectorPreCommitInfo func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) `perm:"read"` + StateSectorPreCommitInfo func(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorPreCommitOnChainInfo, error) `perm:"read"` StateVMCirculatingSupplyInternal func(p0 context.Context, p1 types.TipSetKey) (CirculatingSupply, error) `perm:"read"` @@ -2895,15 +2895,15 @@ func (s *FullNodeStub) StateSectorPartition(p0 context.Context, p1 address.Addre return nil, ErrNotSupported } -func (s *FullNodeStruct) StateSectorPreCommitInfo(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) { +func (s *FullNodeStruct) StateSectorPreCommitInfo(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorPreCommitOnChainInfo, error) { if s.Internal.StateSectorPreCommitInfo == nil { - return *new(miner.SectorPreCommitOnChainInfo), ErrNotSupported + return nil, ErrNotSupported } return s.Internal.StateSectorPreCommitInfo(p0, p1, p2, p3) } -func (s *FullNodeStub) StateSectorPreCommitInfo(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) { - return *new(miner.SectorPreCommitOnChainInfo), ErrNotSupported +func (s *FullNodeStub) StateSectorPreCommitInfo(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorPreCommitOnChainInfo, error) { + return nil, ErrNotSupported } func (s *FullNodeStruct) StateVMCirculatingSupplyInternal(p0 context.Context, p1 types.TipSetKey) (CirculatingSupply, error) { diff --git a/api/v0api/v1_wrapper.go b/api/v0api/v1_wrapper.go index ea9754ea5..03757045e 100644 --- a/api/v0api/v1_wrapper.go +++ b/api/v0api/v1_wrapper.go @@ -12,6 +12,7 @@ import ( "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/builtin/v8/miner" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/api" @@ -24,6 +25,18 @@ type WrapperV1Full struct { v1api.FullNode } +func (w *WrapperV1Full) StateSectorPreCommitInfo(ctx context.Context, maddr address.Address, s abi.SectorNumber, tsk types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) { + pi, err := w.FullNode.StateSectorPreCommitInfo(ctx, maddr, s, tsk) + if err != nil { + return miner.SectorPreCommitOnChainInfo{}, err + } + if pi == nil { + return miner.SectorPreCommitOnChainInfo{}, xerrors.Errorf("precommit info does not exist") + } + + return *pi, nil +} + func (w *WrapperV1Full) StateSearchMsg(ctx context.Context, msg cid.Cid) (*api.MsgLookup, error) { return w.FullNode.StateSearchMsg(ctx, types.EmptyTSK, msg, api.LookbackNoLimit, true) } diff --git a/api/version.go b/api/version.go index b47a6ef33..3b50a9502 100644 --- a/api/version.go +++ b/api/version.go @@ -55,7 +55,7 @@ func VersionForType(nodeType NodeType) (Version, error) { // semver versions of the rpc api exposed var ( FullAPIVersion0 = newVer(1, 5, 0) - FullAPIVersion1 = newVer(2, 2, 0) + FullAPIVersion1 = newVer(2, 3, 0) MinerAPIVersion0 = newVer(1, 5, 0) WorkerAPIVersion0 = newVer(1, 6, 0) diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index f91027c32..6e2ff7986 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 b5e29c991..d08ba0635 100644 Binary files a/build/openrpc/gateway.json.gz and b/build/openrpc/gateway.json.gz differ diff --git a/build/openrpc/worker.json.gz b/build/openrpc/worker.json.gz index b2a3c7617..14aac394e 100644 Binary files a/build/openrpc/worker.json.gz and b/build/openrpc/worker.json.gz differ diff --git a/documentation/en/api-v0-methods-miner.md b/documentation/en/api-v0-methods-miner.md index 71067de3f..3fffdb2b8 100644 --- a/documentation/en/api-v0-methods-miner.md +++ b/documentation/en/api-v0-methods-miner.md @@ -233,7 +233,7 @@ Response: ```json { "Version": "string value", - "APIVersion": 131584, + "APIVersion": 131840, "BlockDelay": 42 } ``` diff --git a/documentation/en/api-v0-methods-worker.md b/documentation/en/api-v0-methods-worker.md index 4885d536d..f13562099 100644 --- a/documentation/en/api-v0-methods-worker.md +++ b/documentation/en/api-v0-methods-worker.md @@ -1460,7 +1460,7 @@ Perms: admin Inputs: `null` -Response: `131584` +Response: `131840` ## Add diff --git a/documentation/en/api-v0-methods.md b/documentation/en/api-v0-methods.md index 7060f9a81..62a929cf2 100644 --- a/documentation/en/api-v0-methods.md +++ b/documentation/en/api-v0-methods.md @@ -292,7 +292,7 @@ Response: ```json { "Version": "string value", - "APIVersion": 131584, + "APIVersion": 131840, "BlockDelay": 42 } ``` diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index 4a8b5bc16..d671b1047 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -300,7 +300,7 @@ Response: ```json { "Version": "string value", - "APIVersion": 131584, + "APIVersion": 131840, "BlockDelay": 42 } ``` @@ -6477,7 +6477,7 @@ Response: ``` ### StateMinerSectorAllocated -StateMinerSectorAllocated checks if a sector is allocated +StateMinerSectorAllocated checks if a sector number is marked as allocated. Perms: read @@ -6990,7 +6990,12 @@ Response: ``` ### StateSectorPreCommitInfo -StateSectorPreCommitInfo returns the PreCommit info for the specified miner's sector +StateSectorPreCommitInfo returns the PreCommit info for the specified miner's sector. +Returns nil and no error if the sector isn't precommitted. + +Note that the sector number may be allocated while PreCommitInfo is nil. This means that either allocated sector +numbers were compacted, and the sector number was marked as allocated in order to reduce size of the allocated +sectors bitfield, or that the sector was precommitted, but the precommit has expired. Perms: read diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 961d8e34c..e586dff02 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -880,20 +880,18 @@ func (a *StateAPI) StateMinerSectorCount(ctx context.Context, addr address.Addre return api.MinerSectors{Live: liveCount, Active: activeCount, Faulty: faultyCount}, nil } -func (a *StateAPI) StateSectorPreCommitInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (minertypes.SectorPreCommitOnChainInfo, error) { +func (a *StateAPI) StateSectorPreCommitInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*minertypes.SectorPreCommitOnChainInfo, error) { ts, err := a.Chain.GetTipSetFromKey(ctx, tsk) if err != nil { - return minertypes.SectorPreCommitOnChainInfo{}, xerrors.Errorf("loading tipset %s: %w", tsk, err) + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } pci, err := stmgr.PreCommitInfo(ctx, a.StateManager, maddr, n, ts) if err != nil { - return minertypes.SectorPreCommitOnChainInfo{}, err - } else if pci == nil { - return minertypes.SectorPreCommitOnChainInfo{}, xerrors.Errorf("precommit info is not exists") + return nil, err } - return *pci, err + return pci, err } func (m *StateModule) StateSectorGetInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorOnChainInfo, error) { diff --git a/storage/adapter_storage_miner.go b/storage/adapter_storage_miner.go index 242a16371..484af550c 100644 --- a/storage/adapter_storage_miner.go +++ b/storage/adapter_storage_miner.go @@ -4,7 +4,6 @@ import ( "context" "github.com/ipfs/go-cid" - "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" @@ -15,9 +14,7 @@ import ( "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/blockstore" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" - "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" pipeline "github.com/filecoin-project/lotus/storage/pipeline" ) @@ -118,36 +115,7 @@ func (s SealingAPIAdapter) StateSectorPartition(ctx context.Context, maddr addre } func (s SealingAPIAdapter) StateSectorPreCommitInfo(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tsk types.TipSetKey) (*minertypes.SectorPreCommitOnChainInfo, error) { - - act, err := s.delegate.StateGetActor(ctx, maddr, tsk) - if err != nil { - return nil, xerrors.Errorf("handleSealFailed(%d): temp error: %+v", sectorNumber, err) - } - - stor := store.ActorStore(ctx, blockstore.NewAPIBlockstore(s.delegate)) - - state, err := miner.Load(stor, act) - if err != nil { - return nil, xerrors.Errorf("handleSealFailed(%d): temp error: loading miner state: %+v", sectorNumber, err) - } - - pci, err := state.GetPrecommittedSector(sectorNumber) - if err != nil { - return nil, err - } - if pci == nil { - set, err := state.IsAllocated(sectorNumber) - if err != nil { - return nil, xerrors.Errorf("checking if sector is allocated: %w", err) - } - if set { - return nil, pipeline.ErrSectorAllocated - } - - return nil, nil - } - - return pci, nil + return s.delegate.StateSectorPreCommitInfo(ctx, maddr, sectorNumber, tsk) } func (s SealingAPIAdapter) SendMsg(ctx context.Context, from, to address.Address, method abi.MethodNum, value, maxFee abi.TokenAmount, params []byte) (cid.Cid, error) { diff --git a/storage/miner.go b/storage/miner.go index b43421243..280e62097 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -82,7 +82,7 @@ type fullNodeFilteredAPI interface { // Call a read only method on actors (no interaction with the chain required) StateCall(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error) StateMinerSectors(context.Context, address.Address, *bitfield.BitField, types.TipSetKey) ([]*miner.SectorOnChainInfo, error) - StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) + StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorPreCommitOnChainInfo, error) StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*lminer.SectorLocation, error) StateMinerInfo(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error) diff --git a/storage/pipeline/checks.go b/storage/pipeline/checks.go index 49aacd2fd..0da31b90f 100644 --- a/storage/pipeline/checks.go +++ b/storage/pipeline/checks.go @@ -107,10 +107,6 @@ func checkPrecommit(ctx context.Context, maddr address.Address, si SectorInfo, t pci, err := api.StateSectorPreCommitInfo(ctx, maddr, si.SectorNumber, tok) if err != nil { - if err == ErrSectorAllocated { - //committed P2 message but commit C2 message too late, pci should be null in this case - return &ErrSectorNumberAllocated{err} - } return &ErrApi{xerrors.Errorf("getting precommit info: %w", err)} } @@ -122,6 +118,15 @@ func checkPrecommit(ctx context.Context, maddr address.Address, si SectorInfo, t return &ErrPrecommitOnChain{xerrors.Errorf("precommit already on chain")} } + alloc, err := api.StateMinerSectorAllocated(ctx, maddr, si.SectorNumber, tok) + if err != nil { + return xerrors.Errorf("checking if sector is allocated: %w", err) + } + if alloc { + //committed P2 message but commit C2 message too late, pci should be null in this case + return &ErrSectorNumberAllocated{xerrors.Errorf("sector %d is allocated, but PreCommit info wasn't found on chain", si.SectorNumber)} + } + //never commit P2 message before, check ticket expiration ticketEarliest := height - policy.MaxPreCommitRandomnessLookback @@ -137,21 +142,26 @@ func (m *Sealing) checkCommit(ctx context.Context, si SectorInfo, proof []byte, } pci, err := m.Api.StateSectorPreCommitInfo(ctx, m.maddr, si.SectorNumber, tok) - if err == ErrSectorAllocated { - // not much more we can check here, basically try to wait for commit, - // and hope that this will work - - if si.CommitMessage != nil { - return &ErrCommitWaitFailed{err} - } - - return err - } if err != nil { return xerrors.Errorf("getting precommit info: %w", err) } if pci == nil { + alloc, err := m.Api.StateMinerSectorAllocated(ctx, m.maddr, si.SectorNumber, tok) + if err != nil { + return xerrors.Errorf("checking if sector is allocated: %w", err) + } + if alloc { + // not much more we can check here, basically try to wait for commit, + // and hope that this will work + + if si.CommitMessage != nil { + return &ErrCommitWaitFailed{err} + } + + return xerrors.Errorf("sector %d is allocated, but PreCommit info wasn't found on chain", si.SectorNumber) + } + return &ErrNoPrecommit{xerrors.Errorf("precommit info not found on-chain")} } diff --git a/storage/pipeline/mocks/api.go b/storage/pipeline/mocks/api.go index 74433ac1a..d393ef0a8 100644 --- a/storage/pipeline/mocks/api.go +++ b/storage/pipeline/mocks/api.go @@ -8,6 +8,9 @@ import ( context "context" reflect "reflect" + gomock "github.com/golang/mock/gomock" + cid "github.com/ipfs/go-cid" + address "github.com/filecoin-project/go-address" abi "github.com/filecoin-project/go-state-types/abi" big "github.com/filecoin-project/go-state-types/big" @@ -15,11 +18,10 @@ import ( crypto "github.com/filecoin-project/go-state-types/crypto" dline "github.com/filecoin-project/go-state-types/dline" network "github.com/filecoin-project/go-state-types/network" + api "github.com/filecoin-project/lotus/api" miner0 "github.com/filecoin-project/lotus/chain/actors/builtin/miner" types "github.com/filecoin-project/lotus/chain/types" - gomock "github.com/golang/mock/gomock" - cid "github.com/ipfs/go-cid" ) // MockSealingAPI is a mock of SealingAPI interface. @@ -45,21 +47,6 @@ func (m *MockSealingAPI) EXPECT() *MockSealingAPIMockRecorder { return m.recorder } -// ChainBaseFee mocks base method. -func (m *MockSealingAPI) ChainBaseFee(arg0 context.Context, arg1 types.TipSetKey) (big.Int, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ChainBaseFee", arg0, arg1) - ret0, _ := ret[0].(big.Int) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ChainBaseFee indicates an expected call of ChainBaseFee. -func (mr *MockSealingAPIMockRecorder) ChainBaseFee(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainBaseFee", reflect.TypeOf((*MockSealingAPI)(nil).ChainBaseFee), arg0, arg1) -} - // ChainGetMessage mocks base method. func (m *MockSealingAPI) ChainGetMessage(arg0 context.Context, arg1 cid.Cid) (*types.Message, error) { m.ctrl.T.Helper() diff --git a/storage/pipeline/mocks/mock_commit_batcher.go b/storage/pipeline/mocks/mock_commit_batcher.go index 260f956a0..d090b9459 100644 --- a/storage/pipeline/mocks/mock_commit_batcher.go +++ b/storage/pipeline/mocks/mock_commit_batcher.go @@ -8,15 +8,17 @@ import ( context "context" reflect "reflect" + gomock "github.com/golang/mock/gomock" + cid "github.com/ipfs/go-cid" + address "github.com/filecoin-project/go-address" abi "github.com/filecoin-project/go-state-types/abi" big "github.com/filecoin-project/go-state-types/big" miner "github.com/filecoin-project/go-state-types/builtin/v8/miner" network "github.com/filecoin-project/go-state-types/network" + api "github.com/filecoin-project/lotus/api" types "github.com/filecoin-project/lotus/chain/types" - gomock "github.com/golang/mock/gomock" - cid "github.com/ipfs/go-cid" ) // MockCommitBatcherApi is a mock of CommitBatcherApi interface. diff --git a/storage/pipeline/mocks/mock_precommit_batcher.go b/storage/pipeline/mocks/mock_precommit_batcher.go index 5a2e09166..dbe58f0fe 100644 --- a/storage/pipeline/mocks/mock_precommit_batcher.go +++ b/storage/pipeline/mocks/mock_precommit_batcher.go @@ -8,14 +8,16 @@ import ( context "context" reflect "reflect" + gomock "github.com/golang/mock/gomock" + cid "github.com/ipfs/go-cid" + address "github.com/filecoin-project/go-address" abi "github.com/filecoin-project/go-state-types/abi" big "github.com/filecoin-project/go-state-types/big" network "github.com/filecoin-project/go-state-types/network" + api "github.com/filecoin-project/lotus/api" types "github.com/filecoin-project/lotus/chain/types" - gomock "github.com/golang/mock/gomock" - cid "github.com/ipfs/go-cid" ) // MockPreCommitBatcherApi is a mock of PreCommitBatcherApi interface. diff --git a/storage/pipeline/sealing.go b/storage/pipeline/sealing.go index c3bae8036..82f0316ac 100644 --- a/storage/pipeline/sealing.go +++ b/storage/pipeline/sealing.go @@ -2,7 +2,6 @@ package sealing import ( "context" - "errors" "sync" "time" @@ -37,8 +36,6 @@ var ErrTooManySectorsSealing = xerrors.New("too many sectors sealing") var log = logging.Logger("sectors") -var ErrSectorAllocated = errors.New("sectorNumber is allocated, but PreCommit info wasn't found on chain") - //go:generate go run github.com/golang/mock/mockgen -destination=mocks/api.go -package=mocks . SealingAPI type SealingAPI interface { diff --git a/storage/pipeline/terminate_batch.go b/storage/pipeline/terminate_batch.go index dee880e7e..01675d019 100644 --- a/storage/pipeline/terminate_batch.go +++ b/storage/pipeline/terminate_batch.go @@ -3,7 +3,6 @@ package sealing import ( "bytes" "context" - lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "sort" "sync" "time" @@ -20,6 +19,7 @@ import ( "github.com/filecoin-project/go-state-types/dline" "github.com/filecoin-project/lotus/api" + lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/config" )