use crate::hash::{Hash, Hasher};
use crate::packet::PACKET_DATA_SIZE;
use crate::pubkey::Pubkey;
use crate::shortvec::{
deserialize_vec_bytes, deserialize_vec_with, encode_len, serialize_vec_bytes,
serialize_vec_with,
};
use crate::signature::{Keypair, KeypairUtil, Signature};
use bincode::{serialize, Error};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use serde::{Deserialize, Serialize, Serializer};
use std::fmt;
use std::io::{Cursor, Read, Write};
use std::mem::size_of;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct Instruction<P, Q> {
pub program_ids_index: P,
pub accounts: Vec<Q>,
pub data: Vec<u8>,
}
impl<P, Q> Instruction<P, Q> {
pub fn new<T: Serialize>(program_ids_index: P, data: &T, accounts: Vec<Q>) -> Self {
let data = serialize(data).unwrap();
Self {
program_ids_index,
data,
accounts,
}
}
}
impl Instruction<u8, u8> {
pub fn serialize_with(mut writer: &mut Cursor<&mut [u8]>, ix: &Self) -> Result<(), Error> {
writer.write_all(&[ix.program_ids_index])?;
serialize_vec_bytes(&mut writer, &ix.accounts[..])?;
serialize_vec_bytes(&mut writer, &ix.data[..])?;
Ok(())
}
pub fn deserialize_from(mut reader: &mut Cursor<&[u8]>) -> Result<Self, Error> {
let mut buf = [0];
reader.read_exact(&mut buf)?;
let program_ids_index = buf[0];
let accounts = deserialize_vec_bytes(&mut reader)?;
let data = deserialize_vec_bytes(&mut reader)?;
Ok(Instruction {
program_ids_index,
accounts,
data,
})
}
pub fn serialized_size(&self) -> Result<u64, Error> {
let mut buf = [0; size_of::<u64>() + 1];
let mut wr = Cursor::new(&mut buf[..]);
let mut size = size_of::<u8>();
let len = self.accounts.len();
encode_len(&mut wr, len)?;
size += wr.position() as usize + (len * size_of::<u8>());
let len = self.data.len();
wr.set_position(0);
encode_len(&mut wr, len)?;
size += wr.position() as usize + (len * size_of::<u8>());
Ok(size as u64)
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Transaction {
pub signatures: Vec<Signature>,
pub account_keys: Vec<Pubkey>,
pub recent_blockhash: Hash,
pub fee: u64,
pub program_ids: Vec<Pubkey>,
pub instructions: Vec<Instruction<u8, u8>>,
}
impl Transaction {
pub fn new<S: Serialize, T: KeypairUtil>(
from_keypair: &T,
transaction_keys: &[Pubkey],
program_id: &Pubkey,
data: &S,
recent_blockhash: Hash,
fee: u64,
) -> Self {
let program_ids = vec![*program_id];
let accounts = (0..=transaction_keys.len() as u8).collect();
let instructions = vec![Instruction::new(0, data, accounts)];
Self::new_with_instructions(
&[from_keypair],
transaction_keys,
recent_blockhash,
fee,
program_ids,
instructions,
)
}
pub fn new_unsigned<T: Serialize>(
from_pubkey: &Pubkey,
transaction_keys: &[Pubkey],
program_id: &Pubkey,
data: &T,
recent_blockhash: Hash,
fee: u64,
) -> Self {
let program_ids = vec![*program_id];
let accounts = (0..=transaction_keys.len() as u8).collect();
let instructions = vec![Instruction::new(0, data, accounts)];
let mut keys = vec![*from_pubkey];
keys.extend_from_slice(transaction_keys);
Self::new_with_instructions::<Keypair>(
&[],
&keys[..],
recent_blockhash,
fee,
program_ids,
instructions,
)
}
pub fn new_with_instructions<T: KeypairUtil>(
from_keypairs: &[&T],
keys: &[Pubkey],
recent_blockhash: Hash,
fee: u64,
program_ids: Vec<Pubkey>,
instructions: Vec<Instruction<u8, u8>>,
) -> Self {
let mut account_keys: Vec<_> = from_keypairs
.iter()
.map(|keypair| keypair.pubkey())
.collect();
account_keys.extend_from_slice(keys);
let mut tx = Transaction {
signatures: vec![],
account_keys,
recent_blockhash: Hash::default(),
fee,
program_ids,
instructions,
};
tx.sign(from_keypairs, recent_blockhash);
tx
}
pub fn data(&self, instruction_index: usize) -> &[u8] {
&self.instructions[instruction_index].data
}
fn key_index(&self, instruction_index: usize, accounts_index: usize) -> Option<usize> {
self.instructions
.get(instruction_index)
.and_then(|instruction| instruction.accounts.get(accounts_index))
.map(|&account_keys_index| account_keys_index as usize)
}
pub fn key(&self, instruction_index: usize, accounts_index: usize) -> Option<&Pubkey> {
self.key_index(instruction_index, accounts_index)
.and_then(|account_keys_index| self.account_keys.get(account_keys_index))
}
pub fn signer_key(&self, instruction_index: usize, accounts_index: usize) -> Option<&Pubkey> {
match self.key_index(instruction_index, accounts_index) {
None => None,
Some(signature_index) => {
if signature_index >= self.signatures.len() {
return None;
}
self.account_keys.get(signature_index)
}
}
}
pub fn program_id(&self, instruction_index: usize) -> &Pubkey {
let program_ids_index = self.instructions[instruction_index].program_ids_index;
&self.program_ids[program_ids_index as usize]
}
pub fn message(&self) -> Vec<u8> {
let mut buf = vec![0u8; PACKET_DATA_SIZE];
let mut wr = Cursor::new(&mut buf[..]);
serialize_vec_with(&mut wr, &self.account_keys, Transaction::serialize_pubkey)
.expect("serialize account_keys");
wr.write_all(self.recent_blockhash.as_ref())
.expect("serialize recent_blockhash");
wr.write_u64::<LittleEndian>(self.fee)
.expect("serialize fee");
serialize_vec_with(&mut wr, &self.program_ids, Transaction::serialize_pubkey)
.expect("serialize program_ids");
serialize_vec_with(&mut wr, &self.instructions, Instruction::serialize_with)
.expect("serialize instructions");
let len = wr.position() as usize;
wr.into_inner()[..len].to_vec()
}
pub fn sign<T: KeypairUtil>(&mut self, keypairs: &[&T], recent_blockhash: Hash) {
self.recent_blockhash = recent_blockhash;
let message = self.message();
self.signatures = keypairs
.iter()
.map(|keypair| keypair.sign_message(&message))
.collect();
}
pub fn sign_checked<T: KeypairUtil>(&mut self, keypairs: &[&T], recent_blockhash: Hash) {
let signed_keys = &self.account_keys[0..self.signatures.capacity()];
for (i, keypair) in keypairs.iter().enumerate() {
assert_eq!(keypair.pubkey(), signed_keys[i], "keypair-pubkey mismatch");
}
assert_eq!(keypairs.len(), signed_keys.len(), "not enough keypairs");
self.sign(keypairs, recent_blockhash);
}
pub fn verify_signature(&self) -> bool {
self.signatures
.iter()
.all(|s| s.verify(&self.from().as_ref(), &self.message()))
}
pub fn verify_refs(&self) -> bool {
for instruction in &self.instructions {
if (instruction.program_ids_index as usize) >= self.program_ids.len() {
return false;
}
for account_index in &instruction.accounts {
if (*account_index as usize) >= self.account_keys.len() {
return false;
}
}
}
true
}
pub fn from(&self) -> &Pubkey {
&self.account_keys[0]
}
pub fn hash(transactions: &[Transaction]) -> Hash {
let mut hasher = Hasher::default();
transactions.iter().for_each(|tx| {
if !tx.signatures.is_empty() {
hasher.hash(&tx.signatures[0].as_ref());
}
});
hasher.result()
}
pub fn serialized_size(&self) -> Result<u64, Error> {
let mut buf = [0u8; size_of::<u64>() + 1];
let mut wr = Cursor::new(&mut buf[..]);
let mut size = size_of::<u64>();
let len = self.signatures.len();
encode_len(&mut wr, len)?;
size += wr.position() as usize + (len * size_of::<Signature>());
let len = self.account_keys.len();
wr.set_position(0);
encode_len(&mut wr, len)?;
size += wr.position() as usize + (len * size_of::<Pubkey>());
size += size_of::<Hash>();
size += size_of::<u64>();
let len = self.program_ids.len();
wr.set_position(0);
encode_len(&mut wr, len)?;
size += wr.position() as usize + (len * size_of::<Pubkey>());
let len = self.instructions.len();
wr.set_position(0);
encode_len(&mut wr, len)?;
size += wr.position() as usize;
let inst_size: u64 = self
.instructions
.iter()
.map(|ix| ix.serialized_size().unwrap())
.sum();
Ok(size as u64 + inst_size)
}
fn serialize_signature(writer: &mut Cursor<&mut [u8]>, sig: &Signature) -> Result<(), Error> {
writer.write_all(sig.as_ref())?;
Ok(())
}
fn serialize_pubkey(writer: &mut Cursor<&mut [u8]>, key: &Pubkey) -> Result<(), Error> {
writer.write_all(key.as_ref())?;
Ok(())
}
fn deserialize_signature(reader: &mut Cursor<&[u8]>) -> Result<Signature, Error> {
let mut buf = [0; size_of::<Signature>()];
reader.read_exact(&mut buf)?;
Ok(Signature::new(&buf))
}
fn deserialize_pubkey(reader: &mut Cursor<&[u8]>) -> Result<Pubkey, Error> {
let mut buf = [0; size_of::<Pubkey>()];
reader.read_exact(&mut buf)?;
Ok(Pubkey::new(&buf))
}
}
impl Serialize for Transaction {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use serde::ser::Error;
let mut buf = vec![0u8; self.serialized_size().unwrap() as usize];
let mut wr = Cursor::new(&mut buf[..]);
serialize_vec_with(&mut wr, &self.signatures, Transaction::serialize_signature)
.map_err(Error::custom)?;
serialize_vec_with(&mut wr, &self.account_keys, Transaction::serialize_pubkey)
.map_err(Error::custom)?;
wr.write_all(self.recent_blockhash.as_ref())
.map_err(Error::custom)?;
wr.write_u64::<LittleEndian>(self.fee)
.map_err(Error::custom)?;
serialize_vec_with(&mut wr, &self.program_ids, Transaction::serialize_pubkey)
.map_err(Error::custom)?;
serialize_vec_with(&mut wr, &self.instructions, Instruction::serialize_with)
.map_err(Error::custom)?;
let size = wr.position() as usize;
serializer.serialize_bytes(&wr.into_inner()[..size])
}
}
struct TransactionVisitor;
impl<'a> serde::de::Visitor<'a> for TransactionVisitor {
type Value = Transaction;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Expecting Instruction")
}
fn visit_bytes<E>(self, data: &[u8]) -> Result<Transaction, E>
where
E: serde::de::Error,
{
use serde::de::Error;
let mut rd = Cursor::new(&data[..]);
let signatures: Vec<Signature> =
deserialize_vec_with(&mut rd, Transaction::deserialize_signature)
.map_err(Error::custom)?;
let account_keys: Vec<Pubkey> =
deserialize_vec_with(&mut rd, Transaction::deserialize_pubkey)
.map_err(Error::custom)?;
let mut buf = [0; size_of::<Hash>()];
rd.read_exact(&mut buf).map_err(Error::custom)?;
let recent_blockhash: Hash = Hash::new(&buf);
let fee = rd.read_u64::<LittleEndian>().map_err(Error::custom)?;
let program_ids: Vec<Pubkey> =
deserialize_vec_with(&mut rd, Transaction::deserialize_pubkey)
.map_err(Error::custom)?;
let instructions: Vec<Instruction<u8, u8>> =
deserialize_vec_with(&mut rd, Instruction::deserialize_from).map_err(Error::custom)?;
Ok(Transaction {
signatures,
account_keys,
recent_blockhash,
fee,
program_ids,
instructions,
})
}
}
impl<'de> Deserialize<'de> for Transaction {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
deserializer.deserialize_bytes(TransactionVisitor)
}
}
#[cfg(test)]
mod tests {
use super::*;
use bincode::deserialize;
#[test]
fn test_refs() {
let key = Keypair::new();
let key1 = Keypair::new().pubkey();
let key2 = Keypair::new().pubkey();
let prog1 = Keypair::new().pubkey();
let prog2 = Keypair::new().pubkey();
let instructions = vec![
Instruction::new(0, &(), vec![0, 1]),
Instruction::new(1, &(), vec![0, 2]),
];
let tx = Transaction::new_with_instructions(
&[&key],
&[key1, key2],
Hash::default(),
0,
vec![prog1, prog2],
instructions,
);
assert!(tx.verify_refs());
assert_eq!(tx.key(0, 0), Some(&key.pubkey()));
assert_eq!(tx.signer_key(0, 0), Some(&key.pubkey()));
assert_eq!(tx.key(1, 0), Some(&key.pubkey()));
assert_eq!(tx.signer_key(1, 0), Some(&key.pubkey()));
assert_eq!(tx.key(0, 1), Some(&key1));
assert_eq!(tx.signer_key(0, 1), None);
assert_eq!(tx.key(1, 1), Some(&key2));
assert_eq!(tx.signer_key(1, 1), None);
assert_eq!(tx.key(2, 0), None);
assert_eq!(tx.signer_key(2, 0), None);
assert_eq!(tx.key(0, 2), None);
assert_eq!(tx.signer_key(0, 2), None);
assert_eq!(*tx.program_id(0), prog1);
assert_eq!(*tx.program_id(1), prog2);
}
#[test]
fn test_refs_invalid_program_id() {
let key = Keypair::new();
let instructions = vec![Instruction::new(1, &(), vec![])];
let tx = Transaction::new_with_instructions(
&[&key],
&[],
Hash::default(),
0,
vec![],
instructions,
);
assert!(!tx.verify_refs());
}
#[test]
fn test_refs_invalid_account() {
let key = Keypair::new();
let instructions = vec![Instruction::new(0, &(), vec![1])];
let tx = Transaction::new_with_instructions(
&[&key],
&[],
Hash::default(),
0,
vec![Pubkey::default()],
instructions,
);
assert_eq!(*tx.program_id(0), Pubkey::default());
assert!(!tx.verify_refs());
}
#[test]
fn test_transaction_serialize() {
let keypair = Keypair::new();
let program_id = Pubkey::new(&[4; 32]);
let to = Pubkey::new(&[5; 32]);
let tx = Transaction::new(
&keypair,
&[keypair.pubkey(), to],
&program_id,
&(1u8, 2u8, 3u8),
Hash::default(),
99,
);
let ser = serialize(&tx).unwrap();
let deser = deserialize(&ser).unwrap();
assert_eq!(tx, deser);
}
#[test]
fn test_transaction_serialized_size() {
let keypair = Keypair::new();
let program_id = Pubkey::new(&[4; 32]);
let to = Pubkey::new(&[5; 32]);
let tx = Transaction::new(
&keypair,
&[keypair.pubkey(), to],
&program_id,
&(1u8, 2u8, 3u8),
Hash::default(),
99,
);
let req_size = size_of::<u64>()
+ 1
+ (tx.signatures.len() * size_of::<Signature>())
+ 1
+ (tx.account_keys.len() * size_of::<Pubkey>())
+ size_of::<Hash>()
+ size_of::<u64>()
+ 1
+ (tx.program_ids.len() * size_of::<Pubkey>())
+ 1
+ tx.instructions[0].serialized_size().unwrap() as usize;
let size = tx.serialized_size().unwrap() as usize;
assert_eq!(req_size, size);
}
#[test]
fn test_sdk_serialize() {
use untrusted::Input;
let keypair = Keypair::from_pkcs8(Input::from(&[
48, 83, 2, 1, 1, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32, 255, 101, 36, 24, 124, 23,
167, 21, 132, 204, 155, 5, 185, 58, 121, 75, 156, 227, 116, 193, 215, 38, 142, 22, 8,
14, 229, 239, 119, 93, 5, 218, 161, 35, 3, 33, 0, 36, 100, 158, 252, 33, 161, 97, 185,
62, 89, 99, 195, 250, 249, 187, 189, 171, 118, 241, 90, 248, 14, 68, 219, 231, 62, 157,
5, 142, 27, 210, 117,
]))
.unwrap();
let to = Pubkey::new(&[
1, 1, 1, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 7, 6, 5, 4,
1, 1, 1,
]);
let program_id = Pubkey::new(&[
2, 2, 2, 4, 5, 6, 7, 8, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 8, 7, 6, 5, 4,
2, 2, 2,
]);
let tx = Transaction::new(
&keypair,
&[keypair.pubkey(), to],
&program_id,
&(1u8, 2u8, 3u8),
Hash::default(),
99,
);
assert_eq!(
serialize(&tx).unwrap(),
vec![
245, 0, 0, 0, 0, 0, 0, 0, 1, 151, 224, 239, 74, 248, 111, 129, 62, 193, 150, 178,
53, 242, 136, 228, 153, 16, 245, 127, 217, 6, 122, 114, 165, 224, 243, 191, 164,
197, 107, 71, 41, 57, 132, 240, 19, 166, 239, 109, 168, 225, 215, 1, 59, 120, 57,
141, 103, 243, 182, 221, 176, 161, 153, 217, 129, 87, 178, 228, 151, 57, 163, 75,
13, 3, 36, 100, 158, 252, 33, 161, 97, 185, 62, 89, 99, 195, 250, 249, 187, 189,
171, 118, 241, 90, 248, 14, 68, 219, 231, 62, 157, 5, 142, 27, 210, 117, 36, 100,
158, 252, 33, 161, 97, 185, 62, 89, 99, 195, 250, 249, 187, 189, 171, 118, 241, 90,
248, 14, 68, 219, 231, 62, 157, 5, 142, 27, 210, 117, 1, 1, 1, 4, 5, 6, 7, 8, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 7, 6, 5, 4, 1, 1, 1, 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, 0, 0, 0, 99,
0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 4, 5, 6, 7, 8, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 9, 8, 7, 6, 5, 4, 2, 2, 2, 1, 0, 3, 0, 1, 2, 3, 1, 2, 3
],
);
}
}