Remove InstructionContext::verify. Verify in handlers

Change-Id: I661308951de261bff572398b6834523563906907
This commit is contained in:
Reisen 2021-07-29 14:16:53 +00:00 committed by David Paryente
parent d37375e9a3
commit 108a4a2ff9
13 changed files with 131 additions and 187 deletions

View File

@ -2,7 +2,6 @@ use solitaire::*;
use solana_program::{
program::invoke_signed,
pubkey::Pubkey,
sysvar::{
clock::Clock,
rent::Rent,
@ -21,7 +20,6 @@ use crate::{
},
error::Error::{
InvalidFeeRecipient,
InvalidGovernanceKey,
InvalidGovernanceWithdrawal,
InvalidGuardianSetUpgrade,
},
@ -31,32 +29,9 @@ use crate::{
GovernancePayloadTransferFees,
GovernancePayloadUpgrade,
},
vaa::{
ClaimableVAA,
DeserializePayload,
},
CHAIN_ID_SOLANA,
vaa::ClaimableVAA,
};
// Confirm that a ClaimableVAA came from the correct chain, signed by the right emitter.
fn verify_claim<'a, T>(vaa: &ClaimableVAA<'a, T>) -> Result<()>
where
T: DeserializePayload,
{
let expected_emitter = std::env!("EMITTER_ADDRESS");
let current_emitter = format!(
"{}",
Pubkey::new_from_array(vaa.message.meta().emitter_address)
);
// Fail if the emitter is not the known governance key, or the emitting chain is not Solana.
if expected_emitter != current_emitter || vaa.message.meta().emitter_chain != CHAIN_ID_SOLANA {
Err(InvalidGovernanceKey.into())
} else {
Ok(())
}
}
#[derive(FromAccounts)]
pub struct UpgradeContract<'b> {
/// Payer for account creation (vaa-claim)
@ -101,8 +76,7 @@ pub fn upgrade_contract(
accs: &mut UpgradeContract,
_data: UpgradeContractData,
) -> Result<()> {
verify_claim(&accs.vaa)?;
accs.vaa.verify(ctx.program_id)?;
accs.vaa.claim(ctx, accs.payer.key)?;
let upgrade_ix = solana_program::bpf_loader_upgradeable::upgrade(
@ -141,17 +115,6 @@ pub struct UpgradeGuardianSet<'b> {
}
impl<'b> InstructionContext<'b> for UpgradeGuardianSet<'b> {
fn verify(&self, _program_id: &Pubkey) -> Result<()> {
if self.guardian_set_old.index != self.vaa.new_guardian_set_index - 1 {
return Err(InvalidGuardianSetUpgrade.into());
}
if self.bridge.guardian_set_index != self.vaa.new_guardian_set_index - 1 {
return Err(InvalidGuardianSetUpgrade.into());
}
Ok(())
}
}
#[derive(BorshDeserialize, BorshSerialize, Default)]
@ -162,8 +125,17 @@ pub fn upgrade_guardian_set(
accs: &mut UpgradeGuardianSet,
_data: UpgradeGuardianSetData,
) -> Result<()> {
verify_claim(&accs.vaa)?;
// Enforce single increments when upgrading.
if accs.guardian_set_old.index != accs.vaa.new_guardian_set_index - 1 {
return Err(InvalidGuardianSetUpgrade.into());
}
// Confirm that the version the bridge has active is the previous version.
if accs.bridge.guardian_set_index != accs.vaa.new_guardian_set_index - 1 {
return Err(InvalidGuardianSetUpgrade.into());
}
accs.vaa.verify(ctx.program_id)?;
accs.guardian_set_old.verify_derivation(
ctx.program_id,
&GuardianSetDerivationData {
@ -224,10 +196,8 @@ impl<'b> InstructionContext<'b> for SetFees<'b> {
pub struct SetFeesData {}
pub fn set_fees(ctx: &ExecutionContext, accs: &mut SetFees, _data: SetFeesData) -> Result<()> {
verify_claim(&accs.vaa)?;
accs.vaa.verify(ctx.program_id)?;
accs.vaa.claim(ctx, accs.payer.key)?;
accs.bridge.config.fee = accs.vaa.fee.as_u64();
Ok(())
@ -255,13 +225,6 @@ pub struct TransferFees<'b> {
}
impl<'b> InstructionContext<'b> for TransferFees<'b> {
fn verify(&self, _program_id: &Pubkey) -> Result<()> {
if self.vaa.to != self.recipient.key.to_bytes() {
return Err(InvalidFeeRecipient.into());
}
Ok(())
}
}
#[derive(BorshDeserialize, BorshSerialize, Default)]
@ -272,7 +235,12 @@ pub fn transfer_fees(
accs: &mut TransferFees,
_data: TransferFeesData,
) -> Result<()> {
verify_claim(&accs.vaa)?;
// Make sure the account loaded to receive funds is equal to the one the VAA requested.
if accs.vaa.to != accs.recipient.key.to_bytes() {
return Err(InvalidFeeRecipient.into());
}
accs.vaa.verify(ctx.program_id)?;
if accs
.fee_collector

View File

@ -15,7 +15,6 @@ use crate::{
CHAIN_ID_SOLANA,
};
use solana_program::{
pubkey::Pubkey,
sysvar::clock::Clock,
};
use solitaire::{
@ -59,10 +58,6 @@ pub struct PostMessage<'b> {
}
impl<'b> InstructionContext<'b> for PostMessage<'b> {
fn verify(&self, program_id: &Pubkey) -> Result<()> {
self.sequence.verify_derivation(program_id, &self.into())?;
Ok(())
}
}
#[derive(BorshDeserialize, BorshSerialize)]
@ -86,6 +81,8 @@ pub fn post_message(
trace!("Emitter Address: {}", accs.emitter.info().key);
trace!("Nonce: {}", data.nonce);
accs.sequence.verify_derivation(ctx.program_id, &(&*accs).into())?;
let msg_derivation = MessageDerivationData {
emitter_key: accs.emitter.key.to_bytes(),
emitter_chain: CHAIN_ID_SOLANA,

View File

@ -30,10 +30,7 @@ use byteorder::{
WriteBytesExt,
};
use sha3::Digest;
use solana_program::{
program_error::ProgramError,
pubkey::Pubkey,
};
use solana_program::program_error::ProgramError;
use solitaire::{
processors::seeded::Seeded,
CreationLamports::Exempt,
@ -77,9 +74,6 @@ pub struct PostVAA<'b> {
}
impl<'b> InstructionContext<'b> for PostVAA<'b> {
fn verify(&self, _program_id: &Pubkey) -> Result<()> {
Ok(())
}
}
#[derive(Default, BorshSerialize, BorshDeserialize)]

View File

@ -6,6 +6,7 @@ use crate::{
error::Error::{
InvalidGovernanceAction,
InvalidGovernanceChain,
InvalidGovernanceKey,
InvalidGovernanceModule,
VAAAlreadyExecuted,
},
@ -25,7 +26,6 @@ use solitaire::{
CreationLamports::Exempt,
Data,
ExecutionContext,
InstructionContext,
Peel,
SolitaireError,
*,
@ -158,12 +158,25 @@ impl<'b, T: DeserializePayload> Deref for ClaimableVAA<'b, T> {
}
}
impl<'b, T: DeserializePayload> InstructionContext<'b> for ClaimableVAA<'b, T> {
fn verify(&self, program_id: &Pubkey) -> Result<()> {
impl<'b, T: DeserializePayload> ClaimableVAA<'b, T> {
pub fn verify(&self, program_id: &Pubkey) -> Result<()> {
trace!("Seq: {}", self.message.meta().sequence);
// Do the Posted Message verification
let (expected_emitter, current_emitter) = (
std::env!("EMITTER_ADDRESS"),
format!(
"{}",
Pubkey::new_from_array(self.message.meta().emitter_address)
),
);
// Fail if the emitter is not the known governance key, or the emitting chain is not Solana.
if expected_emitter != current_emitter || self.message.meta().emitter_chain != CHAIN_ID_SOLANA {
return Err(InvalidGovernanceKey.into());
}
// Verify that the claim account is derived correctly
trace!("Seq: {}", self.message.meta().sequence);
self.claim.verify_derivation(
program_id,
&ClaimDerivationData {
@ -272,4 +285,4 @@ impl VAA {
Ok(v)
}
}
}

View File

@ -18,7 +18,6 @@ use bridge::{
},
CHAIN_ID_SOLANA,
};
use solana_program::pubkey::Pubkey;
use solitaire::{
processors::seeded::Seeded,
CreationLamports::Exempt,
@ -54,9 +53,6 @@ pub struct PostVAA<'b> {
}
impl<'b> InstructionContext<'b> for PostVAA<'b> {
fn verify(&self, _program_id: &Pubkey) -> Result<()> {
Ok(())
}
}
#[derive(Default, BorshSerialize, BorshDeserialize)]

View File

@ -78,9 +78,6 @@ pub struct AttestToken<'b> {
}
impl<'b> InstructionContext<'b> for AttestToken<'b> {
fn verify(&self, _: &Pubkey) -> Result<()> {
Ok(())
}
}
#[derive(BorshDeserialize, BorshSerialize, Default)]

View File

@ -71,35 +71,6 @@ impl<'a> From<&CompleteNative<'a>> for CustodyAccountDerivationData {
}
impl<'b> InstructionContext<'b> for CompleteNative<'b> {
fn verify(&self, program_id: &Pubkey) -> Result<()> {
// Verify the chain registration
self.chain_registration
.verify_derivation(program_id, &(self.into()))?;
// Verify that the custody account is derived correctly
self.custody.verify_derivation(program_id, &(self.into()))?;
// Verify mints
if self.mint.info().key != self.to.info().key {
return Err(InvalidMint.into());
}
if self.mint.info().key != self.custody.info().key {
return Err(InvalidMint.into());
}
if &self.custody.owner != self.custody_signer.key {
return Err(InvalidMint.into());
}
// Verify VAA
if self.vaa.token_address != self.mint.info().key.to_bytes() {
return Err(InvalidMint.into());
}
if self.vaa.token_chain != 1 {
return Err(InvalidChain.into());
}
Ok(())
}
}
#[derive(BorshDeserialize, BorshSerialize, Default)]
@ -110,6 +81,33 @@ pub fn complete_native(
accs: &mut CompleteNative,
data: CompleteNativeData,
) -> Result<()> {
// Verify the chain registration
let derivation_data: EndpointDerivationData = (&*accs).into();
accs.chain_registration.verify_derivation(ctx.program_id, &derivation_data)?;
// Verify that the custody account is derived correctly
let derivation_data: CustodyAccountDerivationData = (&*accs).into();
accs.custody.verify_derivation(ctx.program_id, &derivation_data)?;
// Verify mints
if accs.mint.info().key != accs.to.info().key {
return Err(InvalidMint.into());
}
if accs.mint.info().key != accs.custody.info().key {
return Err(InvalidMint.into());
}
if &accs.custody.owner != accs.custody_signer.key {
return Err(InvalidMint.into());
}
// Verify VAA
if accs.vaa.token_address != accs.mint.info().key.to_bytes() {
return Err(InvalidMint.into());
}
if accs.vaa.token_chain != 1 {
return Err(InvalidChain.into());
}
// Prevent vaa double signing
accs.vaa.claim(ctx, accs.payer.key)?;
@ -171,20 +169,6 @@ impl<'a> From<&CompleteWrapped<'a>> for WrappedDerivationData {
}
impl<'b> InstructionContext<'b> for CompleteWrapped<'b> {
fn verify(&self, program_id: &Pubkey) -> Result<()> {
// Verify the chain registration
self.chain_registration
.verify_derivation(program_id, &(self.into()))?;
// Verify mint
self.mint.verify_derivation(program_id, &(self.into()))?;
// Verify mints
if self.mint.info().key != self.to.info().key {
return Err(InvalidMint.into());
}
Ok(())
}
}
#[derive(BorshDeserialize, BorshSerialize, Default)]
@ -195,6 +179,20 @@ pub fn complete_wrapped(
accs: &mut CompleteWrapped,
data: CompleteWrappedData,
) -> Result<()> {
// Verify the chain registration
let derivation_data: EndpointDerivationData = (&*accs).into();
accs.chain_registration
.verify_derivation(ctx.program_id, &derivation_data)?;
// Verify mint
let derivation_data: WrappedDerivationData = (&*accs).into();
accs.mint.verify_derivation(ctx.program_id, &derivation_data)?;
// Verify mints
if accs.mint.info().key != accs.to.info().key {
return Err(InvalidMint.into());
}
accs.vaa.claim(ctx, accs.payer.key)?;
// Mint tokens

View File

@ -72,14 +72,6 @@ impl<'a> From<&CreateWrapped<'a>> for WrappedDerivationData {
}
impl<'b> InstructionContext<'b> for CreateWrapped<'b> {
fn verify(&self, program_id: &Pubkey) -> Result<()> {
self.mint.verify_derivation(program_id, &(self.into()))?;
self.meta.verify_derivation(program_id, &(self.into()))?;
self.chain_registration
.verify_derivation(program_id, &(self.into()))?;
Ok(())
}
}
#[derive(BorshDeserialize, BorshSerialize, Default)]
@ -90,6 +82,13 @@ pub fn create_wrapped(
accs: &mut CreateWrapped,
data: CreateWrappedData,
) -> Result<()> {
let derivation_data: WrappedDerivationData = (&*accs).into();
accs.mint.verify_derivation(ctx.program_id, &derivation_data)?;
accs.meta.verify_derivation(ctx.program_id, &derivation_data)?;
let derivation_data: EndpointDerivationData = (&*accs).into();
accs.chain_registration.verify_derivation(ctx.program_id, &derivation_data)?;
accs.vaa.claim(ctx, accs.payer.key)?;
// Create mint account

View File

@ -140,10 +140,6 @@ impl<'a> From<&RegisterChain<'a>> for EndpointDerivationData {
}
impl<'b> InstructionContext<'b> for RegisterChain<'b> {
fn verify(&self, program_id: &Pubkey) -> Result<()> {
self.endpoint.verify_derivation(program_id, &self.into())?;
Ok(())
}
}
#[derive(BorshDeserialize, BorshSerialize, Default)]
@ -154,6 +150,9 @@ pub fn register_chain(
accs: &mut RegisterChain,
data: RegisterChainData,
) -> Result<()> {
let derivation_data: EndpointDerivationData = (&*accs).into();
accs.endpoint.verify_derivation(ctx.program_id, &derivation_data)?;
// Claim VAA
accs.vaa.claim(ctx, accs.payer.key)?;

View File

@ -105,24 +105,6 @@ impl<'a> From<&TransferNative<'a>> for CustodyAccountDerivationData {
}
impl<'b> InstructionContext<'b> for TransferNative<'b> {
fn verify(&self, program_id: &Pubkey) -> Result<()> {
// Verify that the custody account is derived correctly
self.custody.verify_derivation(program_id, &self.into())?;
// Verify mints
if self.mint.info().key != self.from.info().key {
return Err(TokenBridgeError::InvalidMint.into());
}
// Verify that the token is not a wrapped token
if let COption::Some(mint_authority) = self.mint.mint_authority {
if mint_authority == MintSigner::key(None, program_id) {
return Err(TokenBridgeError::TokenNotNative.into());
}
}
Ok(())
}
}
#[derive(BorshDeserialize, BorshSerialize, Default)]
@ -139,6 +121,22 @@ pub fn transfer_native(
accs: &mut TransferNative,
data: TransferNativeData,
) -> Result<()> {
// Verify that the custody account is derived correctly
let derivation_data: CustodyAccountDerivationData = (&*accs).into();
accs.custody.verify_derivation(ctx.program_id, &derivation_data)?;
// Verify mints
if accs.mint.info().key != accs.from.info().key {
return Err(TokenBridgeError::InvalidMint.into());
}
// Verify that the token is not a wrapped token
if let COption::Some(mint_authority) = accs.mint.mint_authority {
if mint_authority == MintSigner::key(None, ctx.program_id) {
return Err(TokenBridgeError::TokenNotNative.into());
}
}
if !accs.custody.is_initialized() {
accs.custody
.create(&(&*accs).into(), ctx, accs.payer.key, Exempt)?;
@ -246,23 +244,6 @@ impl<'a> From<&TransferWrapped<'a>> for WrappedDerivationData {
}
impl<'b> InstructionContext<'b> for TransferWrapped<'b> {
fn verify(&self, program_id: &Pubkey) -> Result<()> {
// Verify that the from account is owned by the from_owner
if &self.from.owner != self.from_owner.key {
return Err(WrongAccountOwner.into());
}
// Verify mints
if self.mint.info().key != &self.from.mint {
return Err(TokenBridgeError::InvalidMint.into());
}
// Verify that meta is correct
self.wrapped_meta
.verify_derivation(program_id, &self.into())?;
Ok(())
}
}
#[derive(BorshDeserialize, BorshSerialize, Default)]
@ -279,6 +260,20 @@ pub fn transfer_wrapped(
accs: &mut TransferWrapped,
data: TransferWrappedData,
) -> Result<()> {
// Verify that the from account is owned by the from_owner
if &accs.from.owner != accs.from_owner.key {
return Err(WrongAccountOwner.into());
}
// Verify mints
if accs.mint.info().key != &accs.from.mint {
return Err(TokenBridgeError::InvalidMint.into());
}
// Verify that meta is correct
accs.wrapped_meta
.verify_derivation(ctx.program_id, &(&*accs).into())?;
// Burn tokens
let burn_ix = spl_token::instruction::burn(
&spl_token::id(),

View File

@ -16,20 +16,6 @@ pub struct SetConfig<'b> {
}
impl<'b> InstructionContext<'b> for SetConfig<'b> {
fn verify(&self, _program_id: &Pubkey) -> SoliResult<()> {
if &self.config.0.owner != self.current_owner.info().key {
msg!(
"Current owner account mismatch (expected {:?})",
self.config.0.owner
);
return Err(SolitaireError::InvalidSigner(
self.current_owner.info().key.clone(),
));
}
Ok(())
}
fn deps(&self) -> Vec<Pubkey> {
vec![]
}
@ -41,6 +27,16 @@ pub fn set_config(
accs: &mut SetConfig,
data: Pyth2WormholeConfig,
) -> SoliResult<()> {
if &accs.config.0.owner != accs.current_owner.info().key {
msg!(
"Current owner account mismatch (expected {:?})",
accs.config.0.owner
);
return Err(SolitaireError::InvalidSigner(
accs.current_owner.info().key.clone(),
));
}
accs.config.1 = data;
Ok(())

View File

@ -110,10 +110,6 @@ impl CreationLamports {
}
pub trait InstructionContext<'a> {
fn verify(&self, program_id: &Pubkey) -> Result<()> {
Ok(())
}
fn deps(&self) -> Vec<Pubkey> {
vec![]
}

View File

@ -120,10 +120,6 @@ pub fn derive_from_accounts(input: TokenStream) -> TokenStream {
impl #combined_impl_g solitaire::Peel<'a, 'b, 'c> for #name #type_g {
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> solitaire::Result<Self> where Self: Sized {
let v: #name #type_g = FromAccounts::from(ctx.this, ctx.iter, ctx.data)?;
// Verify the instruction constraints
solitaire::InstructionContext::verify(&v, ctx.this)?;
Ok(v)
}