Adapt solana agent for v2
Change-Id: I81fc8b959f33a157371d1c59b1d5323dfc11f1ce
This commit is contained in:
parent
a341c2a5b5
commit
6d1b3d2651
|
@ -2,6 +2,7 @@ syntax = "proto3";
|
|||
|
||||
package agent.v1;
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
// TODO: documentation
|
||||
|
||||
option go_package = "github.com/certusone/wormhole/bridge/pkg/proto/agent/v1;agentv1";
|
||||
|
@ -15,10 +16,27 @@ message Empty {
|
|||
}
|
||||
|
||||
message SubmitVAARequest {
|
||||
bytes vaa = 1;
|
||||
VAA vaa = 1;
|
||||
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 {
|
||||
string signature = 1;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
|||
name = "agent"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"bridge",
|
||||
"bs58",
|
||||
"byteorder",
|
||||
|
@ -46,6 +47,7 @@ dependencies = [
|
|||
"serde_bytes",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"sha3",
|
||||
"solana-client",
|
||||
"solana-program",
|
||||
"solana-sdk",
|
||||
|
|
|
@ -14,7 +14,7 @@ solana-program = "=1.7.0"
|
|||
solana-sdk = "=1.7.0"
|
||||
solitaire = { path = "../../solitaire/program" }
|
||||
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" }
|
||||
hex = "0.4.2"
|
||||
thiserror = "1.0.20"
|
||||
|
@ -26,10 +26,12 @@ log = "0.4.11"
|
|||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.57"
|
||||
bs58 = "0.3.1"
|
||||
byteorder = "1.3.4"
|
||||
byteorder = "1.4.3"
|
||||
futures = "0.3.8"
|
||||
libc = "0.2.80"
|
||||
clap = "2.33.3"
|
||||
borsh = "0.8.1"
|
||||
sha3 = "0.9.1"
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = { version = "0.3.0", features = ["prost"] }
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
fn main() {
|
||||
tonic_build::compile_protos("../../proto/agent/v1/service.proto").unwrap();
|
||||
tonic_build::compile_protos("../../../proto/agent/v1/service.proto").unwrap();
|
||||
}
|
||||
|
|
|
@ -1,34 +1,80 @@
|
|||
use std::{env, io::Write, mem::size_of, str::FromStr, fs};
|
||||
use std::path::Path;
|
||||
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 solana_client::{
|
||||
client_error::ClientError, rpc_client::RpcClient, rpc_config::RpcSendTransactionConfig,
|
||||
client_error::ClientError,
|
||||
rpc_client::RpcClient,
|
||||
rpc_config::RpcSendTransactionConfig,
|
||||
};
|
||||
use solana_sdk::{
|
||||
commitment_config::{CommitmentConfig, CommitmentLevel},
|
||||
commitment_config::{
|
||||
CommitmentConfig,
|
||||
CommitmentLevel,
|
||||
},
|
||||
instruction::Instruction,
|
||||
pubkey::Pubkey,
|
||||
signature::{read_keypair_file, write_keypair_file, Keypair, Signature, Signer},
|
||||
signature::{
|
||||
read_keypair_file,
|
||||
Keypair,
|
||||
Signature,
|
||||
Signer,
|
||||
},
|
||||
transaction::Transaction,
|
||||
};
|
||||
use tokio::net::UnixListener;
|
||||
use tokio::sync::mpsc;
|
||||
use tonic::{transport::Server, Code, Request, Response, Status};
|
||||
|
||||
use service::{
|
||||
agent_server::{Agent, AgentServer},
|
||||
Empty,SubmitVaaRequest, SubmitVaaResponse,
|
||||
GetBalanceResponse, GetBalanceRequest,
|
||||
use tonic::{
|
||||
transport::Server,
|
||||
Code,
|
||||
Request,
|
||||
Response,
|
||||
Status,
|
||||
};
|
||||
use spl_bridge::{
|
||||
instruction::{post_vaa, verify_signatures, VerifySigPayload, CHAIN_ID_SOLANA},
|
||||
state::{Bridge, GuardianSet, PostedMessage},
|
||||
vaa::VAA,
|
||||
|
||||
use borsh::BorshDeserialize;
|
||||
use bridge::{
|
||||
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;
|
||||
|
@ -38,7 +84,6 @@ pub mod service {
|
|||
}
|
||||
|
||||
pub struct AgentImpl {
|
||||
url: String,
|
||||
bridge: Pubkey,
|
||||
|
||||
rpc_url: String,
|
||||
|
@ -46,7 +91,7 @@ pub struct AgentImpl {
|
|||
}
|
||||
|
||||
pub struct SignatureItem {
|
||||
signature: [u8; 64 + 1],
|
||||
signature: Vec<u8>,
|
||||
key: [u8; 20],
|
||||
index: u8,
|
||||
}
|
||||
|
@ -68,43 +113,46 @@ impl Agent for AgentImpl {
|
|||
std::thread::spawn(move || {
|
||||
let rpc = RpcClient::new(rpc_url);
|
||||
|
||||
let mut vaa = match VAA::deserialize(&request.get_ref().vaa) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return Err(Status::new(
|
||||
Code::InvalidArgument,
|
||||
format!("could not parse VAA: {}", e),
|
||||
));
|
||||
}
|
||||
let vaa = &request.get_ref().vaa.as_ref().unwrap();
|
||||
|
||||
let mut emitter_address = [0u8; 32];
|
||||
emitter_address.copy_from_slice(vaa.emitter_address.as_slice());
|
||||
let post_data = PostVAAData {
|
||||
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
|
||||
vaa.signatures = Vec::new();
|
||||
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),
|
||||
));
|
||||
}
|
||||
};
|
||||
let ix = post_vaa(bridge, key.pubkey(), post_data);
|
||||
|
||||
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(_) => (),
|
||||
Err(e) => {
|
||||
return Err(Status::new(
|
||||
Code::Internal,
|
||||
format!("tx sending failed: {}", e),
|
||||
format!("tx sending failed: {:?}", e),
|
||||
));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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 {
|
||||
signature: s.to_string(),
|
||||
})),
|
||||
|
@ -114,13 +162,13 @@ impl Agent for AgentImpl {
|
|||
)),
|
||||
}
|
||||
})
|
||||
.join()
|
||||
.unwrap()
|
||||
.join()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
async fn get_balance(
|
||||
&self,
|
||||
request: Request<GetBalanceRequest>,
|
||||
_request: Request<GetBalanceRequest>,
|
||||
) -> Result<Response<GetBalanceResponse>, Status> {
|
||||
// Hack to clone keypair
|
||||
let b = self.key.pubkey();
|
||||
|
@ -136,30 +184,32 @@ impl Agent for AgentImpl {
|
|||
Err(e) => {
|
||||
return Err(Status::new(
|
||||
Code::Internal,
|
||||
format!("failed to fetch balance: {}", e),
|
||||
format!("failed to fetch balance: {:?}", e),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Response::new(GetBalanceResponse {
|
||||
balance,
|
||||
}))
|
||||
Ok(Response::new(GetBalanceResponse { balance }))
|
||||
})
|
||||
.join()
|
||||
.unwrap()
|
||||
.join()
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn pack_sig_verification_txs<'a>(
|
||||
rpc: &RpcClient,
|
||||
bridge: &Pubkey,
|
||||
vaa: &VAA,
|
||||
vaa: &PostVAAData,
|
||||
signatures: &Vec<service::Signature>,
|
||||
sender_keypair: &'a Keypair,
|
||||
) -> Result<Vec<Transaction>, Status> {
|
||||
// Load guardian set
|
||||
let bridge_key = Bridge::derive_bridge_id(bridge).unwrap();
|
||||
let guardian_key =
|
||||
Bridge::derive_guardian_set_id(bridge, &bridge_key, vaa.guardian_set_index).unwrap();
|
||||
let guardian_key = GuardianSet::<'_, { AccountState::Initialized }>::key(
|
||||
&GuardianSetDerivationData {
|
||||
index: vaa.guardian_set_index,
|
||||
},
|
||||
bridge,
|
||||
);
|
||||
let guardian_account = rpc
|
||||
.get_account_with_commitment(
|
||||
&guardian_key,
|
||||
|
@ -171,78 +221,54 @@ fn pack_sig_verification_txs<'a>(
|
|||
.value
|
||||
.unwrap_or_default();
|
||||
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
|
||||
let mut signature_items: Vec<SignatureItem> = Vec::new();
|
||||
for s in vaa.signatures.iter() {
|
||||
for s in signatures.iter() {
|
||||
let mut item = SignatureItem {
|
||||
signature: [0; 64 + 1],
|
||||
signature: s.signature.clone(),
|
||||
key: [0; 20],
|
||||
index: s.index,
|
||||
index: s.guardian_index as u8,
|
||||
};
|
||||
|
||||
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];
|
||||
item.key = guardian_set.keys[s.guardian_index as usize];
|
||||
|
||||
signature_items.push(item);
|
||||
}
|
||||
|
||||
let vaa_hash = match vaa.body_hash() {
|
||||
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 vaa_body = serialize_vaa(vaa);
|
||||
|
||||
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 signature_status = [-1i8; 20];
|
||||
let mut signature_status = [-1i8; 19];
|
||||
|
||||
let data_offset = 1 + chunk.len() * 11;
|
||||
let message_offset = data_offset + chunk.len() * 85;
|
||||
|
||||
// 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)
|
||||
for (i, s) in chunk.iter().enumerate() {
|
||||
secp_payload.write_u16::<LittleEndian>((data_offset + 85 * i) as u16);
|
||||
secp_payload.write_u8(0);
|
||||
secp_payload.write_u16::<LittleEndian>((data_offset + 85 * i + 65) as u16);
|
||||
secp_payload.write_u8(0);
|
||||
secp_payload.write_u16::<LittleEndian>(message_offset as u16);
|
||||
secp_payload.write_u16::<LittleEndian>(vaa_body.len() as u16);
|
||||
secp_payload.write_u8(0);
|
||||
secp_payload.write_u16::<LittleEndian>((data_offset + 85 * i) as u16)?;
|
||||
secp_payload.write_u8(0)?;
|
||||
secp_payload.write_u16::<LittleEndian>((data_offset + 85 * i + 65) as u16)?;
|
||||
secp_payload.write_u8(0)?;
|
||||
secp_payload.write_u16::<LittleEndian>(message_offset as u16)?;
|
||||
secp_payload.write_u16::<LittleEndian>(vaa_body.len() as u16)?;
|
||||
secp_payload.write_u8(0)?;
|
||||
signature_status[s.index as usize] = i as i8;
|
||||
}
|
||||
|
||||
// Write signatures and addresses
|
||||
for s in chunk.iter() {
|
||||
secp_payload.write(&s.signature);
|
||||
secp_payload.write(&s.key);
|
||||
secp_payload.write(&s.signature)?;
|
||||
secp_payload.write(&s.key)?;
|
||||
}
|
||||
|
||||
// Write body
|
||||
secp_payload.write(&vaa_body);
|
||||
secp_payload.write(&vaa_body)?;
|
||||
|
||||
let secp_ix = Instruction {
|
||||
program_id: solana_sdk::secp256k1_program::id(),
|
||||
|
@ -250,24 +276,25 @@ fn pack_sig_verification_txs<'a>(
|
|||
accounts: vec![],
|
||||
};
|
||||
|
||||
let payload = VerifySigPayload {
|
||||
let body_hash: [u8; 32] = hash_vaa(vaa);
|
||||
|
||||
let payload = VerifySignaturesData {
|
||||
signers: signature_status,
|
||||
hash: vaa_hash,
|
||||
hash: body_hash,
|
||||
initial_creation: false,
|
||||
};
|
||||
|
||||
let verify_ix = match verify_signatures(
|
||||
&bridge,
|
||||
&signature_acc,
|
||||
&sender_keypair.pubkey(),
|
||||
*bridge,
|
||||
sender_keypair.pubkey(),
|
||||
vaa.guardian_set_index,
|
||||
&payload,
|
||||
payload,
|
||||
) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return Err(Status::new(
|
||||
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]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let matches = App::new("Wormhole Solana agent")
|
||||
.arg(Arg::with_name("bridge")
|
||||
.long("bridge")
|
||||
.value_name("ADDRESS")
|
||||
.help("Bridge address")
|
||||
.required(true)
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("ws")
|
||||
.long("ws")
|
||||
.value_name("URI")
|
||||
.help("PubSub Websocket URI (ws[s]://)")
|
||||
.required(true)
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("rpc")
|
||||
.long("rpc")
|
||||
.value_name("URI")
|
||||
.help("RPC URI (http[s]://)")
|
||||
.required(true)
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("socket")
|
||||
.long("socket")
|
||||
.value_name("FILE")
|
||||
.help("Path to agent socket")
|
||||
.required(true)
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("keypair")
|
||||
.long("keypair")
|
||||
.value_name("FILE")
|
||||
.help("Fee payer account key ")
|
||||
.required(true)
|
||||
.takes_value(true))
|
||||
.arg(
|
||||
Arg::with_name("bridge")
|
||||
.long("bridge")
|
||||
.value_name("ADDRESS")
|
||||
.help("Bridge address")
|
||||
.required(true)
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("ws")
|
||||
.long("ws")
|
||||
.value_name("URI")
|
||||
.help("PubSub Websocket URI (ws[s]://)")
|
||||
.required(true)
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("rpc")
|
||||
.long("rpc")
|
||||
.value_name("URI")
|
||||
.help("RPC URI (http[s]://)")
|
||||
.required(true)
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("socket")
|
||||
.long("socket")
|
||||
.value_name("FILE")
|
||||
.help("Path to agent socket")
|
||||
.required(true)
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("keypair")
|
||||
.long("keypair")
|
||||
.value_name("FILE")
|
||||
.help("Fee payer account key ")
|
||||
.required(true)
|
||||
.takes_value(true),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let bridge = matches.value_of("bridge").unwrap();
|
||||
let ws_url = matches.value_of("ws").unwrap();
|
||||
let rpc_url = matches.value_of("rpc").unwrap();
|
||||
let socket_path = matches.value_of("socket").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());
|
||||
|
||||
let agent = AgentImpl {
|
||||
url: ws_url.to_string(),
|
||||
rpc_url: rpc_url.to_string(),
|
||||
bridge: Pubkey::from_str(bridge).unwrap(),
|
||||
key: keypair,
|
||||
|
@ -359,7 +394,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
unsafe { libc::umask(0o0077) };
|
||||
|
||||
// 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() {
|
||||
fs::remove_file(path)?;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,6 @@ pub struct PostVAAData {
|
|||
// Header part
|
||||
pub version: u8,
|
||||
pub guardian_set_index: u32,
|
||||
pub signatures: Vec<Signature>,
|
||||
|
||||
// Body part
|
||||
pub timestamp: u32,
|
||||
|
|
|
@ -1,18 +1,10 @@
|
|||
use borsh::BorshSerialize;
|
||||
use solana_program::{
|
||||
borsh::try_from_slice_unchecked,
|
||||
hash,
|
||||
instruction::{
|
||||
AccountMeta,
|
||||
Instruction,
|
||||
},
|
||||
program_pack::Pack,
|
||||
pubkey::Pubkey,
|
||||
system_instruction::{
|
||||
self,
|
||||
create_account,
|
||||
},
|
||||
system_program,
|
||||
sysvar,
|
||||
};
|
||||
|
||||
|
@ -34,7 +26,6 @@ use crate::{
|
|||
SignatureSet,
|
||||
SignatureSetDerivationData,
|
||||
},
|
||||
types::PostedMessage,
|
||||
BridgeConfig,
|
||||
PostMessageData,
|
||||
PostVAAData,
|
||||
|
@ -124,7 +115,7 @@ pub fn verify_signatures(
|
|||
program_id: Pubkey,
|
||||
payer: Pubkey,
|
||||
guardian_set_index: u32,
|
||||
hash: [u8; 32],
|
||||
data: VerifySignaturesData,
|
||||
) -> solitaire::Result<Instruction> {
|
||||
let guardian_set = GuardianSet::<'_, { AccountState::Uninitialized }>::key(
|
||||
&GuardianSetDerivationData {
|
||||
|
@ -134,15 +125,10 @@ pub fn verify_signatures(
|
|||
);
|
||||
|
||||
let signature_set = SignatureSet::<'_, { AccountState::Uninitialized }>::key(
|
||||
&SignatureSetDerivationData { hash },
|
||||
&SignatureSetDerivationData { hash: data.hash },
|
||||
&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 {
|
||||
program_id,
|
||||
|
||||
|
@ -155,40 +141,31 @@ pub fn verify_signatures(
|
|||
AccountMeta::new_readonly(solana_program::system_program::id(), false),
|
||||
],
|
||||
|
||||
data: crate::instruction::Instruction::VerifySignatures(VerifySignaturesData {
|
||||
hash,
|
||||
signers,
|
||||
initial_creation: true,
|
||||
})
|
||||
.try_to_vec()?,
|
||||
data: crate::instruction::Instruction::VerifySignatures(data).try_to_vec()?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn post_vaa(
|
||||
program_id: Pubkey,
|
||||
payer: Pubkey,
|
||||
emitter: Pubkey,
|
||||
guardian_set_index: u32,
|
||||
vaa: PostVAAData,
|
||||
) -> Instruction {
|
||||
pub fn post_vaa(program_id: Pubkey, payer: Pubkey, vaa: PostVAAData) -> Instruction {
|
||||
let bridge = Bridge::<'_, { AccountState::Uninitialized }>::key(None, &program_id);
|
||||
let guardian_set = GuardianSet::<'_, { AccountState::Uninitialized }>::key(
|
||||
&GuardianSetDerivationData {
|
||||
index: guardian_set_index,
|
||||
index: vaa.guardian_set_index,
|
||||
},
|
||||
&program_id,
|
||||
);
|
||||
|
||||
let signature_set = SignatureSet::<'_, { AccountState::Uninitialized }>::key(
|
||||
&SignatureSetDerivationData { hash: hash_vaa(&vaa) },
|
||||
&SignatureSetDerivationData {
|
||||
hash: hash_vaa(&vaa),
|
||||
},
|
||||
&program_id,
|
||||
);
|
||||
|
||||
let message = Message::<'_, { AccountState::MaybeInitialized }>::key(
|
||||
&MessageDerivationData {
|
||||
emitter_key: emitter.to_bytes(),
|
||||
emitter_chain: 1,
|
||||
nonce: 0,
|
||||
emitter_key: vaa.emitter_address,
|
||||
emitter_chain: vaa.emitter_chain,
|
||||
nonce: vaa.nonce,
|
||||
payload: vaa.payload.clone(),
|
||||
},
|
||||
&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
|
||||
// what is hashed and verified by Guardians.
|
||||
fn serialize_vaa(vaa: &PostVAAData) -> Vec<u8> {
|
||||
pub fn serialize_vaa(vaa: &PostVAAData) -> Vec<u8> {
|
||||
use byteorder::{
|
||||
BigEndian,
|
||||
WriteBytesExt,
|
||||
|
@ -231,12 +208,13 @@ fn serialize_vaa(vaa: &PostVAAData) -> Vec<u8> {
|
|||
v.write_u32::<BigEndian>(vaa.nonce).unwrap();
|
||||
v.write_u16::<BigEndian>(vaa.emitter_chain).unwrap();
|
||||
v.write(&vaa.emitter_address).unwrap();
|
||||
v.write_u64::<BigEndian>(vaa.sequence).unwrap();
|
||||
v.write(&vaa.payload).unwrap();
|
||||
v.into_inner()
|
||||
}
|
||||
|
||||
// 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 std::io::Write;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#![feature(const_generics)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
use solana_program::msg;
|
||||
|
||||
|
|
|
@ -152,7 +152,7 @@ mod helpers {
|
|||
0,
|
||||
data,
|
||||
)
|
||||
.unwrap()],
|
||||
.unwrap()],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -164,13 +164,20 @@ mod helpers {
|
|||
body_hash: [u8; 32],
|
||||
secret_key: SecretKey,
|
||||
) {
|
||||
let mut signers = [-1; 19];
|
||||
signers[0] = 0;
|
||||
|
||||
execute(
|
||||
client,
|
||||
payer,
|
||||
&[payer],
|
||||
&[
|
||||
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,
|
||||
program: &Pubkey,
|
||||
payer: &Keypair,
|
||||
emitter: &Pubkey,
|
||||
vaa: PostVAAData,
|
||||
) {
|
||||
execute(
|
||||
|
@ -189,8 +195,6 @@ mod helpers {
|
|||
&[instructions::post_vaa(
|
||||
*program,
|
||||
payer.pubkey(),
|
||||
*emitter,
|
||||
0,
|
||||
vaa,
|
||||
)],
|
||||
);
|
||||
|
|
|
@ -112,7 +112,6 @@ fn test_bridge_messages() {
|
|||
client,
|
||||
program,
|
||||
payer,
|
||||
&emitter.pubkey(),
|
||||
vaa,
|
||||
);
|
||||
|
||||
|
@ -123,12 +122,11 @@ fn test_bridge_messages() {
|
|||
/// is on the chain and creating a signature set for it.
|
||||
fn guardian_sign_round(
|
||||
emitter: &Keypair,
|
||||
data: Vec<u8>
|
||||
data: Vec<u8>,
|
||||
) -> (PostVAAData, Vec<u8>, [u8; 32], secp256k1::SecretKey) {
|
||||
let mut vaa = PostVAAData {
|
||||
version: 0,
|
||||
guardian_set_index: 0,
|
||||
signatures: vec![],
|
||||
|
||||
// Body part
|
||||
nonce: 0,
|
||||
|
@ -155,9 +153,9 @@ fn guardian_sign_round(
|
|||
|
||||
// Public Key: 0x1d72877eb2d898738afe94c6101152ede0435de9
|
||||
let secret_key = secp256k1::SecretKey::parse(&[
|
||||
0x99, 0x70, 0x1c, 0x80, 0x5e, 0xf9, 0x38, 0xe1, 0x3f, 0x0e, 0x48, 0xf0, 0x9e, 0x2c, 0x32,
|
||||
0x78, 0x91, 0xc1, 0xd8, 0x47, 0x29, 0xd1, 0x52, 0xf3, 0x01, 0xe7, 0xe6, 0x2c, 0xbf, 0x1f,
|
||||
0x91, 0xc9
|
||||
0x99, 0x70, 0x1c, 0x80, 0x5e, 0xf9, 0x38, 0xe1, 0x3f, 0x0e, 0x48, 0xf0, 0x9e, 0x2c, 0x32,
|
||||
0x78, 0x91, 0xc1, 0xd8, 0x47, 0x29, 0xd1, 0x52, 0xf3, 0x01, 0xe7, 0xe6, 0x2c, 0xbf, 0x1f,
|
||||
0x91, 0xc9
|
||||
]).unwrap();
|
||||
|
||||
let public_key = secp256k1::PublicKey::from_secret_key(&secret_key);
|
||||
|
@ -181,9 +179,9 @@ fn guardian_sign_round(
|
|||
let signature = sig.0.serialize();
|
||||
vaa.signatures.push(Signature {
|
||||
index: 0,
|
||||
r: signature[0..32].try_into().unwrap(),
|
||||
s: signature[32..64].try_into().unwrap(),
|
||||
v: sig.1.serialize(),
|
||||
r: signature[0..32].try_into().unwrap(),
|
||||
s: signature[32..64].try_into().unwrap(),
|
||||
v: sig.1.serialize(),
|
||||
});
|
||||
|
||||
(vaa, body, body_hash, secret_key)
|
||||
|
|
Loading…
Reference in New Issue