Minor cleanup

This commit is contained in:
Greg Fitzgerald
2019-03-25 20:57:25 -06:00
committed by Grimes
parent e1c0425c2b
commit b61aed7250
5 changed files with 171 additions and 185 deletions

View File

@ -1,89 +1,67 @@
use bincode;
use log::*;
use serde_derive::{Deserialize, Serialize};
use solana_sdk::account::KeyedAccount;
use solana_sdk::pubkey::Pubkey;
use std;
#[derive(Serialize, Debug, PartialEq)]
pub enum Error {
pub enum TokenError {
InvalidArgument,
InsufficentFunds,
NotOwner,
}
impl std::fmt::Display for Error {
impl std::fmt::Display for TokenError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "error")
}
}
impl std::error::Error for Error {}
impl std::error::Error for TokenError {}
pub type Result<T> = std::result::Result<T, Error>;
pub type Result<T> = std::result::Result<T, TokenError>;
#[derive(Debug, Default, Serialize, Deserialize, PartialEq)]
pub struct TokenInfo {
/**
* Total supply of tokens
*/
/// Total supply of tokens
supply: u64,
/**
* Number of base 10 digits to the right of the decimal place in the total supply
*/
/// Number of base 10 digits to the right of the decimal place in the total supply
decimals: u8,
/**
* Descriptive name of this token
*/
/// Descriptive name of this token
name: String,
/**
* Symbol for this token
*/
/// Symbol for this token
symbol: String,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
pub struct TokenAccountDelegateInfo {
/**
* The source account for the tokens
*/
/// The source account for the tokens
source: Pubkey,
/**
* The original amount that this delegate account was authorized to spend up to
*/
/// The original amount that this delegate account was authorized to spend up to
original_amount: u64,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
pub struct TokenAccountInfo {
/**
* The kind of token this account holds
*/
/// The kind of token this account holds
token: Pubkey,
/**
* Owner of this account
*/
/// Owner of this account
owner: Pubkey,
/**
* Amount of tokens this account holds
*/
/// Amount of tokens this account holds
amount: u64,
/**
* If `delegate` None, `amount` belongs to this account.
* If `delegate` is Option<_>, `amount` represents the remaining allowance
* of tokens that may be transferred from the `source` account.
*/
/// If `delegate` None, `amount` belongs to this account.
/// If `delegate` is Option<_>, `amount` represents the remaining allowance
/// of tokens that may be transferred from the `source` account.
delegate: Option<TokenAccountDelegateInfo>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
enum Command {
enum TokenInstruction {
NewToken(TokenInfo),
NewTokenAccount,
Transfer(u64),
@ -106,14 +84,14 @@ impl Default for TokenState {
impl TokenState {
#[allow(clippy::needless_pass_by_value)]
fn map_to_invalid_args(err: std::boxed::Box<bincode::ErrorKind>) -> Error {
fn map_to_invalid_args(err: std::boxed::Box<bincode::ErrorKind>) -> TokenError {
warn!("invalid argument: {:?}", err);
Error::InvalidArgument
TokenError::InvalidArgument
}
pub fn deserialize(input: &[u8]) -> Result<TokenState> {
if input.is_empty() {
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
match input[0] {
0 => Ok(TokenState::Unallocated),
@ -123,17 +101,17 @@ impl TokenState {
2 => Ok(TokenState::Account(
bincode::deserialize(&input[1..]).map_err(Self::map_to_invalid_args)?,
)),
_ => Err(Error::InvalidArgument),
_ => Err(TokenError::InvalidArgument),
}
}
fn serialize(self: &TokenState, output: &mut [u8]) -> Result<()> {
if output.is_empty() {
warn!("serialize fail: ouput.len is 0");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
match self {
TokenState::Unallocated | TokenState::Invalid => Err(Error::InvalidArgument),
TokenState::Unallocated | TokenState::Invalid => Err(TokenError::InvalidArgument),
TokenState::Token(token_info) => {
output[0] = 1;
let writer = std::io::BufWriter::new(&mut output[1..]);
@ -152,7 +130,7 @@ impl TokenState {
if let TokenState::Account(account_info) = self {
Ok(account_info.amount)
} else {
Err(Error::InvalidArgument)
Err(TokenError::InvalidArgument)
}
}
@ -166,63 +144,63 @@ impl TokenState {
}
}
warn!("TokenState: non-owner rejected");
Err(Error::NotOwner)
Err(TokenError::NotOwner)
}
pub fn process_command_newtoken(
pub fn process_newtoken(
info: &mut [KeyedAccount],
token_info: TokenInfo,
input_program_accounts: &[TokenState],
output_program_accounts: &mut Vec<(usize, TokenState)>,
input_accounts: &[TokenState],
output_accounts: &mut Vec<(usize, TokenState)>,
) -> Result<()> {
if input_program_accounts.len() != 2 {
if input_accounts.len() != 2 {
error!("Expected 2 accounts");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
if let TokenState::Account(dest_account) = &input_program_accounts[1] {
if let TokenState::Account(dest_account) = &input_accounts[1] {
if info[0].signer_key().unwrap() != &dest_account.token {
error!("account 1 token mismatch");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
if dest_account.delegate.is_some() {
error!("account 1 is a delegate and cannot accept tokens");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
let mut output_dest_account = dest_account.clone();
output_dest_account.amount = token_info.supply;
output_program_accounts.push((1, TokenState::Account(output_dest_account)));
output_accounts.push((1, TokenState::Account(output_dest_account)));
} else {
error!("account 1 invalid");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
if input_program_accounts[0] != TokenState::Unallocated {
if input_accounts[0] != TokenState::Unallocated {
error!("account 0 not available");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
output_program_accounts.push((0, TokenState::Token(token_info)));
output_accounts.push((0, TokenState::Token(token_info)));
Ok(())
}
pub fn process_command_newaccount(
pub fn process_newaccount(
info: &mut [KeyedAccount],
input_program_accounts: &[TokenState],
output_program_accounts: &mut Vec<(usize, TokenState)>,
input_accounts: &[TokenState],
output_accounts: &mut Vec<(usize, TokenState)>,
) -> Result<()> {
// key 0 - Destination new token account
// key 1 - Owner of the account
// key 2 - Token this account is associated with
// key 3 - Source account that this account is a delegate for (optional)
if input_program_accounts.len() < 3 {
if input_accounts.len() < 3 {
error!("Expected 3 accounts");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
if input_program_accounts[0] != TokenState::Unallocated {
if input_accounts[0] != TokenState::Unallocated {
error!("account 0 is already allocated");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
let mut token_account_info = TokenAccountInfo {
token: *info[2].unsigned_key(),
@ -230,131 +208,131 @@ impl TokenState {
amount: 0,
delegate: None,
};
if input_program_accounts.len() >= 4 {
if input_accounts.len() >= 4 {
token_account_info.delegate = Some(TokenAccountDelegateInfo {
source: *info[3].unsigned_key(),
original_amount: 0,
});
}
output_program_accounts.push((0, TokenState::Account(token_account_info)));
output_accounts.push((0, TokenState::Account(token_account_info)));
Ok(())
}
pub fn process_command_transfer(
pub fn process_transfer(
info: &mut [KeyedAccount],
amount: u64,
input_program_accounts: &[TokenState],
output_program_accounts: &mut Vec<(usize, TokenState)>,
input_accounts: &[TokenState],
output_accounts: &mut Vec<(usize, TokenState)>,
) -> Result<()> {
if input_program_accounts.len() < 3 {
if input_accounts.len() < 3 {
error!("Expected 3 accounts");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
if let (TokenState::Account(source_account), TokenState::Account(dest_account)) =
(&input_program_accounts[1], &input_program_accounts[2])
(&input_accounts[1], &input_accounts[2])
{
if source_account.token != dest_account.token {
error!("account 1/2 token mismatch");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
if dest_account.delegate.is_some() {
error!("account 2 is a delegate and cannot accept tokens");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
if info[0].signer_key().unwrap() != &source_account.owner {
error!("owner of account 1 not present");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
if source_account.amount < amount {
Err(Error::InsufficentFunds)?;
Err(TokenError::InsufficentFunds)?;
}
let mut output_source_account = source_account.clone();
output_source_account.amount -= amount;
output_program_accounts.push((1, TokenState::Account(output_source_account)));
output_accounts.push((1, TokenState::Account(output_source_account)));
if let Some(ref delegate_info) = source_account.delegate {
if input_program_accounts.len() != 4 {
if input_accounts.len() != 4 {
error!("Expected 4 accounts");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
let delegate_account = source_account;
if let TokenState::Account(source_account) = &input_program_accounts[3] {
if let TokenState::Account(source_account) = &input_accounts[3] {
if source_account.token != delegate_account.token {
error!("account 1/3 token mismatch");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
if info[3].unsigned_key() != &delegate_info.source {
error!("Account 1 is not a delegate of account 3");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
if source_account.amount < amount {
Err(Error::InsufficentFunds)?;
Err(TokenError::InsufficentFunds)?;
}
let mut output_source_account = source_account.clone();
output_source_account.amount -= amount;
output_program_accounts.push((3, TokenState::Account(output_source_account)));
output_accounts.push((3, TokenState::Account(output_source_account)));
} else {
error!("account 3 is an invalid account");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
}
let mut output_dest_account = dest_account.clone();
output_dest_account.amount += amount;
output_program_accounts.push((2, TokenState::Account(output_dest_account)));
output_accounts.push((2, TokenState::Account(output_dest_account)));
} else {
error!("account 1 and/or 2 are invalid accounts");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
Ok(())
}
pub fn process_command_approve(
pub fn process_approve(
info: &mut [KeyedAccount],
amount: u64,
input_program_accounts: &[TokenState],
output_program_accounts: &mut Vec<(usize, TokenState)>,
input_accounts: &[TokenState],
output_accounts: &mut Vec<(usize, TokenState)>,
) -> Result<()> {
if input_program_accounts.len() != 3 {
if input_accounts.len() != 3 {
error!("Expected 3 accounts");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
if let (TokenState::Account(source_account), TokenState::Account(delegate_account)) =
(&input_program_accounts[1], &input_program_accounts[2])
(&input_accounts[1], &input_accounts[2])
{
if source_account.token != delegate_account.token {
error!("account 1/2 token mismatch");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
if info[0].signer_key().unwrap() != &source_account.owner {
error!("owner of account 1 not present");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
if source_account.delegate.is_some() {
error!("account 1 is a delegate");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
match &delegate_account.delegate {
None => {
error!("account 2 is not a delegate");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
Some(delegate_info) => {
if info[1].unsigned_key() != &delegate_info.source {
error!("account 2 is not a delegate of account 1");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
let mut output_delegate_account = delegate_account.clone();
@ -363,57 +341,58 @@ impl TokenState {
source: delegate_info.source,
original_amount: amount,
});
output_program_accounts.push((2, TokenState::Account(output_delegate_account)));
output_accounts.push((2, TokenState::Account(output_delegate_account)));
}
}
} else {
error!("account 1 and/or 2 are invalid accounts");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
Ok(())
}
pub fn process_command_setowner(
pub fn process_setowner(
info: &mut [KeyedAccount],
input_program_accounts: &[TokenState],
output_program_accounts: &mut Vec<(usize, TokenState)>,
input_accounts: &[TokenState],
output_accounts: &mut Vec<(usize, TokenState)>,
) -> Result<()> {
if input_program_accounts.len() < 3 {
if input_accounts.len() < 3 {
error!("Expected 3 accounts");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
if let TokenState::Account(source_account) = &input_program_accounts[1] {
if let TokenState::Account(source_account) = &input_accounts[1] {
if info[0].signer_key().unwrap() != &source_account.owner {
info!("owner of account 1 not present");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
let mut output_source_account = source_account.clone();
output_source_account.owner = *info[2].unsigned_key();
output_program_accounts.push((1, TokenState::Account(output_source_account)));
output_accounts.push((1, TokenState::Account(output_source_account)));
} else {
info!("account 1 is invalid");
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
Ok(())
}
pub fn process(program_id: &Pubkey, info: &mut [KeyedAccount], input: &[u8]) -> Result<()> {
let command = bincode::deserialize::<Command>(input).map_err(Self::map_to_invalid_args)?;
let command =
bincode::deserialize::<TokenInstruction>(input).map_err(Self::map_to_invalid_args)?;
info!("process_transaction: command={:?}", command);
if info[0].signer_key().is_none() {
Err(Error::InvalidArgument)?;
Err(TokenError::InvalidArgument)?;
}
let input_program_accounts: Vec<TokenState> = info
let input_accounts: Vec<TokenState> = info
.iter()
.map(|keyed_account| {
let account = &keyed_account.account;
if account.owner == *program_id {
match Self::deserialize(&account.data) {
Ok(token_program) => token_program,
Ok(token_state) => token_state,
Err(err) => {
error!("deserialize failed: {:?}", err);
TokenState::Invalid
@ -425,52 +404,36 @@ impl TokenState {
})
.collect();
for program_account in &input_program_accounts {
info!("input_program_account: data={:?}", program_account);
for account in &input_accounts {
info!("input_account: data={:?}", account);
}
let mut output_program_accounts: Vec<(_, _)> = vec![];
let mut output_accounts: Vec<(_, _)> = vec![];
match command {
Command::NewToken(token_info) => Self::process_command_newtoken(
info,
token_info,
&input_program_accounts,
&mut output_program_accounts,
)?,
Command::NewTokenAccount => Self::process_command_newaccount(
info,
&input_program_accounts,
&mut output_program_accounts,
)?,
TokenInstruction::NewToken(token_info) => {
Self::process_newtoken(info, token_info, &input_accounts, &mut output_accounts)?
}
TokenInstruction::NewTokenAccount => {
Self::process_newaccount(info, &input_accounts, &mut output_accounts)?
}
Command::Transfer(amount) => Self::process_command_transfer(
info,
amount,
&input_program_accounts,
&mut output_program_accounts,
)?,
TokenInstruction::Transfer(amount) => {
Self::process_transfer(info, amount, &input_accounts, &mut output_accounts)?
}
Command::Approve(amount) => Self::process_command_approve(
info,
amount,
&input_program_accounts,
&mut output_program_accounts,
)?,
TokenInstruction::Approve(amount) => {
Self::process_approve(info, amount, &input_accounts, &mut output_accounts)?
}
Command::SetOwner => Self::process_command_setowner(
info,
&input_program_accounts,
&mut output_program_accounts,
)?,
TokenInstruction::SetOwner => {
Self::process_setowner(info, &input_accounts, &mut output_accounts)?
}
}
for (index, program_account) in &output_program_accounts {
info!(
"output_program_account: index={} data={:?}",
index, program_account
);
Self::serialize(program_account, &mut info[*index].account.data)?;
for (index, account) in &output_accounts {
info!("output_account: index={} data={:?}", index, account);
Self::serialize(account, &mut info[*index].account.data)?;
}
Ok(())
}