From 12e8987be6a58428d0cd72e2b1dc5c74b5c1e1ce Mon Sep 17 00:00:00 2001 From: Alexey Chernyshov Date: Thu, 25 Nov 2021 12:33:43 +0300 Subject: [PATCH] deal status protocol with OOP Signed-off-by: Alexey Chernyshov --- core/api/full_node/node_api.hpp | 6 +- core/api/rpc/json.hpp | 4 +- core/codec/cbor/cbor_types.cpp | 73 ----- core/markets/storage/CMakeLists.txt | 1 + core/markets/storage/ask_protocol.hpp | 26 +- .../impl/storage_market_client_impl.cpp | 90 +++--- .../impl/storage_market_client_impl.hpp | 42 +-- .../storage/client/storage_market_client.hpp | 7 +- core/markets/storage/deal_protocol.hpp | 76 ++--- core/markets/storage/protocol/CMakeLists.txt | 14 + .../protocol/ask_protocol_named_cbor.cpp | 79 +++++ core/markets/storage/provider/CMakeLists.txt | 1 + .../storage/provider/impl/provider_impl.cpp | 184 +++++------- .../storage/provider/impl/provider_impl.hpp | 112 +++++--- core/markets/storage/provider/provider.hpp | 2 +- core/markets/storage/status_protocol.hpp | 271 ++++++++++++++++++ housekeeping/clang-tidy.sh | 1 - test/core/markets/storage/CMakeLists.txt | 1 + .../markets/storage/protocol/CMakeLists.txt | 15 + .../protocol/ask_protocol_named_cbor_test.cpp | 166 +++++++++++ .../status_protocol_named_cbor_test.cpp | 147 ++++++++++ .../storage/storage_market_fixture.hpp | 4 +- 22 files changed, 966 insertions(+), 356 deletions(-) create mode 100644 core/markets/storage/protocol/CMakeLists.txt create mode 100644 core/markets/storage/protocol/ask_protocol_named_cbor.cpp create mode 100644 core/markets/storage/status_protocol.hpp create mode 100644 test/core/markets/storage/protocol/CMakeLists.txt create mode 100644 test/core/markets/storage/protocol/ask_protocol_named_cbor_test.cpp create mode 100644 test/core/markets/storage/protocol/status_protocol_named_cbor_test.cpp diff --git a/core/api/full_node/node_api.hpp b/core/api/full_node/node_api.hpp index 31dc5f9059..11fde62186 100644 --- a/core/api/full_node/node_api.hpp +++ b/core/api/full_node/node_api.hpp @@ -35,7 +35,7 @@ namespace fc::api { using libp2p::multi::Multiaddress; using libp2p::peer::PeerId; using markets::retrieval::RetrievalPeer; - using markets::storage::DataRef; + using markets::storage::DataRef0; using markets::storage::SignedStorageAsk; using markets::storage::StorageDeal; using markets::storage::StorageDealStatus; @@ -115,7 +115,7 @@ namespace fc::api { StorageDealStatus state; std::string message; Address provider; - DataRef data_ref; + DataRef0 data_ref; CID piece_cid; uint64_t size; TokenAmount price_per_epoch; @@ -157,7 +157,7 @@ namespace fc::api { }; struct StartDealParams { - DataRef data; + DataRef0 data; Address wallet; Address miner; TokenAmount epoch_price; diff --git a/core/api/rpc/json.hpp b/core/api/rpc/json.hpp index 5756c7c295..8594029899 100644 --- a/core/api/rpc/json.hpp +++ b/core/api/rpc/json.hpp @@ -1341,7 +1341,7 @@ namespace fc::api { Get(j, "Signature", v.signature); } - ENCODE(DataRef) { + ENCODE(DataRef0) { Value j{rapidjson::kObjectType}; Set(j, "TransferType", v.transfer_type); Set(j, "Root", v.root); @@ -1350,7 +1350,7 @@ namespace fc::api { return j; } - DECODE(DataRef) { + DECODE(DataRef0) { decode(v.transfer_type, Get(j, "TransferType")); decode(v.root, Get(j, "Root")); decode(v.piece_cid, Get(j, "PieceCid")); diff --git a/core/codec/cbor/cbor_types.cpp b/core/codec/cbor/cbor_types.cpp index 499a1bd36f..c3d73b6e41 100644 --- a/core/codec/cbor/cbor_types.cpp +++ b/core/codec/cbor/cbor_types.cpp @@ -5,82 +5,9 @@ #include "codec/cbor/cbor_codec.hpp" #include "markets/retrieval/protocols/retrieval_protocol.hpp" -#include "markets/storage/ask_protocol.hpp" #include "primitives/address/address_codec.hpp" #include "storage/ipfs/graphsync/extension.hpp" -namespace fc::markets::storage { - using codec::cbor::CborDecodeStream; - using codec::cbor::CborEncodeStream; - - CBOR2_ENCODE(StorageAsk::Named) { - auto m{CborEncodeStream::map()}; - m["Price"] << v.price; - m["VerifiedPrice"] << v.verified_price; - m["MinPieceSize"] << v.min_piece_size; - m["MaxPieceSize"] << v.max_piece_size; - m["Miner"] << v.miner; - m["Timestamp"] << v.timestamp; - m["Expiry"] << v.expiry; - m["SeqNo"] << v.seq_no; - return s << m; - } - - CBOR2_DECODE(StorageAsk::Named) { - auto m{s.map()}; - CborDecodeStream::named(m, "Price") >> v.price; - CborDecodeStream::named(m, "VerifiedPrice") >> v.verified_price; - CborDecodeStream::named(m, "MinPieceSize") >> v.min_piece_size; - CborDecodeStream::named(m, "MaxPieceSize") >> v.max_piece_size; - CborDecodeStream::named(m, "Miner") >> v.miner; - CborDecodeStream::named(m, "Timestamp") >> v.timestamp; - CborDecodeStream::named(m, "Expiry") >> v.expiry; - CborDecodeStream::named(m, "SeqNo") >> v.seq_no; - return s; - } - - CBOR2_ENCODE(SignedStorageAsk::Named) { - auto m{CborEncodeStream::map()}; - m["Ask"] << static_cast(v.ask); - m["Signature"] << v.signature; - return s << m; - } - - CBOR2_DECODE(SignedStorageAsk::Named) { - auto m{s.map()}; - CborDecodeStream::named(m, "Ask") - >> *(static_cast(&v.ask)); - CborDecodeStream::named(m, "Signature") >> v.signature; - return s; - } - - CBOR2_ENCODE(AskRequest::Named) { - auto m{CborEncodeStream::map()}; - m["Miner"] << v.miner; - return s << m; - } - - CBOR2_DECODE(AskRequest::Named) { - auto m{s.map()}; - - CborDecodeStream::named(m, "Miner") >> v.miner; - return s; - } - - CBOR2_ENCODE(AskResponse::Named) { - auto m{CborEncodeStream::map()}; - m["Ask"] << static_cast(v.ask); - return s << m; - } - - CBOR2_DECODE(AskResponse::Named) { - auto m{s.map()}; - CborDecodeStream::named(m, "Ask") - >> *(static_cast(&v.ask)); - return s; - } -} // namespace fc::markets::storage - namespace fc::markets::retrieval { using codec::cbor::CborDecodeStream; using codec::cbor::CborEncodeStream; diff --git a/core/markets/storage/CMakeLists.txt b/core/markets/storage/CMakeLists.txt index 9fdc43073f..c9684449fb 100644 --- a/core/markets/storage/CMakeLists.txt +++ b/core/markets/storage/CMakeLists.txt @@ -5,4 +5,5 @@ add_subdirectory(chain_events) add_subdirectory(client) +add_subdirectory(protocol) add_subdirectory(provider) diff --git a/core/markets/storage/ask_protocol.hpp b/core/markets/storage/ask_protocol.hpp index 3d1b7147cd..e2aaff90aa 100644 --- a/core/markets/storage/ask_protocol.hpp +++ b/core/markets/storage/ask_protocol.hpp @@ -24,8 +24,12 @@ namespace fc::markets::storage { const libp2p::peer::Protocol kAskProtocolId_v1_0_1 = "/fil/storage/ask/1.0.1"; /** Protocol 1.1.1 uses named cbor */ - const libp2p::peer::Protocol kAskProtocolId_v1_1_1 = "/fil/storage/ask/1.1.1"; + const libp2p::peer::Protocol kAskProtocolId_v1_1_0 = "/fil/storage/ask/1.1.0"; + /** + * StorageAsk defines the parameters by which a miner will choose to accept or + * reject a deal. + */ struct StorageAsk { struct Named; @@ -40,8 +44,6 @@ namespace fc::markets::storage { uint64_t seq_no; }; - struct StorageAsk::Named : StorageAsk {}; - CBOR_TUPLE(StorageAsk, price, verified_price, @@ -52,6 +54,9 @@ namespace fc::markets::storage { expiry, seq_no) + struct StorageAsk::Named : StorageAsk {}; + CBOR2_DECODE_ENCODE(StorageAsk::Named) + struct SignedStorageAsk { struct Named; @@ -59,10 +64,11 @@ namespace fc::markets::storage { Signature signature; }; - struct SignedStorageAsk::Named : SignedStorageAsk {}; - CBOR_TUPLE(SignedStorageAsk, ask, signature) + struct SignedStorageAsk::Named : SignedStorageAsk {}; + CBOR2_DECODE_ENCODE(SignedStorageAsk::Named) + /** * AskRequest is a request for current ask parameters for a given miner */ @@ -72,10 +78,11 @@ namespace fc::markets::storage { Address miner; }; + CBOR_TUPLE(AskRequest, miner) + /** Named ask request for named cbor */ struct AskRequest::Named : AskRequest {}; - - CBOR_TUPLE(AskRequest, miner) + CBOR2_DECODE_ENCODE(AskRequest::Named) /** * AskResponse is the response sent over the network in response to an ask @@ -87,9 +94,10 @@ namespace fc::markets::storage { SignedStorageAsk ask; }; + CBOR_TUPLE(AskResponse, ask) + /** Named ask response for named cbor */ struct AskResponse::Named : AskResponse {}; - - CBOR_TUPLE(AskResponse, ask) + CBOR2_DECODE_ENCODE(AskResponse::Named) } // namespace fc::markets::storage diff --git a/core/markets/storage/client/impl/storage_market_client_impl.cpp b/core/markets/storage/client/impl/storage_market_client_impl.cpp index 7f83f7d6ef..62406ec648 100644 --- a/core/markets/storage/client/impl/storage_market_client_impl.cpp +++ b/core/markets/storage/client/impl/storage_market_client_impl.cpp @@ -97,23 +97,24 @@ namespace fc::markets::storage::client { } void StorageMarketClientImpl::askDealStatus( - const std::shared_ptr &deal) { + const std::shared_ptr &deal) { auto cb{weakCb0( - weak_from_this(), [=](outcome::result &&_res) { + weak_from_this(), + [=](outcome::result &&_res) { if (_res) { auto &res{_res.value()}; - auto state{res.state.status}; + auto state{res.state().status}; if (state == StorageDealStatus::STORAGE_DEAL_STAGED || state == StorageDealStatus::STORAGE_DEAL_SEALING || state == StorageDealStatus::STORAGE_DEAL_ACTIVE || state == StorageDealStatus::STORAGE_DEAL_EXPIRED || state == StorageDealStatus::STORAGE_DEAL_SLASHED) { - deal->publish_message = *res.state.publish_cid; + deal->publish_message = *res.state().publish_cid; FSM_SEND(deal, ClientEvent::ClientEventDealAccepted); } else if (state == StorageDealStatus::STORAGE_DEAL_FAILING || state == StorageDealStatus::STORAGE_DEAL_ERROR) { deal->message = - "Got error deal status response: " + res.state.message; + "Got error deal status response: " + res.state().message; FSM_SEND(deal, ClientEvent::ClientEventDealRejected); } else { std::lock_guard lock{waiting_mutex}; @@ -126,23 +127,23 @@ namespace fc::markets::storage::client { waiting_deals.push_back(deal); } })}; - DealStatusRequest req; - req.proposal = deal->proposal_cid; - OUTCOME_EXCEPT(bytes, codec::cbor::encode(req.proposal)); + OUTCOME_EXCEPT(bytes, codec::cbor::encode(deal->proposal_cid)); OUTCOME_CB( - req.signature, + auto signature, api_->WalletSign(deal->client_deal_proposal.proposal.client, bytes)); + DealStatusRequestV1_1_0 req(deal->proposal_cid, signature); status_streams_->open({ deal->miner, - kDealStatusProtocolId_v1_1_1, + kDealStatusProtocolId_v1_1_0, [MOVE(cb), MOVE(req)](Host::StreamResult _stream) { OUTCOME_CB1(_stream); auto stream{std::make_shared( std::move(_stream.value()))}; stream->write(req, [MOVE(cb), stream](outcome::result _n) { OUTCOME_CB1(_n); - stream->read( - [MOVE(cb), stream](outcome::result _res) { + stream->read( + [MOVE(cb), + stream](outcome::result _res) { cb(std::move(_res)); }); }); @@ -196,16 +197,16 @@ namespace fc::markets::storage::client { return client_deals; } - outcome::result> + outcome::result> StorageMarketClientImpl::listLocalDeals() const { - std::vector res; + std::vector res; for (const auto &it : fsm_->list()) { res.push_back(*it.first); } return res; } - outcome::result StorageMarketClientImpl::getLocalDeal( + outcome::result StorageMarketClientImpl::getLocalDeal( const CID &proposal_cid) const { for (const auto &it : fsm_->list()) { if (it.first->proposal_cid == proposal_cid) { @@ -220,7 +221,7 @@ namespace fc::markets::storage::client { const SignedAskHandler &signed_ask_handler) { host_->newStream( info.peer_info, - kAskProtocolId_v1_1_1, + kAskProtocolId_v1_1_0, [self{shared_from_this()}, info, signed_ask_handler]( auto &&stream_res) { if (stream_res.has_error()) { @@ -257,7 +258,7 @@ namespace fc::markets::storage::client { outcome::result StorageMarketClientImpl::proposeStorageDeal( const Address &client_address, const StorageProviderInfo &provider_info, - const DataRef &data_ref, + const DataRef0 &data_ref, const ChainEpoch &start_epoch, const ChainEpoch &end_epoch, const TokenAmount &price, @@ -295,18 +296,18 @@ namespace fc::markets::storage::client { OUTCOME_TRY(signed_proposal, signProposal(client_address, deal_proposal)); auto proposal_cid{signed_proposal.cid()}; - auto client_deal = std::make_shared( - ClientDeal{.client_deal_proposal = signed_proposal, - .proposal_cid = proposal_cid, - .add_funds_cid = boost::none, - .state = StorageDealStatus::STORAGE_DEAL_UNKNOWN, - .miner = provider_info.peer_info, - .miner_worker = provider_info.worker, - .deal_id = {}, - .data_ref = data_ref, - .is_fast_retrieval = is_fast_retrieval, - .message = {}, - .publish_message = {}}); + auto client_deal = std::make_shared( + ClientDeal0{.client_deal_proposal = signed_proposal, + .proposal_cid = proposal_cid, + .add_funds_cid = boost::none, + .state = StorageDealStatus::STORAGE_DEAL_UNKNOWN, + .miner = provider_info.peer_info, + .miner_worker = provider_info.worker, + .deal_id = {}, + .data_ref = data_ref, + .is_fast_retrieval = is_fast_retrieval, + .message = {}, + .publish_message = {}}); OUTCOME_TRY( fsm_->begin(client_deal, StorageDealStatus::STORAGE_DEAL_UNKNOWN)); @@ -347,7 +348,7 @@ namespace fc::markets::storage::client { outcome::result> StorageMarketClientImpl::calculateCommP( const RegisteredSealProof ®istered_proof, - const DataRef &data_ref) const { + const DataRef0 &data_ref) const { if (data_ref.piece_cid.has_value()) { return std::pair(data_ref.piece_cid.value(), data_ref.piece_size); } @@ -374,7 +375,7 @@ namespace fc::markets::storage::client { } outcome::result> StorageMarketClientImpl::ensureFunds( - const std::shared_ptr &deal) { + const std::shared_ptr &deal) { OUTCOME_TRY( maybe_cid, api_->MarketReserveFunds( @@ -385,7 +386,8 @@ namespace fc::markets::storage::client { } outcome::result StorageMarketClientImpl::verifyDealResponseSignature( - const SignedResponse &response, const std::shared_ptr &deal) { + const SignedResponse &response, + const std::shared_ptr &deal) { OUTCOME_TRY(response_bytes, codec::cbor::encode(response.response)); OUTCOME_TRY(signature_valid, api_->WalletVerify( @@ -397,7 +399,7 @@ namespace fc::markets::storage::client { } outcome::result StorageMarketClientImpl::verifyDealPublished( - const std::shared_ptr &deal, api::MsgWait msg_state) { + const std::shared_ptr &deal, api::MsgWait msg_state) { if (msg_state.receipt.exit_code != VMExitCode::kOk) { deal->message = "Publish deal exit code " @@ -452,7 +454,7 @@ namespace fc::markets::storage::client { } void StorageMarketClientImpl::finalizeDeal( - const std::shared_ptr &deal) {} + const std::shared_ptr &deal) {} std::vector StorageMarketClientImpl::makeFSMTransitions() { return {ClientTransition(ClientEvent::ClientEventOpen) @@ -491,7 +493,7 @@ namespace fc::markets::storage::client { } void StorageMarketClientImpl::onClientEventOpen( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ClientEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -514,7 +516,7 @@ namespace fc::markets::storage::client { } void StorageMarketClientImpl::onClientEventFundingInitiated( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ClientEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -539,7 +541,7 @@ namespace fc::markets::storage::client { } void StorageMarketClientImpl::onClientEventFundsEnsured( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ClientEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -603,7 +605,7 @@ namespace fc::markets::storage::client { } void StorageMarketClientImpl::onClientEventDealRejected( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ClientEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -612,7 +614,7 @@ namespace fc::markets::storage::client { } void StorageMarketClientImpl::onClientEventDealAccepted( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ClientEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -638,7 +640,7 @@ namespace fc::markets::storage::client { } void StorageMarketClientImpl::onClientEventDealPublished( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ClientEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -653,7 +655,7 @@ namespace fc::markets::storage::client { } void StorageMarketClientImpl::onClientEventDealActivated( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ClientEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -662,7 +664,7 @@ namespace fc::markets::storage::client { } void StorageMarketClientImpl::onClientEventFailed( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ClientEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -676,7 +678,7 @@ namespace fc::markets::storage::client { finalizeDeal(deal); } - void StorageMarketClientImpl::propose(std::shared_ptr deal, + void StorageMarketClientImpl::propose(std::shared_ptr deal, ProposeCb cb) { propose_streams_->open({ deal->miner, @@ -684,7 +686,7 @@ namespace fc::markets::storage::client { [=, MOVE(deal), MOVE(cb)](Host::StreamResult _stream) { OUTCOME_CB1(_stream); auto stream{std::make_shared(std::move(_stream.value()))}; - Proposal proposal{ + Proposal0 proposal{ deal->client_deal_proposal, deal->data_ref, deal->is_fast_retrieval, diff --git a/core/markets/storage/client/impl/storage_market_client_impl.hpp b/core/markets/storage/client/impl/storage_market_client_impl.hpp index ad0b04b7d0..d574d2ae30 100644 --- a/core/markets/storage/client/impl/storage_market_client_impl.hpp +++ b/core/markets/storage/client/impl/storage_market_client_impl.hpp @@ -32,8 +32,8 @@ namespace fc::markets::storage::client { using libp2p::Host; using pieceio::PieceIO; using ClientTransition = - fsm::Transition; - using ClientFSM = fsm::FSM; + fsm::Transition; + using ClientFSM = fsm::FSM; using Datastore = fc::storage::face::PersistentMap; using data_transfer::DataTransfer; using libp2p::connection::StreamOpenQueue; @@ -65,9 +65,9 @@ namespace fc::markets::storage::client { outcome::result> listDeals( const Address &address) const override; - outcome::result> listLocalDeals() const override; + outcome::result> listLocalDeals() const override; - outcome::result getLocalDeal( + outcome::result getLocalDeal( const CID &proposal_cid) const override; void getAsk(const StorageProviderInfo &info, @@ -76,7 +76,7 @@ namespace fc::markets::storage::client { outcome::result proposeStorageDeal( const Address &client_address, const StorageProviderInfo &provider_info, - const DataRef &data_ref, + const DataRef0 &data_ref, const ChainEpoch &start_epoch, const ChainEpoch &end_epoch, const TokenAmount &price, @@ -86,7 +86,7 @@ namespace fc::markets::storage::client { bool is_fast_retrieval) override; private: - void askDealStatus(const std::shared_ptr& deal); + void askDealStatus(const std::shared_ptr& deal); outcome::result validateAskResponse( const outcome::result &response, @@ -94,7 +94,7 @@ namespace fc::markets::storage::client { outcome::result> calculateCommP( const RegisteredSealProof ®istered_proof, - const DataRef &data_ref) const; + const DataRef0 &data_ref) const; outcome::result signProposal( const Address &address, const DealProposal &proposal) const; @@ -106,25 +106,25 @@ namespace fc::markets::storage::client { * @return CID of add funds message if it was sent */ outcome::result> ensureFunds( - const std::shared_ptr& deal); + const std::shared_ptr& deal); outcome::result verifyDealResponseSignature( const SignedResponse &response, - const std::shared_ptr &deal); + const std::shared_ptr &deal); /** * Verifies if deal was published correctly * @param deal state with publish message cid set * @return true if published or false otherwise */ - outcome::result verifyDealPublished(const std::shared_ptr& deal, + outcome::result verifyDealPublished(const std::shared_ptr& deal, api::MsgWait msg_state); /** * Finalize deal, close connection, clean up * @param deal - deal to clean up */ - void finalizeDeal(const std::shared_ptr& deal); + void finalizeDeal(const std::shared_ptr& deal); /** * Creates all FSM transitions @@ -141,7 +141,7 @@ namespace fc::markets::storage::client { * @param from - STORAGE_DEAL_UNKNOWN * @param to - STORAGE_DEAL_ENSURE_CLIENT_FUNDS */ - void onClientEventOpen(const std::shared_ptr& deal, + void onClientEventOpen(const std::shared_ptr& deal, ClientEvent event, StorageDealStatus from, StorageDealStatus to); @@ -153,7 +153,7 @@ namespace fc::markets::storage::client { * @param from - STORAGE_DEAL_ENSURE_CLIENT_FUNDS * @param to - STORAGE_DEAL_CLIENT_FUNDING */ - void onClientEventFundingInitiated(const std::shared_ptr& deal, + void onClientEventFundingInitiated(const std::shared_ptr& deal, ClientEvent event, StorageDealStatus from, StorageDealStatus to); @@ -167,7 +167,7 @@ namespace fc::markets::storage::client { * STORAGE_DEAL_CLIENT_FUNDING * @param to - STORAGE_DEAL_FUNDS_ENSURED */ - void onClientEventFundsEnsured(const std::shared_ptr& deal, + void onClientEventFundsEnsured(const std::shared_ptr& deal, ClientEvent event, StorageDealStatus from, StorageDealStatus to); @@ -179,7 +179,7 @@ namespace fc::markets::storage::client { * @param from - STORAGE_DEAL_VALIDATING * @param to - STORAGE_DEAL_FAILING */ - void onClientEventDealRejected(const std::shared_ptr& deal, + void onClientEventDealRejected(const std::shared_ptr& deal, ClientEvent event, StorageDealStatus from, StorageDealStatus to); @@ -193,7 +193,7 @@ namespace fc::markets::storage::client { * @param from - STORAGE_DEAL_VALIDATING * @param to - STORAGE_DEAL_PROPOSAL_ACCEPTED */ - void onClientEventDealAccepted(const std::shared_ptr& deal, + void onClientEventDealAccepted(const std::shared_ptr& deal, ClientEvent event, StorageDealStatus from, StorageDealStatus to); @@ -205,7 +205,7 @@ namespace fc::markets::storage::client { * @param from - STORAGE_DEAL_PROPOSAL_ACCEPTED * @param to - STORAGE_DEAL_SEALING */ - void onClientEventDealPublished(const std::shared_ptr& deal, + void onClientEventDealPublished(const std::shared_ptr& deal, ClientEvent event, StorageDealStatus from, StorageDealStatus to); @@ -217,7 +217,7 @@ namespace fc::markets::storage::client { * @param from - STORAGE_DEAL_SEALING * @param to - STORAGE_DEAL_ACTIVE */ - void onClientEventDealActivated(const std::shared_ptr& deal, + void onClientEventDealActivated(const std::shared_ptr& deal, ClientEvent event, StorageDealStatus from, StorageDealStatus to); @@ -229,7 +229,7 @@ namespace fc::markets::storage::client { * @param from - STORAGE_DEAL_FAILING * @param to - STORAGE_DEAL_ERROR */ - void onClientEventFailed(const std::shared_ptr& deal, + void onClientEventFailed(const std::shared_ptr& deal, ClientEvent event, StorageDealStatus from, StorageDealStatus to); @@ -258,7 +258,7 @@ namespace fc::markets::storage::client { }; using ProposeCb = std::function)>; - void propose(std::shared_ptr deal, ProposeCb cb); + void propose(std::shared_ptr deal, ProposeCb cb); /** libp2p host */ std::shared_ptr host_; @@ -275,7 +275,7 @@ namespace fc::markets::storage::client { std::mutex waiting_mutex; // TODO(turuslan): FIL-420 check cache memory usage - std::vector> waiting_deals; + std::vector> waiting_deals; /** State machine */ std::shared_ptr fsm_; diff --git a/core/markets/storage/client/storage_market_client.hpp b/core/markets/storage/client/storage_market_client.hpp index f52b29516f..eab8663776 100644 --- a/core/markets/storage/client/storage_market_client.hpp +++ b/core/markets/storage/client/storage_market_client.hpp @@ -8,6 +8,7 @@ #include "common/outcome.hpp" #include "markets/storage/ask_protocol.hpp" #include "markets/storage/deal_protocol.hpp" +#include "markets/storage/status_protocol.hpp" #include "markets/storage/types.hpp" #include "primitives/address/address.hpp" #include "primitives/chain_epoch/chain_epoch.hpp" @@ -66,9 +67,9 @@ namespace fc::markets::storage::client { virtual outcome::result> listDeals( const Address &address) const = 0; - virtual outcome::result> listLocalDeals() const = 0; + virtual outcome::result> listLocalDeals() const = 0; - virtual outcome::result getLocalDeal(const CID &cid) const = 0; + virtual outcome::result getLocalDeal(const CID &cid) const = 0; virtual void getAsk(const StorageProviderInfo &info, const SignedAskHandler &signed_ask_handler) = 0; @@ -88,7 +89,7 @@ namespace fc::markets::storage::client { virtual outcome::result proposeStorageDeal( const Address &client_address, const StorageProviderInfo &provider_info, - const DataRef &data_ref, + const DataRef0 &data_ref, const ChainEpoch &start_epoch, const ChainEpoch &end_epoch, const TokenAmount &price, diff --git a/core/markets/storage/deal_protocol.hpp b/core/markets/storage/deal_protocol.hpp index 308de9df3a..361c7759e7 100644 --- a/core/markets/storage/deal_protocol.hpp +++ b/core/markets/storage/deal_protocol.hpp @@ -31,12 +31,15 @@ namespace fc::markets::storage { using vm::actor::builtin::types::market::StorageParticipantBalance; const libp2p::peer::Protocol kDealProtocolId_v1_0_1 = "/fil/storage/mk/1.0.1"; - const libp2p::peer::Protocol kDealProtocolId_v1_1_1 = "/fil/storage/mk/1.1.1"; + + /** Protocol 1.1.0 uses named cbor */ + const libp2p::peer::Protocol kDealProtocolId_v1_1_1 = "/fil/storage/mk/1.1.0"; const std::string kTransferTypeGraphsync = "graphsync"; const std::string kTransferTypeManual = "manual"; - struct DataRef { + /** For protocol v1.0.1. */ + struct DataRef0 { std::string transfer_type; CID root; // Optional, will be recomputed from the data if not given @@ -44,7 +47,7 @@ namespace fc::markets::storage { UnpaddedPieceSize piece_size; }; - CBOR_TUPLE(DataRef, transfer_type, root, piece_cid, piece_size) + CBOR_TUPLE(DataRef0, transfer_type, root, piece_cid, piece_size) enum class StorageDealStatus : uint64_t { STORAGE_DEAL_UNKNOWN = 0, @@ -99,7 +102,8 @@ namespace fc::markets::storage { STORAGE_DEAL_ERROR, }; - struct MinerDeal { + /** For protocol v1.0.1 */ + struct MinerDeal0 { ClientDealProposal client_deal_proposal; CID proposal_cid; boost::optional add_funds_cid; @@ -110,11 +114,11 @@ namespace fc::markets::storage { Path metadata_path; bool is_fast_retrieval; std::string message; - DataRef ref; + DataRef0 ref; DealId deal_id; }; - CBOR_TUPLE(MinerDeal, + CBOR_TUPLE(MinerDeal0, client_deal_proposal, proposal_cid, add_funds_cid, @@ -128,7 +132,8 @@ namespace fc::markets::storage { ref, deal_id) - struct ClientDeal { + /** For protocol v1.0.1 */ + struct ClientDeal0 { ClientDealProposal client_deal_proposal; CID proposal_cid; boost::optional add_funds_cid; @@ -136,13 +141,13 @@ namespace fc::markets::storage { PeerInfo miner; Address miner_worker; DealId deal_id; - DataRef data_ref; + DataRef0 data_ref; bool is_fast_retrieval; std::string message; CID publish_message; }; - CBOR_TUPLE(ClientDeal, + CBOR_TUPLE(ClientDeal0, client_deal_proposal, proposal_cid, add_funds_cid, @@ -173,18 +178,22 @@ namespace fc::markets::storage { * Proposal is the data sent over the network from client to provider when * proposing a deal */ - struct Proposal { + struct Proposal0 { + struct Named; + ClientDealProposal deal_proposal; - DataRef piece; + DataRef0 piece; bool is_fast_retrieval = false; }; - CBOR_TUPLE(Proposal, deal_proposal, piece, is_fast_retrieval) + CBOR_TUPLE(Proposal0, deal_proposal, piece, is_fast_retrieval) /** * Response is a response to a proposal sent over the network */ struct Response { + struct Named; + StorageDealStatus state; // DealProposalRejected @@ -195,52 +204,21 @@ namespace fc::markets::storage { boost::optional _unused; }; + struct Response::Named : Response {}; + CBOR_TUPLE(Response, state, message, proposal, _unused) /** * SignedResponse is a response that is signed */ struct SignedResponse { + struct Named; + Response response; Signature signature; }; - CBOR_TUPLE(SignedResponse, response, signature) - - const libp2p::peer::Protocol kDealStatusProtocolId_v1_0_1{ - "/fil/storage/status/1.0.1"}; - const libp2p::peer::Protocol kDealStatusProtocolId_v1_1_1{ - "/fil/storage/status/1.1.1"}; + struct SignedResponse::Named : SignedResponse {}; - struct ProviderDealState { - StorageDealStatus status{}; - std::string message; - DealProposal proposal; - CID proposal_cid; - boost::optional add_funds_cid; - boost::optional publish_cid; - DealId id{}; - bool fast_retrieval{}; - }; - CBOR_TUPLE(ProviderDealState, - status, - message, - proposal, - proposal_cid, - add_funds_cid, - publish_cid, - id, - fast_retrieval) - - struct DealStatusRequest { - CID proposal; - Signature signature; - }; - CBOR_TUPLE(DealStatusRequest, proposal, signature) - - struct DealStatusResponse { - ProviderDealState state; - Signature signature; - }; - CBOR_TUPLE(DealStatusResponse, state, signature) + CBOR_TUPLE(SignedResponse, response, signature) } // namespace fc::markets::storage diff --git a/core/markets/storage/protocol/CMakeLists.txt b/core/markets/storage/protocol/CMakeLists.txt new file mode 100644 index 0000000000..0982eec80d --- /dev/null +++ b/core/markets/storage/protocol/CMakeLists.txt @@ -0,0 +1,14 @@ +# +# Copyright Soramitsu Co., Ltd. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# + +add_library(ask_protocol_cbor + ask_protocol_named_cbor.cpp + ) +target_link_libraries(ask_protocol_cbor + address + cbor + signature + piece + ) diff --git a/core/markets/storage/protocol/ask_protocol_named_cbor.cpp b/core/markets/storage/protocol/ask_protocol_named_cbor.cpp new file mode 100644 index 0000000000..f3c2792a01 --- /dev/null +++ b/core/markets/storage/protocol/ask_protocol_named_cbor.cpp @@ -0,0 +1,79 @@ +/** +* Copyright Soramitsu Co., Ltd. All Rights Reserved. +* SPDX-License-Identifier: Apache-2.0 +*/ + +#include "markets/storage/ask_protocol.hpp" +#include "codec/cbor/cbor_codec.hpp" + +namespace fc::markets::storage { + using codec::cbor::CborDecodeStream; + using codec::cbor::CborEncodeStream; + + CBOR2_ENCODE(StorageAsk::Named) { + auto m{CborEncodeStream::map()}; + m["Price"] << v.price; + m["VerifiedPrice"] << v.verified_price; + m["MinPieceSize"] << v.min_piece_size; + m["MaxPieceSize"] << v.max_piece_size; + m["Miner"] << v.miner; + m["Timestamp"] << v.timestamp; + m["Expiry"] << v.expiry; + m["SeqNo"] << v.seq_no; + return s << m; + } + + CBOR2_DECODE(StorageAsk::Named) { + auto m{s.map()}; + CborDecodeStream::named(m, "Price") >> v.price; + CborDecodeStream::named(m, "VerifiedPrice") >> v.verified_price; + CborDecodeStream::named(m, "MinPieceSize") >> v.min_piece_size; + CborDecodeStream::named(m, "MaxPieceSize") >> v.max_piece_size; + CborDecodeStream::named(m, "Miner") >> v.miner; + CborDecodeStream::named(m, "Timestamp") >> v.timestamp; + CborDecodeStream::named(m, "Expiry") >> v.expiry; + CborDecodeStream::named(m, "SeqNo") >> v.seq_no; + return s; + } + + CBOR2_ENCODE(SignedStorageAsk::Named) { + auto m{CborEncodeStream::map()}; + m["Ask"] << static_cast(v.ask); + m["Signature"] << v.signature; + return s << m; + } + + CBOR2_DECODE(SignedStorageAsk::Named) { + auto m{s.map()}; + CborDecodeStream::named(m, "Ask") + >> *(static_cast(&v.ask)); + CborDecodeStream::named(m, "Signature") >> v.signature; + return s; + } + + CBOR2_ENCODE(AskRequest::Named) { + auto m{CborEncodeStream::map()}; + m["Miner"] << v.miner; + return s << m; + } + + CBOR2_DECODE(AskRequest::Named) { + auto m{s.map()}; + + CborDecodeStream::named(m, "Miner") >> v.miner; + return s; + } + + CBOR2_ENCODE(AskResponse::Named) { + auto m{CborEncodeStream::map()}; + m["Ask"] << static_cast(v.ask); + return s << m; + } + + CBOR2_DECODE(AskResponse::Named) { + auto m{s.map()}; + CborDecodeStream::named(m, "Ask") + >> *(static_cast(&v.ask)); + return s; + } +} \ No newline at end of file diff --git a/core/markets/storage/provider/CMakeLists.txt b/core/markets/storage/provider/CMakeLists.txt index cf2329c445..d249a2043b 100644 --- a/core/markets/storage/provider/CMakeLists.txt +++ b/core/markets/storage/provider/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(storage_market_provider target_link_libraries(storage_market_provider Boost::boost api + ask_protocol_cbor fuhon_stored_ask outcome piece diff --git a/core/markets/storage/provider/impl/provider_impl.cpp b/core/markets/storage/provider/impl/provider_impl.cpp index 1daa919d4f..06d683807b 100644 --- a/core/markets/storage/provider/impl/provider_impl.cpp +++ b/core/markets/storage/provider/impl/provider_impl.cpp @@ -74,7 +74,7 @@ namespace fc::markets::storage::provider { datatransfer_{std::move(datatransfer)}, deal_info_manager_{std::move(deal_info_manager)} {} - std::shared_ptr StorageProviderImpl::getDealPtr( + std::shared_ptr StorageProviderImpl::getDealPtr( const CID &proposal_cid) { for (auto &it : fsm_->list()) { if (it.first->proposal_cid == proposal_cid) { @@ -89,9 +89,16 @@ namespace fc::markets::storage::provider { filestore_->createDirectories(kStorageMarketImportDir.string())); setAskHandler(kAskProtocolId_v1_0_1); - setAskHandler(kAskProtocolId_v1_1_1); + setAskHandler(kAskProtocolId_v1_1_0); - setDealStatusHandlers(); + setDealStatusHandler( + kDealStatusProtocolId_v1_0_1); + setDealStatusHandler( + kDealStatusProtocolId_v1_1_0); auto handle = [&](auto &&protocol) { host_->setProtocolHandler( @@ -148,7 +155,7 @@ namespace fc::markets::storage::provider { return outcome::success(); } - outcome::result StorageProviderImpl::getDeal( + outcome::result StorageProviderImpl::getDeal( const CID &proposal_cid) const { for (const auto &it : fsm_->list()) { if (it.first->proposal_cid == proposal_cid) { @@ -211,44 +218,43 @@ namespace fc::markets::storage::provider { const std::shared_ptr &stream) { logger_->debug("New deal stream"); - stream->read( - [self{shared_from_this()}, stream](outcome::result proposal) { - if (!self->hasValue(proposal, "Read proposal error: ", stream)) - return; - auto proposal_cid{proposal.value().deal_proposal.cid()}; - auto remote_peer_id = stream->stream()->remotePeerId(); - if (!self->hasValue( - remote_peer_id, "Cannot get remote peer info: ", stream)) - return; - auto remote_multiaddress = stream->stream()->remoteMultiaddr(); - if (!self->hasValue( - remote_multiaddress, "Cannot get remote peer info: ", stream)) - return; - PeerInfo remote_peer_info{.id = remote_peer_id.value(), - .addresses = {remote_multiaddress.value()}}; - std::shared_ptr deal = std::make_shared( - MinerDeal{.client_deal_proposal = proposal.value().deal_proposal, - .proposal_cid = proposal_cid, - .add_funds_cid = boost::none, - .publish_cid = boost::none, - .client = remote_peer_info, - .state = StorageDealStatus::STORAGE_DEAL_UNKNOWN, - .piece_path = {}, - .metadata_path = {}, - .is_fast_retrieval = proposal.value().is_fast_retrieval, - .message = {}, - .ref = proposal.value().piece, - .deal_id = {}}); - std::lock_guard lock(self->connections_mutex_); - self->connections_.emplace(proposal_cid, stream); - OUTCOME_EXCEPT( - self->fsm_->begin(deal, StorageDealStatus::STORAGE_DEAL_UNKNOWN)); - SELF_FSM_SEND(deal, ProviderEvent::ProviderEventOpen); - }); + stream->read([self{shared_from_this()}, + stream](outcome::result proposal) { + if (!self->hasValue(proposal, "Read proposal error: ", stream)) return; + auto proposal_cid{proposal.value().deal_proposal.cid()}; + auto remote_peer_id = stream->stream()->remotePeerId(); + if (!self->hasValue( + remote_peer_id, "Cannot get remote peer info: ", stream)) + return; + auto remote_multiaddress = stream->stream()->remoteMultiaddr(); + if (!self->hasValue( + remote_multiaddress, "Cannot get remote peer info: ", stream)) + return; + PeerInfo remote_peer_info{.id = remote_peer_id.value(), + .addresses = {remote_multiaddress.value()}}; + std::shared_ptr deal = std::make_shared( + MinerDeal0{.client_deal_proposal = proposal.value().deal_proposal, + .proposal_cid = proposal_cid, + .add_funds_cid = boost::none, + .publish_cid = boost::none, + .client = remote_peer_info, + .state = StorageDealStatus::STORAGE_DEAL_UNKNOWN, + .piece_path = {}, + .metadata_path = {}, + .is_fast_retrieval = proposal.value().is_fast_retrieval, + .message = {}, + .ref = proposal.value().piece, + .deal_id = {}}); + std::lock_guard lock(self->connections_mutex_); + self->connections_.emplace(proposal_cid, stream); + OUTCOME_EXCEPT( + self->fsm_->begin(deal, StorageDealStatus::STORAGE_DEAL_UNKNOWN)); + SELF_FSM_SEND(deal, ProviderEvent::ProviderEventOpen); + }); } outcome::result StorageProviderImpl::verifyDealProposal( - const std::shared_ptr &deal) const { + const std::shared_ptr &deal) const { auto proposal = deal->client_deal_proposal.proposal; OUTCOME_TRY(proposal_bytes, codec::cbor::encode(proposal)); OUTCOME_TRY( @@ -324,7 +330,7 @@ namespace fc::markets::storage::provider { outcome::result> StorageProviderImpl::ensureProviderFunds( - const std::shared_ptr &deal) { + const std::shared_ptr &deal) { OUTCOME_TRY(chain_head, api_->ChainHead()); auto proposal = deal->client_deal_proposal.proposal; OUTCOME_TRY(worker_info, @@ -337,7 +343,7 @@ namespace fc::markets::storage::provider { } outcome::result StorageProviderImpl::publishDeal( - const std::shared_ptr &deal) { + const std::shared_ptr &deal) { OUTCOME_TRY(chain_head, api_->ChainHead()); OUTCOME_TRY( worker_info, @@ -362,7 +368,7 @@ namespace fc::markets::storage::provider { } outcome::result StorageProviderImpl::sendSignedResponse( - const std::shared_ptr &deal) { + const std::shared_ptr &deal) { Response response{.state = deal->state, .message = deal->message, .proposal = deal->proposal_cid}; @@ -387,7 +393,7 @@ namespace fc::markets::storage::provider { } outcome::result StorageProviderImpl::locatePiece( - const std::shared_ptr &deal) { + const std::shared_ptr &deal) { OUTCOME_TRY(piece_refs, sector_blocks_->getRefs(deal->deal_id)); boost::optional piece_location; @@ -410,7 +416,7 @@ namespace fc::markets::storage::provider { } outcome::result StorageProviderImpl::recordPieceInfo( - const std::shared_ptr &deal, + const std::shared_ptr &deal, const PieceLocation &piece_location) { std::map locations; if (!deal->metadata_path.empty()) { @@ -441,7 +447,7 @@ namespace fc::markets::storage::provider { } outcome::result StorageProviderImpl::finalizeDeal( - const std::shared_ptr &deal) { + const std::shared_ptr &deal) { std::lock_guard lock(connections_mutex_); auto stream_it = connections_.find(deal->proposal_cid); if (stream_it != connections_.end()) { @@ -521,7 +527,7 @@ namespace fc::markets::storage::provider { } void StorageProviderImpl::onProviderEventOpen( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -535,7 +541,7 @@ namespace fc::markets::storage::provider { } void StorageProviderImpl::onProviderEventDealAccepted( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -555,7 +561,7 @@ namespace fc::markets::storage::provider { } void StorageProviderImpl::onProviderEventWaitingForManualData( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -563,7 +569,7 @@ namespace fc::markets::storage::provider { } void StorageProviderImpl::onProviderEventFundingInitiated( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -586,7 +592,7 @@ namespace fc::markets::storage::provider { } void StorageProviderImpl::onProviderEventFunded( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -597,7 +603,7 @@ namespace fc::markets::storage::provider { } void StorageProviderImpl::onProviderEventDataTransferInitiated( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -605,7 +611,7 @@ namespace fc::markets::storage::provider { } void StorageProviderImpl::onProviderEventDataTransferCompleted( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -623,7 +629,7 @@ namespace fc::markets::storage::provider { } void StorageProviderImpl::onProviderEventVerifiedData( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -641,7 +647,7 @@ namespace fc::markets::storage::provider { } void StorageProviderImpl::onProviderEventDealPublishInitiated( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -667,7 +673,7 @@ namespace fc::markets::storage::provider { } void StorageProviderImpl::onProviderEventDealPublished( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -685,7 +691,7 @@ namespace fc::markets::storage::provider { } void StorageProviderImpl::onProviderEventDealHandedOff( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -699,7 +705,7 @@ namespace fc::markets::storage::provider { } void StorageProviderImpl::onProviderEventDealActivated( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -712,7 +718,7 @@ namespace fc::markets::storage::provider { } void StorageProviderImpl::onProviderEventDealCompleted( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -724,7 +730,7 @@ namespace fc::markets::storage::provider { } void StorageProviderImpl::onProviderEventFailed( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to) { @@ -741,70 +747,20 @@ namespace fc::markets::storage::provider { } } - outcome::result - StorageProviderImpl::prepareDealStateResponse( + outcome::result StorageProviderImpl::handleDealStatus( const DealStatusRequest &request) const { OUTCOME_TRY(deal, getDeal(request.proposal)); // verify client's signature - OUTCOME_TRY(bytes, codec::cbor::encode(request.proposal)); - const auto &address = deal.client_deal_proposal.proposal.client; + OUTCOME_TRY(bytes, request.getDigest()); + const auto &client_address = deal.client_deal_proposal.proposal.client; OUTCOME_TRY(verified, - api_->WalletVerify(address, bytes, request.signature)); + api_->WalletVerify(client_address, bytes, request.signature)); if (!verified) { return ERROR_TEXT("Wrong request signature"); } - return ProviderDealState{ - deal.state, - deal.message, - deal.client_deal_proposal.proposal, - deal.proposal_cid, - deal.add_funds_cid, - deal.publish_cid, - deal.deal_id, - deal.is_fast_retrieval, - }; - } - - outcome::result StorageProviderImpl::handleDealStatus( - const DealStatusRequest &request) const { - ProviderDealState state; - auto maybe_state = prepareDealStateResponse(request); - if (maybe_state.has_error()) { - state.status = StorageDealStatus::STORAGE_DEAL_ERROR; - state.message = maybe_state.error().message(); - } else { - state = std::move(maybe_state.value()); - } - OUTCOME_TRY(input, codec::cbor::encode(state)); - OUTCOME_TRY(siganture, sign(input)); - return DealStatusResponse{state, siganture}; - } - - void StorageProviderImpl::setDealStatusHandlers() { - auto handle{[&](auto &&protocol) { - host_->setProtocolHandler( - protocol, [provider_ptr{weak_from_this()}](auto _stream) { - auto stream{std::make_shared(_stream)}; - stream->template read( - [provider_ptr, stream](auto _request) { - if (_request) { - auto &request{_request.value()}; - if (auto provider{provider_ptr.lock()}) { - if (auto maybe_response{ - provider->handleDealStatus(request)}) { - stream->write(maybe_response.value(), - [stream](auto) { stream->close(); }); - } - } - } - stream->stream()->reset(); - }); - }); - }}; - handle(kDealStatusProtocolId_v1_0_1); - handle(kDealStatusProtocolId_v1_1_1); + return std::move(deal); } } // namespace fc::markets::storage::provider diff --git a/core/markets/storage/provider/impl/provider_impl.hpp b/core/markets/storage/provider/impl/provider_impl.hpp index 5d7e521bde..1073067e5c 100644 --- a/core/markets/storage/provider/impl/provider_impl.hpp +++ b/core/markets/storage/provider/impl/provider_impl.hpp @@ -18,6 +18,7 @@ #include "markets/storage/provider/provider.hpp" #include "markets/storage/provider/provider_events.hpp" #include "markets/storage/provider/stored_ask.hpp" +#include "markets/storage/status_protocol.hpp" #include "sectorblocks/blocks.hpp" #include "storage/filestore/filestore.hpp" #include "storage/keystore/keystore.hpp" @@ -40,9 +41,9 @@ namespace fc::markets::storage::provider { using sectorblocks::SectorBlocks; using vm::actor::builtin::types::market::deal_info_manager::DealInfoManager; using ProviderTransition = - fsm::Transition; + fsm::Transition; using ProviderFSM = - fsm::FSM; + fsm::FSM; using data_transfer::DataTransfer; const EpochDuration kDefaultDealAcceptanceBuffer{100}; @@ -65,7 +66,7 @@ namespace fc::markets::storage::provider { std::shared_ptr filestore, std::shared_ptr deal_info_manager); - std::shared_ptr getDealPtr(const CID &proposal_cid); + std::shared_ptr getDealPtr(const CID &proposal_cid); auto init() -> outcome::result override; @@ -74,7 +75,7 @@ namespace fc::markets::storage::provider { auto stop() -> outcome::result override; auto getDeal(const CID &proposal_cid) const - -> outcome::result override; + -> outcome::result override; auto importDataForDeal(const CID &proposal_cid, const boost::filesystem::path &path) @@ -83,6 +84,12 @@ namespace fc::markets::storage::provider { outcome::result sign(const Bytes &input) const; private: + /** + * Sets deal ask protocol handlers for different protocol versions. + * @tparam AskRequestType - ask request type for the protocol version + * @tparam AskResponseType - ask response type for the protocol + * @param protocol - protocol string + */ template inline void setAskHandler(const std::string &protocol) { host_->setProtocolHandler( @@ -93,7 +100,7 @@ namespace fc::markets::storage::provider { if (request) { if (auto asker{stored_ask.lock()}) { if (auto ask{asker->getAsk(request.value().miner)}) { - return stream->write(AskResponseType{ask.value()}, + return stream->write(AskResponseType{{ask.value()}}, [stream](auto) { stream->close(); }); } } @@ -103,13 +110,49 @@ namespace fc::markets::storage::provider { }); } - outcome::result prepareDealStateResponse( - const DealStatusRequest &request) const; + template + inline void setDealStatusHandler(const std::string &protocol) { + host_->setProtocolHandler( + protocol, [provider_ptr{weak_from_this()}](auto _stream) { + auto stream{std::make_shared(_stream)}; + stream->template read([provider_ptr, stream]( + auto _request) { + if (_request) { + auto &request{_request.value()}; + if (auto provider{provider_ptr.lock()}) { + if (auto maybe_response{provider->prepareDealStateResponse< + ProviderDealStateType, + DealStatusResponseType>(request)}) { + stream->write(maybe_response.value(), + [stream](auto) { stream->close(); }); + } + } + } + stream->stream()->reset(); + }); + }); + } - outcome::result handleDealStatus( - const DealStatusRequest &request) const; + template + outcome::result prepareDealStateResponse( + const DealStatusRequest &request) const { + auto maybe_state = handleDealStatus(request); + ProviderDealStateType state; + if (maybe_state.has_error()) { + state.status = StorageDealStatus::STORAGE_DEAL_ERROR; + state.message = maybe_state.error().message(); + } else { + state = std::move(maybe_state.value()); + } + OUTCOME_TRY(digest, state.getDigest()); + OUTCOME_TRY(signature, sign(digest)); + return DealStatusResponseType{state, signature}; + } - void setDealStatusHandlers(); + outcome::result handleDealStatus( + const DealStatusRequest &request) const; /** * Handle incoming deal proposal stream @@ -123,7 +166,7 @@ namespace fc::markets::storage::provider { * @return true if verified or false otherwise */ outcome::result verifyDealProposal( - const std::shared_ptr &deal) const; + const std::shared_ptr &deal) const; /** * Ensure provider has enough funds @@ -131,21 +174,21 @@ namespace fc::markets::storage::provider { * @return cid of funding message if it was sent */ outcome::result> ensureProviderFunds( - const std::shared_ptr &deal); + const std::shared_ptr &deal); /** * Publish storage deal * @param deal to publish * @return CID of message sent */ - outcome::result publishDeal(const std::shared_ptr &deal); + outcome::result publishDeal(const std::shared_ptr &deal); /** * Send signed response to storage deal proposal and close connection * @param deal - state of deal */ outcome::result sendSignedResponse( - const std::shared_ptr &deal); + const std::shared_ptr &deal); /** * Locate piece for deal @@ -153,7 +196,7 @@ namespace fc::markets::storage::provider { * @return piece info with location */ outcome::result locatePiece( - const std::shared_ptr &deal); + const std::shared_ptr &deal); /** * Records sector information about an activated deal so that the data can @@ -163,7 +206,7 @@ namespace fc::markets::storage::provider { * @return error in case of failure */ outcome::result recordPieceInfo( - const std::shared_ptr &deal, + const std::shared_ptr &deal, const PieceLocation &piece_location); /** @@ -178,7 +221,7 @@ namespace fc::markets::storage::provider { * Finalize deal, close connection, clean up * @param deal - deal to clean up */ - outcome::result finalizeDeal(const std::shared_ptr &deal); + outcome::result finalizeDeal(const std::shared_ptr &deal); /** * Creates all FSM transitions @@ -194,7 +237,7 @@ namespace fc::markets::storage::provider { * @param from - STORAGE_DEAL_UNKNOWN * @param to - STORAGE_DEAL_VALIDATING */ - void onProviderEventOpen(const std::shared_ptr &deal, + void onProviderEventOpen(const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to); @@ -206,7 +249,7 @@ namespace fc::markets::storage::provider { * @param from - STORAGE_DEAL_VALIDATING * @param to - STORAGE_DEAL_PROPOSAL_ACCEPTED */ - void onProviderEventDealAccepted(const std::shared_ptr &deal, + void onProviderEventDealAccepted(const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to); @@ -219,7 +262,7 @@ namespace fc::markets::storage::provider { * @param to - STORAGE_DEAL_WAITING_FOR_DATA */ void onProviderEventWaitingForManualData( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to); @@ -231,10 +274,11 @@ namespace fc::markets::storage::provider { * @param from - STORAGE_DEAL_PROPOSAL_ACCEPTED * @param to - STORAGE_DEAL_WAITING_FOR_DATA */ - void onProviderEventFundingInitiated(const std::shared_ptr &deal, - ProviderEvent event, - StorageDealStatus from, - StorageDealStatus to); + void onProviderEventFundingInitiated( + const std::shared_ptr &deal, + ProviderEvent event, + StorageDealStatus from, + StorageDealStatus to); /** * @brief Handle event funded @@ -243,7 +287,7 @@ namespace fc::markets::storage::provider { * @param from - STORAGE_DEAL_PROPOSAL_ACCEPTED * @param to - STORAGE_DEAL_WAITING_FOR_DATA */ - void onProviderEventFunded(const std::shared_ptr &deal, + void onProviderEventFunded(const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to); @@ -256,7 +300,7 @@ namespace fc::markets::storage::provider { * @param to - STORAGE_DEAL_TRANSFERRING */ void onProviderEventDataTransferInitiated( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to); @@ -269,7 +313,7 @@ namespace fc::markets::storage::provider { * @param to - STORAGE_DEAL_VERIFY_DATA */ void onProviderEventDataTransferCompleted( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to); @@ -281,7 +325,7 @@ namespace fc::markets::storage::provider { * @param from - STORAGE_DEAL_VERIFY_DATA * @param to - STORAGE_DEAL_FAILING */ - void onProviderEventVerifiedData(const std::shared_ptr &deal, + void onProviderEventVerifiedData(const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to); @@ -294,7 +338,7 @@ namespace fc::markets::storage::provider { * @param to - STORAGE_DEAL_FAILING */ void onProviderEventDealPublishInitiated( - const std::shared_ptr &deal, + const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to); @@ -306,7 +350,7 @@ namespace fc::markets::storage::provider { * @param from - STORAGE_DEAL_VERIFY_DATA or STORAGE_DEAL_WAITING_FOR_DATA * @param to - STORAGE_DEAL_ENSURE_PROVIDER_FUNDS */ - void onProviderEventDealPublished(const std::shared_ptr &deal, + void onProviderEventDealPublished(const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to); @@ -318,7 +362,7 @@ namespace fc::markets::storage::provider { * @param from - STORAGE_DEAL_STAGED * @param to - STORAGE_DEAL_SEALING */ - void onProviderEventDealHandedOff(const std::shared_ptr &deal, + void onProviderEventDealHandedOff(const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to); @@ -330,7 +374,7 @@ namespace fc::markets::storage::provider { * @param from - STORAGE_DEAL_SEALING * @param to - STORAGE_DEAL_ACTIVE */ - void onProviderEventDealActivated(const std::shared_ptr &deal, + void onProviderEventDealActivated(const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to); @@ -342,7 +386,7 @@ namespace fc::markets::storage::provider { * @param from - STORAGE_DEAL_ACTIVE * @param to - STORAGE_DEAL_FAILING */ - void onProviderEventDealCompleted(const std::shared_ptr &deal, + void onProviderEventDealCompleted(const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to); @@ -354,7 +398,7 @@ namespace fc::markets::storage::provider { * @param from - STORAGE_DEAL_FAILING * @param to - STORAGE_DEAL_ERROR */ - void onProviderEventFailed(const std::shared_ptr &deal, + void onProviderEventFailed(const std::shared_ptr &deal, ProviderEvent event, StorageDealStatus from, StorageDealStatus to); diff --git a/core/markets/storage/provider/provider.hpp b/core/markets/storage/provider/provider.hpp index a7f4510d9d..9a7ecac6aa 100644 --- a/core/markets/storage/provider/provider.hpp +++ b/core/markets/storage/provider/provider.hpp @@ -32,7 +32,7 @@ namespace fc::markets::storage::provider { * @return deal data */ virtual auto getDeal(const CID &proposal_cid) const - -> outcome::result = 0; + -> outcome::result = 0; /** * Imports data to proceed deal with 'manual' transfer type diff --git a/core/markets/storage/status_protocol.hpp b/core/markets/storage/status_protocol.hpp new file mode 100644 index 0000000000..e75c27c52b --- /dev/null +++ b/core/markets/storage/status_protocol.hpp @@ -0,0 +1,271 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#include "codec/cbor/streams_annotation.hpp" +#include "markets/storage/deal_protocol.hpp" +#include "primitives/cid/cid.hpp" +#include "primitives/types.hpp" +#include "vm/actor/builtin/types/market/deal.hpp" + +namespace fc::markets::storage { + using codec::cbor::CborDecodeStream; + using codec::cbor::CborEncodeStream; + using primitives::DealId; + using vm::actor::builtin::types::market::DealProposal; + + const libp2p::peer::Protocol kDealStatusProtocolId_v1_0_1{ + "/fil/storage/status/1.0.1"}; + const libp2p::peer::Protocol kDealStatusProtocolId_v1_1_0{ + "/fil/storage/status/1.1.0"}; + + /** + * Base class for ProviderDealState + */ + struct ProviderDealState { + virtual ~ProviderDealState() = default; + + virtual outcome::result getDigest() const = 0; + + StorageDealStatus status{}; + std::string message; + DealProposal proposal; + CID proposal_cid; + boost::optional add_funds_cid; + boost::optional publish_cid; + DealId id{}; + bool fast_retrieval{}; + }; + + /** State used in V1.0.1 */ + struct ProviderDealStateV1_0_1 : public ProviderDealState { + ProviderDealStateV1_0_1() = default; + + ProviderDealStateV1_0_1 &operator=(MinerDeal0 &&other) { + status = other.state; + message = std::move(other.message); + proposal = std::move(other.client_deal_proposal.proposal); + proposal_cid = std::move(other.proposal_cid); + add_funds_cid = std::move(other.add_funds_cid); + publish_cid = std::move(other.publish_cid); + id = other.deal_id; + fast_retrieval = other.is_fast_retrieval; + return *this; + } + + outcome::result getDigest() const override { + return codec::cbor::encode(*this); + } + }; + + CBOR_TUPLE(ProviderDealStateV1_0_1, + status, + message, + proposal, + proposal_cid, + add_funds_cid, + publish_cid, + id, + fast_retrieval) + + /** State used in V1.1.0. Cbores with field names. */ + struct ProviderDealStateV1_1_0 : public ProviderDealState { + ProviderDealStateV1_1_0() = default; + + ProviderDealStateV1_1_0(StorageDealStatus status, + std::string message, + DealProposal proposal, + CID proposal_cid, + boost::optional add_funds_cid, + boost::optional publish_cid, + DealId id, + bool fast_retrieval) { + this->status = status; + this->message = std::move(message); + this->proposal = std::move(proposal); + this->proposal_cid = std::move(proposal_cid); + this->add_funds_cid = std::move(add_funds_cid); + this->publish_cid = std::move(publish_cid); + this->id = id; + this->fast_retrieval = fast_retrieval; + } + + ProviderDealStateV1_1_0 &operator=(MinerDeal0 &&other) { + status = other.state; + message = std::move(other.message); + proposal = std::move(other.client_deal_proposal.proposal); + proposal_cid = std::move(other.proposal_cid); + add_funds_cid = std::move(other.add_funds_cid); + publish_cid = std::move(other.publish_cid); + id = other.deal_id; + fast_retrieval = other.is_fast_retrieval; + return *this; + } + + outcome::result getDigest() const override { + return codec::cbor::encode(*this); + } + }; + + inline CBOR2_ENCODE(ProviderDealStateV1_1_0) { + auto m{CborEncodeStream::map()}; + m["State"] << v.status; + m["Message"] << v.message; + m["Proposal"] << v.proposal; + m["ProposalCid"] << v.proposal_cid; + m["AddFundsCid"] << v.add_funds_cid; + m["PublishCid"] << v.publish_cid; + m["DealID"] << v.id; + m["FastRetrieval"] << v.fast_retrieval; + return s << m; + } + + inline CBOR2_DECODE(ProviderDealStateV1_1_0) { + auto m{s.map()}; + CborDecodeStream::named(m, "State") >> v.status; + CborDecodeStream::named(m, "Message") >> v.message; + CborDecodeStream::named(m, "Proposal") >> v.proposal; + CborDecodeStream::named(m, "ProposalCid") >> v.proposal_cid; + CborDecodeStream::named(m, "AddFundsCid") >> v.add_funds_cid; + CborDecodeStream::named(m, "PublishCid") >> v.publish_cid; + CborDecodeStream::named(m, "DealID") >> v.id; + CborDecodeStream::named(m, "FastRetrieval") >> v.fast_retrieval; + return s; + } + + /** + * Base class for deal status request. + */ + struct DealStatusRequest { + /** Returns request digset, it is a cbor of proposal CID */ + outcome::result getDigest() const { + return codec::cbor::encode(proposal); + }; + + CID proposal; + Signature signature; + }; + + /** Request used in V1.0.1 */ + struct DealStatusRequestV1_0_1 : public DealStatusRequest {}; + + CBOR_TUPLE(DealStatusRequestV1_0_1, proposal, signature) + + /** Request used in V1.1.0. Cbores with field names. */ + struct DealStatusRequestV1_1_0 : public DealStatusRequest { + DealStatusRequestV1_1_0() = default; + + DealStatusRequestV1_1_0(CID proposal, Signature signature) { + this->proposal = std::move(proposal); + this->signature = std::move(signature); + } + }; + + inline CBOR2_ENCODE(DealStatusRequestV1_1_0) { + auto m{CborEncodeStream::map()}; + m["Proposal"] << v.proposal; + m["Signature"] << v.signature; + return s << m; + } + + inline CBOR2_DECODE(DealStatusRequestV1_1_0) { + auto m{s.map()}; + CborDecodeStream::named(m, "Proposal") >> v.proposal; + CborDecodeStream::named(m, "Signature") >> v.signature; + return s; + } + + /** + * Base class for deal response. + * State depends on the protocol version. + */ + struct DealStatusResponse { + virtual ~DealStatusResponse() = default; + virtual const ProviderDealState &state() const = 0; + Signature signature; + }; + + /** Response used in V1.0.1 */ + struct DealStatusResponseV1_0_1 : public DealStatusResponse { + DealStatusResponseV1_0_1() + : state_{std::make_shared()} {} + + DealStatusResponseV1_0_1(const ProviderDealStateV1_0_1 &state, + Signature signature) + : state_{std::make_shared(state)} { + this->signature = std::move(signature); + } + + const ProviderDealState &state() const override { + return *state_; + } + + private: + friend CborEncodeStream &operator<<(CborEncodeStream &, + const DealStatusResponseV1_0_1 &); + friend CborDecodeStream &operator>>(CborDecodeStream &, + DealStatusResponseV1_0_1 &); + + std::shared_ptr state_; + }; + + inline CBOR2_ENCODE(DealStatusResponseV1_0_1) { + return s << *v.state_ << v.signature; + } + inline CBOR2_DECODE(DealStatusResponseV1_0_1) { + ProviderDealStateV1_0_1 state; + s >> state; + v.state_ = std::make_shared(std::move(state)); + s >> v.signature; + return s; + } + + /** Response used in V1.1.0 with named fields. */ + struct DealStatusResponseV1_1_0 : public DealStatusResponse { + DealStatusResponseV1_1_0() + : state_{std::make_shared()} {} + + DealStatusResponseV1_1_0(const ProviderDealStateV1_1_0 &state, + Signature signature) + : state_{std::make_shared(state)} { + this->signature = std::move(signature); + } + + DealStatusResponseV1_1_0(std::shared_ptr state, + Signature signature) + : state_(std::move(state)) { + this->signature = std::move(signature); + } + const ProviderDealState &state() const override { + return *state_; + } + + private: + friend CborEncodeStream &operator<<(CborEncodeStream &, + const DealStatusResponseV1_1_0 &); + friend CborDecodeStream &operator>>(CborDecodeStream &, + DealStatusResponseV1_1_0 &); + std::shared_ptr state_; + }; + + inline CBOR2_ENCODE(DealStatusResponseV1_1_0) { + auto m{CborEncodeStream::map()}; + m["DealState"] << *v.state_; + m["Signature"] << v.signature; + return s << m; + } + + inline CBOR2_DECODE(DealStatusResponseV1_1_0) { + auto m{s.map()}; + ProviderDealStateV1_1_0 state; + CborDecodeStream::named(m, "DealState") >> state; + v.state_ = std::make_shared(std::move(state)); + CborDecodeStream::named(m, "Signature") >> v.signature; + return s; + } +} // namespace fc::markets::storage \ No newline at end of file diff --git a/housekeeping/clang-tidy.sh b/housekeeping/clang-tidy.sh index bad7ea42af..f24dde88e9 100755 --- a/housekeeping/clang-tidy.sh +++ b/housekeeping/clang-tidy.sh @@ -26,7 +26,6 @@ function get_files(){ BUILD_DIR=$(get_abs_path $1) cd $(dirname $0)/.. -# EXPLAIN: core/**/*.cpp files FILES=$(get_files | grep '^core\/.*\.cpp$') # LOCAL: replace CLANG_TIDY and RUN_CLANG_TIDY to downloaded version diff --git a/test/core/markets/storage/CMakeLists.txt b/test/core/markets/storage/CMakeLists.txt index c37e03806d..2491909d3d 100644 --- a/test/core/markets/storage/CMakeLists.txt +++ b/test/core/markets/storage/CMakeLists.txt @@ -4,6 +4,7 @@ # add_subdirectory(chain_events) +add_subdirectory(protocol) add_subdirectory(provider) addtest(storage_market_test diff --git a/test/core/markets/storage/protocol/CMakeLists.txt b/test/core/markets/storage/protocol/CMakeLists.txt new file mode 100644 index 0000000000..161006dd70 --- /dev/null +++ b/test/core/markets/storage/protocol/CMakeLists.txt @@ -0,0 +1,15 @@ +#ask_protocol_named_cbor_test +# Copyright Soramitsu Co., Ltd. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# + +addtest(storage_market_protocol_named_cbor_test + ask_protocol_named_cbor_test.cpp + status_protocol_named_cbor_test.cpp + ) +target_link_libraries(storage_market_protocol_named_cbor_test + ask_protocol_cbor + address + cbor + signature + ) diff --git a/test/core/markets/storage/protocol/ask_protocol_named_cbor_test.cpp b/test/core/markets/storage/protocol/ask_protocol_named_cbor_test.cpp new file mode 100644 index 0000000000..d5d8ddc525 --- /dev/null +++ b/test/core/markets/storage/protocol/ask_protocol_named_cbor_test.cpp @@ -0,0 +1,166 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "markets/storage/ask_protocol.hpp" +#include "testutil/cbor.hpp" +#include "testutil/outcome.hpp" + +namespace fc::markets::storage { + using primitives::address::Address; + using primitives::address::decodeFromString; + using primitives::piece::PaddedPieceSize; + + /** + * Tests storage market ask protocol. + * Expected encoded bytes are from go-fil-markets implementation (commit: + * b1a66cfd12686a8af6030fccace49916849b1954). + * Note: The order of named fields is not determined, so we cannot just + * compare raw bytes. + */ + class AskProtocolTest : public ::testing::Test { + public: + // address from go test constants + Address address = + decodeFromString("t2i4llai5x72clnz643iydyplvjmni74x4vyme7ny").value(); + // storage ask used in go tests + StorageAsk expected_storage_ask{ + .price = 123, + .verified_price = 456, + .min_piece_size = PaddedPieceSize{256}, + .max_piece_size = PaddedPieceSize{1 << 20}, + .miner = address, + .timestamp = 1234, + .expiry = 6789, + .seq_no = 42, + }; + crypto::signature::Signature signature{ + crypto::signature::Secp256k1Signature{}}; + + void expectStorageAsksEqual(const StorageAsk &lhs, const StorageAsk &rhs) { + EXPECT_EQ(lhs.price, rhs.price); + EXPECT_EQ(lhs.verified_price, rhs.verified_price); + EXPECT_EQ(lhs.min_piece_size, rhs.min_piece_size); + EXPECT_EQ(lhs.max_piece_size, rhs.max_piece_size); + EXPECT_EQ(lhs.miner, rhs.miner); + EXPECT_EQ(lhs.timestamp, rhs.timestamp); + EXPECT_EQ(lhs.expiry, rhs.expiry); + EXPECT_EQ(lhs.seq_no, rhs.seq_no); + } + + template + T encodeAndDecodeNamed(const T &value) { + using Named = typename T::Named; + EXPECT_OUTCOME_TRUE(encoded, fc::codec::cbor::encode(Named{value})); + EXPECT_OUTCOME_TRUE(decoded, fc::codec::cbor::decode(encoded)); + return decoded; + } + }; + + /** + * Encode and decode, must be equal + */ + TEST_F(AskProtocolTest, StorageAskEncodeAndDecode) { + auto decoded = encodeAndDecodeNamed(expected_storage_ask); + expectStorageAsksEqual(decoded, expected_storage_ask); + } + + /** + * @given StorageAsk encoded in go-fil-markets implementation + * @when decode it + * @then storage ask is decoded and expected values present + */ + TEST_F(AskProtocolTest, StorageAskCborNamedDecodeFromGo) { + const auto go_encoded = + "a865507269636542007b6d56657269666965645072696365430001c86c4d696e506965636553697a651901006c4d6178506965636553697a651a00100000654d696e657255024716b023b7fe84b6e7dcda303c3d754b1a8ff2fc6954696d657374616d701904d266457870697279191a85655365714e6f182a"_unhex; + + EXPECT_OUTCOME_TRUE(decoded, + fc::codec::cbor::decode(go_encoded)); + expectStorageAsksEqual(decoded, expected_storage_ask); + } + + /** + * Encode and decode, must be equal + */ + TEST_F(AskProtocolTest, SignedStorageAskEncodeAndDecode) { + SignedStorageAsk expected_signed_ask{ + .ask = expected_storage_ask, + .signature = signature, + }; + auto decoded = encodeAndDecodeNamed(expected_signed_ask); + expectStorageAsksEqual(decoded.ask, expected_storage_ask); + EXPECT_TRUE(decoded.signature == signature); + } + + /** + * @given StorageAsk encoded in go-fil-markets implementation + * @when decode it + * @then signed storage ask is decoded and expected values present + */ + TEST_F(AskProtocolTest, SignedStorageAskCborNamedDecodeFromGo) { + auto go_encoded = + "a26341736ba865507269636542007b6d56657269666965645072696365430001c86c4d696e506965636553697a651901006c4d6178506965636553697a651a00100000654d696e657255024716b023b7fe84b6e7dcda303c3d754b1a8ff2fc6954696d657374616d701904d266457870697279191a85655365714e6f182a695369676e61747572655842010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"_unhex; + + EXPECT_OUTCOME_TRUE( + decoded, fc::codec::cbor::decode(go_encoded)); + + EXPECT_TRUE(decoded.signature == signature); + expectStorageAsksEqual(decoded.ask, expected_storage_ask); + } + + /** + * Encode and decode, must be equal + */ + TEST_F(AskProtocolTest, AskRequestEncodeAndDecode) { + AskRequest expected_request{ + .miner = address, + }; + auto decoded = encodeAndDecodeNamed(expected_request); + EXPECT_EQ(decoded.miner, expected_request.miner); + } + + /** + * @given AskRequest encoded in go-fil-markets implementation + * @when decode it + * @then decoded and expected values are present + */ + TEST_F(AskProtocolTest, AskRequestCborNamedDecodeFromGo) { + auto go_encoded = + "a1654d696e657255024716b023b7fe84b6e7dcda303c3d754b1a8ff2fc"_unhex; + + EXPECT_OUTCOME_TRUE(decoded, + fc::codec::cbor::decode(go_encoded)); + EXPECT_EQ(decoded.miner, address); + } + + /** + * Encode and decode, must be equal + */ + TEST_F(AskProtocolTest, AskResponseEncodeAndDecode) { + AskResponse expected_response{.ask = SignedStorageAsk{ + .ask = expected_storage_ask, + .signature = signature, + }}; + auto decoded = encodeAndDecodeNamed(expected_response); + EXPECT_TRUE(decoded.ask.signature == signature); + expectStorageAsksEqual(decoded.ask.ask, expected_storage_ask); + } + + /** + * @given AskResponse encoded in go-fil-markets implementation + * @when decode it + * @then decoded and expected values are present + */ + TEST_F(AskProtocolTest, AskResponseCborNamedDecodeFromGo) { + auto go_encoded = + "a16341736ba26341736ba865507269636542007b6d56657269666965645072696365430001c86c4d696e506965636553697a651901006c4d6178506965636553697a651a00100000654d696e657255024716b023b7fe84b6e7dcda303c3d754b1a8ff2fc6954696d657374616d701904d266457870697279191a85655365714e6f182a695369676e61747572655842010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"_unhex; + + EXPECT_OUTCOME_TRUE( + decoded, fc::codec::cbor::decode(go_encoded)); + EXPECT_TRUE(decoded.ask.signature == signature); + expectStorageAsksEqual(decoded.ask.ask, expected_storage_ask); + } +} // namespace fc::markets::storage \ No newline at end of file diff --git a/test/core/markets/storage/protocol/status_protocol_named_cbor_test.cpp b/test/core/markets/storage/protocol/status_protocol_named_cbor_test.cpp new file mode 100644 index 0000000000..d2b65f6347 --- /dev/null +++ b/test/core/markets/storage/protocol/status_protocol_named_cbor_test.cpp @@ -0,0 +1,147 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "markets/storage/status_protocol.hpp" +#include "testutil/cbor.hpp" +#include "testutil/outcome.hpp" + +namespace fc::markets::storage { + using primitives::address::Address; + using primitives::address::decodeFromString; + using primitives::piece::PaddedPieceSize; + using vm::actor::builtin::types::market::ClientDealProposal; + using vm::actor::builtin::types::market::DealProposal; + + /** + * Tests storage market deal status protocol. + * Expected encoded bytes are from go-fil-markets implementation (commit: + * b1a66cfd12686a8af6030fccace49916849b1954). + * Note: The order of named fields is not determined, so we cannot just + * compare raw bytes. + */ + class DealProtocolTest : public ::testing::Test { + public: + // address from go test constants + Address address = + decodeFromString("t2i4llai5x72clnz643iydyplvjmni74x4vyme7ny").value(); + // CID from go-generated string + CID cid = CID::fromString("QmTTA2daxGqo5denp6SwLzzkLJm3fuisYEi9CoWsuHpzfb") + .value(); + crypto::signature::Signature signature{ + crypto::signature::Secp256k1Signature{}}; + + DealProposal deal_proposal{ + .piece_cid = cid, + .piece_size = PaddedPieceSize{256}, + .verified = true, + .client = address, + .provider = address, + .label = "label", + .start_epoch = 101, + .end_epoch = 2002, + .storage_price_per_epoch = 22, + .provider_collateral = 333, + .client_collateral = 4444, + }; + + ProviderDealStateV1_1_0 provider_deal_state{ + StorageDealStatus::STORAGE_DEAL_UNKNOWN, + "message", + deal_proposal, + cid, + cid, + cid, + 42, + true, + }; + + DealStatusResponseV1_1_0 deal_status_response{ + provider_deal_state, + signature, + }; + + template + T encodeAndDecodeNamed(const T &value) { + EXPECT_OUTCOME_TRUE(encoded, fc::codec::cbor::encode(value)); + EXPECT_OUTCOME_TRUE(decoded, fc::codec::cbor::decode(encoded)); + return decoded; + } + + /** Ensures the deal_status_response has expected values */ + void expectDealStatusResponse(const DealStatusResponse &response) { + EXPECT_EQ(response.state().status, + StorageDealStatus::STORAGE_DEAL_UNKNOWN); + EXPECT_EQ(response.state().message, "message"); + EXPECT_EQ(response.state().proposal.piece_cid, cid); + EXPECT_EQ(response.state().proposal.piece_size, PaddedPieceSize{256}); + EXPECT_EQ(response.state().proposal.verified, true); + EXPECT_EQ(response.state().proposal.client, address); + EXPECT_EQ(response.state().proposal.provider, address); + EXPECT_EQ(response.state().proposal.label, "label"); + EXPECT_EQ(response.state().proposal.start_epoch, 101); + EXPECT_EQ(response.state().proposal.end_epoch, 2002); + EXPECT_EQ(response.state().proposal.storage_price_per_epoch, 22); + EXPECT_EQ(response.state().proposal.provider_collateral, 333); + EXPECT_EQ(response.state().proposal.client_collateral, 4444); + EXPECT_EQ(response.state().proposal_cid, cid); + EXPECT_EQ(*response.state().add_funds_cid, cid); + EXPECT_EQ(*response.state().publish_cid, cid); + EXPECT_EQ(response.state().id, 42); + EXPECT_EQ(response.state().fast_retrieval, true); + EXPECT_TRUE(response.signature == signature); + } + }; + + /** + * Encode and decode, must be equal + */ + TEST_F(DealProtocolTest, DealStatusRequestEncodeAndDecode) { + DealStatusRequestV1_1_0 request{cid, signature}; + auto decoded = encodeAndDecodeNamed(request); + EXPECT_EQ(decoded.proposal, request.proposal); + EXPECT_TRUE(decoded.signature == request.signature); + } + + /** + * @given DealStatusRequest encoded in go-fil-markets implementation + * @when decode it + * @then DealStatusRequest is decoded and expected values present + */ + TEST_F(DealProtocolTest, DealStatusRequestCborNamedDecodeFromGo) { + const auto go_encoded = + "a26850726f706f73616cd82a58230012204bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a695369676e61747572655842010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"_unhex; + + EXPECT_OUTCOME_TRUE( + decoded, codec::cbor::decode(go_encoded)); + EXPECT_EQ(decoded.proposal, cid); + EXPECT_TRUE(decoded.signature == signature); + } + + /** + * Encode and decode, must be equal + */ + TEST_F(DealProtocolTest, DealStatusResponseEncodeAndDecode) { + auto decoded = + encodeAndDecodeNamed(deal_status_response); + expectDealStatusResponse(decoded); + } + + /** + * @given DealStatusResponse encoded in go-fil-markets implementation + * @when decode it + * @then DealStatusResponse is decoded and expected values present + */ + TEST_F(DealProtocolTest, DealStatusResponseCborNamedDecodeFromGo) { + const auto go_encoded = + "a2694465616c5374617465a865537461746500674d657373616765676d6573736167656850726f706f73616c8bd82a58230012204bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a190100f555024716b023b7fe84b6e7dcda303c3d754b1a8ff2fc55024716b023b7fe84b6e7dcda303c3d754b1a8ff2fc656c6162656c18651907d24200164300014d4300115c6b50726f706f73616c436964d82a58230012204bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a6b41646446756e6473436964d82a58230012204bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a6a5075626c697368436964d82a58230012204bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a664465616c4944182a6d4661737452657472696576616cf5695369676e61747572655842010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"_unhex; + + EXPECT_OUTCOME_TRUE( + decoded, codec::cbor::decode(go_encoded)); + expectDealStatusResponse(decoded); + } + +} // namespace fc::markets::storage \ No newline at end of file diff --git a/test/core/markets/storage/storage_market_fixture.hpp b/test/core/markets/storage/storage_market_fixture.hpp index 8ee259bad4..c2b24cd88d 100644 --- a/test/core/markets/storage/storage_market_fixture.hpp +++ b/test/core/markets/storage/storage_market_fixture.hpp @@ -456,13 +456,13 @@ namespace fc::markets::storage::test { return new_client; } - outcome::result makeDataRef( + outcome::result makeDataRef( const boost::filesystem::path &file_path) { OUTCOME_TRY(root, import_manager->import(file_path, true)); OUTCOME_TRY(piece_commitment, piece_io_->generatePieceCommitment(registered_proof, file_path.string())); - return DataRef{.transfer_type = kTransferTypeManual, + return DataRef0{.transfer_type = kTransferTypeManual, .root = root, .piece_cid = piece_commitment.first, .piece_size = piece_commitment.second};