diff --git a/.circleci/config.yml b/.circleci/config.yml index 50f1b1696..4a69a4a49 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -806,6 +806,11 @@ workflows: suite: itest-gateway target: "./itests/gateway_test.go" + - test: + name: test-itest-get_messages_in_ts + suite: itest-get_messages_in_ts + target: "./itests/get_messages_in_ts_test.go" + - test: name: test-itest-multisig suite: itest-multisig diff --git a/api/api_full.go b/api/api_full.go index f07fa804e..52b7317f4 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -104,6 +104,9 @@ type FullNode interface { // specified block. ChainGetParentMessages(ctx context.Context, blockCid cid.Cid) ([]Message, error) //perm:read + // ChainGetMessagesInTipset returns message stores in current tipset + ChainGetMessagesInTipset(ctx context.Context, tsk types.TipSetKey) ([]Message, error) //perm:read + // ChainGetTipSetByHeight looks back for a tipset at the specified epoch. // If there are no blocks at the specified epoch, a tipset at an earlier epoch // will be returned. diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index 25029fa15..3ed9e6c3e 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -13,6 +13,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-bitfield" + "github.com/filecoin-project/go-multistore" "github.com/filecoin-project/lotus/node/repo/importmgr" "github.com/google/uuid" "github.com/ipfs/go-cid" @@ -88,6 +89,7 @@ func init() { addExample(pid) addExample(&pid) + multistoreIDExample := multistore.StoreID(50) storeIDExample := importmgr.ImportID(50) addExample(bitfield.NewFromSet([]uint64{5})) @@ -121,6 +123,8 @@ func init() { addExample(datatransfer.Ongoing) addExample(storeIDExample) addExample(&storeIDExample) + addExample(multistoreIDExample) + addExample(&multistoreIDExample) addExample(retrievalmarket.ClientEventDealAccepted) addExample(retrievalmarket.DealStatusNew) addExample(network.ReachabilityPublic) diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index 574d147e1..2105164dd 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -194,6 +194,21 @@ func (mr *MockFullNodeMockRecorder) ChainGetMessage(arg0, arg1 interface{}) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainGetMessage", reflect.TypeOf((*MockFullNode)(nil).ChainGetMessage), arg0, arg1) } +// ChainGetMessagesInTipset mocks base method. +func (m *MockFullNode) ChainGetMessagesInTipset(arg0 context.Context, arg1 types.TipSetKey) ([]api.Message, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ChainGetMessagesInTipset", arg0, arg1) + ret0, _ := ret[0].([]api.Message) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ChainGetMessagesInTipset indicates an expected call of ChainGetMessagesInTipset. +func (mr *MockFullNodeMockRecorder) ChainGetMessagesInTipset(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainGetMessagesInTipset", reflect.TypeOf((*MockFullNode)(nil).ChainGetMessagesInTipset), arg0, arg1) +} + // ChainGetNode mocks base method. func (m *MockFullNode) ChainGetNode(arg0 context.Context, arg1 string) (*api.IpldObject, error) { m.ctrl.T.Helper() diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 536952aac..412735b57 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -127,6 +127,8 @@ type FullNodeStruct struct { ChainGetMessage func(p0 context.Context, p1 cid.Cid) (*types.Message, error) `perm:"read"` + ChainGetMessagesInTipset func(p0 context.Context, p1 types.TipSetKey) ([]Message, error) `perm:"read"` + ChainGetNode func(p0 context.Context, p1 string) (*IpldObject, error) `perm:"read"` ChainGetParentMessages func(p0 context.Context, p1 cid.Cid) ([]Message, error) `perm:"read"` @@ -1101,6 +1103,14 @@ func (s *FullNodeStub) ChainGetMessage(p0 context.Context, p1 cid.Cid) (*types.M return nil, xerrors.New("method not supported") } +func (s *FullNodeStruct) ChainGetMessagesInTipset(p0 context.Context, p1 types.TipSetKey) ([]Message, error) { + return s.Internal.ChainGetMessagesInTipset(p0, p1) +} + +func (s *FullNodeStub) ChainGetMessagesInTipset(p0 context.Context, p1 types.TipSetKey) ([]Message, error) { + return *new([]Message), xerrors.New("method not supported") +} + func (s *FullNodeStruct) ChainGetNode(p0 context.Context, p1 string) (*IpldObject, error) { return s.Internal.ChainGetNode(p0, p1) } diff --git a/api/v0api/full.go b/api/v0api/full.go index 863cf54d9..2063f12a9 100644 --- a/api/v0api/full.go +++ b/api/v0api/full.go @@ -92,6 +92,9 @@ type FullNode interface { // specified block. ChainGetParentMessages(ctx context.Context, blockCid cid.Cid) ([]api.Message, error) //perm:read + // ChainGetMessagesInTipset returns message stores in current tipset + ChainGetMessagesInTipset(ctx context.Context, tsk types.TipSetKey) ([]api.Message, error) //perm:read + // ChainGetTipSetByHeight looks back for a tipset at the specified epoch. // If there are no blocks at the specified epoch, a tipset at an earlier epoch // will be returned. diff --git a/api/v0api/proxy_gen.go b/api/v0api/proxy_gen.go index 90597868f..adb802b00 100644 --- a/api/v0api/proxy_gen.go +++ b/api/v0api/proxy_gen.go @@ -45,6 +45,8 @@ type FullNodeStruct struct { ChainGetMessage func(p0 context.Context, p1 cid.Cid) (*types.Message, error) `perm:"read"` + ChainGetMessagesInTipset func(p0 context.Context, p1 types.TipSetKey) ([]api.Message, error) `perm:"read"` + ChainGetNode func(p0 context.Context, p1 string) (*api.IpldObject, error) `perm:"read"` ChainGetParentMessages func(p0 context.Context, p1 cid.Cid) ([]api.Message, error) `perm:"read"` @@ -514,6 +516,14 @@ func (s *FullNodeStub) ChainGetMessage(p0 context.Context, p1 cid.Cid) (*types.M return nil, xerrors.New("method not supported") } +func (s *FullNodeStruct) ChainGetMessagesInTipset(p0 context.Context, p1 types.TipSetKey) ([]api.Message, error) { + return s.Internal.ChainGetMessagesInTipset(p0, p1) +} + +func (s *FullNodeStub) ChainGetMessagesInTipset(p0 context.Context, p1 types.TipSetKey) ([]api.Message, error) { + return *new([]api.Message), xerrors.New("method not supported") +} + func (s *FullNodeStruct) ChainGetNode(p0 context.Context, p1 string) (*api.IpldObject, error) { return s.Internal.ChainGetNode(p0, p1) } diff --git a/api/v0api/v0mocks/mock_full.go b/api/v0api/v0mocks/mock_full.go index 12367f9fc..d761a4c2a 100644 --- a/api/v0api/v0mocks/mock_full.go +++ b/api/v0api/v0mocks/mock_full.go @@ -194,6 +194,21 @@ func (mr *MockFullNodeMockRecorder) ChainGetMessage(arg0, arg1 interface{}) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainGetMessage", reflect.TypeOf((*MockFullNode)(nil).ChainGetMessage), arg0, arg1) } +// ChainGetMessagesInTipset mocks base method. +func (m *MockFullNode) ChainGetMessagesInTipset(arg0 context.Context, arg1 types.TipSetKey) ([]api.Message, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ChainGetMessagesInTipset", arg0, arg1) + ret0, _ := ret[0].([]api.Message) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ChainGetMessagesInTipset indicates an expected call of ChainGetMessagesInTipset. +func (mr *MockFullNodeMockRecorder) ChainGetMessagesInTipset(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainGetMessagesInTipset", reflect.TypeOf((*MockFullNode)(nil).ChainGetMessagesInTipset), arg0, arg1) +} + // ChainGetNode mocks base method. func (m *MockFullNode) ChainGetNode(arg0 context.Context, arg1 string) (*api.IpldObject, error) { m.ctrl.T.Helper() diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index b530ca9cb..c8e03bd03 100644 Binary files a/build/openrpc/full.json.gz and b/build/openrpc/full.json.gz differ diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index f4684f567..fb6fb7384 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 bb13c8cab..514b75335 100644 Binary files a/build/openrpc/worker.json.gz and b/build/openrpc/worker.json.gz differ diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index dd2e47a57..6d22a294d 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -297,22 +297,26 @@ func TestForkRefuseCall(t *testing.T) { t.Fatal(err) } + pts, err := cg.ChainStore().LoadTipSet(ts.TipSet.TipSet().Parents()) + require.NoError(t, err) + parentHeight := pts.Height() + currentHeight := ts.TipSet.TipSet().Height() + + // CallWithGas calls _at_ the current tipset. ret, err := sm.CallWithGas(ctx, m, nil, ts.TipSet.TipSet()) - switch ts.TipSet.TipSet().Height() { - case testForkHeight, testForkHeight + 1: + if parentHeight <= testForkHeight && currentHeight >= testForkHeight { // If I had a fork, or I _will_ have a fork, it should fail. require.Equal(t, ErrExpensiveFork, err) - default: + } else { require.NoError(t, err) require.True(t, ret.MsgRct.ExitCode.IsSuccess()) } - // Call just runs on the parent state for a tipset, so we only - // expect an error at the fork height. + + // Call always applies the message to the "next block" after the tipset's parent state. ret, err = sm.Call(ctx, m, ts.TipSet.TipSet()) - switch ts.TipSet.TipSet().Height() { - case testForkHeight + 1: + if parentHeight == testForkHeight { require.Equal(t, ErrExpensiveFork, err) - default: + } else { require.NoError(t, err) require.True(t, ret.MsgRct.ExitCode.IsSuccess()) } diff --git a/documentation/en/api-v0-methods-miner.md b/documentation/en/api-v0-methods-miner.md index e69de29bb..89a017430 100644 --- a/documentation/en/api-v0-methods-miner.md +++ b/documentation/en/api-v0-methods-miner.md @@ -0,0 +1,2302 @@ +# Groups +* [](#) + * [Closing](#Closing) + * [Discover](#Discover) + * [Session](#Session) + * [Shutdown](#Shutdown) + * [Version](#Version) +* [Actor](#Actor) + * [ActorAddress](#ActorAddress) + * [ActorAddressConfig](#ActorAddressConfig) + * [ActorSectorSize](#ActorSectorSize) +* [Auth](#Auth) + * [AuthNew](#AuthNew) + * [AuthVerify](#AuthVerify) +* [Check](#Check) + * [CheckProvable](#CheckProvable) +* [Compute](#Compute) + * [ComputeProof](#ComputeProof) +* [Create](#Create) + * [CreateBackup](#CreateBackup) +* [Deals](#Deals) + * [DealsConsiderOfflineRetrievalDeals](#DealsConsiderOfflineRetrievalDeals) + * [DealsConsiderOfflineStorageDeals](#DealsConsiderOfflineStorageDeals) + * [DealsConsiderOnlineRetrievalDeals](#DealsConsiderOnlineRetrievalDeals) + * [DealsConsiderOnlineStorageDeals](#DealsConsiderOnlineStorageDeals) + * [DealsConsiderUnverifiedStorageDeals](#DealsConsiderUnverifiedStorageDeals) + * [DealsConsiderVerifiedStorageDeals](#DealsConsiderVerifiedStorageDeals) + * [DealsImportData](#DealsImportData) + * [DealsList](#DealsList) + * [DealsPieceCidBlocklist](#DealsPieceCidBlocklist) + * [DealsSetConsiderOfflineRetrievalDeals](#DealsSetConsiderOfflineRetrievalDeals) + * [DealsSetConsiderOfflineStorageDeals](#DealsSetConsiderOfflineStorageDeals) + * [DealsSetConsiderOnlineRetrievalDeals](#DealsSetConsiderOnlineRetrievalDeals) + * [DealsSetConsiderOnlineStorageDeals](#DealsSetConsiderOnlineStorageDeals) + * [DealsSetConsiderUnverifiedStorageDeals](#DealsSetConsiderUnverifiedStorageDeals) + * [DealsSetConsiderVerifiedStorageDeals](#DealsSetConsiderVerifiedStorageDeals) + * [DealsSetPieceCidBlocklist](#DealsSetPieceCidBlocklist) +* [I](#I) + * [ID](#ID) +* [Log](#Log) + * [LogList](#LogList) + * [LogSetLevel](#LogSetLevel) +* [Market](#Market) + * [MarketCancelDataTransfer](#MarketCancelDataTransfer) + * [MarketDataTransferUpdates](#MarketDataTransferUpdates) + * [MarketGetAsk](#MarketGetAsk) + * [MarketGetDealUpdates](#MarketGetDealUpdates) + * [MarketGetRetrievalAsk](#MarketGetRetrievalAsk) + * [MarketImportDealData](#MarketImportDealData) + * [MarketListDataTransfers](#MarketListDataTransfers) + * [MarketListDeals](#MarketListDeals) + * [MarketListIncompleteDeals](#MarketListIncompleteDeals) + * [MarketListRetrievalDeals](#MarketListRetrievalDeals) + * [MarketPendingDeals](#MarketPendingDeals) + * [MarketPublishPendingDeals](#MarketPublishPendingDeals) + * [MarketRestartDataTransfer](#MarketRestartDataTransfer) + * [MarketSetAsk](#MarketSetAsk) + * [MarketSetRetrievalAsk](#MarketSetRetrievalAsk) +* [Mining](#Mining) + * [MiningBase](#MiningBase) +* [Net](#Net) + * [NetAddrsListen](#NetAddrsListen) + * [NetAgentVersion](#NetAgentVersion) + * [NetAutoNatStatus](#NetAutoNatStatus) + * [NetBandwidthStats](#NetBandwidthStats) + * [NetBandwidthStatsByPeer](#NetBandwidthStatsByPeer) + * [NetBandwidthStatsByProtocol](#NetBandwidthStatsByProtocol) + * [NetBlockAdd](#NetBlockAdd) + * [NetBlockList](#NetBlockList) + * [NetBlockRemove](#NetBlockRemove) + * [NetConnect](#NetConnect) + * [NetConnectedness](#NetConnectedness) + * [NetDisconnect](#NetDisconnect) + * [NetFindPeer](#NetFindPeer) + * [NetPeerInfo](#NetPeerInfo) + * [NetPeers](#NetPeers) + * [NetPubsubScores](#NetPubsubScores) +* [Pieces](#Pieces) + * [PiecesGetCIDInfo](#PiecesGetCIDInfo) + * [PiecesGetPieceInfo](#PiecesGetPieceInfo) + * [PiecesListCidInfos](#PiecesListCidInfos) + * [PiecesListPieces](#PiecesListPieces) +* [Pledge](#Pledge) + * [PledgeSector](#PledgeSector) +* [Return](#Return) + * [ReturnAddPiece](#ReturnAddPiece) + * [ReturnFetch](#ReturnFetch) + * [ReturnFinalizeSector](#ReturnFinalizeSector) + * [ReturnMoveStorage](#ReturnMoveStorage) + * [ReturnReadPiece](#ReturnReadPiece) + * [ReturnReleaseUnsealed](#ReturnReleaseUnsealed) + * [ReturnSealCommit1](#ReturnSealCommit1) + * [ReturnSealCommit2](#ReturnSealCommit2) + * [ReturnSealPreCommit1](#ReturnSealPreCommit1) + * [ReturnSealPreCommit2](#ReturnSealPreCommit2) + * [ReturnUnsealPiece](#ReturnUnsealPiece) +* [Sealing](#Sealing) + * [SealingAbort](#SealingAbort) + * [SealingSchedDiag](#SealingSchedDiag) +* [Sector](#Sector) + * [SectorAddPieceToAny](#SectorAddPieceToAny) + * [SectorCommitFlush](#SectorCommitFlush) + * [SectorCommitPending](#SectorCommitPending) + * [SectorGetExpectedSealDuration](#SectorGetExpectedSealDuration) + * [SectorGetSealDelay](#SectorGetSealDelay) + * [SectorMarkForUpgrade](#SectorMarkForUpgrade) + * [SectorPreCommitFlush](#SectorPreCommitFlush) + * [SectorPreCommitPending](#SectorPreCommitPending) + * [SectorRemove](#SectorRemove) + * [SectorSetExpectedSealDuration](#SectorSetExpectedSealDuration) + * [SectorSetSealDelay](#SectorSetSealDelay) + * [SectorStartSealing](#SectorStartSealing) + * [SectorTerminate](#SectorTerminate) + * [SectorTerminateFlush](#SectorTerminateFlush) + * [SectorTerminatePending](#SectorTerminatePending) +* [Sectors](#Sectors) + * [SectorsList](#SectorsList) + * [SectorsListInStates](#SectorsListInStates) + * [SectorsRefs](#SectorsRefs) + * [SectorsStatus](#SectorsStatus) + * [SectorsSummary](#SectorsSummary) + * [SectorsUnsealPiece](#SectorsUnsealPiece) + * [SectorsUpdate](#SectorsUpdate) +* [Storage](#Storage) + * [StorageAddLocal](#StorageAddLocal) + * [StorageAttach](#StorageAttach) + * [StorageBestAlloc](#StorageBestAlloc) + * [StorageDeclareSector](#StorageDeclareSector) + * [StorageDropSector](#StorageDropSector) + * [StorageFindSector](#StorageFindSector) + * [StorageInfo](#StorageInfo) + * [StorageList](#StorageList) + * [StorageLocal](#StorageLocal) + * [StorageLock](#StorageLock) + * [StorageReportHealth](#StorageReportHealth) + * [StorageStat](#StorageStat) + * [StorageTryLock](#StorageTryLock) +* [Worker](#Worker) + * [WorkerConnect](#WorkerConnect) + * [WorkerJobs](#WorkerJobs) + * [WorkerStats](#WorkerStats) +## + + +### Closing + + +Perms: read + +Inputs: `null` + +Response: `{}` + +### Discover + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "info": { + "title": "Lotus RPC API", + "version": "1.2.1/generated=2020-11-22T08:22:42-06:00" + }, + "methods": [], + "openrpc": "1.2.6" +} +``` + +### Session + + +Perms: read + +Inputs: `null` + +Response: `"07070707-0707-0707-0707-070707070707"` + +### Shutdown + + +Perms: admin + +Inputs: `null` + +Response: `{}` + +### Version + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "Version": "string value", + "APIVersion": 131328, + "BlockDelay": 42 +} +``` + +## Actor + + +### ActorAddress + + +Perms: read + +Inputs: `null` + +Response: `"f01234"` + +### ActorAddressConfig + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "PreCommitControl": null, + "CommitControl": null, + "TerminateControl": null, + "DealPublishControl": null, + "DisableOwnerFallback": true, + "DisableWorkerFallback": true +} +``` + +### ActorSectorSize + + +Perms: read + +Inputs: +```json +[ + "f01234" +] +``` + +Response: `34359738368` + +## Auth + + +### AuthNew + + +Perms: admin + +Inputs: +```json +[ + null +] +``` + +Response: `"Ynl0ZSBhcnJheQ=="` + +### AuthVerify + + +Perms: read + +Inputs: +```json +[ + "string value" +] +``` + +Response: `null` + +## Check + + +### CheckProvable + + +Perms: admin + +Inputs: +```json +[ + 8, + null, + true +] +``` + +Response: +```json +{ + "123": "can't acquire read lock" +} +``` + +## Compute + + +### ComputeProof + + +Perms: read + +Inputs: +```json +[ + null, + null +] +``` + +Response: `null` + +## Create + + +### CreateBackup +CreateBackup creates node backup onder the specified file name. The +method requires that the lotus-miner is running with the +LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that +the path specified when calling CreateBackup is within the base path + + +Perms: admin + +Inputs: +```json +[ + "string value" +] +``` + +Response: `{}` + +## Deals + + +### DealsConsiderOfflineRetrievalDeals + + +Perms: admin + +Inputs: `null` + +Response: `true` + +### DealsConsiderOfflineStorageDeals + + +Perms: admin + +Inputs: `null` + +Response: `true` + +### DealsConsiderOnlineRetrievalDeals + + +Perms: admin + +Inputs: `null` + +Response: `true` + +### DealsConsiderOnlineStorageDeals + + +Perms: admin + +Inputs: `null` + +Response: `true` + +### DealsConsiderUnverifiedStorageDeals + + +Perms: admin + +Inputs: `null` + +Response: `true` + +### DealsConsiderVerifiedStorageDeals + + +Perms: admin + +Inputs: `null` + +Response: `true` + +### DealsImportData + + +Perms: admin + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "string value" +] +``` + +Response: `{}` + +### DealsList + + +Perms: admin + +Inputs: `null` + +Response: `null` + +### DealsPieceCidBlocklist + + +Perms: admin + +Inputs: `null` + +Response: `null` + +### DealsSetConsiderOfflineRetrievalDeals + + +Perms: admin + +Inputs: +```json +[ + true +] +``` + +Response: `{}` + +### DealsSetConsiderOfflineStorageDeals + + +Perms: admin + +Inputs: +```json +[ + true +] +``` + +Response: `{}` + +### DealsSetConsiderOnlineRetrievalDeals + + +Perms: admin + +Inputs: +```json +[ + true +] +``` + +Response: `{}` + +### DealsSetConsiderOnlineStorageDeals + + +Perms: admin + +Inputs: +```json +[ + true +] +``` + +Response: `{}` + +### DealsSetConsiderUnverifiedStorageDeals + + +Perms: admin + +Inputs: +```json +[ + true +] +``` + +Response: `{}` + +### DealsSetConsiderVerifiedStorageDeals + + +Perms: admin + +Inputs: +```json +[ + true +] +``` + +Response: `{}` + +### DealsSetPieceCidBlocklist + + +Perms: admin + +Inputs: +```json +[ + null +] +``` + +Response: `{}` + +## I + + +### ID + + +Perms: read + +Inputs: `null` + +Response: `"12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf"` + +## Log + + +### LogList + + +Perms: write + +Inputs: `null` + +Response: `null` + +### LogSetLevel + + +Perms: write + +Inputs: +```json +[ + "string value", + "string value" +] +``` + +Response: `{}` + +## Market + + +### MarketCancelDataTransfer +MarketCancelDataTransfer cancels a data transfer with the given transfer ID and other peer + + +Perms: write + +Inputs: +```json +[ + 3, + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + true +] +``` + +Response: `{}` + +### MarketDataTransferUpdates + + +Perms: write + +Inputs: `null` + +Response: +```json +{ + "TransferID": 3, + "Status": 1, + "BaseCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "IsInitiator": true, + "IsSender": true, + "Voucher": "string value", + "Message": "string value", + "OtherPeer": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Transferred": 42, + "Stages": { + "Stages": null + } +} +``` + +### MarketGetAsk + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "Ask": { + "Price": "0", + "VerifiedPrice": "0", + "MinPieceSize": 1032, + "MaxPieceSize": 1032, + "Miner": "f01234", + "Timestamp": 10101, + "Expiry": 10101, + "SeqNo": 42 + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } +} +``` + +### MarketGetDealUpdates + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "Proposal": { + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1032, + "VerifiedDeal": true, + "Client": "f01234", + "Provider": "f01234", + "Label": "string value", + "StartEpoch": 10101, + "EndEpoch": 10101, + "StoragePricePerEpoch": "0", + "ProviderCollateral": "0", + "ClientCollateral": "0" + }, + "ClientSignature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "ProposalCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "AddFundsCid": null, + "PublishCid": null, + "Miner": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Client": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "State": 42, + "PiecePath": ".lotusminer/fstmp123", + "MetadataPath": ".lotusminer/fstmp123", + "SlashEpoch": 10101, + "FastRetrieval": true, + "Message": "string value", + "FundsReserved": "0", + "Ref": { + "TransferType": "string value", + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceCid": null, + "PieceSize": 1024, + "RawBlockSize": 42 + }, + "AvailableForRetrieval": true, + "DealID": 5432, + "CreationTime": "0001-01-01T00:00:00Z", + "TransferChannelId": { + "Initiator": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Responder": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "ID": 3 + }, + "SectorNumber": 9, + "CARv2FilePath": "string value" +} +``` + +### MarketGetRetrievalAsk + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "PricePerByte": "0", + "UnsealPrice": "0", + "PaymentInterval": 42, + "PaymentIntervalIncrease": 42 +} +``` + +### MarketImportDealData + + +Perms: write + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "string value" +] +``` + +Response: `{}` + +### MarketListDataTransfers + + +Perms: write + +Inputs: `null` + +Response: `null` + +### MarketListDeals + + +Perms: read + +Inputs: `null` + +Response: `null` + +### MarketListIncompleteDeals + + +Perms: read + +Inputs: `null` + +Response: `null` + +### MarketListRetrievalDeals + + +Perms: read + +Inputs: `null` + +Response: `null` + +### MarketPendingDeals + + +Perms: write + +Inputs: `null` + +Response: +```json +{ + "Deals": null, + "PublishPeriodStart": "0001-01-01T00:00:00Z", + "PublishPeriod": 60000000000 +} +``` + +### MarketPublishPendingDeals + + +Perms: admin + +Inputs: `null` + +Response: `{}` + +### MarketRestartDataTransfer +MarketRestartDataTransfer attempts to restart a data transfer with the given transfer ID and other peer + + +Perms: write + +Inputs: +```json +[ + 3, + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + true +] +``` + +Response: `{}` + +### MarketSetAsk + + +Perms: admin + +Inputs: +```json +[ + "0", + "0", + 10101, + 1032, + 1032 +] +``` + +Response: `{}` + +### MarketSetRetrievalAsk + + +Perms: admin + +Inputs: +```json +[ + { + "PricePerByte": "0", + "UnsealPrice": "0", + "PaymentInterval": 42, + "PaymentIntervalIncrease": 42 + } +] +``` + +Response: `{}` + +## Mining + + +### MiningBase + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "Cids": null, + "Blocks": null, + "Height": 0 +} +``` + +## Net + + +### NetAddrsListen + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Addrs": [] +} +``` + +### NetAgentVersion + + +Perms: read + +Inputs: +```json +[ + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" +] +``` + +Response: `"string value"` + +### NetAutoNatStatus + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "Reachability": 1, + "PublicAddr": "string value" +} +``` + +### NetBandwidthStats + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "TotalIn": 9, + "TotalOut": 9, + "RateIn": 12.3, + "RateOut": 12.3 +} +``` + +### NetBandwidthStatsByPeer + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "12D3KooWSXmXLJmBR1M7i9RW9GQPNUhZSzXKzxDHWtAgNuJAbyEJ": { + "TotalIn": 174000, + "TotalOut": 12500, + "RateIn": 100, + "RateOut": 50 + } +} +``` + +### NetBandwidthStatsByProtocol + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "/fil/hello/1.0.0": { + "TotalIn": 174000, + "TotalOut": 12500, + "RateIn": 100, + "RateOut": 50 + } +} +``` + +### NetBlockAdd + + +Perms: admin + +Inputs: +```json +[ + { + "Peers": null, + "IPAddrs": null, + "IPSubnets": null + } +] +``` + +Response: `{}` + +### NetBlockList + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "Peers": null, + "IPAddrs": null, + "IPSubnets": null +} +``` + +### NetBlockRemove + + +Perms: admin + +Inputs: +```json +[ + { + "Peers": null, + "IPAddrs": null, + "IPSubnets": null + } +] +``` + +Response: `{}` + +### NetConnect + + +Perms: write + +Inputs: +```json +[ + { + "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Addrs": [] + } +] +``` + +Response: `{}` + +### NetConnectedness + + +Perms: read + +Inputs: +```json +[ + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" +] +``` + +Response: `1` + +### NetDisconnect + + +Perms: write + +Inputs: +```json +[ + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" +] +``` + +Response: `{}` + +### NetFindPeer + + +Perms: read + +Inputs: +```json +[ + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" +] +``` + +Response: +```json +{ + "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Addrs": [] +} +``` + +### NetPeerInfo + + +Perms: read + +Inputs: +```json +[ + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" +] +``` + +Response: +```json +{ + "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Agent": "string value", + "Addrs": null, + "Protocols": null, + "ConnMgrMeta": { + "FirstSeen": "0001-01-01T00:00:00Z", + "Value": 123, + "Tags": { + "name": 42 + }, + "Conns": { + "name": "2021-03-08T22:52:18Z" + } + } +} +``` + +### NetPeers + + +Perms: read + +Inputs: `null` + +Response: `null` + +### NetPubsubScores + + +Perms: read + +Inputs: `null` + +Response: `null` + +## Pieces + + +### PiecesGetCIDInfo + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: +```json +{ + "CID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceBlockLocations": null +} +``` + +### PiecesGetPieceInfo + + +Perms: read + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: +```json +{ + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Deals": null +} +``` + +### PiecesListCidInfos + + +Perms: read + +Inputs: `null` + +Response: `null` + +### PiecesListPieces + + +Perms: read + +Inputs: `null` + +Response: `null` + +## Pledge + + +### PledgeSector +Temp api for testing + + +Perms: write + +Inputs: `null` + +Response: +```json +{ + "Miner": 1000, + "Number": 9 +} +``` + +## Return + + +### ReturnAddPiece +storiface.WorkerReturn + + +Perms: admin + +Inputs: +```json +[ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + }, + { + "Size": 1032, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + }, + { + "Code": 0, + "Message": "string value" + } +] +``` + +Response: `{}` + +### ReturnFetch + + +Perms: admin + +Inputs: +```json +[ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + }, + { + "Code": 0, + "Message": "string value" + } +] +``` + +Response: `{}` + +### ReturnFinalizeSector + + +Perms: admin + +Inputs: +```json +[ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + }, + { + "Code": 0, + "Message": "string value" + } +] +``` + +Response: `{}` + +### ReturnMoveStorage + + +Perms: admin + +Inputs: +```json +[ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + }, + { + "Code": 0, + "Message": "string value" + } +] +``` + +Response: `{}` + +### ReturnReadPiece + + +Perms: admin + +Inputs: +```json +[ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + }, + true, + { + "Code": 0, + "Message": "string value" + } +] +``` + +Response: `{}` + +### ReturnReleaseUnsealed + + +Perms: admin + +Inputs: +```json +[ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + }, + { + "Code": 0, + "Message": "string value" + } +] +``` + +Response: `{}` + +### ReturnSealCommit1 + + +Perms: admin + +Inputs: +```json +[ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + }, + null, + { + "Code": 0, + "Message": "string value" + } +] +``` + +Response: `{}` + +### ReturnSealCommit2 + + +Perms: admin + +Inputs: +```json +[ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + }, + null, + { + "Code": 0, + "Message": "string value" + } +] +``` + +Response: `{}` + +### ReturnSealPreCommit1 + + +Perms: admin + +Inputs: +```json +[ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + }, + null, + { + "Code": 0, + "Message": "string value" + } +] +``` + +Response: `{}` + +### ReturnSealPreCommit2 + + +Perms: admin + +Inputs: +```json +[ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + }, + { + "Unsealed": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Sealed": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + }, + { + "Code": 0, + "Message": "string value" + } +] +``` + +Response: `{}` + +### ReturnUnsealPiece + + +Perms: admin + +Inputs: +```json +[ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + }, + { + "Code": 0, + "Message": "string value" + } +] +``` + +Response: `{}` + +## Sealing + + +### SealingAbort + + +Perms: admin + +Inputs: +```json +[ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } +] +``` + +Response: `{}` + +### SealingSchedDiag +SealingSchedDiag dumps internal sealing scheduler state + + +Perms: admin + +Inputs: +```json +[ + true +] +``` + +Response: `{}` + +## Sector + + +### SectorAddPieceToAny +Add piece to an open sector. If no sectors with enough space are open, +either a new sector will be created, or this call will block until more +sectors can be created. + + +Perms: admin + +Inputs: +```json +[ + 1024, + {}, + { + "PublishCid": null, + "DealID": 5432, + "DealProposal": { + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1032, + "VerifiedDeal": true, + "Client": "f01234", + "Provider": "f01234", + "Label": "string value", + "StartEpoch": 10101, + "EndEpoch": 10101, + "StoragePricePerEpoch": "0", + "ProviderCollateral": "0", + "ClientCollateral": "0" + }, + "DealSchedule": { + "StartEpoch": 10101, + "EndEpoch": 10101 + }, + "KeepUnsealed": true + } +] +``` + +Response: +```json +{ + "Sector": 9, + "Offset": 1032 +} +``` + +### SectorCommitFlush +SectorCommitFlush immediately sends a Commit message with sectors aggregated for Commit. +Returns null if message wasn't sent + + +Perms: admin + +Inputs: `null` + +Response: `null` + +### SectorCommitPending +SectorCommitPending returns a list of pending Commit sectors to be sent in the next aggregate message + + +Perms: admin + +Inputs: `null` + +Response: `null` + +### SectorGetExpectedSealDuration +SectorGetExpectedSealDuration gets the expected time for a sector to seal + + +Perms: read + +Inputs: `null` + +Response: `60000000000` + +### SectorGetSealDelay +SectorGetSealDelay gets the time that a newly-created sector +waits for more deals before it starts sealing + + +Perms: read + +Inputs: `null` + +Response: `60000000000` + +### SectorMarkForUpgrade + + +Perms: admin + +Inputs: +```json +[ + 9 +] +``` + +Response: `{}` + +### SectorPreCommitFlush +SectorPreCommitFlush immediately sends a PreCommit message with sectors batched for PreCommit. +Returns null if message wasn't sent + + +Perms: admin + +Inputs: `null` + +Response: `null` + +### SectorPreCommitPending +SectorPreCommitPending returns a list of pending PreCommit sectors to be sent in the next batch message + + +Perms: admin + +Inputs: `null` + +Response: `null` + +### SectorRemove +SectorRemove removes the sector from storage. It doesn't terminate it on-chain, which can +be done with SectorTerminate. Removing and not terminating live sectors will cause additional penalties. + + +Perms: admin + +Inputs: +```json +[ + 9 +] +``` + +Response: `{}` + +### SectorSetExpectedSealDuration +SectorSetExpectedSealDuration sets the expected time for a sector to seal + + +Perms: write + +Inputs: +```json +[ + 60000000000 +] +``` + +Response: `{}` + +### SectorSetSealDelay +SectorSetSealDelay sets the time that a newly-created sector +waits for more deals before it starts sealing + + +Perms: write + +Inputs: +```json +[ + 60000000000 +] +``` + +Response: `{}` + +### SectorStartSealing +SectorStartSealing can be called on sectors in Empty or WaitDeals states +to trigger sealing early + + +Perms: write + +Inputs: +```json +[ + 9 +] +``` + +Response: `{}` + +### SectorTerminate +SectorTerminate terminates the sector on-chain (adding it to a termination batch first), then +automatically removes it from storage + + +Perms: admin + +Inputs: +```json +[ + 9 +] +``` + +Response: `{}` + +### SectorTerminateFlush +SectorTerminateFlush immediately sends a terminate message with sectors batched for termination. +Returns null if message wasn't sent + + +Perms: admin + +Inputs: `null` + +Response: `null` + +### SectorTerminatePending +SectorTerminatePending returns a list of pending sector terminations to be sent in the next batch message + + +Perms: admin + +Inputs: `null` + +Response: `null` + +## Sectors + + +### SectorsList +List all staged sectors + + +Perms: read + +Inputs: `null` + +Response: +```json +[ + 123, + 124 +] +``` + +### SectorsListInStates +List sectors in particular states + + +Perms: read + +Inputs: +```json +[ + null +] +``` + +Response: +```json +[ + 123, + 124 +] +``` + +### SectorsRefs + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "98000": [ + { + "SectorID": 100, + "Offset": 10485760, + "Size": 1048576 + } + ] +} +``` + +### SectorsStatus +Get the status of a given sector by ID + + +Perms: read + +Inputs: +```json +[ + 9, + true +] +``` + +Response: +```json +{ + "SectorID": 9, + "State": "Proving", + "CommD": null, + "CommR": null, + "Proof": "Ynl0ZSBhcnJheQ==", + "Deals": null, + "Ticket": { + "Value": null, + "Epoch": 10101 + }, + "Seed": { + "Value": null, + "Epoch": 10101 + }, + "PreCommitMsg": null, + "CommitMsg": null, + "Retries": 42, + "ToUpgrade": true, + "LastErr": "string value", + "Log": null, + "SealProof": 8, + "Activation": 10101, + "Expiration": 10101, + "DealWeight": "0", + "VerifiedDealWeight": "0", + "InitialPledge": "0", + "OnTime": 10101, + "Early": 10101 +} +``` + +### SectorsSummary +Get summary info of sectors + + +Perms: read + +Inputs: `null` + +Response: +```json +{ + "Proving": 120 +} +``` + +### SectorsUnsealPiece + + +Perms: admin + +Inputs: +```json +[ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + }, + 1040384, + 1024, + null, + null +] +``` + +Response: `{}` + +### SectorsUpdate + + +Perms: admin + +Inputs: +```json +[ + 9, + "Proving" +] +``` + +Response: `{}` + +## Storage + + +### StorageAddLocal + + +Perms: admin + +Inputs: +```json +[ + "string value" +] +``` + +Response: `{}` + +### StorageAttach +stores.SectorIndex + + +Perms: admin + +Inputs: +```json +[ + { + "ID": "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8", + "URLs": null, + "Weight": 42, + "MaxStorage": 42, + "CanSeal": true, + "CanStore": true + }, + { + "Capacity": 9, + "Available": 9, + "FSAvailable": 9, + "Reserved": 9, + "Max": 9, + "Used": 9 + } +] +``` + +Response: `{}` + +### StorageBestAlloc + + +Perms: admin + +Inputs: +```json +[ + 1, + 34359738368, + "sealing" +] +``` + +Response: `null` + +### StorageDeclareSector + + +Perms: admin + +Inputs: +```json +[ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8", + { + "Miner": 1000, + "Number": 9 + }, + 1, + true +] +``` + +Response: `{}` + +### StorageDropSector + + +Perms: admin + +Inputs: +```json +[ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8", + { + "Miner": 1000, + "Number": 9 + }, + 1 +] +``` + +Response: `{}` + +### StorageFindSector + + +Perms: admin + +Inputs: +```json +[ + { + "Miner": 1000, + "Number": 9 + }, + 1, + 34359738368, + true +] +``` + +Response: `null` + +### StorageInfo + + +Perms: admin + +Inputs: +```json +[ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8" +] +``` + +Response: +```json +{ + "ID": "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8", + "URLs": null, + "Weight": 42, + "MaxStorage": 42, + "CanSeal": true, + "CanStore": true +} +``` + +### StorageList + + +Perms: admin + +Inputs: `null` + +Response: +```json +{ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8": [ + { + "Miner": 1000, + "Number": 100, + "SectorFileType": 2 + } + ] +} +``` + +### StorageLocal + + +Perms: admin + +Inputs: `null` + +Response: +```json +{ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8": "/data/path" +} +``` + +### StorageLock + + +Perms: admin + +Inputs: +```json +[ + { + "Miner": 1000, + "Number": 9 + }, + 1, + 1 +] +``` + +Response: `{}` + +### StorageReportHealth + + +Perms: admin + +Inputs: +```json +[ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8", + { + "Stat": { + "Capacity": 9, + "Available": 9, + "FSAvailable": 9, + "Reserved": 9, + "Max": 9, + "Used": 9 + }, + "Err": "string value" + } +] +``` + +Response: `{}` + +### StorageStat + + +Perms: admin + +Inputs: +```json +[ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8" +] +``` + +Response: +```json +{ + "Capacity": 9, + "Available": 9, + "FSAvailable": 9, + "Reserved": 9, + "Max": 9, + "Used": 9 +} +``` + +### StorageTryLock + + +Perms: admin + +Inputs: +```json +[ + { + "Miner": 1000, + "Number": 9 + }, + 1, + 1 +] +``` + +Response: `true` + +## Worker + + +### WorkerConnect +WorkerConnect tells the node to connect to workers RPC + + +Perms: admin + +Inputs: +```json +[ + "string value" +] +``` + +Response: `{}` + +### WorkerJobs + + +Perms: admin + +Inputs: `null` + +Response: +```json +{ + "ef8d99a2-6865-4189-8ffa-9fef0f806eee": [ + { + "ID": { + "Sector": { + "Miner": 1000, + "Number": 100 + }, + "ID": "76081ba0-61bd-45a5-bc08-af05f1c26e5d" + }, + "Sector": { + "Miner": 1000, + "Number": 100 + }, + "Task": "seal/v0/precommit/2", + "RunWait": 0, + "Start": "2020-11-12T09:22:07Z", + "Hostname": "host" + } + ] +} +``` + +### WorkerStats + + +Perms: admin + +Inputs: `null` + +Response: +```json +{ + "ef8d99a2-6865-4189-8ffa-9fef0f806eee": { + "Info": { + "Hostname": "host", + "IgnoreResources": false, + "Resources": { + "MemPhysical": 274877906944, + "MemSwap": 128849018880, + "MemReserved": 2147483648, + "CPUs": 64, + "GPUs": [ + "aGPU 1337" + ] + } + }, + "Enabled": true, + "MemUsedMin": 0, + "MemUsedMax": 0, + "GpuUsed": false, + "CpuUse": 0 + } +} +``` + diff --git a/documentation/en/api-v0-methods.md b/documentation/en/api-v0-methods.md index f8f090dfa..efdb191b4 100644 --- a/documentation/en/api-v0-methods.md +++ b/documentation/en/api-v0-methods.md @@ -17,6 +17,7 @@ * [ChainGetBlockMessages](#ChainGetBlockMessages) * [ChainGetGenesis](#ChainGetGenesis) * [ChainGetMessage](#ChainGetMessage) + * [ChainGetMessagesInTipset](#ChainGetMessagesInTipset) * [ChainGetNode](#ChainGetNode) * [ChainGetParentMessages](#ChainGetParentMessages) * [ChainGetParentReceipts](#ChainGetParentReceipts) @@ -533,6 +534,28 @@ Response: } ``` +### ChainGetMessagesInTipset +ChainGetMessagesInTipset returns message stores in current tipset + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `null` + ### ChainGetNode diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index e80a5ebb8..6084e8ede 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -17,6 +17,7 @@ * [ChainGetBlockMessages](#ChainGetBlockMessages) * [ChainGetGenesis](#ChainGetGenesis) * [ChainGetMessage](#ChainGetMessage) + * [ChainGetMessagesInTipset](#ChainGetMessagesInTipset) * [ChainGetNode](#ChainGetNode) * [ChainGetParentMessages](#ChainGetParentMessages) * [ChainGetParentReceipts](#ChainGetParentReceipts) @@ -535,6 +536,28 @@ Response: } ``` +### ChainGetMessagesInTipset +ChainGetMessagesInTipset returns message stores in current tipset + + +Perms: read + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `null` + ### ChainGetNode diff --git a/go.mod b/go.mod index ce806a1ac..e1eda8cfc 100644 --- a/go.mod +++ b/go.mod @@ -36,6 +36,7 @@ require ( github.com/filecoin-project/go-fil-commcid v0.0.0-20201016201715-d41df56b4f6a github.com/filecoin-project/go-fil-markets v1.6.0-rc1.0.20210715083804-52c35483392f github.com/filecoin-project/go-jsonrpc v0.1.4-0.20210217175800-45ea43ac2bec + github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 github.com/filecoin-project/go-paramfetch v0.0.2-0.20210614165157-25a6c7769498 github.com/filecoin-project/go-state-types v0.1.1-0.20210506134452-99b279731c48 @@ -156,6 +157,8 @@ require ( gotest.tools v2.2.0+incompatible ) +replace github.com/multiformats/go-multihash => github.com/multiformats/go-multihash v0.0.14 + replace github.com/libp2p/go-libp2p-yamux => github.com/libp2p/go-libp2p-yamux v0.5.1 replace github.com/filecoin-project/lotus => ./ diff --git a/go.sum b/go.sum index 64e30b171..a8d59e265 100644 --- a/go.sum +++ b/go.sum @@ -827,8 +827,6 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/cpuid/v2 v2.0.4 h1:g0I61F2K2DjRHz1cnxlkNSBIaePVoJIjjnHui8QHbiw= -github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= @@ -1228,9 +1226,8 @@ github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+ github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= -github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -1290,16 +1287,8 @@ github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77 github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= github.com/multiformats/go-multicodec v0.2.1-0.20210713081508-b421db6850ae h1:wfljHPpiR0UDOjeqld9ds0Zxl3Nt/j+0wnvyBc01JgY= github.com/multiformats/go-multicodec v0.2.1-0.20210713081508-b421db6850ae/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ= -github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= -github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= -github.com/multiformats/go-multihash v0.0.7/go.mod h1:XuKXPp8VHcTygube3OWZC+aZrA+H1IhmjoCDtJc7PXM= -github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.0.15 h1:hWOPdrNqDjwHDx82vsYGSDZNyktOJJ2dzZJzFkOV1jM= -github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= github.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/multiformats/go-multistream v0.0.4/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= @@ -1712,7 +1701,6 @@ golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1734,7 +1722,6 @@ golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf h1:B2n+Zi5QeYRDAEodEu72OS36gmTWjgpXr2+cWcBW90o= golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= @@ -1861,7 +1848,6 @@ golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1916,12 +1902,10 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426080607-c94f62235c83 h1:kHSDPqCtsHZOg0nVylfTo20DDhE9gG4Y0jn7hKQ0QAM= golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/itests/deals_test.go b/itests/deals_test.go index f2e106f1f..499b53167 100644 --- a/itests/deals_test.go +++ b/itests/deals_test.go @@ -39,4 +39,9 @@ func TestDealsWithSealingAndRPC(t *testing.T) { dh.RunConcurrentDeals(kit.RunConcurrentDealsOpts{N: 1, FastRetrieval: true}) dh.RunConcurrentDeals(kit.RunConcurrentDealsOpts{N: 1, FastRetrieval: true}) }) + + t.Run("stdretrieval-carv1", func(t *testing.T) { + dh.RunConcurrentDeals(kit.RunConcurrentDealsOpts{N: 1, UseCARFileForStorageDeal: true}) + }) + } diff --git a/itests/get_messages_in_ts_test.go b/itests/get_messages_in_ts_test.go new file mode 100644 index 000000000..61219a316 --- /dev/null +++ b/itests/get_messages_in_ts_test.go @@ -0,0 +1,104 @@ +package itests + +import ( + "context" + "testing" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/itests/kit" + "github.com/stretchr/testify/require" + + "time" + + "github.com/filecoin-project/go-state-types/big" +) + +func TestChainGetMessagesInTs(t *testing.T) { + ctx := context.Background() + + kit.QuietMiningLogs() + + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs()) + ens.InterconnectAll().BeginMining(10 * time.Millisecond) + + // create a new address where to send funds. + addr, err := client.WalletNew(ctx, types.KTBLS) + require.NoError(t, err) + + // get the existing balance from the default wallet to then split it. + bal, err := client.WalletBalance(ctx, client.DefaultKey.Address) + require.NoError(t, err) + + const iterations = 100 + + // we'll send half our balance (saving the other half for gas), + // in `iterations` increments. + toSend := big.Div(bal, big.NewInt(2)) + each := big.Div(toSend, big.NewInt(iterations)) + + waitAllCh := make(chan struct{}) + go func() { + headChangeCh, err := client.ChainNotify(ctx) + require.NoError(t, err) + <-headChangeCh //skip hccurrent + + count := 0 + for { + select { + case headChanges := <-headChangeCh: + for _, change := range headChanges { + if change.Type == store.HCApply { + msgs, err := client.ChainGetMessagesInTipset(ctx, change.Val.Key()) + require.NoError(t, err) + count += len(msgs) + if count == iterations { + waitAllCh <- struct{}{} + } + } + } + } + } + }() + + var sms []*types.SignedMessage + for i := 0; i < iterations; i++ { + msg := &types.Message{ + From: client.DefaultKey.Address, + To: addr, + Value: each, + } + + sm, err := client.MpoolPushMessage(ctx, msg, nil) + require.NoError(t, err) + require.EqualValues(t, i, sm.Message.Nonce) + + sms = append(sms, sm) + } + + select { + case <-waitAllCh: + case <-time.After(time.Minute): + t.Errorf("timeout to wait for pack messages") + } + + for _, sm := range sms { + msgLookup, err := client.StateWaitMsg(ctx, sm.Cid(), 3, api.LookbackNoLimit, true) + require.NoError(t, err) + + ts, err := client.ChainGetTipSet(ctx, msgLookup.TipSet) + require.NoError(t, err) + + msgs, err := client.ChainGetMessagesInTipset(ctx, ts.Parents()) + require.NoError(t, err) + + var found bool + for _, msg := range msgs { + if msg.Cid == sm.Cid() { + found = true + } + } + require.EqualValues(t, true, found, "expect got message in tipset %v", msgLookup.TipSet) + } +} diff --git a/itests/kit/deals.go b/itests/kit/deals.go index 4cee13925..e9edb7d39 100644 --- a/itests/kit/deals.go +++ b/itests/kit/deals.go @@ -33,9 +33,10 @@ type DealHarness struct { } type MakeFullDealParams struct { - Rseed int - FastRet bool - StartEpoch abi.ChainEpoch + Rseed int + FastRet bool + StartEpoch abi.ChainEpoch + UseCARFileForStorageDeal bool // SuspendUntilCryptoeconStable suspends deal-making, until cryptoecon // parameters are stabilised. This affects projected collateral, and tests @@ -78,7 +79,11 @@ func NewDealHarness(t *testing.T, client *TestFullNode, main *TestMiner, market // // TODO: convert input parameters to struct, and add size as an input param. func (dh *DealHarness) MakeOnlineDeal(ctx context.Context, params MakeFullDealParams) (deal *cid.Cid, res *api.ImportRes, path string) { - res, path = dh.client.CreateImportFile(ctx, params.Rseed, 0) + if params.UseCARFileForStorageDeal { + res, _, path = dh.client.ClientImportCARFile(ctx, params.Rseed, 200) + } else { + res, path = dh.client.CreateImportFile(ctx, params.Rseed, 0) + } dh.t.Logf("FILE CID: %s", res.Root) @@ -281,10 +286,11 @@ func (dh *DealHarness) ExtractFileFromCAR(ctx context.Context, file *os.File) (o } type RunConcurrentDealsOpts struct { - N int - FastRetrieval bool - CarExport bool - StartEpoch abi.ChainEpoch + N int + FastRetrieval bool + CarExport bool + StartEpoch abi.ChainEpoch + UseCARFileForStorageDeal bool } func (dh *DealHarness) RunConcurrentDeals(opts RunConcurrentDealsOpts) { @@ -300,9 +306,10 @@ func (dh *DealHarness) RunConcurrentDeals(opts RunConcurrentDealsOpts) { } }() deal, res, inPath := dh.MakeOnlineDeal(context.Background(), MakeFullDealParams{ - Rseed: 5 + i, - FastRet: opts.FastRetrieval, - StartEpoch: opts.StartEpoch, + Rseed: 5 + i, + FastRet: opts.FastRetrieval, + StartEpoch: opts.StartEpoch, + UseCARFileForStorageDeal: opts.UseCARFileForStorageDeal, }) outPath := dh.PerformRetrieval(context.Background(), deal, res.Root, opts.CarExport) AssertFilesEqual(dh.t, inPath, outPath) diff --git a/itests/kit/files.go b/itests/kit/files.go index 48592b518..9babac941 100644 --- a/itests/kit/files.go +++ b/itests/kit/files.go @@ -1,17 +1,38 @@ package kit import ( + "bufio" "bytes" + "context" "io" "math/rand" "os" "testing" + "github.com/ipfs/go-blockservice" + "github.com/ipfs/go-cid" + cidutil "github.com/ipfs/go-cidutil" + ds "github.com/ipfs/go-datastore" + dssync "github.com/ipfs/go-datastore/sync" + bstore "github.com/ipfs/go-ipfs-blockstore" + chunk "github.com/ipfs/go-ipfs-chunker" + offline "github.com/ipfs/go-ipfs-exchange-offline" + files "github.com/ipfs/go-ipfs-files" + ipldformat "github.com/ipfs/go-ipld-format" + "github.com/ipfs/go-merkledag" + "github.com/ipfs/go-unixfs/importer/balanced" + ihelper "github.com/ipfs/go-unixfs/importer/helpers" + "github.com/ipld/go-car" "github.com/minio/blake2b-simd" + mh "github.com/multiformats/go-multihash" "github.com/stretchr/testify/require" ) +const unixfsChunkSize uint64 = 1 << 10 + +var defaultHashFunction = uint64(mh.BLAKE2B_MIN + 31) + // CreateRandomFile creates a random file with the provided seed and the // provided size. func CreateRandomFile(t *testing.T, rseed, size int) (path string) { @@ -31,6 +52,79 @@ func CreateRandomFile(t *testing.T, rseed, size int) (path string) { return file.Name() } +// CreateRandomFile creates a normal file with the provided seed and the +// provided size and then transforms it to a CARv1 file and returns it. +func CreateRandomCARv1(t *testing.T, rseed, size int) (carV1FilePath string, origFilePath string) { + ctx := context.Background() + if size == 0 { + size = 1600 + } + + source := io.LimitReader(rand.New(rand.NewSource(int64(rseed))), int64(size)) + + file, err := os.CreateTemp(t.TempDir(), "sourcefile.dat") + require.NoError(t, err) + + n, err := io.Copy(file, source) + require.NoError(t, err) + require.EqualValues(t, n, size) + + // + _, err = file.Seek(0, io.SeekStart) + require.NoError(t, err) + bs := bstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())) + dagSvc := merkledag.NewDAGService(blockservice.New(bs, offline.Exchange(bs))) + + root := writeUnixfsDAG(ctx, t, file, dagSvc) + + // create a CARv1 file from the DAG + tmp, err := os.CreateTemp(t.TempDir(), "randcarv1") + require.NoError(t, err) + require.NoError(t, car.WriteCar(ctx, dagSvc, []cid.Cid{root}, tmp)) + _, err = tmp.Seek(0, io.SeekStart) + require.NoError(t, err) + hd, _, err := car.ReadHeader(bufio.NewReader(tmp)) + require.NoError(t, err) + require.EqualValues(t, 1, hd.Version) + require.Len(t, hd.Roots, 1) + require.NoError(t, tmp.Close()) + + return tmp.Name(), file.Name() +} + +func writeUnixfsDAG(ctx context.Context, t *testing.T, rd io.Reader, dag ipldformat.DAGService) cid.Cid { + rpf := files.NewReaderFile(rd) + + // generate the dag and get the root + // import to UnixFS + prefix, err := merkledag.PrefixForCidVersion(1) + require.NoError(t, err) + prefix.MhType = defaultHashFunction + + bufferedDS := ipldformat.NewBufferedDAG(ctx, dag) + params := ihelper.DagBuilderParams{ + Maxlinks: 1024, + RawLeaves: true, + CidBuilder: cidutil.InlineBuilder{ + Builder: prefix, + Limit: 126, + }, + Dagserv: bufferedDS, + } + + db, err := params.New(chunk.NewSizeSplitter(rpf, int64(unixfsChunkSize))) + require.NoError(t, err) + + nd, err := balanced.Layout(db) + require.NoError(t, err) + require.NotEqualValues(t, cid.Undef, nd.Cid()) + + err = bufferedDS.Commit() + require.NoError(t, err) + require.NoError(t, rpf.Close()) + return nd.Cid() +} + // AssertFilesEqual compares two files by blake2b hash equality and // fails the test if unequal. func AssertFilesEqual(t *testing.T, left, right string) { diff --git a/itests/kit/node_full.go b/itests/kit/node_full.go index 83586e188..b606db8f4 100644 --- a/itests/kit/node_full.go +++ b/itests/kit/node_full.go @@ -28,6 +28,13 @@ type TestFullNode struct { options nodeOpts } +func (f *TestFullNode) ClientImportCARFile(ctx context.Context, rseed int, size int) (res *api.ImportRes, carv1FilePath string, origFilePath string) { + carv1FilePath, origFilePath = CreateRandomCARv1(f.t, rseed, size) + res, err := f.ClientImport(ctx, api.FileRef{Path: carv1FilePath, IsCAR: true}) + require.NoError(f.t, err) + return res, carv1FilePath, origFilePath +} + // CreateImportFile creates a random file with the specified seed and size, and // imports it into the full node. func (f *TestFullNode) CreateImportFile(ctx context.Context, rseed int, size int) (res *api.ImportRes, path string) { diff --git a/node/impl/client/client.go b/node/impl/client/client.go index d84e89fee..a59b602c4 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -473,25 +473,41 @@ func (a *API) ClientImport(ctx context.Context, ref api.FileRef) (res *api.Impor return nil, err } - carV2File, err := a.imgr().NewTempFile(id) - if err != nil { - return nil, xerrors.Errorf("failed to create temp CARv2 file: %w", err) - } - // make sure to remove the CARv2 file if anything goes wrong from here on. - defer func() { - if finalErr != nil { - _ = os.Remove(carV2File) - } - }() - var root cid.Cid + var carFile string if ref.IsCAR { - root, err = transformCarToCARv2(ref.Path, carV2File) + // if user has given us a CAR file -> just ensure it's either a v1 or a v2, has one root and save it as it is as markets can do deal making for both. + f, err := os.Open(ref.Path) if err != nil { - return nil, xerrors.Errorf("failed to import CAR file: %w", err) + return nil, xerrors.Errorf("failed to open CAR file: %w", err) } + defer f.Close() //nolint:errcheck + hd, _, err := car.ReadHeader(bufio.NewReader(f)) + if err != nil { + return nil, xerrors.Errorf("failed to read CAR header: %w", err) + } + if len(hd.Roots) != 1 { + return nil, xerrors.New("car file can have one and only one header") + } + if hd.Version != 1 && hd.Version != 2 { + return nil, xerrors.Errorf("car version must be 1 or 2, is %d", hd.Version) + } + + carFile = ref.Path + root = hd.Roots[0] } else { - root, err = a.importNormalFileToFilestoreCARv2(ctx, id, ref.Path, carV2File) + carFile, err = a.imgr().NewTempFile(id) + if err != nil { + return nil, xerrors.Errorf("failed to create temp CARv2 file: %w", err) + } + // make sure to remove the CARv2 file if anything goes wrong from here on. + defer func() { + if finalErr != nil { + _ = os.Remove(carFile) + } + }() + + root, err = a.importNormalFileToFilestoreCARv2(ctx, id, ref.Path, carFile) if err != nil { return nil, xerrors.Errorf("failed to import normal file to CARv2: %w", err) } @@ -503,7 +519,7 @@ func (a *API) ClientImport(ctx context.Context, ref api.FileRef) (res *api.Impor if err := a.imgr().AddLabel(id, importmgr.LFileName, ref.Path); err != nil { return nil, err } - if err := a.imgr().AddLabel(id, importmgr.LFileStoreCARv2FilePath, carV2File); err != nil { + if err := a.imgr().AddLabel(id, importmgr.LFileStoreCARv2FilePath, carFile); err != nil { return nil, err } if err := a.imgr().AddLabel(id, importmgr.LRootCid, root.String()); err != nil { @@ -854,6 +870,7 @@ func (a *API) clientRetrieve(ctx context.Context, order api.RetrievalOrder, ref return } finish(files.WriteTo(file, ref.Path)) + return } diff --git a/node/impl/client/import.go b/node/impl/client/import.go index be1e37e92..eb0ed5472 100644 --- a/node/impl/client/import.go +++ b/node/impl/client/import.go @@ -1,9 +1,7 @@ package client import ( - "bufio" "context" - "io" "os" "github.com/filecoin-project/go-fil-markets/filestorecaradapter" @@ -23,8 +21,6 @@ import ( "github.com/ipfs/go-merkledag" "github.com/ipfs/go-unixfs/importer/balanced" ihelper "github.com/ipfs/go-unixfs/importer/helpers" - "github.com/ipld/go-car" - carv2 "github.com/ipld/go-car/v2" "golang.org/x/xerrors" ) @@ -124,52 +120,3 @@ func importNormalFileToUnixfsDAG(ctx context.Context, inputFilePath string, dag return nd.Cid(), nil } - -// transformCarToCARv2 transforms a client's CAR file to a CARv2 file. -func transformCarToCARv2(inputCARPath string, outputCARv2Path string) (root cid.Cid, err error) { - inputF, err := os.Open(inputCARPath) - if err != nil { - return cid.Undef, xerrors.Errorf("failed to open input CAR: %w", err) - } - defer inputF.Close() //nolint:errcheck - - // read the CAR header to determine the DAG root and the CAR version. - hd, _, err := car.ReadHeader(bufio.NewReader(inputF)) - if err != nil { - return cid.Undef, xerrors.Errorf("failed to read CAR header: %w", err) - } - if len(hd.Roots) != 1 { - return cid.Undef, xerrors.New("cannot import CAR with more than one root") - } - - // we read the file to read the header -> seek to the start again to be able to read again. - if _, err := inputF.Seek(0, io.SeekStart); err != nil { - return cid.Undef, xerrors.Errorf("failed to seek to start of input CAR: %w", err) - } - - switch hd.Version { - case 2: - - // This is a CARv2, we can import it as it is by simply copying it. - outF, err := os.Open(outputCARv2Path) - if err != nil { - return cid.Undef, xerrors.Errorf("failed to open output CARv2 file: %w", err) - } - defer outF.Close() //nolint:errcheck - _, err = io.Copy(outF, inputF) - if err != nil { - return cid.Undef, xerrors.Errorf("failed to copy CARv2 file: %w", err) - } - case 1: - - // This is a CARv1, let's transform it to a CARv2. - if err := carv2.WrapV1File(inputCARPath, outputCARv2Path); err != nil { - return cid.Undef, xerrors.Errorf("failed to transform CARv1 to CARv2: %w", err) - } - - default: - return cid.Undef, xerrors.Errorf("unrecognized CAR version %d", hd.Version) - } - - return hd.Roots[0], nil -} diff --git a/node/impl/client/import_test.go b/node/impl/client/import_test.go index 9c32fd523..e512be75f 100644 --- a/node/impl/client/import_test.go +++ b/node/impl/client/import_test.go @@ -1,7 +1,6 @@ package client import ( - "bufio" "context" "io" "io/ioutil" @@ -11,7 +10,6 @@ import ( "testing" "github.com/filecoin-project/go-fil-markets/filestorecaradapter" - bstore "github.com/filecoin-project/lotus/blockstore" "github.com/filecoin-project/lotus/node/repo/importmgr" "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" @@ -19,12 +17,7 @@ import ( files "github.com/ipfs/go-ipfs-files" "github.com/ipfs/go-merkledag" unixfile "github.com/ipfs/go-unixfs/file" - "github.com/ipld/go-car" - carv2 "github.com/ipld/go-car/v2" "github.com/ipld/go-car/v2/blockstore" - basicnode "github.com/ipld/go-ipld-prime/node/basic" - "github.com/ipld/go-ipld-prime/traversal/selector" - "github.com/ipld/go-ipld-prime/traversal/selector/builder" "github.com/stretchr/testify/require" ) @@ -110,94 +103,6 @@ func TestImportNormalFileToCARv2(t *testing.T) { require.Equal(t, inputContents, bz2) } -func TestTransformCarv1ToCARv2(t *testing.T) { - inputFilePath, _ := genNormalInputFile(t) - defer os.Remove(inputFilePath) //nolint:errcheck - - carv1FilePath := genCARv1(t, inputFilePath) - defer os.Remove(carv1FilePath) //nolint:errcheck - - outputCARv2 := genTmpFile(t) - defer os.Remove(outputCARv2) //nolint:errcheck - - root, err := transformCarToCARv2(carv1FilePath, outputCARv2) - require.NoError(t, err) - require.NotEqual(t, cid.Undef, root) - - // assert what we got back is a valid CARv2 and that the CARv1 payload is exactly what we gave it - f2, err := os.Open(outputCARv2) - require.NoError(t, err) - hd, _, err := car.ReadHeader(bufio.NewReader(f2)) - require.NoError(t, err) - require.EqualValues(t, 2, hd.Version) - require.NoError(t, f2.Close()) - - v2r, err := carv2.NewReaderMmap(outputCARv2) - require.NoError(t, err) - bzout, err := ioutil.ReadAll(v2r.CarV1Reader()) - require.NoError(t, err) - require.NotNil(t, bzout) - require.NoError(t, v2r.Close()) - - fi, err := os.Open(carv1FilePath) - require.NoError(t, err) - bzin, err := ioutil.ReadAll(fi) - require.NoError(t, err) - require.NoError(t, fi.Close()) - require.NotNil(t, bzin) - - require.Equal(t, bzin, bzout) -} - -func TestLoadCARv2ToBlockstore(t *testing.T) { - inputFilePath, _ := genNormalInputFile(t) - defer os.Remove(inputFilePath) //nolint:errcheck - - carv1FilePath := genCARv1(t, inputFilePath) - defer os.Remove(carv1FilePath) //nolint:errcheck - - outputCARv2 := genTmpFile(t) - defer os.Remove(outputCARv2) //nolint:errcheck - - root, err := transformCarToCARv2(carv1FilePath, outputCARv2) - require.NoError(t, err) - require.NotEqual(t, cid.Undef, root) - - bs := bstore.NewMemorySync() - - carv2, err := carv2.NewReaderMmap(outputCARv2) - require.NoError(t, err) - defer carv2.Close() //nolint:errcheck - header, err := car.LoadCar(bs, carv2.CarV1Reader()) - require.NoError(t, err) - require.EqualValues(t, root, header.Roots[0]) - require.EqualValues(t, 1, header.Version) -} - -func genCARv1(t *testing.T, normalFilePath string) string { - ctx := context.Background() - bs := bstore.NewMemorySync() - root, err := importNormalFileToUnixfsDAG(ctx, normalFilePath, merkledag.NewDAGService(blockservice.New(bs, offline.Exchange(bs)))) - require.NoError(t, err) - - ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any) - allSelector := ssb.ExploreRecursive(selector.RecursionLimitNone(), - ssb.ExploreAll(ssb.ExploreRecursiveEdge())).Node() - sc := car.NewSelectiveCar(ctx, bs, []car.Dag{{Root: root, Selector: allSelector}}) - f, err := os.CreateTemp("", "") - require.NoError(t, err) - require.NoError(t, sc.Write(f)) - - _, err = f.Seek(0, io.SeekStart) - require.NoError(t, err) - hd, _, err := car.ReadHeader(bufio.NewReader(f)) - require.NoError(t, err) - require.EqualValues(t, 1, hd.Version) - - require.NoError(t, f.Close()) - return f.Name() -} - func genTmpFile(t *testing.T) string { f, err := os.CreateTemp("", "") require.NoError(t, err) diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index d26c2d7ea..33d14d3ba 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -228,6 +228,33 @@ func (a *ChainAPI) ChainGetParentReceipts(ctx context.Context, bcid cid.Cid) ([] return out, nil } +func (a *ChainAPI) ChainGetMessagesInTipset(ctx context.Context, tsk types.TipSetKey) ([]api.Message, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, err + } + + // genesis block has no parent messages... + if ts.Height() == 0 { + return nil, nil + } + + cm, err := a.Chain.MessagesForTipset(ts) + if err != nil { + return nil, err + } + + var out []api.Message + for _, m := range cm { + out = append(out, api.Message{ + Cid: m.Cid(), + Message: m.VMMessage(), + }) + } + + return out, nil +} + func (m *ChainModule) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) { ts, err := m.Chain.GetTipSetFromKey(tsk) if err != nil {