From e69c464ba4770f3171225cab0caf378af435176d Mon Sep 17 00:00:00 2001 From: Reisen Date: Wed, 7 Jul 2021 08:48:37 +0000 Subject: [PATCH] Check on chain state for message tests. Change-Id: I82ca799431ba7bd9b5bb9e5d907c396c67b3d42a --- solana/bridge/program/tests/integration.rs | 116 ++++++++++++++++++++- 1 file changed, 113 insertions(+), 3 deletions(-) diff --git a/solana/bridge/program/tests/integration.rs b/solana/bridge/program/tests/integration.rs index 7a4c94ca..7122e069 100644 --- a/solana/bridge/program/tests/integration.rs +++ b/solana/bridge/program/tests/integration.rs @@ -188,11 +188,80 @@ fn test_initialize(context: &mut Context) { fn test_bridge_messages(context: &mut Context) { let (ref payer, ref client, ref program) = common::setup(); - // Data/Nonce used for emitting a message we want to prove exists. - let nonce = 12397; - let message = b"Prove Me".to_vec(); + // Data/Nonce used for emitting a message we want to prove exists. Run this twice to make sure + // that duplicate data does not clash. + let message = [0u8; 32].to_vec(); let emitter = Keypair::new(); + for _ in 0..2 { + let nonce = rand::thread_rng().gen(); + let sequence = context.seq.next(emitter.pubkey().to_bytes()); + + // Post the message, publishing the data for guardian consumption. + let message_key = common::post_message( + client, + program, + payer, + &emitter, + nonce, + message.clone(), + 10_000, + false, + ) + .unwrap(); + + // Emulate Guardian behaviour, verifying the data and publishing signatures/VAA. + let (vaa, body, body_hash) = common::generate_vaa(&emitter, message.clone(), nonce, 0, 1); + common::verify_signatures(client, program, payer, body, body_hash, &context.secret, 0).unwrap(); + common::post_vaa(client, program, payer, vaa).unwrap(); + common::sync(client, payer); + + // Derive where we expect created accounts to be. + let signature_set = SignatureSet::<'_, { AccountState::Uninitialized }>::key( + &SignatureSetDerivationData { hash: body_hash }, + &program, + ); + + // Fetch chain accounts to verify state. + let posted_message: PostedMessage = common::get_account_data(client, &message_key); + let signatures: SignatureSetData = common::get_account_data(client, &signature_set); + + // Verify on chain Message + assert_eq!(posted_message.0.vaa_version, 0); + assert_eq!(posted_message.0.persist, false); + assert_eq!(posted_message.0.vaa_signature_account, signature_set); + assert_eq!(posted_message.0.nonce, nonce); + assert_eq!(posted_message.0.sequence, sequence); + assert_eq!(posted_message.0.emitter_chain, 1); + assert_eq!(posted_message.0.payload, message); + assert_eq!( + posted_message.0.emitter_address, + emitter.pubkey().to_bytes() + ); + + // Verify on chain Signatures + assert_eq!(signatures.hash, body_hash); + assert_eq!(signatures.guardian_set_index, 0); + + for (signature, secret_key) in signatures.signatures.iter().zip(context.secret.iter()) { + // Sign message locally. + let (local_sig, recover_id) = secp256k1::sign(&Secp256k1Message::parse(&body_hash), &secret_key); + + // Combine recoverify with signature to match 65 byte layout. + let mut signature_bytes = [0u8; 65]; + signature_bytes[64] = recover_id.serialize(); + (&mut signature_bytes[0..64]).copy_from_slice(&local_sig.serialize()); + + // Signature stored should on chain be as expected. + assert_eq!(*signature, signature_bytes); + } + } + + // Prepare another message with no data in its message to confirm it succeeds. + let nonce = rand::thread_rng().gen(); + let message = b"".to_vec(); + let sequence = context.seq.next(emitter.pubkey().to_bytes()); + // Post the message, publishing the data for guardian consumption. let message_key = common::post_message( client, @@ -210,6 +279,47 @@ fn test_bridge_messages(context: &mut Context) { let (vaa, body, body_hash) = common::generate_vaa(&emitter, message.clone(), nonce, 0, 1); common::verify_signatures(client, program, payer, body, body_hash, &context.secret, 0).unwrap(); common::post_vaa(client, program, payer, vaa).unwrap(); + common::sync(client, payer); + + // Derive where we expect created accounts to be. + let signature_set = SignatureSet::<'_, { AccountState::Uninitialized }>::key( + &SignatureSetDerivationData { hash: body_hash }, + &program, + ); + + // Fetch chain accounts to verify state. + let posted_message: PostedMessage = common::get_account_data(client, &message_key); + let signatures: SignatureSetData = common::get_account_data(client, &signature_set); + + // Verify on chain Message + assert_eq!(posted_message.0.vaa_version, 0); + assert_eq!(posted_message.0.persist, false); + assert_eq!(posted_message.0.vaa_signature_account, signature_set); + assert_eq!(posted_message.0.nonce, nonce); + assert_eq!(posted_message.0.sequence, sequence); + assert_eq!(posted_message.0.emitter_chain, 1); + assert_eq!(posted_message.0.payload, message); + assert_eq!( + posted_message.0.emitter_address, + emitter.pubkey().to_bytes() + ); + + // Verify on chain Signatures + assert_eq!(signatures.hash, body_hash); + assert_eq!(signatures.guardian_set_index, 0); + + for (signature, secret_key) in signatures.signatures.iter().zip(context.secret.iter()) { + // Sign message locally. + let (local_sig, recover_id) = secp256k1::sign(&Secp256k1Message::parse(&body_hash), &secret_key); + + // Combine recoverify with signature to match 65 byte layout. + let mut signature_bytes = [0u8; 65]; + signature_bytes[64] = recover_id.serialize(); + (&mut signature_bytes[0..64]).copy_from_slice(&local_sig.serialize()); + + // Signature stored should on chain be as expected. + assert_eq!(*signature, signature_bytes); + } } fn test_persistent_bridge_messages(context: &mut Context) {