1
// Copyright 2019-2025 PureStake Inc.
2
// This file is part of Moonbeam.
3

            
4
// Moonbeam 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
// Moonbeam 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 Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
use crate::mock::{
18
	ExtBuilder, PCall, Precompiles, PrecompilesValue, Registry, Removed, Runtime, SmartContract,
19
};
20
use precompile_utils::{prelude::*, testing::*};
21
use sp_core::H160;
22

            
23
13
fn precompiles() -> Precompiles<Runtime> {
24
13
	PrecompilesValue::get()
25
13
}
26

            
27
mod selectors {
28
	use super::*;
29

            
30
	#[test]
31
1
	fn selectors() {
32
1
		assert!(PCall::is_precompile_selectors().contains(&0x446b450e));
33
1
		assert!(PCall::is_active_precompile_selectors().contains(&0x6f5e23cf));
34
1
		assert!(PCall::update_account_code_selectors().contains(&0x48ceb1b4));
35
1
	}
36

            
37
	#[test]
38
1
	fn modifiers() {
39
1
		ExtBuilder::default()
40
1
			.with_balances(vec![(CryptoAlith.into(), 1000)])
41
1
			.build()
42
1
			.execute_with(|| {
43
1
				let mut tester =
44
1
					PrecompilesModifierTester::new(precompiles(), CryptoAlith, Registry);
45
1

            
46
1
				tester.test_view_modifier(PCall::is_precompile_selectors());
47
1
				tester.test_view_modifier(PCall::is_active_precompile_selectors());
48
1
				tester.test_default_modifier(PCall::update_account_code_selectors());
49
1
			});
50
1
	}
51
}
52

            
53
mod is_precompile {
54

            
55
	use super::*;
56

            
57
4
	fn call(target_address: impl Into<H160>, output: bool) {
58
4
		ExtBuilder::default()
59
4
			.with_balances(vec![(CryptoAlith.into(), 1000)])
60
4
			.build()
61
4
			.execute_with(|| {
62
4
				precompiles()
63
4
					.prepare_test(
64
4
						Alice, // can be anyone
65
4
						Registry,
66
4
						PCall::is_precompile {
67
4
							address: Address(target_address.into()),
68
4
						},
69
4
					)
70
4
					.expect_no_logs()
71
4
					.execute_returns(output);
72
4
			});
73
4
	}
74

            
75
	#[test]
76
1
	fn works_on_precompile() {
77
1
		call(Registry, true);
78
1
	}
79

            
80
	#[test]
81
1
	fn works_on_removed_precompile() {
82
1
		call(Removed, true);
83
1
	}
84

            
85
	#[test]
86
1
	fn works_on_eoa() {
87
1
		call(CryptoAlith, false);
88
1
	}
89

            
90
	#[test]
91
1
	fn works_on_smart_contract() {
92
1
		call(SmartContract, false);
93
1
	}
94
}
95

            
96
mod is_active_precompile {
97

            
98
	use super::*;
99

            
100
4
	fn call(target_address: impl Into<H160>, output: bool) {
101
4
		ExtBuilder::default()
102
4
			.with_balances(vec![(CryptoAlith.into(), 1000)])
103
4
			.build()
104
4
			.execute_with(|| {
105
4
				precompiles()
106
4
					.prepare_test(
107
4
						Alice, // can be anyone
108
4
						Registry,
109
4
						PCall::is_active_precompile {
110
4
							address: Address(target_address.into()),
111
4
						},
112
4
					)
113
4
					.expect_no_logs()
114
4
					.execute_returns(output);
115
4
			});
116
4
	}
117

            
118
	#[test]
119
1
	fn works_on_precompile() {
120
1
		call(Registry, true);
121
1
	}
122

            
123
	#[test]
124
1
	fn works_on_removed_precompile() {
125
1
		call(Removed, false);
126
1
	}
127

            
128
	#[test]
129
1
	fn works_on_eoa() {
130
1
		call(CryptoAlith, false);
131
1
	}
132

            
133
	#[test]
134
1
	fn works_on_smart_contract() {
135
1
		call(SmartContract, false);
136
1
	}
137
}
138

            
139
mod update_account_code {
140
	use super::*;
141

            
142
4
	fn call(target_address: impl Into<H160>, expect_changes: bool) {
143
4
		ExtBuilder::default()
144
4
			.with_balances(vec![(CryptoAlith.into(), 1000)])
145
4
			.build()
146
4
			.execute_with(|| {
147
4
				let target_address = target_address.into();
148
4

            
149
4
				let precompiles = precompiles();
150
4
				let tester = precompiles.prepare_test(
151
4
					Alice, // can be anyone
152
4
					Registry,
153
4
					PCall::update_account_code {
154
4
						address: Address(target_address),
155
4
					},
156
4
				);
157
4

            
158
4
				if expect_changes {
159
2
					tester.execute_returns(());
160
2
					let new_code = pallet_evm::AccountCodes::<Runtime>::get(target_address);
161
2
					assert_eq!(&new_code, &[0x60, 0x00, 0x60, 0x00, 0xfd]);
162
				} else {
163
2
					let current_code = pallet_evm::AccountCodes::<Runtime>::get(target_address);
164
2

            
165
2
					tester.execute_reverts(|revert| {
166
2
						revert == b"provided address is not a precompile"
167
2
					});
168
2

            
169
2
					let new_code = pallet_evm::AccountCodes::<Runtime>::get(target_address);
170
2
					assert_eq!(current_code, new_code);
171
				}
172
4
			});
173
4
	}
174

            
175
	#[test]
176
1
	fn works_on_precompile() {
177
1
		call(Registry, true);
178
1
	}
179

            
180
	#[test]
181
1
	fn works_on_removed_precompile() {
182
1
		call(Removed, true);
183
1
	}
184

            
185
	#[test]
186
1
	fn works_on_eoa() {
187
1
		call(CryptoAlith, false);
188
1
	}
189

            
190
	#[test]
191
1
	fn works_on_smart_contract() {
192
1
		call(SmartContract, false);
193
1
	}
194
}
195

            
196
#[test]
197
1
fn test_solidity_interface() {
198
1
	check_precompile_implements_solidity_interfaces(
199
1
		&["PrecompileRegistry.sol"],
200
1
		PCall::supports_selector,
201
1
	)
202
1
}