diff --git a/api/test/deals.go b/api/test/deals.go index aa7e23bcc99..69870beb6d7 100644 --- a/api/test/deals.go +++ b/api/test/deals.go @@ -75,6 +75,19 @@ func MakeDeal(t *testing.T, ctx context.Context, rseed int, client api.FullNode, } func CreateClientFile(ctx context.Context, client api.FullNode, rseed, size int) (*api.ImportRes, []byte, error) { + data, path, err := createRandomFile(rseed, size) + if err != nil { + return nil, nil, err + } + + res, err := client.ClientImport(ctx, api.FileRef{Path: path}) + if err != nil { + return nil, nil, err + } + return res, data, nil +} + +func createRandomFile(rseed, size int) ([]byte, string, error) { if size == 0 { size = 1600 } @@ -83,20 +96,16 @@ func CreateClientFile(ctx context.Context, client api.FullNode, rseed, size int) dir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-") if err != nil { - return nil, nil, err + return nil, "", err } path := filepath.Join(dir, "sourcefile.dat") err = ioutil.WriteFile(path, data, 0644) if err != nil { - return nil, nil, err + return nil, "", err } - res, err := client.ClientImport(ctx, api.FileRef{Path: path}) - if err != nil { - return nil, nil, err - } - return res, data, nil + return data, path, nil } func TestPublishDealsBatching(t *testing.T, b APIBuilder, blocktime time.Duration, startEpoch abi.ChainEpoch) { @@ -382,6 +391,79 @@ func TestZeroPricePerByteRetrievalDealFlow(t *testing.T, b APIBuilder, blocktime MakeDeal(t, s.ctx, 6, s.client, s.miner, false, false, startEpoch) } +func TestOfflineDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, startEpoch abi.ChainEpoch, fastRet bool) { + s := setupOneClientOneMiner(t, b, blocktime) + defer s.blockMiner.Stop() + + // Create a random file + data, path, err := createRandomFile(1, 0) + require.NoError(t, err) + + // Import the file on the client + importRes, err := s.client.ClientImport(s.ctx, api.FileRef{Path: path}) + require.NoError(t, err) + + // Get the piece size and commP + fcid := importRes.Root + pieceInfo, err := s.client.ClientDealPieceCID(s.ctx, fcid) + require.NoError(t, err) + fmt.Println("FILE CID: ", fcid) + + // Create a storage deal with the miner + maddr, err := s.miner.ActorAddress(s.ctx) + require.NoError(t, err) + + addr, err := s.client.WalletDefaultAddress(s.ctx) + require.NoError(t, err) + + // Manual storage deal (offline deal) + dataRef := &storagemarket.DataRef{ + TransferType: storagemarket.TTManual, + Root: fcid, + PieceCid: &pieceInfo.PieceCID, + PieceSize: pieceInfo.PieceSize.Unpadded(), + } + + proposalCid, err := s.client.ClientStartDeal(s.ctx, &api.StartDealParams{ + Data: dataRef, + Wallet: addr, + Miner: maddr, + EpochPrice: types.NewInt(1000000), + DealStartEpoch: startEpoch, + MinBlocksDuration: uint64(build.MinDealDuration), + FastRetrieval: fastRet, + }) + require.NoError(t, err) + + // Wait for the deal to reach StorageDealCheckForAcceptance on the client + cd, err := s.client.ClientGetDealInfo(s.ctx, *proposalCid) + require.NoError(t, err) + require.Eventually(t, func() bool { + cd, _ := s.client.ClientGetDealInfo(s.ctx, *proposalCid) + return cd.State == storagemarket.StorageDealCheckForAcceptance + }, 1*time.Second, 100*time.Millisecond, "actual deal status is %s", storagemarket.DealStates[cd.State]) + + // Create a CAR file from the raw file + carFileDir, err := ioutil.TempDir(os.TempDir(), "test-make-deal-car") + require.NoError(t, err) + carFilePath := filepath.Join(carFileDir, "out.car") + err = s.client.ClientGenCar(s.ctx, api.FileRef{Path: path}, carFilePath) + require.NoError(t, err) + + // Import the CAR file on the miner - this is the equivalent to + // transferring the file across the wire in a normal (non-offline) deal + err = s.miner.DealsImportData(s.ctx, *proposalCid, carFilePath) + require.NoError(t, err) + + // Wait for the deal to be published + waitDealPublished(t, s.ctx, s.miner, proposalCid) + + t.Logf("deal published, retrieving") + + // Retrieve the deal + testRetrieval(t, s.ctx, s.client, fcid, &pieceInfo.PieceCID, false, data) +} + func startDeal(t *testing.T, ctx context.Context, miner TestStorageNode, client api.FullNode, fcid cid.Cid, fastRet bool, startEpoch abi.ChainEpoch) *cid.Cid { maddr, err := miner.ActorAddress(ctx) if err != nil { diff --git a/node/node_test.go b/node/node_test.go index dcbc70469c6..7adc9352b3d 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -58,6 +58,12 @@ func TestAPIDealFlow(t *testing.T) { t.Run("TestPublishDealsBatching", func(t *testing.T) { test.TestPublishDealsBatching(t, builder.MockSbBuilder, blockTime, dealStartEpoch) }) + t.Run("TestOfflineDealFlow", func(t *testing.T) { + test.TestOfflineDealFlow(t, builder.MockSbBuilder, blockTime, dealStartEpoch, false) + }) + t.Run("TestOfflineDealFlowFastRetrieval", func(t *testing.T) { + test.TestOfflineDealFlow(t, builder.MockSbBuilder, blockTime, dealStartEpoch, true) + }) } func TestBatchDealInput(t *testing.T) {