1
// Copyright 2024 Moonbeam foundation
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
//! # Lazy Migration Pallet
18
//!
19
//! An empty pallet reserved for future migrations.
20

            
21
#![allow(non_camel_case_types)]
22
#![cfg_attr(not(feature = "std"), no_std)]
23

            
24
#[cfg(test)]
25
pub mod mock;
26

            
27
#[cfg(test)]
28
mod tests;
29

            
30
// #[cfg(any(test, feature = "runtime-benchmarks"))]
31
// mod benchmarks;
32

            
33
pub mod weights;
34
pub use weights::WeightInfo;
35

            
36
use frame_support::pallet;
37
use frame_support::pallet_prelude::*;
38
use frame_system::pallet_prelude::*;
39
pub use pallet::*;
40

            
41
const MAX_CONTRACT_CODE_SIZE: u64 = 25 * 1024;
42

            
43
63
#[pallet]
44
pub mod pallet {
45

            
46
	use super::*;
47
	use sp_core::H160;
48

            
49
	/// Pallet for multi block migrations
50
70
	#[pallet::pallet]
51
	pub struct Pallet<T>(PhantomData<T>);
52

            
53
	/// Configuration trait of this pallet.
54
	#[pallet::config]
55
	pub trait Config: frame_system::Config + pallet_evm::Config {
56
		type WeightInfo: WeightInfo;
57
	}
58

            
59
8
	#[pallet::error]
60
	pub enum Error<T> {
61
		/// The contract already have metadata
62
		ContractMetadataAlreadySet,
63
		/// Contract not exist
64
		ContractNotExist,
65
	}
66

            
67
	#[pallet::call]
68
	impl<T: Config> Pallet<T>
69
	where
70
		<T as frame_system::Config>::AccountId: Into<H160> + From<H160>,
71
	{
72
		#[pallet::call_index(2)]
73
		#[pallet::weight(Pallet::<T>::create_contract_metadata_weight(MAX_CONTRACT_CODE_SIZE))]
74
		pub fn create_contract_metadata(
75
			origin: OriginFor<T>,
76
			address: H160,
77
3
		) -> DispatchResultWithPostInfo {
78
3
			ensure_signed(origin)?;
79

            
80
3
			ensure!(
81
3
				pallet_evm::AccountCodesMetadata::<T>::get(address).is_none(),
82
1
				Error::<T>::ContractMetadataAlreadySet
83
			);
84

            
85
			// Ensure contract exist
86
2
			let code = pallet_evm::AccountCodes::<T>::get(address);
87
2
			ensure!(!code.is_empty(), Error::<T>::ContractNotExist);
88

            
89
			// Construct metadata
90
1
			let code_size = code.len() as u64;
91
1
			let code_hash = sp_core::H256::from(sp_io::hashing::keccak_256(&code));
92
1
			let meta = pallet_evm::CodeMetadata {
93
1
				size: code_size,
94
1
				hash: code_hash,
95
1
			};
96
1

            
97
1
			// Set metadata
98
1
			pallet_evm::AccountCodesMetadata::<T>::insert(address, meta);
99
1

            
100
1
			Ok((
101
1
				Some(Self::create_contract_metadata_weight(code_size)),
102
1
				Pays::No,
103
1
			)
104
1
				.into())
105
		}
106
	}
107

            
108
	impl<T: Config> Pallet<T> {
109
1
		fn create_contract_metadata_weight(code_size: u64) -> Weight {
110
			// max entry size of AccountCodesMetadata (full key + value)
111
			const PROOF_SIZE_CODE_METADATA: u64 = 100;
112
			// intermediates nodes might be up to 3Kb
113
			const PROOF_SIZE_INTERMEDIATES_NODES: u64 = 3 * 1024;
114

            
115
			// Account for 2 reads, 1 write
116
1
			<T as frame_system::Config>::DbWeight::get()
117
1
				.reads_writes(2, 1)
118
1
				.set_proof_size(
119
1
					code_size + (PROOF_SIZE_INTERMEDIATES_NODES * 2) + PROOF_SIZE_CODE_METADATA,
120
1
				)
121
1
		}
122
	}
123
}