14
14
// You should have received a copy of the GNU General Public License
15
15
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
16
16
17
- use crate :: {
18
- messages:: {
19
- source:: FromBridgedChainMessagesDeliveryProof , target:: FromBridgedChainMessagesProof ,
20
- } ,
21
- BridgeRuntimeFilterCall ,
17
+ use crate :: messages:: {
18
+ source:: FromBridgedChainMessagesDeliveryProof , target:: FromBridgedChainMessagesProof ,
22
19
} ;
20
+ use bp_messages:: { LaneId , MessageNonce } ;
23
21
use frame_support:: { dispatch:: CallableCallFor , traits:: IsSubType } ;
24
22
use pallet_bridge_messages:: { Config , Pallet } ;
25
- use sp_runtime:: transaction_validity:: TransactionValidity ;
23
+ use sp_runtime:: { transaction_validity:: TransactionValidity , RuntimeDebug } ;
24
+
25
+ /// Info about a `ReceiveMessagesProof` call which tries to update a single lane.
26
+ #[ derive( Copy , Clone , PartialEq , RuntimeDebug ) ]
27
+ pub struct ReceiveMessagesProofInfo {
28
+ pub lane_id : LaneId ,
29
+ pub best_proof_nonce : MessageNonce ,
30
+ pub best_stored_nonce : MessageNonce ,
31
+ }
32
+
33
+ /// Helper struct that provides methods for working with the `ReceiveMessagesProof` call.
34
+ pub struct ReceiveMessagesProofHelper < T : Config < I > , I : ' static > {
35
+ pub _phantom_data : sp_std:: marker:: PhantomData < ( T , I ) > ,
36
+ }
37
+
38
+ impl < T : Config < I > , I : ' static > ReceiveMessagesProofHelper < T , I > {
39
+ /// Check if the `ReceiveMessagesProof` call delivered at least some of the messages that
40
+ /// it contained.
41
+ pub fn was_partially_successful ( info : & ReceiveMessagesProofInfo ) -> bool {
42
+ let inbound_lane_data = pallet_bridge_messages:: InboundLanes :: < T , I > :: get ( info. lane_id ) ;
43
+ inbound_lane_data. last_delivered_nonce ( ) > info. best_stored_nonce
44
+ }
45
+ }
46
+
47
+ /// Trait representing a call that is a sub type of `pallet_bridge_messages::Call`.
48
+ pub trait MessagesCallSubType < T : Config < I , RuntimeCall = Self > , I : ' static > :
49
+ IsSubType < CallableCallFor < Pallet < T , I > , T > >
50
+ {
51
+ /// Create a new instance of `ReceiveMessagesProofInfo` from a `ReceiveMessagesProof` call.
52
+ fn receive_messages_proof_info ( & self ) -> Option < ReceiveMessagesProofInfo > ;
53
+
54
+ /// Create a new instance of `ReceiveMessagesProofInfo` from a `ReceiveMessagesProof` call,
55
+ /// if the call is for the provided lane.
56
+ fn receive_messages_proof_info_for ( & self , lane_id : LaneId ) -> Option < ReceiveMessagesProofInfo > ;
57
+
58
+ /// Check that a `ReceiveMessagesProof` call is trying to deliver at least some messages that
59
+ /// are better than the ones we know of.
60
+ fn check_obsolete_receive_messages_proof ( & self ) -> TransactionValidity ;
61
+
62
+ /// Check that a `ReceiveMessagesDeliveryProof` call is trying to deliver at least some message
63
+ /// confirmations that are better than the ones we know of.
64
+ fn check_obsolete_receive_messages_delivery_proof ( & self ) -> TransactionValidity ;
65
+ }
26
66
27
- /// Validate messages in order to avoid "mining" messages delivery and delivery confirmation
28
- /// transactions, that are delivering outdated messages/confirmations. Without this validation,
29
- /// even honest relayers may lose their funds if there are multiple relays running and submitting
30
- /// the same messages/confirmations.
31
67
impl <
32
68
BridgedHeaderHash ,
33
69
SourceHeaderChain : bp_messages:: target_chain:: SourceHeaderChain <
@@ -42,52 +78,69 @@ impl<
42
78
T : frame_system:: Config < RuntimeCall = Call >
43
79
+ Config < I , SourceHeaderChain = SourceHeaderChain , TargetHeaderChain = TargetHeaderChain > ,
44
80
I : ' static ,
45
- > BridgeRuntimeFilterCall < Call > for Pallet < T , I >
81
+ > MessagesCallSubType < T , I > for T :: RuntimeCall
46
82
{
47
- fn validate ( call : & Call ) -> TransactionValidity {
48
- match call. is_sub_type ( ) {
49
- Some ( pallet_bridge_messages:: Call :: < T , I > :: receive_messages_proof {
50
- ref proof,
51
- ..
52
- } ) => {
53
- let inbound_lane_data =
54
- pallet_bridge_messages:: InboundLanes :: < T , I > :: get ( proof. lane ) ;
55
- if proof. nonces_end <= inbound_lane_data. last_delivered_nonce ( ) {
56
- log:: trace!(
57
- target: pallet_bridge_messages:: LOG_TARGET ,
58
- "Rejecting obsolete messages delivery transaction: \
83
+ fn receive_messages_proof_info ( & self ) -> Option < ReceiveMessagesProofInfo > {
84
+ if let Some ( pallet_bridge_messages:: Call :: < T , I > :: receive_messages_proof {
85
+ ref proof,
86
+ ..
87
+ } ) = self . is_sub_type ( )
88
+ {
89
+ let inbound_lane_data = pallet_bridge_messages:: InboundLanes :: < T , I > :: get ( proof. lane ) ;
90
+
91
+ return Some ( ReceiveMessagesProofInfo {
92
+ lane_id : proof. lane ,
93
+ best_proof_nonce : proof. nonces_end ,
94
+ best_stored_nonce : inbound_lane_data. last_delivered_nonce ( ) ,
95
+ } )
96
+ }
97
+
98
+ None
99
+ }
100
+
101
+ fn receive_messages_proof_info_for ( & self , lane_id : LaneId ) -> Option < ReceiveMessagesProofInfo > {
102
+ self . receive_messages_proof_info ( ) . filter ( |info| info. lane_id == lane_id)
103
+ }
104
+
105
+ fn check_obsolete_receive_messages_proof ( & self ) -> TransactionValidity {
106
+ if let Some ( proof_info) = self . receive_messages_proof_info ( ) {
107
+ if proof_info. best_proof_nonce <= proof_info. best_stored_nonce {
108
+ log:: trace!(
109
+ target: pallet_bridge_messages:: LOG_TARGET ,
110
+ "Rejecting obsolete messages delivery transaction: \
59
111
lane {:?}, bundled {:?}, best {:?}",
60
- proof . lane ,
61
- proof . nonces_end ,
62
- inbound_lane_data . last_delivered_nonce ( ) ,
63
- ) ;
112
+ proof_info . lane_id ,
113
+ proof_info . best_proof_nonce ,
114
+ proof_info . best_stored_nonce ,
115
+ ) ;
64
116
65
- return sp_runtime:: transaction_validity:: InvalidTransaction :: Stale . into ( )
66
- }
67
- } ,
68
- Some ( pallet_bridge_messages:: Call :: < T , I > :: receive_messages_delivery_proof {
69
- ref proof,
70
- ref relayers_state,
71
- ..
72
- } ) => {
73
- let latest_delivered_nonce = relayers_state. last_delivered_nonce ;
74
-
75
- let outbound_lane_data =
76
- pallet_bridge_messages:: OutboundLanes :: < T , I > :: get ( proof. lane ) ;
77
- if latest_delivered_nonce <= outbound_lane_data. latest_received_nonce {
78
- log:: trace!(
79
- target: pallet_bridge_messages:: LOG_TARGET ,
80
- "Rejecting obsolete messages confirmation transaction: \
117
+ return sp_runtime:: transaction_validity:: InvalidTransaction :: Stale . into ( )
118
+ }
119
+ }
120
+
121
+ Ok ( sp_runtime:: transaction_validity:: ValidTransaction :: default ( ) )
122
+ }
123
+
124
+ fn check_obsolete_receive_messages_delivery_proof ( & self ) -> TransactionValidity {
125
+ if let Some ( pallet_bridge_messages:: Call :: < T , I > :: receive_messages_delivery_proof {
126
+ ref proof,
127
+ ref relayers_state,
128
+ ..
129
+ } ) = self . is_sub_type ( )
130
+ {
131
+ let outbound_lane_data = pallet_bridge_messages:: OutboundLanes :: < T , I > :: get ( proof. lane ) ;
132
+ if relayers_state. last_delivered_nonce <= outbound_lane_data. latest_received_nonce {
133
+ log:: trace!(
134
+ target: pallet_bridge_messages:: LOG_TARGET ,
135
+ "Rejecting obsolete messages confirmation transaction: \
81
136
lane {:?}, bundled {:?}, best {:?}",
82
- proof. lane,
83
- latest_delivered_nonce ,
84
- outbound_lane_data. latest_received_nonce,
85
- ) ;
137
+ proof. lane,
138
+ relayers_state . last_delivered_nonce ,
139
+ outbound_lane_data. latest_received_nonce,
140
+ ) ;
86
141
87
- return sp_runtime:: transaction_validity:: InvalidTransaction :: Stale . into ( )
88
- }
89
- } ,
90
- _ => { } ,
142
+ return sp_runtime:: transaction_validity:: InvalidTransaction :: Stale . into ( )
143
+ }
91
144
}
92
145
93
146
Ok ( sp_runtime:: transaction_validity:: ValidTransaction :: default ( ) )
0 commit comments