Fix Derivation issues for PostVAA accounts.

Change-Id: Ia08003dc8aadfe3963598c81745813e6e09e5d3a
This commit is contained in:
Reisen 2021-06-23 10:46:21 +00:00 committed by Hendrik Hofstadt
parent a28540de0d
commit 16f7e156ae
10 changed files with 69 additions and 46 deletions

View File

@ -85,7 +85,6 @@ impl<'b, const State: AccountState> Seeded<&MessageDerivationData> for Message<'
data.nonce.to_be_bytes().to_vec(), data.nonce.to_be_bytes().to_vec(),
]; ];
seeds.append(&mut data.payload.chunks(32).map(|v| v.to_vec()).collect()); seeds.append(&mut data.payload.chunks(32).map(|v| v.to_vec()).collect());
seeds seeds
} }
} }

View File

@ -1,7 +1,5 @@
use solitaire::*; use solitaire::*;
use solana_program::{self,};
use crate::types::{ use crate::types::{
self, self,
GovernancePayloadSetMessageFee, GovernancePayloadSetMessageFee,

View File

@ -114,7 +114,6 @@ pub struct PostVAAData {
} }
pub fn post_vaa(ctx: &ExecutionContext, accs: &mut PostVAA, vaa: PostVAAData) -> Result<()> { pub fn post_vaa(ctx: &ExecutionContext, accs: &mut PostVAA, vaa: PostVAAData) -> Result<()> {
msg!("Post VAA Entered");
let msg_derivation = MessageDerivationData { let msg_derivation = MessageDerivationData {
emitter_key: vaa.emitter_address, emitter_key: vaa.emitter_address,
emitter_chain: vaa.emitter_chain, emitter_chain: vaa.emitter_chain,
@ -135,11 +134,7 @@ pub fn post_vaa(ctx: &ExecutionContext, accs: &mut PostVAA, vaa: PostVAAData) ->
.signature_set .signature_set
.signatures .signatures
.iter() .iter()
.filter(|v| .filter(|v| v.iter().filter(|v| **v != 0).count() != 0)
v.0.iter().filter(|v| **v != 0).count() != 0 ||
v.1.iter().filter(|v| **v != 0).count() != 0 ||
v.2 != 0
)
.count(); .count();
// Calculate how many signatures are required to reach consensus. This calculation is in // Calculate how many signatures are required to reach consensus. This calculation is in

View File

@ -200,6 +200,7 @@ pub fn verify_signatures(
// Track whether the account needs initialization // Track whether the account needs initialization
// Prepare message/payload-specific sig_info account // Prepare message/payload-specific sig_info account
if !accs.signature_set.is_initialized() { if !accs.signature_set.is_initialized() {
accs.signature_set.signatures = vec![[0u8; 65]; 19];
accs.signature_set.guardian_set_index = accs.guardian_set.index; accs.signature_set.guardian_set_index = accs.guardian_set.index;
accs.signature_set.hash = data.hash; accs.signature_set.hash = data.hash;
@ -237,12 +238,8 @@ pub fn verify_signatures(
} }
// Overwritten content should be zeros except double signs by the signer or harmless replays // Overwritten content should be zeros except double signs by the signer or harmless replays
accs.signature_set.signatures[s.signer_index as usize].0 accs.signature_set.signatures[s.signer_index as usize]
.copy_from_slice(&secp_ixs[s.sig_index as usize].signature[0..32]); .copy_from_slice(&secp_ixs[s.sig_index as usize].signature);
accs.signature_set.signatures[s.signer_index as usize].1
.copy_from_slice(&secp_ixs[s.sig_index as usize].signature[32..64]);
accs.signature_set.signatures[s.signer_index as usize].2 =
secp_ixs[s.sig_index as usize].signature[64];
} }
Ok(()) Ok(())

View File

@ -73,6 +73,7 @@ pub struct BridgeConfig {
/// guarantees that VAAs issued by that set can still be submitted for a certain period. In /// guarantees that VAAs issued by that set can still be submitted for a certain period. In
/// this period we still trust the old guardian set. /// this period we still trust the old guardian set.
pub guardian_set_expiration_time: u32, pub guardian_set_expiration_time: u32,
/// Amount of lamports that needs to be paid to the protocol to post a message /// Amount of lamports that needs to be paid to the protocol to post a message
pub fee: u64, pub fee: u64,
} }
@ -95,18 +96,10 @@ impl Owned for BridgeData {
} }
} }
// Temporary work around the fact there is no Default for [u8; 64/65] and therefore no Borsh
// implementation for the type. Cannot use Vec<> as we don't know the size to deserialize.
type SplitSignature = (
[u8; 32],
[u8; 32],
u8,
);
#[derive(Default, BorshSerialize, BorshDeserialize)] #[derive(Default, BorshSerialize, BorshDeserialize)]
pub struct SignatureSet { pub struct SignatureSet {
/// Signatures of validators /// Signatures of validators
pub signatures: [SplitSignature; 19], pub signatures: Vec<[u8; 65]>,
/// Hash of the data /// Hash of the data
pub hash: [u8; 32], pub hash: [u8; 32],
@ -126,6 +119,7 @@ pub struct PostedMessage(pub PostedMessageData);
impl BorshSerialize for PostedMessage { impl BorshSerialize for PostedMessage {
fn serialize<W: Write>(&self, writer: &mut W) -> std::io::Result<()> { fn serialize<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
// King of Flavour
writer.write(&['m' as u8, 's' as u8, 'g' as u8]); writer.write(&['m' as u8, 's' as u8, 'g' as u8]);
BorshSerialize::serialize(&self.0, writer) BorshSerialize::serialize(&self.0, writer)
} }
@ -133,8 +127,9 @@ impl BorshSerialize for PostedMessage {
impl BorshDeserialize for PostedMessage { impl BorshDeserialize for PostedMessage {
fn deserialize(buf: &mut &[u8]) -> std::io::Result<Self> { fn deserialize(buf: &mut &[u8]) -> std::io::Result<Self> {
*buf = &buf[3..];
Ok(PostedMessage( Ok(PostedMessage(
<PostedMessageData as BorshDeserialize>::deserialize(&mut &buf[3..])?, <PostedMessageData as BorshDeserialize>::deserialize(buf)?,
)) ))
} }
} }

View File

@ -3,6 +3,7 @@
use secp256k1::SecretKey; use secp256k1::SecretKey;
use borsh::BorshSerialize; use borsh::BorshSerialize;
use solana_client::rpc_client::RpcClient; use solana_client::rpc_client::RpcClient;
use solana_client::rpc_config::RpcSendTransactionConfig;
use solana_program::{ use solana_program::{
borsh::try_from_slice_unchecked, borsh::try_from_slice_unchecked,
hash, hash,
@ -29,6 +30,7 @@ use std::{
}; };
use solana_sdk::{ use solana_sdk::{
commitment_config::CommitmentConfig,
secp256k1_instruction::new_secp256k1_instruction, secp256k1_instruction::new_secp256k1_instruction,
signature::{ signature::{
read_keypair_file, read_keypair_file,
@ -44,6 +46,7 @@ use bridge::{
GuardianSetDerivationData, GuardianSetDerivationData,
SignatureSet, SignatureSet,
SignaturesSetDerivationData, SignaturesSetDerivationData,
Message,
MessageDerivationData, MessageDerivationData,
}, },
instruction, instruction,
@ -68,6 +71,18 @@ pub use instructions::*;
mod helpers { mod helpers {
use super::*; use super::*;
fn rpc_send(client: &RpcClient, tx: Transaction) {
client.send_and_confirm_transaction_with_spinner_and_config(
&tx,
CommitmentConfig::processed(),
RpcSendTransactionConfig {
skip_preflight: true,
preflight_commitment: None,
encoding: None,
},
).unwrap();
}
pub fn setup() -> (Keypair, RpcClient, Pubkey) { pub fn setup() -> (Keypair, RpcClient, Pubkey) {
let payer = read_keypair_file(env::var("BRIDGE_PAYER").unwrap_or("./payer.json".to_string())).unwrap(); let payer = read_keypair_file(env::var("BRIDGE_PAYER").unwrap_or("./payer.json".to_string())).unwrap();
let rpc = RpcClient::new(env::var("BRIDGE_RPC").unwrap_or("http://127.0.0.1:8899".to_string())); let rpc = RpcClient::new(env::var("BRIDGE_RPC").unwrap_or("http://127.0.0.1:8899".to_string()));
@ -75,7 +90,6 @@ mod helpers {
.unwrap_or("6mFKdAtUBVbsQ5dgvBrUkn1Pixb7BMTUtVKj4dpwrmQs".to_string()) .unwrap_or("6mFKdAtUBVbsQ5dgvBrUkn1Pixb7BMTUtVKj4dpwrmQs".to_string())
.parse::<Pubkey>() .parse::<Pubkey>()
.unwrap(); .unwrap();
(payer, rpc, program) (payer, rpc, program)
} }
@ -85,7 +99,7 @@ mod helpers {
let mut transaction = Transaction::new_with_payer(&instructions, Some(&from.pubkey())); let mut transaction = Transaction::new_with_payer(&instructions, Some(&from.pubkey()));
let recent_blockhash = client.get_recent_blockhash().unwrap().0; let recent_blockhash = client.get_recent_blockhash().unwrap().0;
transaction.sign(&signers, recent_blockhash); transaction.sign(&signers, recent_blockhash);
client.send_and_confirm_transaction(&transaction).unwrap(); rpc_send(client, transaction);
} }
pub fn initialize( pub fn initialize(
@ -112,7 +126,7 @@ mod helpers {
let recent_blockhash = client.get_recent_blockhash().unwrap().0; let recent_blockhash = client.get_recent_blockhash().unwrap().0;
transaction.sign(&signers, recent_blockhash); transaction.sign(&signers, recent_blockhash);
client.send_and_confirm_transaction(&transaction).unwrap(); rpc_send(client, transaction);
} }
pub fn post_message( pub fn post_message(
@ -132,7 +146,7 @@ mod helpers {
emitter_key: emitter.pubkey().to_bytes(), emitter_key: emitter.pubkey().to_bytes(),
emitter_chain: message.emitter_chain, emitter_chain: message.emitter_chain,
nonce: message.nonce, nonce: message.nonce,
payload: message.payload, payload: message.payload.clone(),
}, program); }, program);
println!("PostMessage: Derived Keys:"); println!("PostMessage: Derived Keys:");
@ -160,7 +174,7 @@ mod helpers {
let recent_blockhash = client.get_recent_blockhash().unwrap().0; let recent_blockhash = client.get_recent_blockhash().unwrap().0;
transaction.sign(&signers, recent_blockhash); transaction.sign(&signers, recent_blockhash);
client.send_and_confirm_transaction(&transaction).unwrap(); rpc_send(client, transaction);
} }
pub fn verify_signatures( pub fn verify_signatures(
@ -208,23 +222,45 @@ mod helpers {
let recent_blockhash = client.get_recent_blockhash().unwrap().0; let recent_blockhash = client.get_recent_blockhash().unwrap().0;
transaction.sign(&signers, recent_blockhash); transaction.sign(&signers, recent_blockhash);
client.send_and_confirm_transaction(&transaction).unwrap(); rpc_send(client, transaction);
} }
pub fn post_vaa( pub fn post_vaa(
client: &RpcClient, client: &RpcClient,
program: &Pubkey, program: &Pubkey,
payer: &Keypair, payer: &Keypair,
body_hash: [u8; 32],
message: Vec<u8>,
emitter: &Keypair,
guardian_set: GuardianSetDerivationData, guardian_set: GuardianSetDerivationData,
vaa: PostVAAData, vaa: PostVAAData,
) { ) {
let (bridge, _) = Pubkey::find_program_address(&["Bridge".as_ref()], program);
let guardian_set = GuardianSet::<'_, { AccountState::Uninitialized }>::key( let guardian_set = GuardianSet::<'_, { AccountState::Uninitialized }>::key(
&guardian_set, &guardian_set,
&program, &program,
); );
let (bridge, _) = Pubkey::find_program_address(&["Bridge".as_ref()], program);
let signature_set = Pubkey::new_unique(); let signatures = SignatureSet::<'_, { AccountState::Uninitialized }>::key(
let message = Pubkey::new_unique(); &SignaturesSetDerivationData {
hash: body_hash,
},
&program,
);
let message = Message::<'_, { AccountState::MaybeInitialized }>::key(
&MessageDerivationData {
emitter_key: emitter.pubkey().to_bytes(),
emitter_chain: 1,
nonce: 0,
payload: message,
},
&program,
);
println!("PostVAA: Derived Key:");
println!("GuardianSet: {}", guardian_set);
println!("Signatures: {}", signatures);
let signers = vec![payer]; let signers = vec![payer];
let instructions = [instructions::create_post_vaa( let instructions = [instructions::create_post_vaa(
@ -232,7 +268,7 @@ mod helpers {
payer.pubkey(), payer.pubkey(),
guardian_set, guardian_set,
bridge, bridge,
signature_set, signatures,
message, message,
vaa, vaa,
)]; )];
@ -241,7 +277,7 @@ mod helpers {
let recent_blockhash = client.get_recent_blockhash().unwrap().0; let recent_blockhash = client.get_recent_blockhash().unwrap().0;
transaction.sign(&signers, recent_blockhash); transaction.sign(&signers, recent_blockhash);
client.send_and_confirm_transaction(&transaction).unwrap(); rpc_send(client, transaction);
} }
} }

View File

@ -53,6 +53,7 @@ use bridge::{
types::{ types::{
BridgeConfig, BridgeConfig,
PostedMessage, PostedMessage,
PostedMessageData,
SequenceTracker, SequenceTracker,
SignatureSet, SignatureSet,
}, },
@ -94,7 +95,7 @@ fn test_bridge_messages() {
// Guardians sign, verify, and we produce VAA data here. // Guardians sign, verify, and we produce VAA data here.
let (vaa, body, body_hash, secret_key) = guardian_sign_round( let (vaa, body, body_hash, secret_key) = guardian_sign_round(
&emitter, &emitter,
data, data.clone(),
); );
common::verify_signatures( common::verify_signatures(
@ -112,12 +113,14 @@ fn test_bridge_messages() {
client, client,
program, program,
payer, payer,
body_hash,
data,
&emitter,
GuardianSetDerivationData { index: 0 }, GuardianSetDerivationData { index: 0 },
vaa, vaa,
); );
// // Verify a Signature // Did it actually work?
// common::verify_signature(client, program, payer);
} }
/// A utility function for emulating what the guardians should be doing, I.E, detecting a message /// A utility function for emulating what the guardians should be doing, I.E, detecting a message
@ -172,8 +175,6 @@ fn guardian_sign_round(
h.finalize().into() h.finalize().into()
}; };
println!("Ahs: {:?}", body_hash);
// Sign the body hash of the VAA. // Sign the body hash of the VAA.
let sig = secp256k1::sign( let sig = secp256k1::sign(
&Message::parse(&body_hash), &Message::parse(&body_hash),
@ -193,7 +194,7 @@ fn guardian_sign_round(
} }
fn create_message(data: Vec<u8>) -> PostedMessage { fn create_message(data: Vec<u8>) -> PostedMessage {
PostedMessage { PostedMessage(PostedMessageData {
vaa_version: 0, vaa_version: 0,
vaa_time: 0, vaa_time: 0,
vaa_signature_account: Pubkey::new_unique(), vaa_signature_account: Pubkey::new_unique(),
@ -207,5 +208,5 @@ fn create_message(data: Vec<u8>) -> PostedMessage {
.duration_since(SystemTime::UNIX_EPOCH) .duration_since(SystemTime::UNIX_EPOCH)
.unwrap() .unwrap()
.as_secs() as u32, .as_secs() as u32,
} })
} }

View File

@ -19,8 +19,9 @@ macro_rules! solitaire {
use solana_program::{ use solana_program::{
account_info::AccountInfo, account_info::AccountInfo,
entrypoint::ProgramResult, entrypoint::ProgramResult,
program_error::ProgramError, program_error::ProgramError,
pubkey::Pubkey, pubkey::Pubkey,
msg,
}; };
use solitaire::{FromAccounts, Persist, Result}; use solitaire::{FromAccounts, Persist, Result};
@ -39,6 +40,7 @@ macro_rules! solitaire {
match Instruction::try_from_slice(d).map_err(|e| SolitaireError::InstructionDeserializeFailed(e))? { match Instruction::try_from_slice(d).map_err(|e| SolitaireError::InstructionDeserializeFailed(e))? {
$( $(
Instruction::$row(ix_data) => { Instruction::$row(ix_data) => {
msg!("Dispatch: {}", stringify!($row));
let (mut accounts): ($row) = FromAccounts::from(p, &mut a.iter(), &())?; let (mut accounts): ($row) = FromAccounts::from(p, &mut a.iter(), &())?;
$fn(&ExecutionContext{program_id: p, accounts: a}, &mut accounts, ix_data)?; $fn(&ExecutionContext{program_id: p, accounts: a}, &mut accounts, ix_data)?;
Persist::persist(&accounts, p)?; Persist::persist(&accounts, p)?;

View File

@ -158,7 +158,7 @@ impl<
} }
AccountState::Initialized => { AccountState::Initialized => {
initialized = true; initialized = true;
T::try_from_slice(&mut *ctx.info().data.borrow_mut())? T::try_from_slice(&mut *ctx.info().data.borrow_mut()).expect("Blew up in Initialized")
} }
AccountState::MaybeInitialized => { AccountState::MaybeInitialized => {
if **ctx.info().lamports.borrow() == 0 { if **ctx.info().lamports.borrow() == 0 {

View File

@ -45,7 +45,7 @@ pub enum AccountState {
/// ///
/// Data<(), { AccountState::Uninitialized }> /// Data<(), { AccountState::Uninitialized }>
#[rustfmt::skip] #[rustfmt::skip]
pub struct Data<'r, T: Owned + Default + Default, const IsInitialized: AccountState> ( pub struct Data<'r, T: Owned + Default, const IsInitialized: AccountState> (
pub Info<'r>, pub Info<'r>,
pub T, pub T,
); );