1
// Copyright (C) Parity Technologies (UK) Ltd.
2
// This file is part of Parity Bridges Common.
3

            
4
// Parity Bridges Common is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Parity Bridges Common is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
//! A module that is responsible for migration of storage.
18

            
19
use crate::{Config, Pallet, Receiver, LOG_TARGET};
20
use frame_support::{
21
	traits::{Get, OnRuntimeUpgrade},
22
	weights::Weight,
23
};
24
use xcm::prelude::{InteriorLocation, Location};
25

            
26
/// This migration does not modify storage but can be used to open a bridge and link it to the
27
/// specified LaneId. This is useful when we want to open a bridge and use a custom LaneId instead
28
/// of the pre-calculated one provided by the `fn open_bridge extrinsic`.
29
/// Or perhaps if you want to ensure that your runtime (e.g., for testing) always has an open
30
/// bridge.
31
pub struct OpenBridgeForLane<
32
	T,
33
	I,
34
	Lane,
35
	CreateLane,
36
	SourceRelativeLocation,
37
	BridgedUniversalLocation,
38
	MaybeNotifyRelativeLocation,
39
>(
40
	core::marker::PhantomData<(
41
		T,
42
		I,
43
		Lane,
44
		CreateLane,
45
		SourceRelativeLocation,
46
		BridgedUniversalLocation,
47
		MaybeNotifyRelativeLocation,
48
	)>,
49
);
50
impl<
51
		T: Config<I>,
52
		I: 'static,
53
		Lane: Get<T::LaneId>,
54
		CreateLane: Get<bool>,
55
		SourceRelativeLocation: Get<Location>,
56
		BridgedUniversalLocation: Get<InteriorLocation>,
57
		MaybeNotifyRelativeLocation: Get<Option<Receiver>>,
58
	> OnRuntimeUpgrade
59
	for OpenBridgeForLane<
60
		T,
61
		I,
62
		Lane,
63
		CreateLane,
64
		SourceRelativeLocation,
65
		BridgedUniversalLocation,
66
		MaybeNotifyRelativeLocation,
67
	>
68
{
69
	fn on_runtime_upgrade() -> Weight {
70
		let bridge_origin_relative_location = SourceRelativeLocation::get();
71
		let bridge_destination_universal_location = BridgedUniversalLocation::get();
72
		let lane_id = Lane::get();
73
		let create_lane = CreateLane::get();
74
		let maybe_notify = MaybeNotifyRelativeLocation::get();
75
		log::info!(
76
			target: LOG_TARGET,
77
			"OpenBridgeForLane - going to open bridge with lane_id: {lane_id:?} (create_lane: {create_lane:?}) \
78
			between bridge_origin_relative_location: {bridge_origin_relative_location:?} and \
79
			bridge_destination_universal_location: {bridge_destination_universal_location:?} \
80
			maybe_notify: {maybe_notify:?}",
81
		);
82

            
83
		let locations = match Pallet::<T, I>::bridge_locations(
84
			bridge_origin_relative_location.clone(),
85
			bridge_destination_universal_location.clone(),
86
		) {
87
			Ok(locations) => locations,
88
			Err(e) => {
89
				log::error!(
90
					target: LOG_TARGET,
91
					"OpenBridgeForLane - on_runtime_upgrade failed to construct bridge_locations with error: {e:?}"
92
				);
93
				return T::DbWeight::get().reads(0);
94
			}
95
		};
96

            
97
		// check if already exists
98
		if let Some((bridge_id, bridge)) = Pallet::<T, I>::bridge_by_lane_id(&lane_id) {
99
			log::info!(
100
				target: LOG_TARGET,
101
				"OpenBridgeForLane - bridge: {bridge:?} with bridge_id: {bridge_id:?} already exist for lane_id: {lane_id:?}!"
102
			);
103
			if &bridge_id != locations.bridge_id() {
104
				log::warn!(
105
					target: LOG_TARGET,
106
					"OpenBridgeForLane - check you parameters, because a different bridge: {bridge:?} \
107
					with bridge_id: {bridge_id:?} exist for lane_id: {lane_id:?} for requested \
108
					bridge_origin_relative_location: {bridge_origin_relative_location:?} and \
109
					bridge_destination_universal_location: {bridge_destination_universal_location:?} !",
110
				);
111
			}
112

            
113
			return T::DbWeight::get().reads(2);
114
		}
115

            
116
		if let Err(e) =
117
			Pallet::<T, I>::do_open_bridge(locations, lane_id, create_lane, maybe_notify)
118
		{
119
			log::error!(target: LOG_TARGET, "OpenBridgeForLane - do_open_bridge failed with error: {e:?}");
120
			T::DbWeight::get().reads(6)
121
		} else {
122
			log::info!(target: LOG_TARGET, "OpenBridgeForLane - do_open_bridge passed!");
123
			T::DbWeight::get().reads_writes(6, 4)
124
		}
125
	}
126

            
127
	#[cfg(feature = "try-runtime")]
128
	fn post_upgrade(_state: sp_std::vec::Vec<u8>) -> Result<(), sp_runtime::DispatchError> {
129
		let bridge_origin_relative_location = SourceRelativeLocation::get();
130
		let bridge_destination_universal_location = BridgedUniversalLocation::get();
131
		let lane_id = Lane::get();
132

            
133
		// check that requested bridge is stored
134
		let Ok(locations) = Pallet::<T, I>::bridge_locations(
135
			bridge_origin_relative_location.clone(),
136
			bridge_destination_universal_location.clone(),
137
		) else {
138
			return Err(sp_runtime::DispatchError::Other("Invalid locations!"));
139
		};
140
		let Some((bridge_id, _)) = Pallet::<T, I>::bridge_by_lane_id(&lane_id) else {
141
			return Err(sp_runtime::DispatchError::Other("Missing bridge!"));
142
		};
143
		frame_support::ensure!(
144
			locations.bridge_id() == &bridge_id,
145
			"Bridge is not stored correctly!"
146
		);
147

            
148
		log::info!(
149
			target: LOG_TARGET,
150
			"OpenBridgeForLane - post_upgrade found opened bridge with lane_id: {lane_id:?} \
151
			between bridge_origin_relative_location: {bridge_origin_relative_location:?} and \
152
			bridge_destination_universal_location: {bridge_destination_universal_location:?}",
153
		);
154

            
155
		Ok(())
156
	}
157
}