Adapt solana agent for v2

Change-Id: I81fc8b959f33a157371d1c59b1d5323dfc11f1ce
This commit is contained in:
Hendrik Hofstadt 2021-06-25 12:25:17 +02:00
parent a341c2a5b5
commit 6d1b3d2651
10 changed files with 230 additions and 193 deletions

View File

@ -2,6 +2,7 @@ syntax = "proto3";
package agent.v1; package agent.v1;
import "google/protobuf/timestamp.proto";
// TODO: documentation // TODO: documentation
option go_package = "github.com/certusone/wormhole/bridge/pkg/proto/agent/v1;agentv1"; option go_package = "github.com/certusone/wormhole/bridge/pkg/proto/agent/v1;agentv1";
@ -15,10 +16,27 @@ message Empty {
} }
message SubmitVAARequest { message SubmitVAARequest {
bytes vaa = 1; VAA vaa = 1;
bool skip_preflight = 2; bool skip_preflight = 2;
} }
message VAA {
uint32 Version = 1;
google.protobuf.Timestamp Timestamp = 2;
uint32 Nonce = 3;
uint32 EmitterChain = 4;
bytes EmitterAddress = 5;
uint64 Sequence = 6;
bytes Payload = 7;
uint32 GuardianSetIndex = 8;
repeated Signature Signatures = 9;
}
message Signature{
uint32 GuardianIndex = 1;
bytes Signature = 2;
}
message SubmitVAAResponse { message SubmitVAAResponse {
string signature = 1; string signature = 1;
} }

View File

@ -31,6 +31,7 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
name = "agent" name = "agent"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"borsh",
"bridge", "bridge",
"bs58", "bs58",
"byteorder", "byteorder",
@ -46,6 +47,7 @@ dependencies = [
"serde_bytes", "serde_bytes",
"serde_derive", "serde_derive",
"serde_json", "serde_json",
"sha3",
"solana-client", "solana-client",
"solana-program", "solana-program",
"solana-sdk", "solana-sdk",

View File

@ -14,7 +14,7 @@ solana-program = "=1.7.0"
solana-sdk = "=1.7.0" solana-sdk = "=1.7.0"
solitaire = { path = "../../solitaire/program" } solitaire = { path = "../../solitaire/program" }
solitaire-client = {path = "../../solitaire/client" } solitaire-client = {path = "../../solitaire/client" }
bridge = { path = "../program", default-features = false, features = ["no-entrypoint"] } bridge = { path = "../program", features = ["no-idl", "no-entrypoint", "client"] }
primitive-types = { version = "0.7.2" } primitive-types = { version = "0.7.2" }
hex = "0.4.2" hex = "0.4.2"
thiserror = "1.0.20" thiserror = "1.0.20"
@ -26,10 +26,12 @@ log = "0.4.11"
serde_derive = "1.0.103" serde_derive = "1.0.103"
serde_json = "1.0.57" serde_json = "1.0.57"
bs58 = "0.3.1" bs58 = "0.3.1"
byteorder = "1.3.4" byteorder = "1.4.3"
futures = "0.3.8" futures = "0.3.8"
libc = "0.2.80" libc = "0.2.80"
clap = "2.33.3" clap = "2.33.3"
borsh = "0.8.1"
sha3 = "0.9.1"
[build-dependencies] [build-dependencies]
tonic-build = { version = "0.3.0", features = ["prost"] } tonic-build = { version = "0.3.0", features = ["prost"] }

View File

@ -1,3 +1,3 @@
fn main() { fn main() {
tonic_build::compile_protos("../../proto/agent/v1/service.proto").unwrap(); tonic_build::compile_protos("../../../proto/agent/v1/service.proto").unwrap();
} }

View File

@ -1,34 +1,80 @@
use std::{env, io::Write, mem::size_of, str::FromStr, fs};
use std::path::Path;
use libc; use libc;
use std::{
fs,
io::Write,
path::Path,
str::FromStr,
};
use clap::{Arg, App, SubCommand}; use clap::{
App,
Arg,
};
use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{
LittleEndian,
WriteBytesExt,
};
use futures::stream::TryStreamExt; use futures::stream::TryStreamExt;
use solana_client::{ use solana_client::{
client_error::ClientError, rpc_client::RpcClient, rpc_config::RpcSendTransactionConfig, client_error::ClientError,
rpc_client::RpcClient,
rpc_config::RpcSendTransactionConfig,
}; };
use solana_sdk::{ use solana_sdk::{
commitment_config::{CommitmentConfig, CommitmentLevel}, commitment_config::{
CommitmentConfig,
CommitmentLevel,
},
instruction::Instruction, instruction::Instruction,
pubkey::Pubkey, pubkey::Pubkey,
signature::{read_keypair_file, write_keypair_file, Keypair, Signature, Signer}, signature::{
read_keypair_file,
Keypair,
Signature,
Signer,
},
transaction::Transaction, transaction::Transaction,
}; };
use tokio::net::UnixListener; use tokio::net::UnixListener;
use tokio::sync::mpsc;
use tonic::{transport::Server, Code, Request, Response, Status};
use service::{ use tonic::{
agent_server::{Agent, AgentServer}, transport::Server,
Empty,SubmitVaaRequest, SubmitVaaResponse, Code,
GetBalanceResponse, GetBalanceRequest, Request,
Response,
Status,
}; };
use spl_bridge::{
instruction::{post_vaa, verify_signatures, VerifySigPayload, CHAIN_ID_SOLANA}, use borsh::BorshDeserialize;
state::{Bridge, GuardianSet, PostedMessage}, use bridge::{
vaa::VAA, accounts::{
GuardianSet,
GuardianSetDerivationData,
},
instructions::{
hash_vaa,
post_vaa,
serialize_vaa,
verify_signatures,
},
types::GuardianSetData,
PostVAAData,
VerifySignaturesData,
};
use service::{
agent_server::{
Agent,
AgentServer,
},
GetBalanceRequest,
GetBalanceResponse,
SubmitVaaRequest,
SubmitVaaResponse,
};
use solitaire::{
processors::seeded::Seeded,
AccountState,
}; };
mod socket; mod socket;
@ -38,7 +84,6 @@ pub mod service {
} }
pub struct AgentImpl { pub struct AgentImpl {
url: String,
bridge: Pubkey, bridge: Pubkey,
rpc_url: String, rpc_url: String,
@ -46,7 +91,7 @@ pub struct AgentImpl {
} }
pub struct SignatureItem { pub struct SignatureItem {
signature: [u8; 64 + 1], signature: Vec<u8>,
key: [u8; 20], key: [u8; 20],
index: u8, index: u8,
} }
@ -68,43 +113,46 @@ impl Agent for AgentImpl {
std::thread::spawn(move || { std::thread::spawn(move || {
let rpc = RpcClient::new(rpc_url); let rpc = RpcClient::new(rpc_url);
let mut vaa = match VAA::deserialize(&request.get_ref().vaa) { let vaa = &request.get_ref().vaa.as_ref().unwrap();
Ok(v) => v,
Err(e) => { let mut emitter_address = [0u8; 32];
return Err(Status::new( emitter_address.copy_from_slice(vaa.emitter_address.as_slice());
Code::InvalidArgument, let post_data = PostVAAData {
format!("could not parse VAA: {}", e), version: vaa.version as u8,
)); guardian_set_index: vaa.guardian_set_index,
} timestamp: vaa.timestamp.as_ref().unwrap().seconds as u32,
nonce: vaa.nonce,
emitter_chain: vaa.emitter_chain as u16,
emitter_address: emitter_address,
sequence: vaa.sequence,
payload: vaa.payload.clone(),
}; };
let verify_txs = pack_sig_verification_txs(&rpc, &bridge, &vaa, &key)?;
let verify_txs =
pack_sig_verification_txs(&rpc, &bridge, &post_data, &vaa.signatures, &key)?;
// Strip signatures // Strip signatures
vaa.signatures = Vec::new(); let ix = post_vaa(bridge, key.pubkey(), post_data);
let ix = match post_vaa(&bridge, &key.pubkey(), vaa.serialize().unwrap()) {
Ok(v) => v,
Err(e) => {
return Err(Status::new(
Code::InvalidArgument,
format!("could not create post_vaa instruction: {}", e),
));
}
};
for mut tx in verify_txs { for mut tx in verify_txs {
match sign_and_send(&rpc, &mut tx, vec![&key], request.skip_preflight) { match sign_and_send(&rpc, &mut tx, vec![&key], request.get_ref().skip_preflight) {
Ok(_) => (), Ok(_) => (),
Err(e) => { Err(e) => {
return Err(Status::new( return Err(Status::new(
Code::Internal, Code::Internal,
format!("tx sending failed: {}", e), format!("tx sending failed: {:?}", e),
)); ));
} }
}; };
} }
let mut transaction2 = Transaction::new_with_payer(&[ix], Some(&key.pubkey())); let mut transaction2 = Transaction::new_with_payer(&[ix], Some(&key.pubkey()));
match sign_and_send(&rpc, &mut transaction2, vec![&key], request.skip_preflight) { match sign_and_send(
&rpc,
&mut transaction2,
vec![&key],
request.into_inner().skip_preflight,
) {
Ok(s) => Ok(Response::new(SubmitVaaResponse { Ok(s) => Ok(Response::new(SubmitVaaResponse {
signature: s.to_string(), signature: s.to_string(),
})), })),
@ -120,7 +168,7 @@ impl Agent for AgentImpl {
async fn get_balance( async fn get_balance(
&self, &self,
request: Request<GetBalanceRequest>, _request: Request<GetBalanceRequest>,
) -> Result<Response<GetBalanceResponse>, Status> { ) -> Result<Response<GetBalanceResponse>, Status> {
// Hack to clone keypair // Hack to clone keypair
let b = self.key.pubkey(); let b = self.key.pubkey();
@ -136,14 +184,12 @@ impl Agent for AgentImpl {
Err(e) => { Err(e) => {
return Err(Status::new( return Err(Status::new(
Code::Internal, Code::Internal,
format!("failed to fetch balance: {}", e), format!("failed to fetch balance: {:?}", e),
)); ));
} }
}; };
Ok(Response::new(GetBalanceResponse { Ok(Response::new(GetBalanceResponse { balance }))
balance,
}))
}) })
.join() .join()
.unwrap() .unwrap()
@ -153,13 +199,17 @@ impl Agent for AgentImpl {
fn pack_sig_verification_txs<'a>( fn pack_sig_verification_txs<'a>(
rpc: &RpcClient, rpc: &RpcClient,
bridge: &Pubkey, bridge: &Pubkey,
vaa: &VAA, vaa: &PostVAAData,
signatures: &Vec<service::Signature>,
sender_keypair: &'a Keypair, sender_keypair: &'a Keypair,
) -> Result<Vec<Transaction>, Status> { ) -> Result<Vec<Transaction>, Status> {
// Load guardian set // Load guardian set
let bridge_key = Bridge::derive_bridge_id(bridge).unwrap(); let guardian_key = GuardianSet::<'_, { AccountState::Initialized }>::key(
let guardian_key = &GuardianSetDerivationData {
Bridge::derive_guardian_set_id(bridge, &bridge_key, vaa.guardian_set_index).unwrap(); index: vaa.guardian_set_index,
},
bridge,
);
let guardian_account = rpc let guardian_account = rpc
.get_account_with_commitment( .get_account_with_commitment(
&guardian_key, &guardian_key,
@ -171,78 +221,54 @@ fn pack_sig_verification_txs<'a>(
.value .value
.unwrap_or_default(); .unwrap_or_default();
let data = guardian_account.data; let data = guardian_account.data;
let guardian_set: &GuardianSet = Bridge::unpack_immutable(data.as_slice()).unwrap(); let guardian_set: GuardianSetData = GuardianSetData::try_from_slice(data.as_slice()).unwrap();
// Map signatures to guardian set // Map signatures to guardian set
let mut signature_items: Vec<SignatureItem> = Vec::new(); let mut signature_items: Vec<SignatureItem> = Vec::new();
for s in vaa.signatures.iter() { for s in signatures.iter() {
let mut item = SignatureItem { let mut item = SignatureItem {
signature: [0; 64 + 1], signature: s.signature.clone(),
key: [0; 20], key: [0; 20],
index: s.index, index: s.guardian_index as u8,
}; };
item.key = guardian_set.keys[s.guardian_index as usize];
item.signature[0..32].copy_from_slice(&s.r);
item.signature[32..64].copy_from_slice(&s.s);
item.signature[64] = s.v;
item.key = guardian_set.keys[s.index as usize];
signature_items.push(item); signature_items.push(item);
} }
let vaa_hash = match vaa.body_hash() { let vaa_body = serialize_vaa(vaa);
Ok(v) => v,
Err(e) => {
return Err(Status::new(
Code::InvalidArgument,
format!("could get vaa body hash: {}", e),
));
}
};
let vaa_body = match vaa.signature_body() {
Ok(v) => v,
Err(e) => {
return Err(Status::new(
Code::InvalidArgument,
format!("could get vaa body: {}", e),
));
}
};
let signature_acc =
Bridge::derive_signature_id(&bridge, &bridge_key, &vaa_hash, guardian_set.index).unwrap();
let mut verify_txs: Vec<Transaction> = Vec::new(); let mut verify_txs: Vec<Transaction> = Vec::new();
for (tx_index, chunk) in signature_items.chunks(6).enumerate() { for (_tx_index, chunk) in signature_items.chunks(6).enumerate() {
let mut secp_payload = Vec::new(); let mut secp_payload = Vec::new();
let mut signature_status = [-1i8; 20]; let mut signature_status = [-1i8; 19];
let data_offset = 1 + chunk.len() * 11; let data_offset = 1 + chunk.len() * 11;
let message_offset = data_offset + chunk.len() * 85; let message_offset = data_offset + chunk.len() * 85;
// 1 number of signatures // 1 number of signatures
secp_payload.write_u8(chunk.len() as u8); secp_payload.write_u8(chunk.len() as u8)?;
// Secp signature info description (11 bytes * n) // Secp signature info description (11 bytes * n)
for (i, s) in chunk.iter().enumerate() { for (i, s) in chunk.iter().enumerate() {
secp_payload.write_u16::<LittleEndian>((data_offset + 85 * i) as u16); secp_payload.write_u16::<LittleEndian>((data_offset + 85 * i) as u16)?;
secp_payload.write_u8(0); secp_payload.write_u8(0)?;
secp_payload.write_u16::<LittleEndian>((data_offset + 85 * i + 65) as u16); secp_payload.write_u16::<LittleEndian>((data_offset + 85 * i + 65) as u16)?;
secp_payload.write_u8(0); secp_payload.write_u8(0)?;
secp_payload.write_u16::<LittleEndian>(message_offset as u16); secp_payload.write_u16::<LittleEndian>(message_offset as u16)?;
secp_payload.write_u16::<LittleEndian>(vaa_body.len() as u16); secp_payload.write_u16::<LittleEndian>(vaa_body.len() as u16)?;
secp_payload.write_u8(0); secp_payload.write_u8(0)?;
signature_status[s.index as usize] = i as i8; signature_status[s.index as usize] = i as i8;
} }
// Write signatures and addresses // Write signatures and addresses
for s in chunk.iter() { for s in chunk.iter() {
secp_payload.write(&s.signature); secp_payload.write(&s.signature)?;
secp_payload.write(&s.key); secp_payload.write(&s.key)?;
} }
// Write body // Write body
secp_payload.write(&vaa_body); secp_payload.write(&vaa_body)?;
let secp_ix = Instruction { let secp_ix = Instruction {
program_id: solana_sdk::secp256k1_program::id(), program_id: solana_sdk::secp256k1_program::id(),
@ -250,24 +276,25 @@ fn pack_sig_verification_txs<'a>(
accounts: vec![], accounts: vec![],
}; };
let payload = VerifySigPayload { let body_hash: [u8; 32] = hash_vaa(vaa);
let payload = VerifySignaturesData {
signers: signature_status, signers: signature_status,
hash: vaa_hash, hash: body_hash,
initial_creation: false, initial_creation: false,
}; };
let verify_ix = match verify_signatures( let verify_ix = match verify_signatures(
&bridge, *bridge,
&signature_acc, sender_keypair.pubkey(),
&sender_keypair.pubkey(),
vaa.guardian_set_index, vaa.guardian_set_index,
&payload, payload,
) { ) {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
return Err(Status::new( return Err(Status::new(
Code::InvalidArgument, Code::InvalidArgument,
format!("could not create verify instruction: {}", e), format!("could not create verify instruction: {:?}", e),
)); ));
} }
}; };
@ -307,40 +334,49 @@ fn sign_and_send(
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
let matches = App::new("Wormhole Solana agent") let matches = App::new("Wormhole Solana agent")
.arg(Arg::with_name("bridge") .arg(
Arg::with_name("bridge")
.long("bridge") .long("bridge")
.value_name("ADDRESS") .value_name("ADDRESS")
.help("Bridge address") .help("Bridge address")
.required(true) .required(true)
.takes_value(true)) .takes_value(true),
.arg(Arg::with_name("ws") )
.arg(
Arg::with_name("ws")
.long("ws") .long("ws")
.value_name("URI") .value_name("URI")
.help("PubSub Websocket URI (ws[s]://)") .help("PubSub Websocket URI (ws[s]://)")
.required(true) .required(true)
.takes_value(true)) .takes_value(true),
.arg(Arg::with_name("rpc") )
.arg(
Arg::with_name("rpc")
.long("rpc") .long("rpc")
.value_name("URI") .value_name("URI")
.help("RPC URI (http[s]://)") .help("RPC URI (http[s]://)")
.required(true) .required(true)
.takes_value(true)) .takes_value(true),
.arg(Arg::with_name("socket") )
.arg(
Arg::with_name("socket")
.long("socket") .long("socket")
.value_name("FILE") .value_name("FILE")
.help("Path to agent socket") .help("Path to agent socket")
.required(true) .required(true)
.takes_value(true)) .takes_value(true),
.arg(Arg::with_name("keypair") )
.arg(
Arg::with_name("keypair")
.long("keypair") .long("keypair")
.value_name("FILE") .value_name("FILE")
.help("Fee payer account key ") .help("Fee payer account key ")
.required(true) .required(true)
.takes_value(true)) .takes_value(true),
)
.get_matches(); .get_matches();
let bridge = matches.value_of("bridge").unwrap(); let bridge = matches.value_of("bridge").unwrap();
let ws_url = matches.value_of("ws").unwrap();
let rpc_url = matches.value_of("rpc").unwrap(); let rpc_url = matches.value_of("rpc").unwrap();
let socket_path = matches.value_of("socket").unwrap(); let socket_path = matches.value_of("socket").unwrap();
let keypair = read_keypair_file(matches.value_of("keypair").unwrap()).unwrap(); let keypair = read_keypair_file(matches.value_of("keypair").unwrap()).unwrap();
@ -348,7 +384,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Agent using account: {}", keypair.pubkey()); println!("Agent using account: {}", keypair.pubkey());
let agent = AgentImpl { let agent = AgentImpl {
url: ws_url.to_string(),
rpc_url: rpc_url.to_string(), rpc_url: rpc_url.to_string(),
bridge: Pubkey::from_str(bridge).unwrap(), bridge: Pubkey::from_str(bridge).unwrap(),
key: keypair, key: keypair,
@ -359,7 +394,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
unsafe { libc::umask(0o0077) }; unsafe { libc::umask(0o0077) };
// Delete existing socket file and recreate it with restrictive permissions. // Delete existing socket file and recreate it with restrictive permissions.
let mut path = Path::new(socket_path); let path = Path::new(socket_path);
if path.exists() { if path.exists() {
fs::remove_file(path)?; fs::remove_file(path)?;
} }

View File

@ -100,7 +100,6 @@ pub struct PostVAAData {
// Header part // Header part
pub version: u8, pub version: u8,
pub guardian_set_index: u32, pub guardian_set_index: u32,
pub signatures: Vec<Signature>,
// Body part // Body part
pub timestamp: u32, pub timestamp: u32,

View File

@ -1,18 +1,10 @@
use borsh::BorshSerialize; use borsh::BorshSerialize;
use solana_program::{ use solana_program::{
borsh::try_from_slice_unchecked,
hash,
instruction::{ instruction::{
AccountMeta, AccountMeta,
Instruction, Instruction,
}, },
program_pack::Pack,
pubkey::Pubkey, pubkey::Pubkey,
system_instruction::{
self,
create_account,
},
system_program,
sysvar, sysvar,
}; };
@ -34,7 +26,6 @@ use crate::{
SignatureSet, SignatureSet,
SignatureSetDerivationData, SignatureSetDerivationData,
}, },
types::PostedMessage,
BridgeConfig, BridgeConfig,
PostMessageData, PostMessageData,
PostVAAData, PostVAAData,
@ -124,7 +115,7 @@ pub fn verify_signatures(
program_id: Pubkey, program_id: Pubkey,
payer: Pubkey, payer: Pubkey,
guardian_set_index: u32, guardian_set_index: u32,
hash: [u8; 32], data: VerifySignaturesData,
) -> solitaire::Result<Instruction> { ) -> solitaire::Result<Instruction> {
let guardian_set = GuardianSet::<'_, { AccountState::Uninitialized }>::key( let guardian_set = GuardianSet::<'_, { AccountState::Uninitialized }>::key(
&GuardianSetDerivationData { &GuardianSetDerivationData {
@ -134,15 +125,10 @@ pub fn verify_signatures(
); );
let signature_set = SignatureSet::<'_, { AccountState::Uninitialized }>::key( let signature_set = SignatureSet::<'_, { AccountState::Uninitialized }>::key(
&SignatureSetDerivationData { hash }, &SignatureSetDerivationData { hash: data.hash },
&program_id, &program_id,
); );
// Bridge with a single pre-existing signer.
// TODO: Get rid of this, exists to make testing easier for now.
let mut signers = [-1; 19];
signers[0] = 0;
Ok(Instruction { Ok(Instruction {
program_id, program_id,
@ -155,40 +141,31 @@ pub fn verify_signatures(
AccountMeta::new_readonly(solana_program::system_program::id(), false), AccountMeta::new_readonly(solana_program::system_program::id(), false),
], ],
data: crate::instruction::Instruction::VerifySignatures(VerifySignaturesData { data: crate::instruction::Instruction::VerifySignatures(data).try_to_vec()?,
hash,
signers,
initial_creation: true,
})
.try_to_vec()?,
}) })
} }
pub fn post_vaa( pub fn post_vaa(program_id: Pubkey, payer: Pubkey, vaa: PostVAAData) -> Instruction {
program_id: Pubkey,
payer: Pubkey,
emitter: Pubkey,
guardian_set_index: u32,
vaa: PostVAAData,
) -> Instruction {
let bridge = Bridge::<'_, { AccountState::Uninitialized }>::key(None, &program_id); let bridge = Bridge::<'_, { AccountState::Uninitialized }>::key(None, &program_id);
let guardian_set = GuardianSet::<'_, { AccountState::Uninitialized }>::key( let guardian_set = GuardianSet::<'_, { AccountState::Uninitialized }>::key(
&GuardianSetDerivationData { &GuardianSetDerivationData {
index: guardian_set_index, index: vaa.guardian_set_index,
}, },
&program_id, &program_id,
); );
let signature_set = SignatureSet::<'_, { AccountState::Uninitialized }>::key( let signature_set = SignatureSet::<'_, { AccountState::Uninitialized }>::key(
&SignatureSetDerivationData { hash: hash_vaa(&vaa) }, &SignatureSetDerivationData {
hash: hash_vaa(&vaa),
},
&program_id, &program_id,
); );
let message = Message::<'_, { AccountState::MaybeInitialized }>::key( let message = Message::<'_, { AccountState::MaybeInitialized }>::key(
&MessageDerivationData { &MessageDerivationData {
emitter_key: emitter.to_bytes(), emitter_key: vaa.emitter_address,
emitter_chain: 1, emitter_chain: vaa.emitter_chain,
nonce: 0, nonce: vaa.nonce,
payload: vaa.payload.clone(), payload: vaa.payload.clone(),
}, },
&program_id, &program_id,
@ -216,7 +193,7 @@ pub fn post_vaa(
// Convert a full VAA structure into the serialization of its unique components, this structure is // Convert a full VAA structure into the serialization of its unique components, this structure is
// what is hashed and verified by Guardians. // what is hashed and verified by Guardians.
fn serialize_vaa(vaa: &PostVAAData) -> Vec<u8> { pub fn serialize_vaa(vaa: &PostVAAData) -> Vec<u8> {
use byteorder::{ use byteorder::{
BigEndian, BigEndian,
WriteBytesExt, WriteBytesExt,
@ -231,12 +208,13 @@ fn serialize_vaa(vaa: &PostVAAData) -> Vec<u8> {
v.write_u32::<BigEndian>(vaa.nonce).unwrap(); v.write_u32::<BigEndian>(vaa.nonce).unwrap();
v.write_u16::<BigEndian>(vaa.emitter_chain).unwrap(); v.write_u16::<BigEndian>(vaa.emitter_chain).unwrap();
v.write(&vaa.emitter_address).unwrap(); v.write(&vaa.emitter_address).unwrap();
v.write_u64::<BigEndian>(vaa.sequence).unwrap();
v.write(&vaa.payload).unwrap(); v.write(&vaa.payload).unwrap();
v.into_inner() v.into_inner()
} }
// Hash a VAA, this combines serialization and hashing. // Hash a VAA, this combines serialization and hashing.
fn hash_vaa(vaa: &PostVAAData) -> [u8; 32] { pub fn hash_vaa(vaa: &PostVAAData) -> [u8; 32] {
use sha3::Digest; use sha3::Digest;
use std::io::Write; use std::io::Write;

View File

@ -1,5 +1,6 @@
#![feature(const_generics)] #![feature(const_generics)]
#![allow(non_upper_case_globals)] #![allow(non_upper_case_globals)]
#![allow(incomplete_features)]
use solana_program::msg; use solana_program::msg;

View File

@ -164,13 +164,20 @@ mod helpers {
body_hash: [u8; 32], body_hash: [u8; 32],
secret_key: SecretKey, secret_key: SecretKey,
) { ) {
let mut signers = [-1; 19];
signers[0] = 0;
execute( execute(
client, client,
payer, payer,
&[payer], &[payer],
&[ &[
new_secp256k1_instruction(&secret_key, &body), new_secp256k1_instruction(&secret_key, &body),
instructions::verify_signatures(*program, payer.pubkey(), 0, body_hash).unwrap(), instructions::verify_signatures(*program, payer.pubkey(), 0, VerifySignaturesData {
hash: body_hash,
signers,
initial_creation: true,
}).unwrap(),
], ],
); );
} }
@ -179,7 +186,6 @@ mod helpers {
client: &RpcClient, client: &RpcClient,
program: &Pubkey, program: &Pubkey,
payer: &Keypair, payer: &Keypair,
emitter: &Pubkey,
vaa: PostVAAData, vaa: PostVAAData,
) { ) {
execute( execute(
@ -189,8 +195,6 @@ mod helpers {
&[instructions::post_vaa( &[instructions::post_vaa(
*program, *program,
payer.pubkey(), payer.pubkey(),
*emitter,
0,
vaa, vaa,
)], )],
); );

View File

@ -112,7 +112,6 @@ fn test_bridge_messages() {
client, client,
program, program,
payer, payer,
&emitter.pubkey(),
vaa, vaa,
); );
@ -123,12 +122,11 @@ fn test_bridge_messages() {
/// is on the chain and creating a signature set for it. /// is on the chain and creating a signature set for it.
fn guardian_sign_round( fn guardian_sign_round(
emitter: &Keypair, emitter: &Keypair,
data: Vec<u8> data: Vec<u8>,
) -> (PostVAAData, Vec<u8>, [u8; 32], secp256k1::SecretKey) { ) -> (PostVAAData, Vec<u8>, [u8; 32], secp256k1::SecretKey) {
let mut vaa = PostVAAData { let mut vaa = PostVAAData {
version: 0, version: 0,
guardian_set_index: 0, guardian_set_index: 0,
signatures: vec![],
// Body part // Body part
nonce: 0, nonce: 0,