diff --git a/api/api_full.go b/api/api_full.go index 06aaff99cb6..9ca0f883aa5 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -900,6 +900,7 @@ type QueryOffer struct { Size uint64 MinPrice types.BigInt UnsealPrice types.BigInt + PricePerByte abi.TokenAmount PaymentInterval uint64 PaymentIntervalIncrease uint64 Miner address.Address diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index 4bb7835d28c..33a869e4a27 100644 Binary files a/build/openrpc/full.json.gz and b/build/openrpc/full.json.gz differ diff --git a/cli/client.go b/cli/client.go index f5b38788b00..634bd18e5b4 100644 --- a/cli/client.go +++ b/cli/client.go @@ -92,6 +92,7 @@ var clientCmd = &cli.Command{ WithCategory("data", clientLocalCmd), WithCategory("data", clientStat), WithCategory("retrieval", clientFindCmd), + WithCategory("retrieval", clientQueryRetrievalAskCmd), WithCategory("retrieval", clientRetrieveCmd), WithCategory("retrieval", clientRetrieveCatCmd), WithCategory("retrieval", clientRetrieveLsCmd), @@ -1030,6 +1031,67 @@ var clientFindCmd = &cli.Command{ }, } +var clientQueryRetrievalAskCmd = &cli.Command{ + Name: "retrieval-ask", + Usage: "Get a miner's retrieval ask", + ArgsUsage: "[minerAddress] [data CID]", + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "size", + Usage: "data size in bytes", + }, + }, + Action: func(cctx *cli.Context) error { + afmt := NewAppFmt(cctx.App) + if cctx.NArg() != 2 { + afmt.Println("Usage: retrieval-ask [minerAddress] [data CID]") + return nil + } + + maddr, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return err + } + + dataCid, err := cid.Parse(cctx.Args().Get(1)) + if err != nil { + return fmt.Errorf("parsing data cid: %w", err) + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + ask, err := api.ClientMinerQueryOffer(ctx, maddr, dataCid, nil) + if err != nil { + return err + } + + afmt.Printf("Ask: %s\n", maddr) + afmt.Printf("Unseal price: %s\n", types.FIL(ask.UnsealPrice)) + afmt.Printf("Price per byte: %s\n", types.FIL(ask.PricePerByte)) + afmt.Printf("Payment interval: %s\n", types.SizeStr(types.NewInt(ask.PaymentInterval))) + afmt.Printf("Payment interval increase: %s\n", types.SizeStr(types.NewInt(ask.PaymentIntervalIncrease))) + + size := cctx.Uint64("size") + if size == 0 { + if ask.Size == 0 { + return nil + } + size = ask.Size + afmt.Printf("Size: %s\n", types.SizeStr(types.NewInt(ask.Size))) + } + transferPrice := types.BigMul(ask.PricePerByte, types.NewInt(size)) + totalPrice := types.BigAdd(ask.UnsealPrice, transferPrice) + afmt.Printf("Total price for %d bytes: %s\n", size, types.FIL(totalPrice)) + + return nil + }, +} + var clientListRetrievalsCmd = &cli.Command{ Name: "list-retrievals", Usage: "List retrieval market deals", diff --git a/documentation/en/api-v0-methods.md b/documentation/en/api-v0-methods.md index 257da9d1396..0544a9acc97 100644 --- a/documentation/en/api-v0-methods.md +++ b/documentation/en/api-v0-methods.md @@ -1386,6 +1386,7 @@ Response: "Size": 42, "MinPrice": "0", "UnsealPrice": "0", + "PricePerByte": "0", "PaymentInterval": 42, "PaymentIntervalIncrease": 42, "Miner": "f01234", diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index 9624f0e2699..c1d6c76e0f4 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -1425,6 +1425,7 @@ Response: "Size": 42, "MinPrice": "0", "UnsealPrice": "0", + "PricePerByte": "0", "PaymentInterval": 42, "PaymentIntervalIncrease": 42, "Miner": "f01234", diff --git a/documentation/en/cli-lotus.md b/documentation/en/cli-lotus.md index eaefe25cea9..606921f872f 100644 --- a/documentation/en/cli-lotus.md +++ b/documentation/en/cli-lotus.md @@ -425,6 +425,7 @@ COMMANDS: stat Print information about a locally stored file (piece size, etc) RETRIEVAL: find Find data in the network + retrieval-ask Get a miner's retrieval ask retrieve Retrieve data from network cat Show data from network ls List object links @@ -535,6 +536,23 @@ OPTIONS: ``` +### lotus client retrieval-ask +``` +NAME: + lotus client retrieval-ask - Get a miner's retrieval ask + +USAGE: + lotus client retrieval-ask [command options] [minerAddress] [data CID] + +CATEGORY: + RETRIEVAL + +OPTIONS: + --size value data size in bytes (default: 0) + --help, -h show help (default: false) + +``` + ### lotus client retrieve ``` NAME: diff --git a/itests/kit/client.go b/itests/kit/client.go index c9f8946ec8c..4c20e37c192 100644 --- a/itests/kit/client.go +++ b/itests/kit/client.go @@ -101,9 +101,14 @@ func RunClientTest(t *testing.T, cmds []*lcli.Command, clientNode *TestFullNode) time.Sleep(time.Second) } + // client retrieval-ask --size=1 + out = clientCLI.RunCmd("client", "retrieval-ask", "--size=1", minerAddr.String(), dataCid.String()) + require.Regexp(t, regexp.MustCompile("Ask:"), out) + fmt.Println("retrieval ask:\n", out) + // Retrieve the first file from the Miner // client retrieve - tmpdir, err := ioutil.TempDir(os.TempDir(), "test-cli-Client") + tmpdir, err := ioutil.TempDir(os.TempDir(), "test-cli-client") require.NoError(t, err) path := filepath.Join(tmpdir, "outfile.dat") out = clientCLI.RunCmd("client", "retrieve", dataCid.String(), path) diff --git a/node/impl/client/client.go b/node/impl/client/client.go index e3c365fee30..7848c84f92d 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -490,6 +490,7 @@ func (a *API) makeRetrievalQuery(ctx context.Context, rp rm.RetrievalPeer, paylo Size: queryResponse.Size, MinPrice: queryResponse.PieceRetrievalPrice(), UnsealPrice: queryResponse.UnsealPrice, + PricePerByte: queryResponse.MinPricePerByte, PaymentInterval: queryResponse.MaxPaymentInterval, PaymentIntervalIncrease: queryResponse.MaxPaymentIntervalIncrease, Miner: queryResponse.PaymentAddress, // TODO: check