@@ -393,10 +393,12 @@ pub mod pallet {
393393 > ;
394394
395395 type Denominator : common:: Denominator < Self :: AssetId , Balance > ;
396+ /// Maximum number of requests that can be queued per network.
397+ type MaxRequestsPerQueue : Get < u32 > ;
396398 }
397399
398400 /// The current storage version.
399- const STORAGE_VERSION : StorageVersion = StorageVersion :: new ( 1 ) ;
401+ const STORAGE_VERSION : StorageVersion = StorageVersion :: new ( 2 ) ;
400402
401403 #[ pallet:: pallet]
402404 #[ pallet:: generate_store( pub ( super ) trait Store ) ]
@@ -1038,6 +1040,36 @@ pub mod pallet {
10381040 SidechainAssetPrecision :: < T > :: insert ( network_id, & asset_id, precision) ;
10391041 Ok ( ( ) . into ( ) )
10401042 }
1043+
1044+ /// Explicitly clear collected signatures for a request.
1045+ ///
1046+ /// Used by operators to recover from failed finalization without implicitly wiping
1047+ /// approvals on-chain.
1048+ #[ pallet:: call_index( 17 ) ]
1049+ #[ pallet:: weight( EXTRINSIC_FIXED_WEIGHT ) ]
1050+ pub fn reset_request_signatures (
1051+ origin : OriginFor < T > ,
1052+ network_id : BridgeNetworkId < T > ,
1053+ hash : H256 ,
1054+ ) -> DispatchResultWithPostInfo {
1055+ ensure_root ( origin) ?;
1056+ let status =
1057+ RequestStatuses :: < T > :: get ( network_id, & hash) . ok_or ( Error :: < T > :: UnknownRequest ) ?;
1058+ ensure ! (
1059+ matches!(
1060+ status,
1061+ RequestStatus :: Failed ( _) | RequestStatus :: Broken ( _, _)
1062+ ) ,
1063+ Error :: <T >:: RequestStatusNotResettable
1064+ ) ;
1065+ ensure ! (
1066+ Requests :: <T >:: contains_key( network_id, & hash) ,
1067+ Error :: <T >:: UnknownRequest
1068+ ) ;
1069+ Self :: clear_request_signatures ( network_id, & hash) ;
1070+ Self :: deposit_event ( Event :: RequestSignaturesCleared ( hash) ) ;
1071+ Ok ( ( ) . into ( ) )
1072+ }
10411073 }
10421074
10431075 #[ pallet:: event]
@@ -1059,6 +1091,8 @@ pub mod pallet {
10591091 CancellationFailed ( H256 ) ,
10601092 /// The request registration has been failed. [Request Hash, Error]
10611093 RegisterRequestFailed ( H256 , DispatchError ) ,
1094+ /// Operators cleared stored signatures for a request. [Request Hash]
1095+ RequestSignaturesCleared ( H256 ) ,
10621096 }
10631097
10641098 #[ cfg_attr( test, derive( PartialEq , Eq ) ) ]
@@ -1224,6 +1258,10 @@ pub mod pallet {
12241258 Other ,
12251259 /// Expected pending request.
12261260 ExpectedPendingRequest ,
1261+ /// Too many requests queued for the network.
1262+ RequestsQueueFull ,
1263+ /// Signatures can only be reset when a request failed or is broken.
1264+ RequestStatusNotResettable ,
12271265 /// Expected Ethereum network.
12281266 ExpectedEthNetwork ,
12291267 /// Request was removed and refunded.
@@ -1309,6 +1347,18 @@ pub mod pallet {
13091347 ValueQuery ,
13101348 > ;
13111349
1350+ /// Outgoing request approval authors.
1351+ #[ pallet:: storage]
1352+ pub ( super ) type RequestApprovers < T : Config > = StorageDoubleMap <
1353+ _ ,
1354+ Twox64Concat ,
1355+ BridgeNetworkId < T > ,
1356+ Identity ,
1357+ H256 ,
1358+ BTreeSet < T :: AccountId > ,
1359+ ValueQuery ,
1360+ > ;
1361+
13121362 /// Requests made by an account.
13131363 #[ pallet:: storage]
13141364 #[ pallet:: getter( fn account_requests) ]
@@ -1574,11 +1624,17 @@ impl<T: Config> Pallet<T> {
15741624 Error :: <T >:: DuplicatedRequest
15751625 ) ;
15761626 }
1627+ let queue_len = RequestsQueue :: < T > :: get ( net_id) . len ( ) ;
1628+ ensure ! (
1629+ queue_len < T :: MaxRequestsPerQueue :: get( ) as usize ,
1630+ Error :: <T >:: RequestsQueueFull
1631+ ) ;
15771632 request. validate ( ) ?;
15781633 request. prepare ( ) ?;
1634+ Self :: clear_request_signatures ( net_id, & hash) ;
15791635 AccountRequests :: < T > :: mutate ( & request. author ( ) , |vec| vec. push ( ( net_id, hash) ) ) ;
15801636 Requests :: < T > :: insert ( net_id, & hash, request) ;
1581- RequestsQueue :: < T > :: mutate ( net_id, |v| v . push ( hash) ) ;
1637+ RequestsQueue :: < T > :: mutate ( net_id, |queue| queue . push ( hash) ) ;
15821638 RequestStatuses :: < T > :: insert ( net_id, & hash, RequestStatus :: Pending ) ;
15831639 let block_number = frame_system:: Pallet :: < T > :: current_block_number ( ) ;
15841640 RequestSubmissionHeight :: < T > :: insert ( net_id, & hash, block_number) ;
@@ -1603,13 +1659,6 @@ impl<T: Config> Pallet<T> {
16031659 !Requests :: <T >:: contains_key( network_id, incoming_request_hash) ,
16041660 Error :: <T >:: RequestIsAlreadyRegistered
16051661 ) ;
1606- Self :: remove_request_from_queue ( network_id, & sidechain_tx_hash) ;
1607- RequestStatuses :: < T > :: insert ( network_id, sidechain_tx_hash, RequestStatus :: Done ) ;
1608- LoadToIncomingRequestHash :: < T > :: insert (
1609- network_id,
1610- sidechain_tx_hash,
1611- incoming_request_hash,
1612- ) ;
16131662 if let Err ( e) = incoming_request
16141663 . validate ( )
16151664 . and_then ( |_| incoming_request. prepare ( ) )
@@ -1623,12 +1672,24 @@ impl<T: Config> Pallet<T> {
16231672 Self :: deposit_event ( Event :: RegisterRequestFailed ( incoming_request_hash, e) ) ;
16241673 return Ok ( incoming_request_hash) ;
16251674 }
1675+ let queue_len = RequestsQueue :: < T > :: get ( network_id) . len ( ) ;
1676+ ensure ! (
1677+ queue_len < T :: MaxRequestsPerQueue :: get( ) as usize ,
1678+ Error :: <T >:: RequestsQueueFull
1679+ ) ;
16261680 Requests :: < T > :: insert ( network_id, & incoming_request_hash, incoming_request) ;
1627- RequestsQueue :: < T > :: mutate ( network_id, |v| v . push ( incoming_request_hash) ) ;
1681+ RequestsQueue :: < T > :: mutate ( network_id, |queue| queue . push ( incoming_request_hash) ) ;
16281682 RequestStatuses :: < T > :: insert ( network_id, incoming_request_hash, RequestStatus :: Pending ) ;
16291683 AccountRequests :: < T > :: mutate ( request_author, |v| {
16301684 v. push ( ( network_id, incoming_request_hash) )
16311685 } ) ;
1686+ Self :: remove_request_from_queue ( network_id, & sidechain_tx_hash) ;
1687+ RequestStatuses :: < T > :: insert ( network_id, sidechain_tx_hash, RequestStatus :: Done ) ;
1688+ LoadToIncomingRequestHash :: < T > :: insert (
1689+ network_id,
1690+ sidechain_tx_hash,
1691+ incoming_request_hash,
1692+ ) ;
16321693 Ok ( incoming_request_hash)
16331694 }
16341695
@@ -1669,6 +1730,12 @@ impl<T: Config> Pallet<T> {
16691730 } ) ;
16701731 }
16711732
1733+ #[ inline]
1734+ pub ( crate ) fn clear_request_signatures ( network_id : T :: NetworkId , hash : & H256 ) {
1735+ RequestApprovals :: < T > :: remove ( network_id, hash) ;
1736+ RequestApprovers :: < T > :: remove ( network_id, hash) ;
1737+ }
1738+
16721739 /// Registers new sidechain asset and grants mint permission to the bridge account.
16731740 fn register_sidechain_asset (
16741741 token_address : EthAddress ,
@@ -1785,6 +1852,7 @@ impl<T: Config> Pallet<T> {
17851852 }
17861853 info ! ( "Verified request approve {:?}" , request_encoded) ;
17871854 let mut approvals = RequestApprovals :: < T > :: get ( net_id, & hash) ;
1855+ let mut approvers = RequestApprovers :: < T > :: get ( net_id, & hash) ;
17881856 let pending_peers_len = if Self :: is_additional_signature_needed ( net_id, & request) {
17891857 1
17901858 } else {
@@ -1793,8 +1861,17 @@ impl<T: Config> Pallet<T> {
17931861 let need_sigs = majority ( Self :: peers ( net_id) . len ( ) ) + pending_peers_len;
17941862 let current_status =
17951863 RequestStatuses :: < T > :: get ( net_id, & hash) . ok_or ( Error :: < T > :: UnknownRequest ) ?;
1864+ if !approvers. insert ( author. clone ( ) ) {
1865+ debug ! (
1866+ "Peer {:?} attempted to resubmit approval for {:?}" ,
1867+ author, hash
1868+ ) ;
1869+ RequestApprovers :: < T > :: insert ( net_id, & hash, & approvers) ;
1870+ return Ok ( None ) ;
1871+ }
17961872 approvals. insert ( signature_params) ;
17971873 RequestApprovals :: < T > :: insert ( net_id, & hash, & approvals) ;
1874+ RequestApprovers :: < T > :: insert ( net_id, & hash, & approvers) ;
17981875 if current_status == RequestStatus :: Pending && approvals. len ( ) == need_sigs {
17991876 if let Err ( err) = request. finalize ( hash) {
18001877 error ! ( "Outgoing request finalization failed: {:?}" , err) ;
0 commit comments