tempo_precompiles/validator_config/
dispatch.rs1use super::{IValidatorConfig, ValidatorConfig};
2use crate::{Precompile, fill_precompile_output, input_cost, mutate_void, unknown_selector, view};
3use alloy::{primitives::Address, sol_types::SolCall};
4use revm::precompile::{PrecompileError, PrecompileResult};
5
6impl Precompile for ValidatorConfig {
7 fn call(&mut self, calldata: &[u8], msg_sender: Address) -> PrecompileResult {
8 self.storage
9 .deduct_gas(input_cost(calldata.len()))
10 .map_err(|_| PrecompileError::OutOfGas)?;
11
12 let selector: [u8; 4] = calldata
13 .get(..4)
14 .ok_or_else(|| {
15 PrecompileError::Other("Invalid input: missing function selector".into())
16 })?
17 .try_into()
18 .map_err(|_| PrecompileError::Other("Invalid function selector length".into()))?;
19
20 let result = match selector {
21 IValidatorConfig::ownerCall::SELECTOR => {
23 view::<IValidatorConfig::ownerCall>(calldata, |_call| self.owner())
24 }
25 IValidatorConfig::getValidatorsCall::SELECTOR => {
26 view::<IValidatorConfig::getValidatorsCall>(calldata, |_call| self.get_validators())
27 }
28
29 IValidatorConfig::addValidatorCall::SELECTOR => {
31 mutate_void::<IValidatorConfig::addValidatorCall>(
32 calldata,
33 msg_sender,
34 |s, call| self.add_validator(s, call),
35 )
36 }
37 IValidatorConfig::updateValidatorCall::SELECTOR => {
38 mutate_void::<IValidatorConfig::updateValidatorCall>(
39 calldata,
40 msg_sender,
41 |s, call| self.update_validator(s, call),
42 )
43 }
44 IValidatorConfig::changeValidatorStatusCall::SELECTOR => {
45 mutate_void::<IValidatorConfig::changeValidatorStatusCall>(
46 calldata,
47 msg_sender,
48 |s, call| self.change_validator_status(s, call),
49 )
50 }
51 IValidatorConfig::changeOwnerCall::SELECTOR => {
52 mutate_void::<IValidatorConfig::changeOwnerCall>(calldata, msg_sender, |s, call| {
53 self.change_owner(s, call)
54 })
55 }
56
57 _ => unknown_selector(selector, self.storage.gas_used(), self.storage.spec()),
58 };
59
60 result.map(|res| fill_precompile_output(res, &mut self.storage))
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67 use crate::{
68 expect_precompile_revert,
69 storage::{StorageCtx, hashmap::HashMapStorageProvider},
70 test_util::{assert_full_coverage, check_selector_coverage},
71 };
72 use alloy::{
73 primitives::{Address, FixedBytes},
74 sol_types::SolValue,
75 };
76 use tempo_chainspec::hardfork::TempoHardfork;
77 use tempo_contracts::precompiles::{
78 IValidatorConfig::IValidatorConfigCalls, ValidatorConfigError,
79 };
80
81 #[test]
82 fn test_function_selector_dispatch() -> eyre::Result<()> {
83 let mut storage = HashMapStorageProvider::new(1).with_spec(TempoHardfork::Moderato);
84 let sender = Address::random();
85 let owner = Address::random();
86 StorageCtx::enter(&mut storage, || {
87 let mut validator_config = ValidatorConfig::new();
88
89 validator_config.initialize(owner)?;
91
92 let result = validator_config.call(&[0x12, 0x34, 0x56, 0x78], sender)?;
94 assert!(result.reverted);
95
96 let result = validator_config.call(&[0x12, 0x34], sender);
98 assert!(matches!(result, Err(PrecompileError::Other(_))));
99
100 Ok(())
101 })
102 }
103
104 #[test]
105 fn test_owner_view_dispatch() -> eyre::Result<()> {
106 let mut storage = HashMapStorageProvider::new(1);
107 let sender = Address::random();
108 let owner = Address::random();
109 StorageCtx::enter(&mut storage, || {
110 let mut validator_config = ValidatorConfig::new();
111
112 validator_config.initialize(owner)?;
114
115 let owner_call = IValidatorConfig::ownerCall {};
117 let calldata = owner_call.abi_encode();
118
119 let result = validator_config.call(&calldata, sender)?;
120 assert_eq!(result.gas_used, 0);
122
123 let decoded = Address::abi_decode(&result.bytes)?;
125 assert_eq!(decoded, owner);
126
127 Ok(())
128 })
129 }
130
131 #[test]
132 fn test_add_validator_dispatch() -> eyre::Result<()> {
133 let mut storage = HashMapStorageProvider::new(1);
134 let owner = Address::random();
135 let validator_addr = Address::random();
136 StorageCtx::enter(&mut storage, || {
137 let mut validator_config = ValidatorConfig::new();
138
139 validator_config.initialize(owner)?;
141
142 let public_key = FixedBytes::<32>::from([0x42; 32]);
144 let add_call = IValidatorConfig::addValidatorCall {
145 newValidatorAddress: validator_addr,
146 publicKey: public_key,
147 active: true,
148 inboundAddress: "192.168.1.1:8000".to_string(),
149 outboundAddress: "192.168.1.1:9000".to_string(),
150 };
151 let calldata = add_call.abi_encode();
152
153 let result = validator_config.call(&calldata, owner)?;
154
155 assert_eq!(result.gas_used, 0);
157
158 let validators = validator_config.get_validators()?;
160 assert_eq!(validators.len(), 1);
161 assert_eq!(validators[0].validatorAddress, validator_addr);
162 assert_eq!(validators[0].publicKey, public_key);
163 assert_eq!(validators[0].inboundAddress, "192.168.1.1:8000");
164 assert_eq!(validators[0].outboundAddress, "192.168.1.1:9000");
165 assert!(validators[0].active);
166
167 Ok(())
168 })
169 }
170
171 #[test]
172 fn test_unauthorized_add_validator_dispatch() -> eyre::Result<()> {
173 let mut storage = HashMapStorageProvider::new(1);
174 let owner = Address::random();
175 let non_owner = Address::random();
176 let validator_addr = Address::random();
177 StorageCtx::enter(&mut storage, || {
178 let mut validator_config = ValidatorConfig::new();
179
180 validator_config.initialize(owner)?;
182
183 let public_key = FixedBytes::<32>::from([0x42; 32]);
185 let add_call = IValidatorConfig::addValidatorCall {
186 newValidatorAddress: validator_addr,
187 publicKey: public_key,
188 active: true,
189 inboundAddress: "192.168.1.1:8000".to_string(),
190 outboundAddress: "192.168.1.1:9000".to_string(),
191 };
192 let calldata = add_call.abi_encode();
193
194 let result = validator_config.call(&calldata, non_owner);
195 expect_precompile_revert(&result, ValidatorConfigError::unauthorized());
196
197 Ok(())
198 })
199 }
200
201 #[test]
202 fn test_selector_coverage() -> eyre::Result<()> {
203 let mut storage = HashMapStorageProvider::new(1);
204 StorageCtx::enter(&mut storage, || {
205 let mut validator_config = ValidatorConfig::new();
206
207 let unsupported = check_selector_coverage(
208 &mut validator_config,
209 IValidatorConfigCalls::SELECTORS,
210 "IValidatorConfig",
211 IValidatorConfigCalls::name_by_selector,
212 );
213
214 assert_full_coverage([unsupported]);
215
216 Ok(())
217 })
218 }
219}