1use solana_program::{
4 instruction::{AccountMeta, Instruction},
5 pubkey::Pubkey,
6};
7
8use crate::{consts::*, instruction::MinerInstruction, pda};
9
10pub fn initialize(admin: Pubkey, mint: Pubkey) -> Instruction {
11 let (config, _) = pda::config_pda();
12 let (round0, _) = pda::round_pda(0);
13 Instruction {
14 program_id: crate::id(),
15 accounts: vec![
16 AccountMeta::new(admin, true),
17 AccountMeta::new(config, false),
18 AccountMeta::new_readonly(mint, false),
19 AccountMeta::new(round0, false),
20 AccountMeta::new_readonly(SYSTEM_PROGRAM_ID, false),
21 ],
22 data: vec![MinerInstruction::Initialize as u8],
23 }
24}
25
26pub fn register(authority: Pubkey) -> Instruction {
27 let (miner, _) = pda::miner_pda(&authority);
28 Instruction {
29 program_id: crate::id(),
30 accounts: vec![
31 AccountMeta::new(authority, true),
32 AccountMeta::new(miner, false),
33 AccountMeta::new_readonly(SLOT_HASHES_SYSVAR_ID, false),
34 AccountMeta::new_readonly(SYSTEM_PROGRAM_ID, false),
35 ],
36 data: vec![MinerInstruction::Register as u8],
37 }
38}
39
40pub fn authorize_session(authority: Pubkey, session_key: Pubkey) -> Instruction {
41 let (miner, _) = pda::miner_pda(&authority);
42 let mut data = vec![MinerInstruction::AuthorizeSession as u8];
43 data.extend_from_slice(session_key.as_ref());
44 Instruction {
45 program_id: crate::id(),
46 accounts: vec![
47 AccountMeta::new_readonly(authority, true),
48 AccountMeta::new(miner, false),
49 ],
50 data,
51 }
52}
53
54pub fn mine(
55 signer: Pubkey,
56 authority: Pubkey,
57 mint: Pubkey,
58 current_round_index: u64,
59 prev_round_index: u64,
60 nonce: u64,
61) -> Instruction {
62 let (miner, _) = pda::miner_pda(&authority);
63 let (config, _) = pda::config_pda();
64 let (current_round, _) = pda::round_pda(current_round_index);
65 let (prev_round, _) = pda::round_pda(prev_round_index);
66 let token_account = pda::ata(&authority, &mint);
67 let mut data = vec![MinerInstruction::Mine as u8];
68 data.extend_from_slice(&nonce.to_le_bytes());
69 Instruction {
70 program_id: crate::id(),
71 accounts: vec![
72 AccountMeta::new_readonly(signer, true),
73 AccountMeta::new(miner, false),
74 AccountMeta::new_readonly(config, false),
75 AccountMeta::new(current_round, false),
76 AccountMeta::new_readonly(prev_round, false),
77 AccountMeta::new_readonly(token_account, false),
78 AccountMeta::new_readonly(SLOT_HASHES_SYSVAR_ID, false),
79 ],
80 data,
81 }
82}
83
84pub fn claim(authority: Pubkey, mint: Pubkey, prev_round_index: u64) -> Instruction {
85 let (miner, _) = pda::miner_pda(&authority);
86 let (config, _) = pda::config_pda();
87 let (prev_round, _) = pda::round_pda(prev_round_index);
88 let (treasury, _) = pda::treasury_pda();
89 let token_account = pda::ata(&authority, &mint);
90 Instruction {
91 program_id: crate::id(),
92 accounts: vec![
93 AccountMeta::new_readonly(authority, true),
94 AccountMeta::new(miner, false),
95 AccountMeta::new_readonly(config, false),
96 AccountMeta::new_readonly(prev_round, false),
97 AccountMeta::new(mint, false),
98 AccountMeta::new_readonly(treasury, false),
99 AccountMeta::new(token_account, false),
100 AccountMeta::new_readonly(SPL_TOKEN_PROGRAM_ID, false),
101 ],
102 data: vec![MinerInstruction::Claim as u8],
103 }
104}
105
106pub fn crank(payer: Pubkey, new_round_index: u64) -> Instruction {
107 let (config, _) = pda::config_pda();
108 let (new_round, _) = pda::round_pda(new_round_index);
109 Instruction {
110 program_id: crate::id(),
111 accounts: vec![
112 AccountMeta::new(payer, true),
113 AccountMeta::new(config, false),
114 AccountMeta::new(new_round, false),
115 AccountMeta::new_readonly(SYSTEM_PROGRAM_ID, false),
116 ],
117 data: vec![MinerInstruction::Crank as u8],
118 }
119}
120
121pub fn close_round(recipient: Pubkey, round_index: u64) -> Instruction {
122 let (config, _) = pda::config_pda();
123 let (round, _) = pda::round_pda(round_index);
124 Instruction {
125 program_id: crate::id(),
126 accounts: vec![
127 AccountMeta::new(recipient, true),
128 AccountMeta::new_readonly(config, false),
129 AccountMeta::new(round, false),
130 ],
131 data: vec![MinerInstruction::CloseRound as u8],
132 }
133}
134
135pub fn update_config(
136 admin: Pubkey,
137 min_difficulty: u64,
138 base_weight: u64,
139 round_seconds: u64,
140) -> Instruction {
141 let (config, _) = pda::config_pda();
142 let mut data = vec![MinerInstruction::UpdateConfig as u8];
143 data.extend_from_slice(&min_difficulty.to_le_bytes());
144 data.extend_from_slice(&base_weight.to_le_bytes());
145 data.extend_from_slice(&round_seconds.to_le_bytes());
146 Instruction {
147 program_id: crate::id(),
148 accounts: vec![
149 AccountMeta::new_readonly(admin, true),
150 AccountMeta::new(config, false),
151 ],
152 data,
153 }
154}
155
156pub fn set_admin(admin: Pubkey, new_admin: Pubkey) -> Instruction {
157 let (config, _) = pda::config_pda();
158 let mut data = vec![MinerInstruction::SetAdmin as u8];
159 data.extend_from_slice(new_admin.as_ref());
160 Instruction {
161 program_id: crate::id(),
162 accounts: vec![
163 AccountMeta::new_readonly(admin, true),
164 AccountMeta::new(config, false),
165 ],
166 data,
167 }
168}
169
170pub fn hash_meets_difficulty(
172 challenge: &[u8; 32],
173 authority: &Pubkey,
174 nonce: u64,
175 min_difficulty: u64,
176) -> bool {
177 let hash = solana_program::keccak::hashv(&[
178 challenge.as_slice(),
179 authority.as_ref(),
180 &nonce.to_le_bytes(),
181 ]);
182 leading_zero_bits(hash.as_ref()) >= min_difficulty
183}
184
185pub fn leading_zero_bits(bytes: &[u8]) -> u64 {
186 let mut bits: u64 = 0;
187 for b in bytes {
188 if *b == 0 {
189 bits += 8;
190 } else {
191 bits += b.leading_zeros() as u64;
192 break;
193 }
194 }
195 bits
196}