common.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. use borsh::BorshDeserialize;
  2. use byteorder::{
  3. BigEndian,
  4. WriteBytesExt,
  5. };
  6. use libsecp256k1::{
  7. PublicKey,
  8. SecretKey,
  9. };
  10. use sha3::Digest;
  11. use solana_program::{
  12. instruction::Instruction,
  13. pubkey::Pubkey,
  14. system_instruction,
  15. };
  16. use solana_program_test::{
  17. BanksClient,
  18. BanksClientError,
  19. ProgramTest,
  20. };
  21. use solana_sdk::{
  22. commitment_config::CommitmentLevel,
  23. secp256k1_instruction::new_secp256k1_instruction,
  24. signature::{
  25. Keypair,
  26. Signer,
  27. },
  28. signers::Signers,
  29. transaction::Transaction,
  30. };
  31. use std::{
  32. env,
  33. io::{
  34. Cursor,
  35. Write,
  36. },
  37. time::SystemTime,
  38. };
  39. use bridge::{
  40. accounts::FeeCollector,
  41. instruction,
  42. instructions,
  43. types::ConsistencyLevel,
  44. PostVAAData,
  45. VerifySignaturesData,
  46. };
  47. use solitaire::processors::seeded::Seeded;
  48. pub use helpers::*;
  49. /// Simple API wrapper for quickly preparing and sending transactions.
  50. pub async fn execute<T: Signers>(
  51. client: &mut BanksClient,
  52. payer: &Keypair,
  53. signers: &T,
  54. instructions: &[Instruction],
  55. commitment_level: CommitmentLevel,
  56. ) -> Result<(), BanksClientError> {
  57. let mut transaction = Transaction::new_with_payer(instructions, Some(&payer.pubkey()));
  58. let recent_blockhash = client.get_latest_blockhash().await?;
  59. transaction.sign(signers, recent_blockhash);
  60. client
  61. .process_transaction_with_commitment(transaction, commitment_level)
  62. .await
  63. }
  64. mod helpers {
  65. use super::*;
  66. use solana_program_test::processor;
  67. /// Initialize the test environment, spins up a solana-test-validator in the background so that
  68. /// each test has a fresh environment to work within.
  69. pub async fn setup() -> (BanksClient, Keypair, Pubkey) {
  70. let program = env::var("BRIDGE_PROGRAM")
  71. .unwrap_or_else(|_| "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o".to_string())
  72. .parse::<Pubkey>()
  73. .unwrap();
  74. let builder = ProgramTest::new("bridge", program, processor!(instruction::solitaire));
  75. let (client, payer, _) = builder.start().await;
  76. (client, payer, program)
  77. }
  78. /// Fetch account data, the loop is there to re-attempt until data is available.
  79. pub async fn get_account_data<T: BorshDeserialize>(
  80. client: &mut BanksClient,
  81. account: Pubkey,
  82. ) -> T {
  83. let account = client.get_account(account).await.unwrap().unwrap();
  84. T::try_from_slice(&account.data).unwrap()
  85. }
  86. /// Fetch account balance
  87. pub async fn get_account_balance(client: &mut BanksClient, account: Pubkey) -> u64 {
  88. client.get_account(account).await.unwrap().unwrap().lamports
  89. }
  90. /// Generate `count` secp256k1 private keys, along with their ethereum-styled public key
  91. /// encoding: 0x0123456789ABCDEF01234
  92. pub fn generate_keys(count: u8) -> (Vec<[u8; 20]>, Vec<SecretKey>) {
  93. let mut rng = rand::thread_rng();
  94. // Generate Guardian Keys
  95. let secret_keys: Vec<SecretKey> = std::iter::repeat_with(|| SecretKey::random(&mut rng))
  96. .take(count as usize)
  97. .collect();
  98. (
  99. secret_keys
  100. .iter()
  101. .map(|key| {
  102. let public_key = PublicKey::from_secret_key(key);
  103. let mut h = sha3::Keccak256::default();
  104. h.write_all(&public_key.serialize()[1..]).unwrap();
  105. let key: [u8; 32] = h.finalize().into();
  106. let mut address = [0u8; 20];
  107. address.copy_from_slice(&key[12..]);
  108. address
  109. })
  110. .collect(),
  111. secret_keys,
  112. )
  113. }
  114. /// Utility function for generating VAA's from message data.
  115. pub fn generate_vaa(
  116. emitter: &Keypair,
  117. data: Vec<u8>,
  118. nonce: u32,
  119. sequence: u64,
  120. guardian_set_index: u32,
  121. emitter_chain: u16,
  122. ) -> (PostVAAData, [u8; 32], [u8; 32]) {
  123. let vaa = PostVAAData {
  124. version: 0,
  125. guardian_set_index,
  126. // Body part
  127. emitter_chain,
  128. emitter_address: emitter.pubkey().to_bytes(),
  129. sequence,
  130. payload: data,
  131. timestamp: SystemTime::now()
  132. .duration_since(SystemTime::UNIX_EPOCH)
  133. .unwrap()
  134. .as_secs() as u32,
  135. nonce,
  136. consistency_level: ConsistencyLevel::Confirmed as u8,
  137. };
  138. // Hash data, the thing we wish to actually sign.
  139. let body = {
  140. let mut v = Cursor::new(Vec::new());
  141. v.write_u32::<BigEndian>(vaa.timestamp).unwrap();
  142. v.write_u32::<BigEndian>(vaa.nonce).unwrap();
  143. v.write_u16::<BigEndian>(vaa.emitter_chain).unwrap();
  144. v.write_all(&vaa.emitter_address).unwrap();
  145. v.write_u64::<BigEndian>(vaa.sequence).unwrap();
  146. v.write_u8(vaa.consistency_level).unwrap();
  147. v.write_all(&vaa.payload).unwrap();
  148. v.into_inner()
  149. };
  150. // Hash this body, which is expected to be the same as the hash currently stored in the
  151. // signature account, binding that set of signatures to this VAA.
  152. let body: [u8; 32] = {
  153. let mut h = sha3::Keccak256::default();
  154. h.write_all(body.as_slice()).unwrap();
  155. h.finalize().into()
  156. };
  157. let body_hash: [u8; 32] = {
  158. let mut h = sha3::Keccak256::default();
  159. h.write_all(&body).unwrap();
  160. h.finalize().into()
  161. };
  162. (vaa, body, body_hash)
  163. }
  164. pub async fn initialize(
  165. client: &mut BanksClient,
  166. program: Pubkey,
  167. payer: &Keypair,
  168. initial_guardians: &[[u8; 20]],
  169. fee: u64,
  170. ) -> Result<(), BanksClientError> {
  171. execute(
  172. client,
  173. payer,
  174. &[payer],
  175. &[instructions::initialize(
  176. program,
  177. payer.pubkey(),
  178. fee,
  179. 2_000_000_000,
  180. initial_guardians,
  181. )
  182. .unwrap()],
  183. CommitmentLevel::Processed,
  184. )
  185. .await
  186. }
  187. #[allow(clippy::too_many_arguments)]
  188. pub async fn post_message(
  189. client: &mut BanksClient,
  190. program: &Pubkey,
  191. payer: &Keypair,
  192. emitter: &Keypair,
  193. // when None, then a new keypair is generated
  194. message: Option<&Keypair>,
  195. nonce: u32,
  196. data: Vec<u8>,
  197. fee: u64,
  198. ) -> Result<Pubkey, BanksClientError> {
  199. // Transfer money into the fee collector as it needs a balance/must exist.
  200. let fee_collector = FeeCollector::<'_>::key(None, program);
  201. let new_message_pair = &Keypair::new();
  202. let message: &Keypair = match message {
  203. Some(keypair) => keypair,
  204. None => new_message_pair,
  205. };
  206. // Capture the resulting message, later functions will need this.
  207. let instruction = instructions::post_message(
  208. *program,
  209. payer.pubkey(),
  210. emitter.pubkey(),
  211. message.pubkey(),
  212. nonce,
  213. data,
  214. ConsistencyLevel::Confirmed,
  215. )
  216. .unwrap();
  217. execute(
  218. client,
  219. payer,
  220. &[payer, emitter, message],
  221. &[
  222. system_instruction::transfer(&payer.pubkey(), &fee_collector, fee),
  223. instruction,
  224. ],
  225. CommitmentLevel::Processed,
  226. )
  227. .await?;
  228. Ok(message.pubkey())
  229. }
  230. #[allow(clippy::too_many_arguments)]
  231. pub async fn post_message_unreliable(
  232. client: &mut BanksClient,
  233. program: &Pubkey,
  234. payer: &Keypair,
  235. emitter: &Keypair,
  236. message: &Keypair,
  237. nonce: u32,
  238. data: Vec<u8>,
  239. fee: u64,
  240. ) -> Result<(), BanksClientError> {
  241. // Transfer money into the fee collector as it needs a balance/must exist.
  242. let fee_collector = FeeCollector::<'_>::key(None, program);
  243. // Capture the resulting message, later functions will need this.
  244. let instruction = instructions::post_message_unreliable(
  245. *program,
  246. payer.pubkey(),
  247. emitter.pubkey(),
  248. message.pubkey(),
  249. nonce,
  250. data,
  251. ConsistencyLevel::Confirmed,
  252. )
  253. .unwrap();
  254. execute(
  255. client,
  256. payer,
  257. &[payer, emitter, message],
  258. &[
  259. system_instruction::transfer(&payer.pubkey(), &fee_collector, fee),
  260. instruction,
  261. ],
  262. CommitmentLevel::Processed,
  263. )
  264. .await
  265. }
  266. pub async fn verify_signatures(
  267. client: &mut BanksClient,
  268. program: &Pubkey,
  269. payer: &Keypair,
  270. body: [u8; 32],
  271. secret_keys: &[SecretKey],
  272. guardian_set_version: u32,
  273. ) -> Result<Pubkey, BanksClientError> {
  274. let signature_set = Keypair::new();
  275. let tx_signers = [payer, &signature_set];
  276. // Push Secp256k1 instructions for each signature we want to verify.
  277. for (i, key) in secret_keys.iter().enumerate() {
  278. // Set this signers signature position as present at 0.
  279. let mut signers = [-1; 19];
  280. signers[i] = 0;
  281. execute(
  282. client,
  283. payer,
  284. &tx_signers,
  285. &[
  286. new_secp256k1_instruction(key, &body),
  287. instructions::verify_signatures(
  288. *program,
  289. payer.pubkey(),
  290. guardian_set_version,
  291. signature_set.pubkey(),
  292. VerifySignaturesData { signers },
  293. )
  294. .unwrap(),
  295. ],
  296. CommitmentLevel::Processed,
  297. )
  298. .await?;
  299. }
  300. Ok(signature_set.pubkey())
  301. }
  302. pub async fn post_vaa(
  303. client: &mut BanksClient,
  304. program: &Pubkey,
  305. payer: &Keypair,
  306. signature_set: Pubkey,
  307. vaa: PostVAAData,
  308. ) -> Result<(), BanksClientError> {
  309. execute(
  310. client,
  311. payer,
  312. &[payer],
  313. &[instructions::post_vaa(
  314. *program,
  315. payer.pubkey(),
  316. signature_set,
  317. vaa,
  318. )],
  319. CommitmentLevel::Processed,
  320. )
  321. .await
  322. }
  323. #[allow(clippy::too_many_arguments)]
  324. pub async fn upgrade_guardian_set(
  325. client: &mut BanksClient,
  326. program: &Pubkey,
  327. payer: &Keypair,
  328. payload_message: Pubkey,
  329. emitter: Pubkey,
  330. old_index: u32,
  331. new_index: u32,
  332. sequence: u64,
  333. ) -> Result<(), BanksClientError> {
  334. execute(
  335. client,
  336. payer,
  337. &[payer],
  338. &[instructions::upgrade_guardian_set(
  339. *program,
  340. payer.pubkey(),
  341. payload_message,
  342. emitter,
  343. old_index,
  344. new_index,
  345. sequence,
  346. )],
  347. CommitmentLevel::Processed,
  348. )
  349. .await
  350. }
  351. #[allow(clippy::too_many_arguments)]
  352. pub async fn upgrade_contract(
  353. client: &mut BanksClient,
  354. program: &Pubkey,
  355. payer: &Keypair,
  356. payload_message: Pubkey,
  357. emitter: Pubkey,
  358. new_contract: Pubkey,
  359. spill: Pubkey,
  360. sequence: u64,
  361. ) -> Result<(), BanksClientError> {
  362. execute(
  363. client,
  364. payer,
  365. &[payer],
  366. &[instructions::upgrade_contract(
  367. *program,
  368. payer.pubkey(),
  369. payload_message,
  370. emitter,
  371. new_contract,
  372. spill,
  373. sequence,
  374. )],
  375. CommitmentLevel::Processed,
  376. )
  377. .await
  378. }
  379. pub async fn set_fees(
  380. client: &mut BanksClient,
  381. program: &Pubkey,
  382. payer: &Keypair,
  383. message: Pubkey,
  384. emitter: Pubkey,
  385. sequence: u64,
  386. ) -> Result<(), BanksClientError> {
  387. execute(
  388. client,
  389. payer,
  390. &[payer],
  391. &[instructions::set_fees(
  392. *program,
  393. payer.pubkey(),
  394. message,
  395. emitter,
  396. sequence,
  397. )],
  398. CommitmentLevel::Processed,
  399. )
  400. .await
  401. }
  402. pub async fn transfer_fees(
  403. client: &mut BanksClient,
  404. program: &Pubkey,
  405. payer: &Keypair,
  406. message: Pubkey,
  407. emitter: Pubkey,
  408. recipient: Pubkey,
  409. sequence: u64,
  410. ) -> Result<(), BanksClientError> {
  411. execute(
  412. client,
  413. payer,
  414. &[payer],
  415. &[instructions::transfer_fees(
  416. *program,
  417. payer.pubkey(),
  418. message,
  419. emitter,
  420. sequence,
  421. recipient,
  422. )],
  423. CommitmentLevel::Processed,
  424. )
  425. .await
  426. }
  427. }