12
12
#include " markets/pieceio/pieceio_impl.hpp"
13
13
#include " vm/message/message.hpp"
14
14
#include " vm/message/message_util.hpp"
15
+ #include " markets/storage/common.hpp"
15
16
16
17
#define CALLBACK_ACTION (_action ) \
17
18
[self{shared_from_this ()}](auto deal, auto event, auto from, auto to) { \
20
21
deal->state = to; \
21
22
}
22
23
23
- #define FSM_SEND (client_deal, event ) \
24
- OUTCOME_EXCEPT (fsm_->send (client_deal, event))
25
-
26
- #define SELF_FSM_SEND (client_deal, event ) \
27
- OUTCOME_EXCEPT (self->fsm_->send (client_deal, event))
24
+ #define FSM_HALT_ON_ERROR (result, msg, deal ) \
25
+ if (result.has_error()) { \
26
+ deal->message = msg + std::string (" . " ) + result.error ().message (); \
27
+ FSM_SEND (deal, ClientEvent::ClientEventFailed); \
28
+ return ; \
29
+ }
28
30
29
31
#define SELF_FSM_HALT_ON_ERROR (result, msg, deal ) \
30
32
if (result.has_error()) { \
34
36
}
35
37
36
38
namespace fc ::markets::storage::client {
37
-
39
+ using api::MsgWait;
38
40
using host::HostContext;
39
41
using host::HostContextImpl;
40
42
using libp2p::peer::PeerId;
@@ -43,6 +45,7 @@ namespace fc::markets::storage::client {
43
45
using vm::VMExitCode;
44
46
using vm::actor::kStorageMarketAddress ;
45
47
using vm::actor::builtin::market::getProposalCid;
48
+ using vm::actor::builtin::market::PublishStorageDeals;
46
49
using vm::message::kMessageVersion ;
47
50
using vm::message::SignedMessage;
48
51
using vm::message::UnsignedMessage;
@@ -146,24 +149,25 @@ namespace fc::markets::storage::client {
146
149
}
147
150
auto stream = std::move (stream_res.value ());
148
151
AskRequest request{.miner = info.address };
149
- stream->write (request,
150
- [self, info, stream, signed_ask_handler](
151
- outcome::result<size_t > written) {
152
- if (!self->hasValue (written,
153
- " Cannot send request" ,
154
- stream,
155
- signed_ask_handler)) {
156
- return ;
157
- }
158
- stream->template read <AskResponse>(
159
- [self, info, stream, signed_ask_handler](
160
- outcome::result<AskResponse> response) {
161
- auto validated_ask_response =
162
- self->validateAskResponse (response, info);
163
- signed_ask_handler (validated_ask_response);
164
- self->network_ ->closeStreamGracefully (stream);
165
- });
166
- });
152
+ stream->write (
153
+ request,
154
+ [self, info, stream, signed_ask_handler](
155
+ outcome::result<size_t > written) {
156
+ if (!self->hasValue (written,
157
+ " Cannot send request" ,
158
+ stream,
159
+ signed_ask_handler)) {
160
+ return ;
161
+ }
162
+ stream->template read <AskResponse>(
163
+ [self, info, stream, signed_ask_handler](
164
+ outcome::result<AskResponse> response) {
165
+ auto validated_ask_response =
166
+ self->validateAskResponse (response, info);
167
+ signed_ask_handler (validated_ask_response);
168
+ self->network_ ->closeStreamGracefully (stream);
169
+ });
170
+ });
167
171
});
168
172
}
169
173
@@ -223,7 +227,8 @@ namespace fc::markets::storage::client {
223
227
" DealStream opened to "
224
228
+ peerInfoToPrettyString (provider_info.peer_info ));
225
229
226
- self->connections_ [proposal_cid] = stream.value ();
230
+ std::lock_guard<std::mutex> lock (self->connections_mutex_ );
231
+ self->connections_ .emplace (proposal_cid, stream.value ());
227
232
SELF_FSM_SEND (client_deal, ClientEvent::ClientEventOpen);
228
233
});
229
234
@@ -347,6 +352,79 @@ namespace fc::markets::storage::client {
347
352
return outcome::success ();
348
353
}
349
354
355
+ outcome::result<bool > StorageMarketClientImpl::verifyDealPublished (
356
+ std::shared_ptr<ClientDeal> deal) {
357
+ OUTCOME_TRY (msg_wait, api_->StateWaitMsg (deal->publish_message ));
358
+ OUTCOME_TRY (msg_state, msg_wait.waitSync ());
359
+ if (msg_state.receipt .exit_code != VMExitCode::Ok) {
360
+ deal->message =
361
+ " Publish deal exit code "
362
+ + std::to_string (static_cast <uint64_t >(msg_state.receipt .exit_code ));
363
+ return false ;
364
+ }
365
+
366
+ // check if published
367
+ OUTCOME_TRY (publish_message, api_->ChainGetMessage (deal->publish_message ));
368
+ OUTCOME_TRY (chain_head, api_->ChainHead ());
369
+ OUTCOME_TRY (tipset_key, chain_head.makeKey ());
370
+ OUTCOME_TRY (miner_info,
371
+ api_->StateMinerInfo (
372
+ deal->client_deal_proposal .proposal .provider , tipset_key));
373
+ OUTCOME_TRY (from_id_address,
374
+ api_->StateLookupID (publish_message.from , tipset_key));
375
+ if (from_id_address != miner_info.worker ) {
376
+ deal->message = " Publisher is not storage provider" ;
377
+ return false ;
378
+ }
379
+ if (publish_message.to != kStorageMarketAddress ) {
380
+ deal->message = " Receiver is not storage market actor" ;
381
+ return false ;
382
+ }
383
+ if (publish_message.method != PublishStorageDeals::Number) {
384
+ deal->message = " Wrong method called" ;
385
+ return false ;
386
+ }
387
+
388
+ // check publish contains proposal cid
389
+ OUTCOME_TRY (proposals,
390
+ codec::cbor::decode<std::vector<ClientDealProposal>>(
391
+ publish_message.params ));
392
+ auto it = std::find (
393
+ proposals.begin (), proposals.end (), deal->client_deal_proposal );
394
+ if (it == proposals.end ()) {
395
+ OUTCOME_TRY (proposal_cid_str, deal->proposal_cid .toString ());
396
+ deal->message = " deal publish didn't contain our deal (message cid: "
397
+ + proposal_cid_str + " )" ;
398
+ }
399
+
400
+ // get proposal id from publish call return
401
+ int index = std::distance (proposals.begin (), it);
402
+ OUTCOME_TRY (publish_result,
403
+ codec::cbor::decode<PublishStorageDeals::Result>(
404
+ msg_state.receipt .return_value ));
405
+ deal->deal_id = publish_result.deals [index];
406
+ return true ;
407
+ }
408
+
409
+ outcome::result<std::shared_ptr<CborStream>>
410
+ StorageMarketClientImpl::getStream (const CID &proposal_cid) {
411
+ std::lock_guard<std::mutex> lock (connections_mutex_);
412
+ auto stream_it = connections_.find (proposal_cid);
413
+ if (stream_it == connections_.end ()) {
414
+ return StorageMarketClientError::STREAM_LOOKUP_ERROR;
415
+ }
416
+ return stream_it->second ;
417
+ }
418
+
419
+ void StorageMarketClientImpl::finalizeDeal (std::shared_ptr<ClientDeal> deal) {
420
+ std::lock_guard<std::mutex> lock (connections_mutex_);
421
+ auto stream_it = connections_.find (deal->proposal_cid );
422
+ if (stream_it != connections_.end ()) {
423
+ network_->closeStreamGracefully (stream_it->second );
424
+ }
425
+ connections_.erase (stream_it);
426
+ }
427
+
350
428
std::vector<ClientTransition> StorageMarketClientImpl::makeFSMTransitions () {
351
429
return {ClientTransition (ClientEvent::ClientEventOpen)
352
430
.from (StorageDealStatus::STORAGE_DEAL_UNKNOWN)
@@ -414,36 +492,49 @@ namespace fc::markets::storage::client {
414
492
ClientEvent event,
415
493
StorageDealStatus from,
416
494
StorageDealStatus to) {
417
- // TODO wait for funding
495
+ auto maybe_wait = api_->StateWaitMsg (deal->add_funds_cid .get ());
496
+ FSM_HALT_ON_ERROR (maybe_wait, " Wait for funding error" , deal);
497
+ maybe_wait.value ().wait (
498
+ [self{shared_from_this ()}, deal](outcome::result<MsgWait> result) {
499
+ SELF_FSM_HALT_ON_ERROR (result, " Wait for funding error" , deal);
500
+ if (result.value ().receipt .exit_code != VMExitCode::Ok) {
501
+ deal->message = " Funding exit code "
502
+ + std::to_string (static_cast <uint64_t >(
503
+ result.value ().receipt .exit_code ));
504
+ SELF_FSM_SEND (deal, ClientEvent::ClientEventFailed);
505
+ return ;
506
+ }
507
+ SELF_FSM_SEND (deal, ClientEvent::ClientEventFundsEnsured);
508
+ });
418
509
}
419
510
420
511
void StorageMarketClientImpl::onClientEventFundsEnsured (
421
512
std::shared_ptr<ClientDeal> deal,
422
513
ClientEvent event,
423
514
StorageDealStatus from,
424
515
StorageDealStatus to) {
425
- // TODO handle if stream is absent
426
- auto stream = connections_[ deal-> proposal_cid ] ;
516
+ auto stream = getStream (deal-> proposal_cid );
517
+ FSM_HALT_ON_ERROR ( stream, " Stream not found. " , deal) ;
427
518
428
519
Proposal proposal{.deal_proposal = deal->client_deal_proposal ,
429
520
.piece = deal->data_ref };
430
- stream->write (proposal,
431
- [self{shared_from_this ()}, deal, stream](
432
- outcome::result<size_t > written) {
433
- SELF_FSM_HALT_ON_ERROR (
434
- written, " Send proposal error" , deal);
435
- self->network_ ->closeStreamGracefully (stream);
436
- SELF_FSM_SEND (deal, ClientEvent::ClientEventDealProposed);
437
- });
521
+ stream.value ()->write (
522
+ proposal,
523
+ [self{shared_from_this ()}, deal, stream](
524
+ outcome::result<size_t > written) {
525
+ SELF_FSM_HALT_ON_ERROR (written, " Send proposal error" , deal);
526
+ SELF_FSM_SEND (deal, ClientEvent::ClientEventDealProposed);
527
+ });
438
528
}
439
529
440
530
void StorageMarketClientImpl::onClientEventDealProposed (
441
531
std::shared_ptr<ClientDeal> deal,
442
532
ClientEvent event,
443
533
StorageDealStatus from,
444
534
StorageDealStatus to) {
445
- // TODO handle if stream is absent
446
- auto stream = connections_[deal->proposal_cid ];
535
+ auto stream_res = getStream (deal->proposal_cid );
536
+ FSM_HALT_ON_ERROR (stream_res, " Stream not found." , deal);
537
+ auto stream = std::move (stream_res.value ());
447
538
stream->read <SignedResponse>([self{shared_from_this ()}, deal, stream](
448
539
outcome::result<SignedResponse> response) {
449
540
SELF_FSM_HALT_ON_ERROR (response, " Read response error" , deal);
@@ -457,11 +548,12 @@ namespace fc::markets::storage::client {
457
548
return ;
458
549
}
459
550
if (response.value ().response .state
460
- != StorageDealStatus::STORAGE_DEAL_PROPOSAL_ACCEPTED ) {
461
- // TODO handle reject reason
551
+ != StorageDealStatus::STORAGE_DEAL_PUBLISHING ) {
552
+ deal-> message = response. value (). response . message ;
462
553
SELF_FSM_SEND (deal, ClientEvent::ClientEventDealRejected);
463
554
return ;
464
555
}
556
+ deal->publish_message = response.value ().response .publish_message ;
465
557
self->network_ ->closeStreamGracefully (stream);
466
558
SELF_FSM_SEND (deal, ClientEvent::ClientEventDealAccepted);
467
559
});
@@ -481,16 +573,21 @@ namespace fc::markets::storage::client {
481
573
ClientEvent event,
482
574
StorageDealStatus from,
483
575
StorageDealStatus to) {
484
- // todo validate deal published
485
- OUTCOME_EXCEPT (fsm_->send (deal, ClientEvent::ClientEventDealPublished));
576
+ auto verified = verifyDealPublished (deal);
577
+ FSM_HALT_ON_ERROR (verified, " Cannot get publish message" , deal);
578
+ if (!verified.value ()) {
579
+ FSM_SEND (deal, ClientEvent::ClientEventFailed);
580
+ return ;
581
+ }
582
+ FSM_SEND (deal, ClientEvent::ClientEventDealPublished);
486
583
}
487
584
488
585
void StorageMarketClientImpl::onClientEventDealPublished (
489
586
std::shared_ptr<ClientDeal> deal,
490
587
ClientEvent event,
491
588
StorageDealStatus from,
492
589
StorageDealStatus to) {
493
- // verify deal activated - on deal sector commit
590
+ // TODO (a.chernyshov) verify deal activated - on deal sector commit
494
591
OUTCOME_EXCEPT (fsm_->send (deal, ClientEvent::ClientEventDealActivated));
495
592
}
496
593
@@ -499,21 +596,23 @@ namespace fc::markets::storage::client {
499
596
ClientEvent event,
500
597
StorageDealStatus from,
501
598
StorageDealStatus to) {
502
- // final state
503
- // todo cleanup
599
+ // final success state
600
+ finalizeDeal (deal);
504
601
}
505
602
506
603
void StorageMarketClientImpl::onClientEventFailed (
507
604
std::shared_ptr<ClientDeal> deal,
508
605
ClientEvent event,
509
606
StorageDealStatus from,
510
607
StorageDealStatus to) {
608
+ // final error state
511
609
std::stringstream ss;
512
610
ss << " Proposal " ;
513
611
auto maybe_prpoposal_cid = deal->proposal_cid .toString ();
514
612
if (maybe_prpoposal_cid) ss << maybe_prpoposal_cid.value () << " " ;
515
613
ss << " failed. " << deal->message ;
516
614
logger_->error (ss.str ());
615
+ finalizeDeal (deal);
517
616
}
518
617
519
618
} // namespace fc::markets::storage::client
@@ -537,6 +636,8 @@ OUTCOME_CPP_DEFINE_CATEGORY(fc::markets::storage::client,
537
636
return " StorageMarketClientError: add funds method call returned error" ;
538
637
case StorageMarketClientError::LOCAL_DEAL_NOT_FOUND:
539
638
return " StorageMarketClientError: local deal not found" ;
639
+ case StorageMarketClientError::STREAM_LOOKUP_ERROR:
640
+ return " StorageMarketClientError: stream look up error" ;
540
641
}
541
642
542
643
return " StorageMarketClientError: unknown error" ;
0 commit comments