From 99c3e40968c51f6b57d00588967af670a825474b Mon Sep 17 00:00:00 2001 From: Reisen Date: Tue, 20 Jul 2021 15:40:56 +0000 Subject: [PATCH] Fix Governance Headers Change-Id: If2026ff4a6107327f69c5d0675a736e6ab87f1bd --- solana/bridge/program/src/api/governance.rs | 9 ++-- .../program/src/api/verify_signature.rs | 2 - solana/bridge/program/src/instructions.rs | 6 +-- solana/bridge/program/src/types.rs | 13 ++++- solana/bridge/program/src/vaa.rs | 16 +++++- solana/bridge/program/tests/common.rs | 49 ++++++++++--------- solana/bridge/program/tests/integration.rs | 48 ++++++++++++++++++ solana/modules/token_bridge/Cargo.lock | 12 +++++ solana/{bridge => }/rustfmt.toml | 0 9 files changed, 122 insertions(+), 33 deletions(-) rename solana/{bridge => }/rustfmt.toml (100%) diff --git a/solana/bridge/program/src/api/governance.rs b/solana/bridge/program/src/api/governance.rs index fb8abe91f..4e463a44f 100644 --- a/solana/bridge/program/src/api/governance.rs +++ b/solana/bridge/program/src/api/governance.rs @@ -57,7 +57,7 @@ where #[derive(FromAccounts)] pub struct UpgradeContract<'b> { /// Payer for account creation (vaa-claim) - pub payer: Signer>, + pub payer: Mut>>, /// Upgrade VAA pub vaa: ClaimableVAA<'b, GovernancePayloadUpgrade>, @@ -91,8 +91,10 @@ pub fn upgrade_contract( accs.spill.key, ); - let _seeds = accs.upgrade_authority.self_seeds(None); - invoke_signed(&upgrade_ix, ctx.accounts, &[])?; + let seeds = accs.upgrade_authority.self_bumped_seeds(None, ctx.program_id); + let seeds: Vec<&[u8]> = seeds.iter().map(|item| item.as_slice()).collect(); + let seeds = seeds.as_slice(); + invoke_signed(&upgrade_ix, ctx.accounts, &[seeds])?; Ok(()) } @@ -138,6 +140,7 @@ pub fn upgrade_guardian_set( _data: UpgradeGuardianSetData, ) -> Result<()> { verify_claim(&accs.vaa)?; + accs.guardian_set_old.verify_derivation( ctx.program_id, &GuardianSetDerivationData { diff --git a/solana/bridge/program/src/api/verify_signature.rs b/solana/bridge/program/src/api/verify_signature.rs index dce663f2d..4fec6f7de 100644 --- a/solana/bridge/program/src/api/verify_signature.rs +++ b/solana/bridge/program/src/api/verify_signature.rs @@ -62,8 +62,6 @@ pub struct VerifySignaturesData { pub hash: [u8; 32], /// instruction indices of signers (-1 for missing) pub signers: [i8; MAX_LEN_GUARDIAN_KEYS], - /// indicates whether this verification should only succeed if the sig account does not exist - pub initial_creation: bool, } /// SigInfo contains metadata about signers in a VerifySignature ix diff --git a/solana/bridge/program/src/instructions.rs b/solana/bridge/program/src/instructions.rs index 832058479..ed6b20777 100644 --- a/solana/bridge/program/src/instructions.rs +++ b/solana/bridge/program/src/instructions.rs @@ -240,10 +240,10 @@ pub fn upgrade_contract( accounts: vec![ AccountMeta::new(payer, true), - AccountMeta::new(payload_message, false), + AccountMeta::new_readonly(payload_message, false), AccountMeta::new(claim, false), - AccountMeta::new(upgrade_authority, false), - AccountMeta::new(spill, false), + AccountMeta::new_readonly(upgrade_authority, false), + AccountMeta::new_readonly(spill, false), ], data: (crate::instruction::Instruction::UpgradeContract, UpgradeContractData {}) diff --git a/solana/bridge/program/src/types.rs b/solana/bridge/program/src/types.rs index fdda9e88b..0a8af42ca 100644 --- a/solana/bridge/program/src/types.rs +++ b/solana/bridge/program/src/types.rs @@ -251,6 +251,7 @@ where { fn deserialize(buf: &mut &[u8]) -> Result { let mut c = Cursor::new(buf); + Self::check_governance_header(&mut c)?; let new_index = c.read_u32::()?; @@ -270,7 +271,7 @@ where } impl DeserializeGovernancePayload for GovernancePayloadGuardianSetChange { - const MODULE: &'static str = "CORE"; + const MODULE: &'static str = "Core"; const ACTION: u8 = 1; } @@ -279,13 +280,19 @@ pub struct GovernancePayloadUpgrade { pub new_contract: Pubkey, } +impl SerializePayload for GovernancePayloadUpgrade { + fn serialize(&self, v: &mut W) -> std::result::Result<(), SolitaireError> { + v.write(&self.new_contract.to_bytes())?; + Ok(()) + } +} + impl DeserializePayload for GovernancePayloadUpgrade where Self: DeserializeGovernancePayload, { fn deserialize(buf: &mut &[u8]) -> Result { let mut c = Cursor::new(buf); - Self::check_governance_header(&mut c)?; let mut addr = [0u8; 32]; @@ -329,6 +336,7 @@ where { fn deserialize(buf: &mut &[u8]) -> Result { let mut c = Cursor::new(buf); + Self::check_governance_header(&mut c)?; let mut fee_data: [u8; 32] = [0; 32]; c.read_exact(&mut fee_data)?; @@ -374,6 +382,7 @@ where { fn deserialize(buf: &mut &[u8]) -> Result { let mut c = Cursor::new(buf); + Self::check_governance_header(&mut c)?; let mut amount_data: [u8; 32] = [0; 32]; c.read_exact(&mut amount_data)?; diff --git a/solana/bridge/program/src/vaa.rs b/solana/bridge/program/src/vaa.rs index 931657fe0..faebdb712 100644 --- a/solana/bridge/program/src/vaa.rs +++ b/solana/bridge/program/src/vaa.rs @@ -39,13 +39,27 @@ use std::{ ops::Deref, }; -pub trait SerializePayload: Sized { +pub trait SerializePayload: Sized + DeserializeGovernancePayload { fn serialize(&self, writer: &mut W) -> std::result::Result<(), SolitaireError>; fn try_to_vec(&self) -> std::result::Result, SolitaireError> { let mut result = Vec::with_capacity(256); + self.write_governance_header(&mut result)?; self.serialize(&mut result)?; Ok(result) } + + fn write_governance_header( + &self, + c: &mut W, + ) -> std::result::Result<(), SolitaireError> { + use byteorder::WriteBytesExt; + let module = format!("{:\0>32}", Self::MODULE); + let module = module.as_bytes(); + c.write(&module)?; + c.write_u8(Self::ACTION)?; + c.write_u16::(CHAIN_ID_SOLANA)?; + Ok(()) + } } pub trait DeserializePayload: Sized { diff --git a/solana/bridge/program/tests/common.rs b/solana/bridge/program/tests/common.rs index 8964b2d07..0dd3bad32 100644 --- a/solana/bridge/program/tests/common.rs +++ b/solana/bridge/program/tests/common.rs @@ -75,6 +75,7 @@ use bridge::{ instructions, types::{ BridgeConfig, + ConsistencyLevel, PostedMessage, SequenceTracker, }, @@ -207,6 +208,7 @@ mod helpers { .unwrap() .as_secs() as u32, nonce, + consistency_level: ConsistencyLevel::Confirmed as u8, }; // Hash data, the thing we wish to actually sign. @@ -217,6 +219,7 @@ mod helpers { v.write_u16::(vaa.emitter_chain).unwrap(); v.write(&vaa.emitter_address).unwrap(); v.write_u64::(vaa.sequence).unwrap(); + v.write_u8(vaa.consistency_level).unwrap(); v.write(&vaa.payload).unwrap(); v.into_inner() }; @@ -293,6 +296,7 @@ mod helpers { nonce, data, persist, + ConsistencyLevel::Confirmed, ) .unwrap(); @@ -337,7 +341,6 @@ mod helpers { guardian_set_version, VerifySignaturesData { hash: body_hash, - initial_creation: true, signers, }, ) @@ -364,27 +367,6 @@ mod helpers { ) } - pub fn upgrade_contract( - client: &RpcClient, - program: &Pubkey, - payer: &Keypair, - payload_message: Pubkey, - spill: Pubkey, - ) -> Result { - execute( - client, - payer, - &[payer], - &[instructions::upgrade_contract( - *program, - payer.pubkey(), - payload_message, - spill, - )], - CommitmentConfig::processed(), - ) - } - pub fn upgrade_guardian_set( client: &RpcClient, program: &Pubkey, @@ -412,6 +394,29 @@ mod helpers { ) } + pub fn upgrade_contract( + client: &RpcClient, + program: &Pubkey, + payer: &Keypair, + payload_message: Pubkey, + emitter: Pubkey, + spill: Pubkey, + sequence: u64, + ) -> Result { + execute( + client, + payer, + &[payer], + &[instructions::upgrade_contract( + *program, + payer.pubkey(), + payload_message, + spill, + )], + CommitmentConfig::processed(), + ) + } + pub fn set_fees( client: &RpcClient, program: &Pubkey, diff --git a/solana/bridge/program/tests/integration.rs b/solana/bridge/program/tests/integration.rs index 7e8bb3af8..82f94c780 100644 --- a/solana/bridge/program/tests/integration.rs +++ b/solana/bridge/program/tests/integration.rs @@ -69,9 +69,11 @@ use bridge::{ types::{ BridgeConfig, BridgeData, + ConsistencyLevel, GovernancePayloadGuardianSetChange, GovernancePayloadSetMessageFee, GovernancePayloadTransferFees, + GovernancePayloadUpgrade, GuardianSetData, PostedMessage, PostedMessageData, @@ -140,6 +142,7 @@ fn run_integration_tests() { test_persistent_bridge_messages(&mut context); test_invalid_emitter(&mut context); test_duplicate_messages_fail(&mut context); + test_upgrade_contract(&mut context); test_guardian_set_change(&mut context); test_guardian_set_change_fails(&mut context); test_set_fees(&mut context); @@ -444,6 +447,7 @@ fn test_invalid_emitter(context: &mut Context) { nonce, message, false, + ConsistencyLevel::Confirmed, ) .unwrap(); @@ -1255,3 +1259,47 @@ fn test_transfer_total_fails(context: &mut Context) { account_balance + 10_000 ); } + +fn test_upgrade_contract(context: &mut Context) { + // Initialize a wormhole bridge on Solana to test with. + let (ref payer, ref client, ref program) = common::setup(); + + // Upgrade the guardian set with a new set of guardians. + let (new_public_keys, new_secret_keys) = common::generate_keys(1); + + let nonce = rand::thread_rng().gen(); + let emitter = Keypair::from_bytes(&GOVERNANCE_KEY).unwrap(); + let sequence = context.seq.next(emitter.pubkey().to_bytes()); + let message = GovernancePayloadUpgrade { + new_contract: Pubkey::new_unique(), + } + .try_to_vec() + .unwrap(); + + let message_key = common::post_message( + client, + program, + payer, + &emitter, + nonce, + message.clone(), + 10_000, + false, + ) + .unwrap(); + + 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::upgrade_contract( + client, + program, + payer, + message_key, + emitter.pubkey(), + Pubkey::new_unique(), + sequence, + ) + .unwrap(); + common::sync(client, payer); +} diff --git a/solana/modules/token_bridge/Cargo.lock b/solana/modules/token_bridge/Cargo.lock index 1d75b498c..82fd697db 100644 --- a/solana/modules/token_bridge/Cargo.lock +++ b/solana/modules/token_bridge/Cargo.lock @@ -1189,6 +1189,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-literal" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76505e26b6ca3bbdbbb360b68472abbb80998c5fa5dc43672eca34f28258e138" + [[package]] name = "hidapi" version = "1.2.6" @@ -3442,10 +3448,16 @@ dependencies = [ "borsh", "bridge", "byteorder", + "hex", + "hex-literal", + "libsecp256k1", "primitive-types", + "rand 0.7.3", "rocksalt", "sha3", + "solana-client", "solana-program", + "solana-sdk", "solitaire", "solitaire-client", "spl-token", diff --git a/solana/bridge/rustfmt.toml b/solana/rustfmt.toml similarity index 100% rename from solana/bridge/rustfmt.toml rename to solana/rustfmt.toml