Skip to content

Commit f5542c1

Browse files
authored
Merge pull request #1043 from opentensor/metagraph-contract
Metagraph contract
2 parents cfe0c29 + c2106ec commit f5542c1

File tree

4 files changed

+891
-1
lines changed

4 files changed

+891
-1
lines changed
Lines changed: 360 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,360 @@
1+
extern crate alloc;
2+
use crate::precompiles::{get_method_id, get_slice};
3+
use crate::Runtime;
4+
use fp_evm::{
5+
ExitError, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult,
6+
};
7+
use sp_core::{ByteArray, U256};
8+
use sp_std::vec;
9+
pub const METAGRAPH_PRECOMPILE_INDEX: u64 = 2050;
10+
pub struct MetagraphPrecompile;
11+
12+
const NO_HOTKEY: &str = "no hotkey";
13+
14+
impl MetagraphPrecompile {
15+
pub fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult {
16+
let txdata = handle.input();
17+
let method_id = get_slice(txdata, 0, 4)?;
18+
let method_input = txdata
19+
.get(4..)
20+
.map_or_else(vec::Vec::new, |slice| slice.to_vec()); // Avoiding borrowing conflicts
21+
22+
match method_id {
23+
id if id == get_method_id("getUidCount(uint16)") => Self::get_uid_count(&method_input),
24+
id if id == get_method_id("getStake(uint16,uint16)") => Self::get_stake(&method_input),
25+
id if id == get_method_id("getRank(uint16,uint16)") => Self::get_rank(&method_input),
26+
id if id == get_method_id("getTrust(uint16,uint16)") => Self::get_trust(&method_input),
27+
id if id == get_method_id("getConsensus(uint16,uint16)") => {
28+
Self::get_consensus(&method_input)
29+
}
30+
id if id == get_method_id("getIncentive(uint16,uint16)") => {
31+
Self::get_incentive(&method_input)
32+
}
33+
id if id == get_method_id("getDividends(uint16,uint16)") => {
34+
Self::get_dividends(&method_input)
35+
}
36+
id if id == get_method_id("getEmission(uint16,uint16)") => {
37+
Self::get_emission(&method_input)
38+
}
39+
id if id == get_method_id("getVtrust(uint16,uint16)") => {
40+
Self::get_vtrust(&method_input)
41+
}
42+
id if id == get_method_id("getValidatorStatus(uint16,uint16)") => {
43+
Self::get_validator_status(&method_input)
44+
}
45+
id if id == get_method_id("getLastUpdate(uint16,uint16)") => {
46+
Self::get_last_update(&method_input)
47+
}
48+
id if id == get_method_id("getIsActive(uint16,uint16)") => {
49+
Self::get_is_active(&method_input)
50+
}
51+
id if id == get_method_id("getAxon(uint16,uint16)") => Self::get_axon(&method_input),
52+
id if id == get_method_id("getHotkey(uint16,uint16)") => {
53+
Self::get_hotkey(&method_input)
54+
}
55+
id if id == get_method_id("getColdkey(uint16,uint16)") => {
56+
Self::get_coldkey(&method_input)
57+
}
58+
59+
_ => Err(PrecompileFailure::Error {
60+
exit_status: ExitError::InvalidRange,
61+
}),
62+
}
63+
}
64+
65+
fn get_uid_count(data: &[u8]) -> PrecompileResult {
66+
let netuid = Self::parse_netuid(data)?;
67+
let uid_count = pallet_subtensor::SubnetworkN::<Runtime>::get(netuid);
68+
69+
let uid_count_u256 = U256::from(uid_count);
70+
let mut result = [0_u8; 32];
71+
U256::to_big_endian(&uid_count_u256, &mut result);
72+
73+
Ok(PrecompileOutput {
74+
exit_status: ExitSucceed::Returned,
75+
output: result.into(),
76+
})
77+
}
78+
79+
fn get_stake(data: &[u8]) -> PrecompileResult {
80+
let netuid = Self::parse_netuid(data)?;
81+
let uid = Self::parse_uid(get_slice(data, 32, 64)?)?;
82+
let hotkey = pallet_subtensor::Pallet::<Runtime>::get_hotkey_for_net_and_uid(netuid, uid)
83+
.map_err(|_| PrecompileFailure::Error {
84+
exit_status: ExitError::InvalidRange,
85+
})?;
86+
87+
let stake = pallet_subtensor::TotalHotkeyStake::<Runtime>::get(&hotkey);
88+
let result_u256 = U256::from(stake);
89+
let mut result = [0_u8; 32];
90+
U256::to_big_endian(&result_u256, &mut result);
91+
92+
Ok(PrecompileOutput {
93+
exit_status: ExitSucceed::Returned,
94+
output: result.into(),
95+
})
96+
}
97+
98+
fn get_rank(data: &[u8]) -> PrecompileResult {
99+
let netuid = Self::parse_netuid(data)?;
100+
let uid = Self::parse_uid(get_slice(data, 32, 64)?)?;
101+
let rank = pallet_subtensor::Pallet::<Runtime>::get_rank_for_uid(netuid, uid);
102+
103+
let result_u256 = U256::from(rank);
104+
let mut result = [0_u8; 32];
105+
U256::to_big_endian(&result_u256, &mut result);
106+
107+
Ok(PrecompileOutput {
108+
exit_status: ExitSucceed::Returned,
109+
output: result.into(),
110+
})
111+
}
112+
113+
fn get_trust(data: &[u8]) -> PrecompileResult {
114+
let netuid = Self::parse_netuid(data)?;
115+
let uid = Self::parse_uid(get_slice(data, 32, 64)?)?;
116+
117+
let trust = pallet_subtensor::Pallet::<Runtime>::get_trust_for_uid(netuid, uid);
118+
119+
let result_u256 = U256::from(trust);
120+
let mut result = [0_u8; 32];
121+
U256::to_big_endian(&result_u256, &mut result);
122+
123+
Ok(PrecompileOutput {
124+
exit_status: ExitSucceed::Returned,
125+
output: result.into(),
126+
})
127+
}
128+
129+
fn get_consensus(data: &[u8]) -> PrecompileResult {
130+
let netuid = Self::parse_netuid(data)?;
131+
let uid = Self::parse_uid(get_slice(data, 32, 64)?)?;
132+
133+
let consensus = pallet_subtensor::Pallet::<Runtime>::get_consensus_for_uid(netuid, uid);
134+
135+
let result_u256 = U256::from(consensus);
136+
let mut result = [0_u8; 32];
137+
U256::to_big_endian(&result_u256, &mut result);
138+
139+
Ok(PrecompileOutput {
140+
exit_status: ExitSucceed::Returned,
141+
output: result.into(),
142+
})
143+
}
144+
145+
fn get_incentive(data: &[u8]) -> PrecompileResult {
146+
let netuid = Self::parse_netuid(data)?;
147+
let uid = Self::parse_uid(get_slice(data, 32, 64)?)?;
148+
149+
let incentive = pallet_subtensor::Pallet::<Runtime>::get_incentive_for_uid(netuid, uid);
150+
151+
let result_u256 = U256::from(incentive);
152+
let mut result = [0_u8; 32];
153+
U256::to_big_endian(&result_u256, &mut result);
154+
155+
Ok(PrecompileOutput {
156+
exit_status: ExitSucceed::Returned,
157+
output: result.into(),
158+
})
159+
}
160+
161+
fn get_dividends(data: &[u8]) -> PrecompileResult {
162+
let netuid = Self::parse_netuid(data)?;
163+
let uid = Self::parse_uid(get_slice(data, 32, 64)?)?;
164+
165+
let dividends = pallet_subtensor::Pallet::<Runtime>::get_dividends_for_uid(netuid, uid);
166+
167+
let result_u256 = U256::from(dividends);
168+
let mut result = [0_u8; 32];
169+
U256::to_big_endian(&result_u256, &mut result);
170+
171+
Ok(PrecompileOutput {
172+
exit_status: ExitSucceed::Returned,
173+
output: result.into(),
174+
})
175+
}
176+
177+
fn get_emission(data: &[u8]) -> PrecompileResult {
178+
let netuid = Self::parse_netuid(data)?;
179+
let uid = Self::parse_uid(get_slice(data, 32, 64)?)?;
180+
181+
let emission = pallet_subtensor::Pallet::<Runtime>::get_emission_for_uid(netuid, uid);
182+
183+
let result_u256 = U256::from(emission);
184+
let mut result = [0_u8; 32];
185+
U256::to_big_endian(&result_u256, &mut result);
186+
187+
Ok(PrecompileOutput {
188+
exit_status: ExitSucceed::Returned,
189+
output: result.into(),
190+
})
191+
}
192+
193+
fn get_vtrust(data: &[u8]) -> PrecompileResult {
194+
let netuid = Self::parse_netuid(data)?;
195+
let uid = Self::parse_uid(get_slice(data, 32, 64)?)?;
196+
197+
let vtrust = pallet_subtensor::Pallet::<Runtime>::get_validator_trust_for_uid(netuid, uid);
198+
199+
let result_u256 = U256::from(vtrust);
200+
let mut result = [0_u8; 32];
201+
U256::to_big_endian(&result_u256, &mut result);
202+
203+
Ok(PrecompileOutput {
204+
exit_status: ExitSucceed::Returned,
205+
output: result.into(),
206+
})
207+
}
208+
209+
fn get_validator_status(data: &[u8]) -> PrecompileResult {
210+
let netuid = Self::parse_netuid(data)?;
211+
let uid = Self::parse_uid(get_slice(data, 32, 64)?)?;
212+
213+
let validator_permit =
214+
pallet_subtensor::Pallet::<Runtime>::get_validator_permit_for_uid(netuid, uid);
215+
216+
let result_u256 = if validator_permit {
217+
U256::from(1)
218+
} else {
219+
U256::from(0)
220+
};
221+
let mut result = [0_u8; 32];
222+
U256::to_big_endian(&result_u256, &mut result);
223+
224+
Ok(PrecompileOutput {
225+
exit_status: ExitSucceed::Returned,
226+
output: result.into(),
227+
})
228+
}
229+
230+
fn get_last_update(data: &[u8]) -> PrecompileResult {
231+
let netuid = Self::parse_netuid(data)?;
232+
let uid = Self::parse_uid(get_slice(data, 32, 64)?)?;
233+
234+
let last_update = pallet_subtensor::Pallet::<Runtime>::get_last_update_for_uid(netuid, uid);
235+
236+
let result_u256 = U256::from(last_update);
237+
let mut result = [0_u8; 32];
238+
U256::to_big_endian(&result_u256, &mut result);
239+
240+
Ok(PrecompileOutput {
241+
exit_status: ExitSucceed::Returned,
242+
output: result.into(),
243+
})
244+
}
245+
246+
fn get_is_active(data: &[u8]) -> PrecompileResult {
247+
let netuid = Self::parse_netuid(data)?;
248+
let uid = Self::parse_uid(get_slice(data, 32, 64)?)?;
249+
250+
let active = pallet_subtensor::Pallet::<Runtime>::get_active_for_uid(netuid, uid);
251+
252+
let result_u256 = if active { U256::from(1) } else { U256::from(0) };
253+
let mut result = [0_u8; 32];
254+
U256::to_big_endian(&result_u256, &mut result);
255+
256+
Ok(PrecompileOutput {
257+
exit_status: ExitSucceed::Returned,
258+
output: result.into(),
259+
})
260+
}
261+
262+
fn get_axon(data: &[u8]) -> PrecompileResult {
263+
let netuid = Self::parse_netuid(data)?;
264+
let uid = Self::parse_uid(get_slice(data, 32, 64)?)?;
265+
266+
let hotkey = pallet_subtensor::Pallet::<Runtime>::get_hotkey_for_net_and_uid(netuid, uid)
267+
.map_err(|_| PrecompileFailure::Error {
268+
exit_status: ExitError::Other(sp_version::Cow::Borrowed(NO_HOTKEY)),
269+
})?;
270+
271+
let axon = pallet_subtensor::Pallet::<Runtime>::get_axon_info(netuid, &hotkey);
272+
273+
let mut block_result = [0_u8; 32];
274+
U256::to_big_endian(&U256::from(axon.block), &mut block_result);
275+
276+
let mut version_result = [0_u8; 32];
277+
U256::to_big_endian(&U256::from(axon.version), &mut version_result);
278+
279+
let mut ip_result = [0_u8; 32];
280+
U256::to_big_endian(&U256::from(axon.ip), &mut ip_result);
281+
282+
let mut port_result = [0_u8; 32];
283+
U256::to_big_endian(&U256::from(axon.port), &mut port_result);
284+
285+
let mut ip_type_result = [0_u8; 32];
286+
U256::to_big_endian(&U256::from(axon.ip_type), &mut ip_type_result);
287+
288+
let mut protocol_result = [0_u8; 32];
289+
U256::to_big_endian(&U256::from(axon.protocol), &mut protocol_result);
290+
291+
let mut result = [0_u8; 192];
292+
result[..32].copy_from_slice(&block_result);
293+
result[32..64].copy_from_slice(&version_result);
294+
result[64..96].copy_from_slice(&ip_result);
295+
result[96..128].copy_from_slice(&port_result);
296+
result[128..160].copy_from_slice(&ip_type_result);
297+
result[160..].copy_from_slice(&protocol_result);
298+
299+
Ok(PrecompileOutput {
300+
exit_status: ExitSucceed::Returned,
301+
output: result.into(),
302+
})
303+
}
304+
305+
fn get_hotkey(data: &[u8]) -> PrecompileResult {
306+
let netuid = Self::parse_netuid(data)?;
307+
let uid = Self::parse_uid(get_slice(data, 32, 64)?)?;
308+
309+
let hotkey = pallet_subtensor::Pallet::<Runtime>::get_hotkey_for_net_and_uid(netuid, uid)
310+
.map_err(|_| PrecompileFailure::Error {
311+
exit_status: ExitError::InvalidRange,
312+
})?;
313+
314+
Ok(PrecompileOutput {
315+
exit_status: ExitSucceed::Returned,
316+
output: hotkey.as_slice().into(),
317+
})
318+
}
319+
320+
fn get_coldkey(data: &[u8]) -> PrecompileResult {
321+
let netuid = Self::parse_netuid(data)?;
322+
let uid = Self::parse_uid(get_slice(data, 32, 64)?)?;
323+
324+
let hotkey = pallet_subtensor::Pallet::<Runtime>::get_hotkey_for_net_and_uid(netuid, uid)
325+
.map_err(|_| PrecompileFailure::Error {
326+
exit_status: ExitError::InvalidRange,
327+
})?;
328+
329+
let coldkey = pallet_subtensor::Owner::<Runtime>::get(&hotkey);
330+
331+
Ok(PrecompileOutput {
332+
exit_status: ExitSucceed::Returned,
333+
output: coldkey.as_slice().into(),
334+
})
335+
}
336+
337+
fn parse_netuid(data: &[u8]) -> Result<u16, PrecompileFailure> {
338+
if data.len() < 32 {
339+
return Err(PrecompileFailure::Error {
340+
exit_status: ExitError::InvalidRange,
341+
});
342+
}
343+
let mut netuid = [0u8; 2];
344+
netuid.copy_from_slice(get_slice(data, 30, 32)?);
345+
let result = u16::from_be_bytes(netuid);
346+
Ok(result)
347+
}
348+
349+
fn parse_uid(data: &[u8]) -> Result<u16, PrecompileFailure> {
350+
if data.len() < 32 {
351+
return Err(PrecompileFailure::Error {
352+
exit_status: ExitError::InvalidRange,
353+
});
354+
}
355+
let mut uid = [0u8; 2];
356+
uid.copy_from_slice(get_slice(data, 30, 32)?);
357+
let result = u16::from_be_bytes(uid);
358+
Ok(result)
359+
}
360+
}

0 commit comments

Comments
 (0)