@@ -10,7 +10,7 @@ use crate::cid_collections::CidHashSet;
10
10
use crate :: eth:: EthChainId ;
11
11
use crate :: interpreter:: { MessageCallbackCtx , VMTrace } ;
12
12
use crate :: libp2p:: NetworkMessage ;
13
- use crate :: lotus_json:: lotus_json_with_self;
13
+ use crate :: lotus_json:: { LotusJson , lotus_json_with_self} ;
14
14
use crate :: networks:: ChainConfig ;
15
15
use crate :: rpc:: registry:: actors_reg:: load_and_serialize_actor_state;
16
16
use crate :: shim:: actors:: init;
@@ -68,6 +68,7 @@ use nunny::vec as nonempty;
68
68
use parking_lot:: Mutex ;
69
69
use schemars:: JsonSchema ;
70
70
use serde:: { Deserialize , Serialize } ;
71
+ use std:: io:: Write ;
71
72
use std:: ops:: Mul ;
72
73
use std:: path:: PathBuf ;
73
74
use std:: { sync:: Arc , time:: Duration } ;
@@ -497,7 +498,7 @@ impl RpcMethod<1> for StateMarketDeals {
497
498
let sa = market_state. states ( ctx. store ( ) ) ?;
498
499
499
500
let mut out = HashMap :: new ( ) ;
500
- da. for_each ( |deal_id, d| {
501
+ da. for_each_cacheless ( |deal_id, d| {
501
502
let s = sa. get ( deal_id) ?. unwrap_or ( market:: DealState {
502
503
sector_start_epoch : -1 ,
503
504
last_updated_epoch : -1 ,
@@ -519,6 +520,125 @@ impl RpcMethod<1> for StateMarketDeals {
519
520
}
520
521
}
521
522
523
+ pub enum StateMarketDealsDump { }
524
+
525
+ impl RpcMethod < 2 > for StateMarketDealsDump {
526
+ const NAME : & ' static str = "Forest.StateMarketDealsDump" ;
527
+ const PARAM_NAMES : [ & ' static str ; 2 ] = [ "tipsetKey" , "outputFile" ] ;
528
+ const API_PATHS : BitFlags < ApiPaths > = make_bitflags ! ( ApiPaths :: Experimental ) ;
529
+ const PERMISSION : Permission = Permission :: Read ;
530
+ const DESCRIPTION : Option < & ' static str > =
531
+ Some ( "Dumps information about every deal in the Storage Market to a NDJSON file." ) ;
532
+
533
+ type Params = ( ApiTipsetKey , String ) ;
534
+ type Ok = ( ) ;
535
+
536
+ async fn handle (
537
+ ctx : Ctx < impl Blockstore + Send + Sync + ' static > ,
538
+ ( ApiTipsetKey ( tsk) , output_file) : Self :: Params ,
539
+ ) -> Result < Self :: Ok , ServerError > {
540
+ let ts = ctx. chain_store ( ) . load_required_tipset_or_heaviest ( & tsk) ?;
541
+ let market_state: market:: State = ctx. state_manager . get_actor_state ( & ts) ?;
542
+
543
+ let da = market_state. proposals ( ctx. store ( ) ) ?;
544
+ let sa = market_state. states ( ctx. store ( ) ) ?;
545
+
546
+ let output_path = PathBuf :: from ( & output_file) ;
547
+ if let Some ( parent) = output_path. parent ( ) {
548
+ std:: fs:: create_dir_all ( parent)
549
+ . context ( "Failed to create output directory for market deals" ) ?;
550
+ }
551
+ let file = std:: fs:: File :: create ( & output_path)
552
+ . context ( "Failed to create market deals output file" ) ?;
553
+ let mut writer = std:: io:: BufWriter :: new ( file) ;
554
+
555
+ da. for_each_cacheless ( |deal_id, d| {
556
+ let s = sa. get ( deal_id) ?. unwrap_or_else ( DealState :: empty) ;
557
+ let market_deal = ApiMarketDeal {
558
+ proposal : d?. into ( ) ,
559
+ state : s. into ( ) ,
560
+ } ;
561
+ write ! (
562
+ writer,
563
+ "{}\n " ,
564
+ crate :: lotus_json:: HasLotusJson :: into_lotus_json_string( market_deal) ?
565
+ ) ?;
566
+ Ok ( ( ) )
567
+ } ) ?;
568
+ Ok ( ( ) )
569
+ }
570
+ }
571
+
572
+ #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq , JsonSchema ) ]
573
+ #[ serde( rename_all = "PascalCase" ) ]
574
+ pub struct StateMarketDealsFilter {
575
+ #[ schemars( with = "LotusJson<Option<Address>>" ) ]
576
+ #[ serde( with = "crate::lotus_json" ) ]
577
+ pub allowed_clients : Option < Vec < Address > > ,
578
+ #[ schemars( with = "LotusJson<Option<Address>>" ) ]
579
+ #[ serde( with = "crate::lotus_json" ) ]
580
+ pub allowed_providers : Option < Vec < Address > > ,
581
+ }
582
+
583
+ lotus_json_with_self ! ( StateMarketDealsFilter ) ;
584
+
585
+ pub enum StateMarketDealsFiltered { }
586
+
587
+ impl RpcMethod < 2 > for StateMarketDealsFiltered {
588
+ const NAME : & ' static str = "Forest.StateMarketDealsFiltered" ;
589
+ const PARAM_NAMES : [ & ' static str ; 2 ] = [ "tipsetKey" , "filter" ] ;
590
+ const API_PATHS : BitFlags < ApiPaths > = make_bitflags ! ( ApiPaths :: Experimental ) ;
591
+ const PERMISSION : Permission = Permission :: Read ;
592
+ const DESCRIPTION : Option < & ' static str > = Some (
593
+ "Returns information about every deal in the Storage Market, optionally filtered by client and provider addresses." ,
594
+ ) ;
595
+
596
+ type Params = ( ApiTipsetKey , StateMarketDealsFilter ) ;
597
+ type Ok = HashMap < u64 , ApiMarketDeal > ;
598
+
599
+ async fn handle (
600
+ ctx : Ctx < impl Blockstore + Send + Sync + ' static > ,
601
+ (
602
+ ApiTipsetKey ( tsk) ,
603
+ StateMarketDealsFilter {
604
+ allowed_clients,
605
+ allowed_providers,
606
+ } ,
607
+ ) : Self :: Params ,
608
+ ) -> Result < Self :: Ok , ServerError > {
609
+ let ts = ctx. chain_store ( ) . load_required_tipset_or_heaviest ( & tsk) ?;
610
+ let market_state: market:: State = ctx. state_manager . get_actor_state ( & ts) ?;
611
+
612
+ let da = market_state. proposals ( ctx. store ( ) ) ?;
613
+ let sa = market_state. states ( ctx. store ( ) ) ?;
614
+
615
+ let mut out = HashMap :: default ( ) ;
616
+
617
+ let allowed_clients = allowed_clients
618
+ . into_iter ( )
619
+ . flatten ( )
620
+ . collect :: < HashSet < _ > > ( ) ;
621
+ let allowed_providers = allowed_providers
622
+ . into_iter ( )
623
+ . flatten ( )
624
+ . collect :: < HashSet < _ > > ( ) ;
625
+ da. for_each_cacheless ( |deal_id, d| {
626
+ let state = sa. get ( deal_id) ?. unwrap_or_else ( DealState :: empty) ;
627
+
628
+ let proposal = d?;
629
+ if !allowed_clients. contains ( & proposal. client . into ( ) )
630
+ && !allowed_providers. contains ( & proposal. provider . into ( ) )
631
+ {
632
+ return Ok ( ( ) ) ;
633
+ }
634
+
635
+ out. insert ( deal_id, MarketDeal { proposal, state } . into ( ) ) ;
636
+ Ok ( ( ) )
637
+ } ) ?;
638
+ Ok ( out)
639
+ }
640
+ }
641
+
522
642
/// looks up the miner info of the given address.
523
643
pub enum StateMinerInfo { }
524
644
0 commit comments