Merge changes Ie2827893,I8304d257 into dev.v2

* changes:
  reformat errors, remove transfer specific errors
  solana/bridge: change VAA structure
This commit is contained in:
Leopold Schabel 2021-04-16 10:33:06 +00:00 committed by Gerrit Code Review
commit d1a24f745d
3 changed files with 64 additions and 467 deletions

View File

@ -1,6 +1,8 @@
//! Error types
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use solana_program::program_error::PrintProgramError;
use solana_program::{decode_error::DecodeError, program_error::ProgramError};
use thiserror::Error;
@ -31,12 +33,6 @@ pub enum Error {
/// The deserialization of the GuardianSet state returned something besides State::GuardianSet.
#[error("ExpectedGuardianSet")]
ExpectedGuardianSet,
/// The deserialization of the TransferOutProposal state returned something besides State::TransferOutProposal.
#[error("ExpectedTransferOutProposal")]
ExpectedTransferOutProposal,
/// The deserialization of the GuardianSet state returned something besides State::WrappedAssetMeta.
#[error("ExpectedWrappedAssetMeta")]
ExpectedWrappedAssetMeta,
/// State is uninitialized.
#[error("State is unititialized")]
UninitializedState,
@ -58,18 +54,9 @@ pub enum Error {
/// An account was not derived correctly
#[error("InvalidDerivedAccount")]
InvalidDerivedAccount,
/// A given token account does not belong to the given mint
#[error("TokenMintMismatch")]
TokenMintMismatch,
/// A given mint account does not belong to the program
#[error("WrongMintOwner")]
WrongMintOwner,
/// A given bridge account does not belong to the program
#[error("WrongBridgeOwner")]
WrongBridgeOwner,
/// A given token account does not belong to the program
#[error("WrongTokenAccountOwner")]
WrongTokenAccountOwner,
/// A parsing operation failed
#[error("ParseFailed")]
ParseFailed,
@ -87,16 +74,10 @@ pub enum Error {
GuardianIndexNotIncreasing,
/// The given VAA does not match the proposal
#[error("VAAProposalMismatch")]
VAAProposalMismatch,
/// Invalid transfer with src=dst
#[error("SameChainTransfer")]
SameChainTransfer,
VAAMessageMismatch,
/// VAA is longer than the maximum size
#[error("VAATooLong")]
VAATooLong,
/// Cannot wrap a solana native asset
#[error("CannotWrapNative")]
CannotWrapNative,
/// VAA for this transfer has already been submitted
#[error("VAAAlreadySubmitted")]
VAAAlreadySubmitted,
@ -115,6 +96,46 @@ pub enum Error {
/// Invalid Chain
#[error("InvalidChain")]
InvalidChain,
/// Emitter is not a signer
#[error("EmitterNotSigner")]
EmitterNotSigner,
}
#[cfg(feature = "program")]
impl PrintProgramError for Error {
fn print<E>(&self)
where
E: 'static + std::error::Error + DecodeError<E> + PrintProgramError + FromPrimitive,
{
match self {
Error::ExpectedToken => msg!("Error: ExpectedToken"),
Error::ExpectedAccount => msg!("Error: ExpectedAccount"),
Error::ExpectedBridge => msg!("Error: ExpectedBridge"),
Error::ExpectedGuardianSet => msg!("Error: ExpectedGuardianSet"),
Error::UninitializedState => msg!("Error: State is unititialized"),
Error::InvalidProgramAddress => msg!("Error: InvalidProgramAddress"),
Error::InvalidVAAFormat => msg!("Error: InvalidVAAFormat"),
Error::InvalidVAASignature => msg!("Error: InvalidVAASignature"),
Error::AlreadyExists => msg!("Error: AlreadyExists"),
Error::InvalidDerivedAccount => msg!("Error: InvalidDerivedAccount"),
Error::ParseFailed => msg!("Error: ParseFailed"),
Error::GuardianSetExpired => msg!("Error: GuardianSetExpired"),
Error::VAAClaimed => msg!("Error: VAAClaimed"),
Error::WrongBridgeOwner => msg!("Error: WrongBridgeOwner"),
Error::OldGuardianSet => msg!("Error: OldGuardianSet"),
Error::GuardianIndexNotIncreasing => msg!("Error: GuardianIndexNotIncreasing"),
Error::VAAMessageMismatch => msg!("Error: VAAProposalMismatch"),
Error::VAATooLong => msg!("Error: VAATooLong"),
Error::VAAAlreadySubmitted => msg!("Error: VAAAlreadySubmitted"),
Error::GuardianSetMismatch => msg!("Error: GuardianSetMismatch"),
Error::InsufficientFees => msg!("Error: InsufficientFees"),
Error::InvalidOwner => msg!("Error: InvalidOwner"),
Error::InvalidSysvar => msg!("Error: InvalidSysvar"),
Error::InvalidChain => msg!("Error: InvalidChain"),
Error::InvalidVAAAction => msg!("Error: InvalidVAAAction"),
Error::EmitterNotSigner => msg!("Error: EmitterNotSigner"),
}
}
}
impl From<Error> for ProgramError {

View File

@ -1,48 +0,0 @@
#![cfg(feature = "program")]
use num_traits::FromPrimitive;
use solana_program::{decode_error::DecodeError, program_error::PrintProgramError};
use crate::error::*;
impl PrintProgramError for Error {
fn print<E>(&self)
where
E: 'static + std::error::Error + DecodeError<E> + PrintProgramError + FromPrimitive,
{
match self {
Error::ExpectedToken => msg!("Error: ExpectedToken"),
Error::ExpectedAccount => msg!("Error: ExpectedAccount"),
Error::ExpectedBridge => msg!("Error: ExpectedBridge"),
Error::ExpectedGuardianSet => msg!("Error: ExpectedGuardianSet"),
Error::ExpectedWrappedAssetMeta => msg!("Error: ExpectedWrappedAssetMeta"),
Error::UninitializedState => msg!("Error: State is unititialized"),
Error::InvalidProgramAddress => msg!("Error: InvalidProgramAddress"),
Error::InvalidVAAFormat => msg!("Error: InvalidVAAFormat"),
Error::InvalidVAAAction => msg!("Error: InvalidVAAAction"),
Error::InvalidVAASignature => msg!("Error: InvalidVAASignature"),
Error::AlreadyExists => msg!("Error: AlreadyExists"),
Error::InvalidDerivedAccount => msg!("Error: InvalidDerivedAccount"),
Error::TokenMintMismatch => msg!("Error: TokenMintMismatch"),
Error::WrongMintOwner => msg!("Error: WrongMintOwner"),
Error::WrongTokenAccountOwner => msg!("Error: WrongTokenAccountOwner"),
Error::ParseFailed => msg!("Error: ParseFailed"),
Error::GuardianSetExpired => msg!("Error: GuardianSetExpired"),
Error::VAAClaimed => msg!("Error: VAAClaimed"),
Error::WrongBridgeOwner => msg!("Error: WrongBridgeOwner"),
Error::OldGuardianSet => msg!("Error: OldGuardianSet"),
Error::GuardianIndexNotIncreasing => msg!("Error: GuardianIndexNotIncreasing"),
Error::ExpectedTransferOutProposal => msg!("Error: ExpectedTransferOutProposal"),
Error::VAAProposalMismatch => msg!("Error: VAAProposalMismatch"),
Error::SameChainTransfer => msg!("Error: SameChainTransfer"),
Error::VAATooLong => msg!("Error: VAATooLong"),
Error::CannotWrapNative => msg!("Error: CannotWrapNative"),
Error::VAAAlreadySubmitted => msg!("Error: VAAAlreadySubmitted"),
Error::GuardianSetMismatch => msg!("Error: GuardianSetMismatch"),
Error::InsufficientFees => msg!("Error: InsufficientFees"),
Error::InvalidOwner => msg!("Error: InvalidOwner"),
Error::InvalidSysvar => msg!("Error: InvalidSysvar"),
Error::InvalidChain => msg!("Error: InvalidChain"),
}
}
}

View File

@ -1,11 +1,10 @@
use std::io::{Cursor, Read, Write};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use primitive_types::U256;
use sha3::Digest;
use solana_program::program_error::ProgramError;
use crate::{error::Error, state::AssetMeta};
use crate::error::Error;
use solana_program::pubkey::Pubkey;
pub type ForeignAddress = [u8; 32];
@ -19,7 +18,10 @@ pub struct VAA {
// Body part
pub timestamp: u32,
pub payload: Option<VAABody>,
pub nonce: u32,
pub emitter_chain: u8,
pub emitter_address: ForeignAddress,
pub payload: Vec<u8>,
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
@ -37,7 +39,10 @@ impl VAA {
guardian_set_index: 0,
signatures: vec![],
timestamp: 0,
payload: None,
emitter_chain: 0,
emitter_address: [0u8; 32],
nonce: 0,
payload: vec![],
};
}
@ -71,12 +76,10 @@ impl VAA {
}
v.write_u32::<BigEndian>(self.timestamp)?;
let payload = self.payload.as_ref().ok_or(Error::InvalidVAAAction)?;
v.write_u8(payload.action_id())?;
let payload_data = payload.serialize()?;
v.write(payload_data.as_slice())?;
v.write_u32::<BigEndian>(self.nonce)?;
v.write_u8(self.emitter_chain)?;
v.write(&self.emitter_address)?;
v.write(&self.payload)?;
Ok(v.into_inner())
}
@ -85,12 +88,10 @@ impl VAA {
let mut v = Cursor::new(Vec::new());
v.write_u32::<BigEndian>(self.timestamp)?;
let payload = self.payload.as_ref().ok_or(Error::InvalidVAAAction)?;
v.write_u8(payload.action_id())?;
let payload_data = payload.serialize()?;
v.write(payload_data.as_slice())?;
v.write_u32::<BigEndian>(self.nonce)?;
v.write_u8(self.emitter_chain)?;
v.write(&self.emitter_address)?;
v.write(&self.payload)?;
Ok(v.into_inner())
}
@ -117,388 +118,11 @@ impl VAA {
v.signatures = sigs;
v.timestamp = rdr.read_u32::<BigEndian>()?;
let mut payload_d = Vec::new();
rdr.read_to_end(&mut payload_d)?;
v.payload = Some(VAABody::deserialize(&payload_d)?);
v.nonce = rdr.read_u32::<BigEndian>()?;
v.emitter_chain = rdr.read_u8()?;
rdr.read_exact(&mut v.emitter_address)?;
rdr.read_to_end(&mut v.payload)?;
Ok(v)
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum VAABody {
UpdateGuardianSet(BodyUpdateGuardianSet),
Transfer(BodyTransfer),
UpgradeContract(BodyContractUpgrade),
}
impl VAABody {
fn action_id(&self) -> u8 {
match self {
VAABody::UpdateGuardianSet(_) => 0x01,
VAABody::UpgradeContract(_) => 0x02,
VAABody::Transfer(_) => 0x10,
}
}
fn deserialize(data: &Vec<u8>) -> Result<VAABody, Error> {
let mut payload_data = Cursor::new(data);
let action = payload_data.read_u8()?;
let payload = match action {
0x01 => {
VAABody::UpdateGuardianSet(BodyUpdateGuardianSet::deserialize(&mut payload_data)?)
}
0x02 => VAABody::UpgradeContract(BodyContractUpgrade::deserialize(&mut payload_data)?),
0x10 => VAABody::Transfer(BodyTransfer::deserialize(&mut payload_data)?),
_ => {
return Err(Error::InvalidVAAAction);
}
};
Ok(payload)
}
fn serialize(&self) -> Result<Vec<u8>, Error> {
match self {
VAABody::Transfer(b) => b.serialize(),
VAABody::UpdateGuardianSet(b) => b.serialize(),
VAABody::UpgradeContract(b) => b.serialize(),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct BodyUpdateGuardianSet {
pub new_index: u32,
pub new_keys: Vec<[u8; 20]>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct BodyTransfer {
pub nonce: u32,
pub source_chain: u8,
pub target_chain: u8,
pub source_address: ForeignAddress,
pub target_address: ForeignAddress,
pub asset: AssetMeta,
pub amount: U256,
}
#[derive(Clone, Debug, PartialEq)]
pub struct BodyContractUpgrade {
pub chain_id: u8,
pub buffer: Pubkey,
}
impl BodyContractUpgrade {
fn deserialize(data: &mut Cursor<&Vec<u8>>) -> Result<BodyContractUpgrade, Error> {
let chain_id = data.read_u8()?;
let mut key: [u8; 32] = [0; 32];
data.read(&mut key[..])?;
Ok(BodyContractUpgrade {
chain_id,
buffer: Pubkey::new(&key[..]),
})
}
fn serialize(&self) -> Result<Vec<u8>, Error> {
let mut v: Cursor<Vec<u8>> = Cursor::new(Vec::new());
v.write_u8(self.chain_id)?;
v.write(&self.buffer.to_bytes());
Ok(v.into_inner())
}
}
impl BodyUpdateGuardianSet {
fn deserialize(data: &mut Cursor<&Vec<u8>>) -> Result<BodyUpdateGuardianSet, Error> {
let new_index = data.read_u32::<BigEndian>()?;
let keys_len = data.read_u8()?;
let mut keys = Vec::with_capacity(keys_len as usize);
for _ in 0..keys_len {
let mut key: [u8; 20] = [0; 20];
data.read(&mut key)?;
keys.push(key);
}
Ok(BodyUpdateGuardianSet {
new_index,
new_keys: keys,
})
}
fn serialize(&self) -> Result<Vec<u8>, Error> {
let mut v: Cursor<Vec<u8>> = Cursor::new(Vec::new());
v.write_u32::<BigEndian>(self.new_index)?;
v.write_u8(self.new_keys.len() as u8)?;
for k in self.new_keys.iter() {
v.write(k)?;
}
Ok(v.into_inner())
}
}
impl BodyTransfer {
fn deserialize(data: &mut Cursor<&Vec<u8>>) -> Result<BodyTransfer, Error> {
let nonce = data.read_u32::<BigEndian>()?;
let source_chain = data.read_u8()?;
let target_chain = data.read_u8()?;
let mut source_address: ForeignAddress = ForeignAddress::default();
data.read_exact(&mut source_address)?;
let mut target_address: ForeignAddress = ForeignAddress::default();
data.read_exact(&mut target_address)?;
let token_chain = data.read_u8()?;
let mut token_address: ForeignAddress = ForeignAddress::default();
data.read_exact(&mut token_address)?;
let token_decimals = data.read_u8()?;
let mut am_data: [u8; 32] = [0; 32];
data.read_exact(&mut am_data)?;
let amount = U256::from_big_endian(&am_data);
Ok(BodyTransfer {
nonce,
source_chain,
target_chain,
source_address,
target_address,
asset: AssetMeta {
address: token_address,
chain: token_chain,
decimals: token_decimals,
},
amount,
})
}
fn serialize(&self) -> Result<Vec<u8>, Error> {
let mut v: Cursor<Vec<u8>> = Cursor::new(Vec::new());
v.write_u32::<BigEndian>(self.nonce)?;
v.write_u8(self.source_chain)?;
v.write_u8(self.target_chain)?;
v.write(&self.source_address)?;
v.write(&self.target_address)?;
v.write_u8(self.asset.chain)?;
v.write(&self.asset.address)?;
v.write_u8(self.asset.decimals)?;
let mut am_data: [u8; 32] = [0; 32];
self.amount.to_big_endian(&mut am_data);
v.write(&am_data[..])?;
Ok(v.into_inner())
}
}
#[cfg(test)]
mod tests {
use hex;
use primitive_types::U256;
use crate::{
state::AssetMeta,
vaa::{BodyTransfer, BodyUpdateGuardianSet, Signature, VAABody, VAA},
};
use crate::vaa::BodyContractUpgrade;
use solana_program::pubkey::Pubkey;
#[test]
fn serialize_deserialize_vaa_transfer() {
let vaa = VAA {
version: 8,
guardian_set_index: 3,
signatures: vec![Signature {
index: 1,
r: [2; 32],
s: [2; 32],
v: 7,
}],
timestamp: 83,
payload: Some(VAABody::Transfer(BodyTransfer {
nonce: 28,
source_chain: 1,
target_chain: 2,
source_address: [1; 32],
target_address: [1; 32],
asset: AssetMeta {
address: [2; 32],
chain: 8,
decimals: 9,
},
amount: U256::from(3),
})),
};
let data = vaa.serialize().unwrap();
let parsed_vaa = VAA::deserialize(data.as_slice()).unwrap();
assert_eq!(vaa, parsed_vaa)
}
#[test]
fn serialize_deserialize_vaa_guardian() {
let vaa = VAA {
version: 8,
guardian_set_index: 3,
signatures: vec![Signature {
index: 1,
r: [2; 32],
s: [2; 32],
v: 7,
}],
timestamp: 83,
payload: Some(VAABody::UpdateGuardianSet(BodyUpdateGuardianSet {
new_index: 29,
new_keys: vec![],
})),
};
let data = vaa.serialize().unwrap();
let parsed_vaa = VAA::deserialize(data.as_slice()).unwrap();
assert_eq!(vaa, parsed_vaa)
}
#[test]
fn serialize_deserialize_vaa_contract_upgrade() {
let vaa = VAA {
version: 8,
guardian_set_index: 3,
signatures: vec![Signature {
index: 1,
r: [2; 32],
s: [2; 32],
v: 7,
}],
timestamp: 83,
payload: Some(VAABody::UpgradeContract(BodyContractUpgrade {
chain_id: 3,
buffer: Pubkey::new_unique(),
})),
};
let data = vaa.serialize().unwrap();
let parsed_vaa = VAA::deserialize(data.as_slice()).unwrap();
assert_eq!(vaa, parsed_vaa)
}
#[test]
fn parse_given_guardian_set_update() {
let vaa = VAA {
version: 1,
guardian_set_index: 0,
signatures: vec![Signature {
index: 0,
r: [
51, 130, 199, 26, 76, 121, 225, 81, 138, 108, 226, 156, 145, 86, 159, 100, 39,
166, 10, 149, 105, 106, 53, 21, 184, 194, 52, 11, 106, 207, 253, 114,
],
s: [
51, 21, 189, 16, 17, 170, 119, 159, 34, 87, 56, 130, 164, 237, 254, 27, 130, 6,
84, 142, 19, 72, 113, 162, 63, 139, 160, 193, 199, 208, 181, 237,
],
v: 1,
}],
timestamp: 3000,
payload: Some(VAABody::UpdateGuardianSet(BodyUpdateGuardianSet {
new_index: 1,
new_keys: vec![[
190, 250, 66, 157, 87, 205, 24, 183, 248, 164, 217, 26, 45, 169, 171, 74, 240,
93, 15, 190,
]],
})),
};
let data = hex::decode("010000000001003382c71a4c79e1518a6ce29c91569f6427a60a95696a3515b8c2340b6acffd723315bd1011aa779f22573882a4edfe1b8206548e134871a23f8ba0c1c7d0b5ed0100000bb8010000000101befa429d57cd18b7f8a4d91a2da9ab4af05d0fbe").unwrap();
let parsed_vaa = VAA::deserialize(data.as_slice()).unwrap();
assert_eq!(vaa, parsed_vaa);
let rec_data = parsed_vaa.serialize().unwrap();
assert_eq!(data, rec_data);
}
#[test]
fn parse_given_transfer() {
let vaa = VAA {
version: 1,
guardian_set_index: 0,
signatures: vec![Signature {
index: 0,
r: [
146, 115, 122, 21, 4, 243, 179, 223, 140, 147, 203, 133, 198, 74, 72, 96, 187,
39, 14, 38, 2, 107, 110, 55, 240, 149, 53, 106, 64, 111, 106, 244,
],
s: [
57, 198, 178, 233, 119, 95, 161, 198, 102, 149, 37, 240, 110, 218, 176, 51,
186, 93, 68, 115, 8, 244, 227, 189, 179, 60, 15, 54, 29, 195, 46, 195,
],
v: 1,
}],
timestamp: 1597440008,
payload: Some(VAABody::Transfer(BodyTransfer {
nonce: 53,
source_chain: 1,
target_chain: 2,
source_address: [
2, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
],
target_address: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 248, 191, 106, 71, 159, 50, 14, 173,
7, 68, 17, 164, 176, 231, 148, 78, 168, 201, 193,
],
asset: AssetMeta {
address: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 71, 239, 52, 104, 123, 220, 159, 24,
158, 135, 169, 32, 6, 88, 217, 196, 14, 153, 136,
],
chain: 1,
decimals: 8,
},
amount: U256::from_dec_str("5000000000000000000").unwrap(),
})),
};
let data = hex::decode("0100000000010092737a1504f3b3df8c93cb85c64a4860bb270e26026b6e37f095356a406f6af439c6b2e9775fa1c6669525f06edab033ba5d447308f4e3bdb33c0f361dc32ec3015f37000810000000350102020104000000000000000000000000000000000000000000000000000000000000000000000000000000000090f8bf6a479f320ead074411a4b0e7944ea8c9c1010000000000000000000000000347ef34687bdc9f189e87a9200658d9c40e9988080000000000000000000000000000000000000000000000004563918244f40000").unwrap();
let parsed_vaa = VAA::deserialize(data.as_slice()).unwrap();
assert_eq!(vaa, parsed_vaa);
let rec_data = parsed_vaa.serialize().unwrap();
assert_eq!(data, rec_data);
}
#[test]
fn parse_given_contract_upgrade() {
let vaa = VAA {
version: 1,
guardian_set_index: 2,
signatures: vec![Signature {
index: 0,
r: [
72, 156, 56, 20, 222, 146, 161, 112, 22, 97, 69, 59, 188, 199, 130, 240, 89,
249, 241, 79, 96, 27, 235, 10, 99, 16, 56, 80, 232, 188, 235, 11
],
s: [
65, 19, 144, 42, 104, 122, 52, 0, 126, 7, 43, 127, 120, 85, 5, 21, 216, 207,
78, 73, 213, 207, 142, 103, 211, 192, 100, 90, 27, 98, 176, 98
],
v: 1,
}],
timestamp: 4000,
payload: Some(VAABody::UpgradeContract(BodyContractUpgrade {
chain_id: 2,
buffer: Pubkey::new(&[146, 115, 122, 21, 4, 243, 179, 223, 140, 147, 203, 133, 198, 74, 72, 96, 187,
39, 14, 38, 2, 107, 110, 55, 240, 149, 53, 106, 64, 111, 106, 244]),
})),
};
let data = hex::decode("01000000020100489c3814de92a1701661453bbcc782f059f9f14f601beb0a63103850e8bceb0b4113902a687a34007e072b7f78550515d8cf4e49d5cf8e67d3c0645a1b62b0620100000fa0020292737a1504f3b3df8c93cb85c64a4860bb270e26026b6e37f095356a406f6af4").unwrap();
let parsed_vaa = VAA::deserialize(data.as_slice()).unwrap();
assert_eq!(vaa, parsed_vaa);
let rec_data = parsed_vaa.serialize().unwrap();
assert_eq!(data, rec_data);
}
}