Skip to content

Commit

Permalink
fix: solana cluster connection
Browse files Browse the repository at this point in the history
  • Loading branch information
Itshyphen committed Oct 25, 2024
1 parent 7d0e578 commit 8da68a8
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 111 deletions.
15 changes: 0 additions & 15 deletions contracts/solana/programs/cluster-connection/src/contexts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,21 +229,6 @@ pub struct AddValidator<'info> {
pub config: Account<'info, Config>,
}

#[derive(Accounts)]
pub struct RemoveValidator<'info> {
/// Transaction signer
#[account(mut)]
pub admin: Signer<'info>,

/// Config
#[account(
mut,
seeds = [Config::SEED_PREFIX.as_bytes()],
bump = config.bump,
has_one = admin @ ConnectionError::OnlyAdmin,
)]
pub config: Account<'info, Config>,
}

#[derive(Accounts)]
pub struct GetValidators<'info> {
Expand Down
99 changes: 34 additions & 65 deletions contracts/solana/programs/cluster-connection/src/helper.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
use anchor_lang::{
prelude::*,
solana_program::{
hash,
instruction::{AccountMeta,Instruction},
program::{invoke, invoke_signed},
sysvar::{recent_blockhashes::ID as SYSVAR_ID},
ed25519_program,
system_instruction,
hash, instruction::{AccountMeta,Instruction}, keccak::hashv, program::{invoke, invoke_signed}, secp256k1_recover::{secp256k1_recover, Secp256k1Pubkey}, system_instruction, sysvar::recent_blockhashes::ID as SYSVAR_ID
},
};

use ed25519_dalek::{PublicKey as Ed25519PublicKey, Signature, Verifier};
use crate::contexts::*;
use crate::state::*;
use crate::error::*;

use xcall_lib::xcall_type;

Expand Down Expand Up @@ -44,60 +39,51 @@ pub fn get_instruction_data(ix_name: &str, data: Vec<u8>) -> Vec<u8> {
ix_data
}

pub fn verify_message(signature: [u8; 64], message: Vec<u8>, pubkey: Pubkey) -> Result<()> {
// Recover the public key from the signature
pub fn get_message_hash(from_nid: &String, connection_sn: &u128, message: &Vec<u8>) -> [u8; 32] {
let mut result = from_nid.as_bytes().to_vec();
result.extend_from_slice(&connection_sn.to_le_bytes());
result.extend_from_slice(message);

// let pubkey = Pubkey::from([
// 57, 234, 243, 206, 86, 29, 102, 46, 179, 39, 246, 137, 159, 74, 167, 40,
// 69, 191, 199, 163, 68, 114, 221, 40, 45, 129, 56, 73, 87, 58, 119, 149
// ]);

let validator_pubkey = Ed25519PublicKey::from_bytes(&pubkey.to_bytes()).unwrap();

let signature = Signature::from_bytes(&signature).unwrap();

validator_pubkey
.verify(&message, &signature)
.unwrap();

let hash = hashv(&[&result]);
hash.0
}

Ok(())
pub fn recover_pubkey(message: [u8; 32], sig: [u8; 65]) -> Pubkey {
let recovery_key = sig[64];
let signature = &sig[0..64];
let recovered_pubkey = secp256k1_recover(&message, recovery_key, signature).unwrap_or(
Secp256k1Pubkey::new(&[0u8; 64]),);
let pubkey_bytes: [u8; 64] = recovered_pubkey.to_bytes();
let mut solana_pubkey_bytes = [0u8; 32];
solana_pubkey_bytes.copy_from_slice(&pubkey_bytes[..32]);
Pubkey::new_from_array(solana_pubkey_bytes)
}

pub fn call_xcall_handle_message<'info>(
ctx: Context<'_, '_, '_, 'info, RecvMessage<'info>>,
from_nid: String,
message: Vec<u8>,
sequence_no: u128,
) -> Result<()> {
let mut data = vec![];
let args = xcall_type::HandleMessageArgs {
from_nid,
message,
sequence_no,
};
args.serialize(&mut data)?;

let ix_data = get_instruction_data("handle_message", data);

invoke_instruction(
ix_data,
&ctx.accounts.config,
&ctx.accounts.authority,
&ctx.accounts.admin,
&ctx.accounts.system_program,
ctx.remaining_accounts,
)
}

pub fn call_xcall_handle_message_with_signatures<'info>(
ctx: Context<'_, '_, '_, 'info, ReceiveMessageWithSignatures<'info>>,
from_nid: String,
message: Vec<u8>,
connection_sn: u128,
sequence_no: u128,
signatures: Vec<[u8; 64]>,
signatures: Vec<[u8; 65]>,
) -> Result<()> {
let mut data = vec![];

let message_hash = get_message_hash(&from_nid, &connection_sn, &message);
let mut unique_validators = Vec::new();
for sig in signatures {
let pubkey = recover_pubkey(message_hash, sig);
if ctx.accounts.config.is_validator(&pubkey) {
unique_validators.push(pubkey);
}
}

if (unique_validators.len() as u8) < ctx.accounts.config.get_threshold() {
return Err(ConnectionError::ValidatorsMustBeGreaterThanThreshold.into());
}

let args = xcall_type::HandleMessageArgs {
from_nid,
message,
Expand Down Expand Up @@ -178,20 +164,3 @@ pub fn invoke_instruction<'info>(
Ok(())
}

#[test]
fn test_verify_message() {
let message: Vec<u8> = b"Test message".to_vec();
let result = verify_message([
73, 220, 38, 229, 202, 199, 238, 241, 69, 237, 194,
226, 113, 76, 59, 167, 134, 83, 13, 213, 245, 151,
26, 220, 196, 162, 247, 240, 95, 245, 78, 205, 26,
233, 140, 177, 151, 207, 193, 23, 71, 96, 126, 115,
200, 21, 108, 178, 48, 133, 117, 208, 27, 80, 237,
93, 180, 97, 235, 40, 109, 36, 31, 11
], message.clone(), Pubkey::new(&[57, 234, 243, 206, 86, 29, 102, 46, 179, 39, 246, 137, 159, 74, 167, 40,
69, 191, 199, 163, 68, 114, 221, 40, 45, 129, 56, 73, 87, 58, 119, 149]
));

// Step 6: Assert that the signature verification is successful
assert!(result.is_ok(), "Signature verification failed");
}
37 changes: 16 additions & 21 deletions contracts/solana/programs/cluster-connection/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,27 +64,17 @@ pub mod centralized_connection {
Ok(())
}

#[allow(unused_variables)]
pub fn recv_message<'info>(
ctx: Context<'_, '_, '_, 'info, RecvMessage<'info>>,
src_network: String,
conn_sn: u128,
msg: Vec<u8>,
sequence_no: u128,
) -> Result<()> {
helper::call_xcall_handle_message(ctx, src_network, msg, sequence_no)
}

#[allow(unused_variables)]
pub fn receive_message_with_signatures<'info>(
pub fn receive_message<'info>(
ctx: Context<'_, '_, '_, 'info, ReceiveMessageWithSignatures<'info>>,
src_network: String,
conn_sn: u128,
msg: Vec<u8>,
sequence_no: u128,
signatures: Vec<[u8; 64]>,
signatures: Vec<[u8; 65]>,
) -> Result<()> {
helper::call_xcall_handle_message_with_signatures(ctx, src_network, msg, sequence_no,signatures)
helper::call_xcall_handle_message_with_signatures(ctx, src_network, msg, conn_sn, sequence_no,signatures)
}

pub fn revert_message<'info>(
Expand Down Expand Up @@ -118,17 +108,22 @@ pub mod centralized_connection {
}

pub fn set_threshold(ctx: Context<SetThreshold>, threshold: u8) -> Result<()> {
if ctx.accounts.config.get_validators().len() < threshold as usize {
return Err(error::ConnectionError::ValidatorsMustBeGreaterThanThreshold.into());
}
ctx.accounts.config.set_threshold(threshold);
Ok(())
}

pub fn add_validator(ctx: Context<AddValidator>, validator: Pubkey) -> Result<()> {
ctx.accounts.config.add_validator(validator);
Ok(())
}

pub fn remove_validator(ctx: Context<RemoveValidator>, validator: Pubkey) -> Result<()> {
ctx.accounts.config.remove_validator(validator);
pub fn update_validators(ctx: Context<AddValidator>, validators: Vec<Pubkey>, threshold: u8) -> Result<()> {
let mut unique_validators = validators.clone();
unique_validators.sort();
unique_validators.dedup();
if unique_validators.len() < threshold as usize {
return Err(error::ConnectionError::ValidatorsMustBeGreaterThanThreshold.into());
}
ctx.accounts.config.set_threshold(threshold);
ctx.accounts.config.store_validators(unique_validators);
Ok(())
}

Expand All @@ -137,7 +132,7 @@ pub mod centralized_connection {
}

pub fn get_threshold(ctx: Context<GetThreshold>) -> Result<u8> {
Ok(ctx.accounts.config.get_threshold()?)
Ok(ctx.accounts.config.get_threshold())
}

#[allow(unused_variables)]
Expand Down
20 changes: 10 additions & 10 deletions contracts/solana/programs/cluster-connection/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ impl Config {
Ok(account.lamports() - rent_exempt_balance)
}

pub fn get_threshold(&self) -> Result<u8> {
Ok(self.threshold)
pub fn get_threshold(&self) -> u8 {
self.threshold
}

pub fn set_threshold(&mut self, threshold: u8) {
Expand All @@ -75,16 +75,16 @@ impl Config {
self.validators.push(validator);
}

pub fn remove_validator(&mut self, validator: Pubkey) {
if self.admin == validator {
return;
}
if self.validators.len() < self.threshold as usize {
return;
}
self.validators.retain(|x| *x != validator);
pub fn store_validators(&mut self, validators: Vec<Pubkey>) {
self.validators = validators
}

pub fn is_validator(&self, address: &Pubkey) -> bool {
self.validators.contains(address)
}



pub fn get_validators(&self) -> Vec<Pubkey> {
self.validators.clone()
}
Expand Down

0 comments on commit 8da68a8

Please sign in to comment.