Add C API (#5072)
This commit is contained in:
@ -1,5 +1,4 @@
|
||||
use generic_array::typenum::U32;
|
||||
use generic_array::GenericArray;
|
||||
use std::convert::TryFrom;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::fs::{self, File};
|
||||
@ -8,9 +7,9 @@ use std::mem;
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[repr(C)]
|
||||
#[repr(transparent)]
|
||||
#[derive(Serialize, Deserialize, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub struct Pubkey(GenericArray<u8, U32>);
|
||||
pub struct Pubkey([u8; 32]);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ParsePubkeyError {
|
||||
@ -43,7 +42,10 @@ impl FromStr for Pubkey {
|
||||
|
||||
impl Pubkey {
|
||||
pub fn new(pubkey_vec: &[u8]) -> Self {
|
||||
Pubkey(GenericArray::clone_from_slice(&pubkey_vec))
|
||||
Self(
|
||||
<[u8; 32]>::try_from(<&[u8]>::clone(&pubkey_vec))
|
||||
.expect("Slice must be the same length as a Pubkey"),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_rand() -> Self {
|
||||
|
@ -19,6 +19,7 @@ use std::str::FromStr;
|
||||
|
||||
pub type Keypair = ed25519_dalek::Keypair;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Serialize, Deserialize, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub struct Signature(GenericArray<u8, U64>);
|
||||
|
||||
@ -74,6 +75,12 @@ impl fmt::Display for Signature {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<[u8; 64]> for Signature {
|
||||
fn into(self) -> [u8; 64] {
|
||||
<GenericArray<u8, U64> as Into<[u8; 64]>>::into(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ParseSignatureError {
|
||||
WrongSize,
|
||||
|
@ -193,9 +193,24 @@ impl Transaction {
|
||||
/// if recent_blockhash is not the same as currently in the transaction,
|
||||
/// clear any prior signatures and update recent_blockhash
|
||||
pub fn partial_sign<T: KeypairUtil>(&mut self, keypairs: &[&T], recent_blockhash: Hash) {
|
||||
let signed_keys =
|
||||
&self.message.account_keys[0..self.message.header.num_required_signatures as usize];
|
||||
let positions = self
|
||||
.get_signing_keypair_positions(keypairs)
|
||||
.expect("account_keys doesn't contain num_required_signatures keys");
|
||||
let positions: Vec<usize> = positions
|
||||
.iter()
|
||||
.map(|pos| pos.expect("keypair-pubkey mismatch"))
|
||||
.collect();
|
||||
self.partial_sign_unchecked(keypairs, positions, recent_blockhash)
|
||||
}
|
||||
|
||||
/// Sign the transaction and place the signatures in their associated positions in `signatures`
|
||||
/// without checking that the positions are correct.
|
||||
pub fn partial_sign_unchecked<T: KeypairUtil>(
|
||||
&mut self,
|
||||
keypairs: &[&T],
|
||||
positions: Vec<usize>,
|
||||
recent_blockhash: Hash,
|
||||
) {
|
||||
// if you change the blockhash, you're re-signing...
|
||||
if recent_blockhash != self.message.recent_blockhash {
|
||||
self.message.recent_blockhash = recent_blockhash;
|
||||
@ -204,16 +219,32 @@ impl Transaction {
|
||||
.for_each(|signature| *signature = Signature::default());
|
||||
}
|
||||
|
||||
for keypair in keypairs {
|
||||
let i = signed_keys
|
||||
.iter()
|
||||
.position(|pubkey| pubkey == &keypair.pubkey())
|
||||
.expect("keypair-pubkey mismatch");
|
||||
|
||||
self.signatures[i] = keypair.sign_message(&self.message_data())
|
||||
for i in 0..positions.len() {
|
||||
self.signatures[positions[i]] = keypairs[i].sign_message(&self.message_data())
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the positions of the pubkeys in `account_keys` associated with signing keypairs
|
||||
pub fn get_signing_keypair_positions<T: KeypairUtil>(
|
||||
&self,
|
||||
keypairs: &[&T],
|
||||
) -> Result<Vec<Option<usize>>> {
|
||||
if self.message.account_keys.len() < self.message.header.num_required_signatures as usize {
|
||||
return Err(TransactionError::InvalidAccountIndex);
|
||||
}
|
||||
let signed_keys =
|
||||
&self.message.account_keys[0..self.message.header.num_required_signatures as usize];
|
||||
|
||||
Ok(keypairs
|
||||
.iter()
|
||||
.map(|keypair| {
|
||||
signed_keys
|
||||
.iter()
|
||||
.position(|pubkey| pubkey == &keypair.pubkey())
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub fn is_signed(&self) -> bool {
|
||||
self.signatures
|
||||
.iter()
|
||||
|
Reference in New Issue
Block a user