1
1
pub mod config;
2
2
3
- use anyhow:: Result ;
3
+ use std:: sync:: Arc ;
4
+
5
+ use anyhow:: { anyhow, Result } ;
4
6
use async_trait:: async_trait;
5
7
use avail_subxt:: api:: runtime_types:: avail_core:: AppId ;
6
8
use avail_subxt:: api:: runtime_types:: bounded_collections:: bounded_vec:: BoundedVec ;
7
- use avail_subxt:: api:: runtime_types:: da_control:: pallet:: Call as DaCall ;
8
- use avail_subxt:: avail:: { AppUncheckedExtrinsic , Client as AvailSubxtClient } ;
9
+ use avail_subxt:: avail:: Client as AvailSubxtClient ;
9
10
use avail_subxt:: primitives:: AvailExtrinsicParams ;
10
- use avail_subxt:: { api as AvailApi , build_client, AvailConfig , Call } ;
11
+ use avail_subxt:: { api as AvailApi , build_client, AvailConfig } ;
11
12
use ethers:: types:: { I256 , U256 } ;
12
- use sp_core :: H256 ;
13
+ use futures :: lock :: Mutex ;
13
14
use subxt:: ext:: sp_core:: sr25519:: Pair ;
15
+ use subxt:: OnlineClient ;
14
16
15
17
use crate :: utils:: get_bytes_from_state_diff;
16
18
use crate :: { DaClient , DaMode } ;
@@ -19,22 +21,55 @@ type AvailPairSigner = subxt::tx::PairSigner<AvailConfig, Pair>;
19
21
20
22
#[ derive( Clone ) ]
21
23
pub struct AvailClient {
22
- ws_client : AvailSubxtClient ,
24
+ ws_client : Arc < Mutex < SubxtClient > > ,
23
25
app_id : AppId ,
24
26
signer : AvailPairSigner ,
25
27
mode : DaMode ,
26
28
}
27
29
30
+ pub struct SubxtClient {
31
+ client : AvailSubxtClient ,
32
+ config : config:: AvailConfig ,
33
+ }
34
+
35
+ pub fn try_build_avail_subxt ( conf : & config:: AvailConfig ) -> Result < OnlineClient < AvailConfig > > {
36
+ let client =
37
+ futures:: executor:: block_on ( async { build_client ( conf. ws_provider . as_str ( ) , conf. validate_codegen ) . await } )
38
+ . map_err ( |e| anyhow:: anyhow!( "DA Layer error: could not initialize ws endpoint {e}" ) ) ?;
39
+
40
+ Ok ( client)
41
+ }
42
+
43
+ impl SubxtClient {
44
+ pub async fn restart ( & mut self ) -> Result < ( ) , anyhow:: Error > {
45
+ self . client = match build_client ( self . config . ws_provider . as_str ( ) , self . config . validate_codegen ) . await {
46
+ Ok ( i) => i,
47
+ Err ( e) => return Err ( anyhow ! ( "DA Layer error: could not restart ws endpoint {e}" ) ) ,
48
+ } ;
49
+
50
+ Ok ( ( ) )
51
+ }
52
+
53
+ pub fn client ( & self ) -> & OnlineClient < AvailConfig > {
54
+ & self . client
55
+ }
56
+ }
57
+
58
+ impl TryFrom < config:: AvailConfig > for SubxtClient {
59
+ type Error = anyhow:: Error ;
60
+
61
+ fn try_from ( conf : config:: AvailConfig ) -> Result < Self , Self :: Error > {
62
+ Ok ( Self { client : try_build_avail_subxt ( & conf) ?, config : conf } )
63
+ }
64
+ }
65
+
28
66
#[ async_trait]
29
67
impl DaClient for AvailClient {
30
68
async fn publish_state_diff ( & self , state_diff : Vec < U256 > ) -> Result < ( ) > {
31
69
let bytes = get_bytes_from_state_diff ( & state_diff) ;
32
70
let bytes = BoundedVec ( bytes) ;
71
+ self . publish_data ( & bytes) . await ?;
33
72
34
- let submitted_block_hash = self . publish_data ( & bytes) . await ?;
35
-
36
- // This theoritically do not have to be put here since we wait for finalization before
37
- self . verify_bytes_inclusion ( submitted_block_hash, & bytes) . await ?;
38
73
Ok ( ( ) )
39
74
}
40
75
@@ -50,38 +85,22 @@ impl DaClient for AvailClient {
50
85
}
51
86
52
87
impl AvailClient {
53
- async fn publish_data ( & self , bytes : & BoundedVec < u8 > ) -> Result < H256 > {
88
+ async fn publish_data ( & self , bytes : & BoundedVec < u8 > ) -> Result < ( ) > {
89
+ let mut ws_client = self . ws_client . lock ( ) . await ;
90
+
54
91
let data_transfer = AvailApi :: tx ( ) . data_availability ( ) . submit_data ( bytes. clone ( ) ) ;
55
92
let extrinsic_params = AvailExtrinsicParams :: new_with_app_id ( self . app_id ) ;
56
- let events = self
57
- . ws_client
58
- . tx ( )
59
- . sign_and_submit_then_watch ( & data_transfer, & self . signer , extrinsic_params)
60
- . await ?
61
- . wait_for_finalized_success ( )
62
- . await ?;
63
-
64
- Ok ( events. block_hash ( ) )
65
- }
66
93
67
- async fn verify_bytes_inclusion ( & self , block_hash : H256 , bytes : & BoundedVec < u8 > ) -> Result < ( ) > {
68
- let submitted_block = self
69
- . ws_client
70
- . rpc ( )
71
- . block ( Some ( block_hash) )
72
- . await ?
73
- . ok_or ( anyhow:: anyhow!( "Invalid hash, block not found" ) ) ?;
74
-
75
- submitted_block
76
- . block
77
- . extrinsics
78
- . into_iter ( )
79
- . filter_map ( |chain_block_ext| AppUncheckedExtrinsic :: try_from ( chain_block_ext) . map ( |ext| ext. function ) . ok ( ) )
80
- . find ( |call| match call {
81
- Call :: DataAvailability ( DaCall :: submit_data { data } ) => data == bytes,
82
- _ => false ,
83
- } )
84
- . ok_or ( anyhow:: anyhow!( "Bytes not found in specified block" ) ) ?;
94
+ match ws_client. client ( ) . tx ( ) . sign_and_submit ( & data_transfer, & self . signer , extrinsic_params) . await {
95
+ Ok ( i) => i,
96
+ Err ( e) => {
97
+ if e. to_string ( ) . contains ( "restart required" ) {
98
+ ws_client. restart ( ) . await ;
99
+ }
100
+
101
+ return Err ( anyhow ! ( "DA Layer error : failed due to closed websocket connection {e}" ) ) ;
102
+ }
103
+ } ;
85
104
86
105
Ok ( ( ) )
87
106
}
@@ -95,11 +114,12 @@ impl TryFrom<config::AvailConfig> for AvailClient {
95
114
96
115
let app_id = AppId ( conf. app_id ) ;
97
116
98
- let ws_client =
99
- futures:: executor:: block_on ( async { build_client ( conf. ws_provider . as_str ( ) , conf. validate_codegen ) . await } )
100
- . map_err ( |e| anyhow:: anyhow!( "DA Layer error: could not initialize ws endpoint {e}" ) ) ?;
101
-
102
- Ok ( Self { ws_client, app_id, signer, mode : conf. mode } )
117
+ Ok ( Self {
118
+ ws_client : Arc :: new ( Mutex :: new ( SubxtClient :: try_from ( conf. clone ( ) ) ?) ) ,
119
+ app_id,
120
+ signer,
121
+ mode : conf. mode ,
122
+ } )
103
123
}
104
124
}
105
125
0 commit comments