15
15
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
16
16
17
17
use crate :: cli:: { ExplicitOrMaximal , HexBytes } ;
18
- use bp_runtime:: EncodedOrDecodedCall ;
18
+ use bp_runtime:: { ChainId , EncodedOrDecodedCall } ;
19
+ use bridge_runtime_common:: CustomNetworkId ;
19
20
use codec:: Encode ;
20
21
use frame_support:: weights:: Weight ;
21
22
use relay_substrate_client:: Chain ;
22
23
use structopt:: StructOpt ;
24
+ use xcm:: latest:: prelude:: * ;
23
25
24
26
/// All possible messages that may be delivered to generic Substrate chain.
25
27
///
@@ -43,6 +45,31 @@ pub enum Message {
43
45
pub type RawMessage = Vec < u8 > ;
44
46
45
47
pub trait CliEncodeMessage : Chain {
48
+ /// Returns dummy `AccountId32` universal source given this network id.
49
+ fn dummy_universal_source ( ) -> anyhow:: Result < xcm:: v3:: Junctions > {
50
+ use xcm:: v3:: prelude:: * ;
51
+
52
+ let this_network = CustomNetworkId :: try_from ( Self :: ID )
53
+ . map ( |n| n. as_network_id ( ) )
54
+ . map_err ( |_| anyhow:: format_err!( "Unsupported chain: {:?}" , Self :: ID ) ) ?;
55
+ let this_location: InteriorMultiLocation = this_network. into ( ) ;
56
+
57
+ let origin = MultiLocation {
58
+ parents : 0 ,
59
+ interior : X1 ( AccountId32 { network : Some ( this_network) , id : [ 0u8 ; 32 ] } ) ,
60
+ } ;
61
+ let universal_source = this_location
62
+ . within_global ( origin)
63
+ . map_err ( |e| anyhow:: format_err!( "Invalid location: {:?}" , e) ) ?;
64
+
65
+ Ok ( universal_source)
66
+ }
67
+ /// Returns XCM blob that is passed to the `send_message` function of the messages pallet
68
+ /// and then is sent over the wire.
69
+ fn encode_wire_message (
70
+ target : ChainId ,
71
+ at_target_xcm : xcm:: v3:: Xcm < ( ) > ,
72
+ ) -> anyhow:: Result < Vec < u8 > > ;
46
73
/// Encode an `execute` XCM call of the XCM pallet.
47
74
fn encode_execute_xcm (
48
75
message : xcm:: VersionedXcm < Self :: Call > ,
@@ -56,41 +83,42 @@ pub trait CliEncodeMessage: Chain {
56
83
}
57
84
58
85
/// Encode message payload passed through CLI flags.
59
- pub ( crate ) fn encode_message < Source : Chain , Target : Chain > (
86
+ pub ( crate ) fn encode_message < Source : CliEncodeMessage , Target : Chain > (
60
87
message : & Message ,
61
88
) -> anyhow:: Result < RawMessage > {
62
89
Ok ( match message {
63
90
Message :: Raw { ref data } => data. 0 . clone ( ) ,
64
91
Message :: Sized { ref size } => {
65
- let expected_xcm_size = match * size {
92
+ let destination = CustomNetworkId :: try_from ( Target :: ID )
93
+ . map ( |n| n. as_network_id ( ) )
94
+ . map_err ( |_| anyhow:: format_err!( "Unsupported target chain: {:?}" , Target :: ID ) ) ?;
95
+ let expected_size = match * size {
66
96
ExplicitOrMaximal :: Explicit ( size) => size,
67
97
ExplicitOrMaximal :: Maximal => compute_maximal_message_size (
68
98
Source :: max_extrinsic_size ( ) ,
69
99
Target :: max_extrinsic_size ( ) ,
70
100
) ,
71
- } ;
72
-
73
- // there's no way to craft XCM of the given size - we'll be using `ExpectPallet`
74
- // instruction, which has byte vector inside
75
- let mut current_vec_size = expected_xcm_size;
76
- let xcm = loop {
77
- let xcm = xcm:: VersionedXcm :: < ( ) > :: V3 (
78
- vec ! [ xcm:: v3:: Instruction :: ExpectPallet {
79
- index: 0 ,
80
- name: vec![ 42 ; current_vec_size as usize ] ,
81
- module_name: vec![ ] ,
82
- crate_major: 0 ,
83
- min_crate_minor: 0 ,
84
- } ]
85
- . into ( ) ,
86
- ) ;
87
- if xcm. encode ( ) . len ( ) <= expected_xcm_size as usize {
88
- break xcm
89
- }
90
-
91
- current_vec_size -= 1 ;
92
- } ;
93
- xcm. encode ( )
101
+ } as usize ;
102
+
103
+ let at_target_xcm = vec ! [ xcm:: v3:: Instruction :: ClearOrigin ; expected_size] . into ( ) ;
104
+ let at_target_xcm_size =
105
+ Source :: encode_wire_message ( Target :: ID , at_target_xcm) ?. encoded_size ( ) ;
106
+ let at_target_xcm_overhead = at_target_xcm_size. saturating_sub ( expected_size) ;
107
+ let at_target_xcm = vec ! [
108
+ xcm:: v3:: Instruction :: ClearOrigin ;
109
+ expected_size. saturating_sub( at_target_xcm_overhead)
110
+ ]
111
+ . into ( ) ;
112
+
113
+ xcm:: VersionedXcm :: < ( ) > :: V3 (
114
+ vec ! [ ExportMessage {
115
+ network: destination,
116
+ destination: destination. into( ) ,
117
+ xcm: at_target_xcm,
118
+ } ]
119
+ . into ( ) ,
120
+ )
121
+ . encode ( )
94
122
} ,
95
123
} )
96
124
}
@@ -123,13 +151,21 @@ mod tests {
123
151
use relay_millau_client:: Millau ;
124
152
use relay_rialto_client:: Rialto ;
125
153
154
+ fn approximate_message_size < Source : CliEncodeMessage > ( xcm_msg_len : usize ) -> usize {
155
+ xcm_msg_len + Source :: dummy_universal_source ( ) . unwrap ( ) . encoded_size ( )
156
+ }
157
+
126
158
#[ test]
127
159
fn encode_explicit_size_message_works ( ) {
128
160
let msg = encode_message :: < Rialto , Millau > ( & Message :: Sized {
129
161
size : ExplicitOrMaximal :: Explicit ( 100 ) ,
130
162
} )
131
163
. unwrap ( ) ;
132
- assert_eq ! ( msg. len( ) , 100 ) ;
164
+ // since it isn't the returned XCM what is sent over the wire, we can only check if
165
+ // it is close to what we need
166
+ assert ! (
167
+ ( 1f64 - ( approximate_message_size:: <Rialto >( msg. len( ) ) as f64 ) / 100_f64 ) . abs( ) < 0.1
168
+ ) ;
133
169
// check that it decodes to valid xcm
134
170
let _ = decode_xcm :: < ( ) > ( msg) . unwrap ( ) ;
135
171
}
@@ -144,7 +180,12 @@ mod tests {
144
180
let msg =
145
181
encode_message :: < Rialto , Millau > ( & Message :: Sized { size : ExplicitOrMaximal :: Maximal } )
146
182
. unwrap ( ) ;
147
- assert_eq ! ( msg. len( ) , maximal_size as usize ) ;
183
+ // since it isn't the returned XCM what is sent over the wire, we can only check if
184
+ // it is close to what we need
185
+ assert ! (
186
+ ( 1f64 - approximate_message_size:: <Rialto >( msg. len( ) ) as f64 / maximal_size as f64 )
187
+ . abs( ) < 0.1
188
+ ) ;
148
189
// check that it decodes to valid xcm
149
190
let _ = decode_xcm :: < ( ) > ( msg) . unwrap ( ) ;
150
191
}
0 commit comments