From acedf4ca5a8a0e2a5bc9fd117d9548eed7ad022f Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Sat, 23 Mar 2019 21:12:27 -0600 Subject: [PATCH] Move Instruction into its own module --- core/src/banking_stage.rs | 2 +- core/src/sigverify.rs | 3 +- programs/bpf_loader/src/lib.rs | 2 +- programs/budget_api/src/budget_instruction.rs | 2 +- programs/budget_api/src/budget_processor.rs | 5 +- programs/budget_api/src/budget_state.rs | 2 +- programs/config_api/src/config_instruction.rs | 2 +- programs/config_api/src/config_processor.rs | 2 +- .../exchange_api/src/exchange_instruction.rs | 2 +- .../exchange_api/src/exchange_processor.rs | 2 +- programs/failure_program/src/lib.rs | 2 +- programs/failure_program/tests/failure.rs | 3 +- programs/noop_program/src/lib.rs | 2 +- programs/storage_api/src/storage_processor.rs | 5 +- programs/token_api/src/token_processor.rs | 2 +- programs/vote_api/src/vote_instruction.rs | 2 +- programs/vote_api/src/vote_processor.rs | 5 +- programs/vote_api/src/vote_state.rs | 2 +- runtime/src/accounts.rs | 5 +- runtime/src/bank.rs | 2 +- runtime/src/bank_client.rs | 5 +- runtime/src/loader_utils.rs | 2 +- runtime/src/native_loader.rs | 2 +- runtime/src/runtime.rs | 3 +- runtime/src/system_program.rs | 5 +- sdk/src/instruction.rs | 149 +++++++++++++++++ sdk/src/lib.rs | 1 + sdk/src/loader_instruction.rs | 2 +- sdk/src/native_program.rs | 6 +- sdk/src/script.rs | 5 +- sdk/src/system_instruction.rs | 2 +- sdk/src/transaction.rs | 153 +----------------- 32 files changed, 202 insertions(+), 187 deletions(-) create mode 100644 sdk/src/instruction.rs diff --git a/core/src/banking_stage.rs b/core/src/banking_stage.rs index f6db2c2cbc..3521030a6b 100644 --- a/core/src/banking_stage.rs +++ b/core/src/banking_stage.rs @@ -503,9 +503,9 @@ mod tests { use crate::packet::to_packets; use crate::poh_recorder::WorkingBank; use solana_sdk::genesis_block::GenesisBlock; + use solana_sdk::instruction::InstructionError; use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::system_transaction::SystemTransaction; - use solana_sdk::transaction::InstructionError; use std::sync::mpsc::channel; use std::thread::sleep; diff --git a/core/src/sigverify.rs b/core/src/sigverify.rs index 2bbe338ec5..159c247658 100644 --- a/core/src/sigverify.rs +++ b/core/src/sigverify.rs @@ -337,10 +337,11 @@ mod tests { use bincode::{deserialize, serialize}; use solana_budget_api; use solana_sdk::hash::Hash; + use solana_sdk::instruction::CompiledInstruction; use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::system_instruction::SystemInstruction; use solana_sdk::system_program; - use solana_sdk::transaction::{CompiledInstruction, Transaction}; + use solana_sdk::transaction::Transaction; const SIG_OFFSET: usize = std::mem::size_of::() + 1; diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 8a4a96bbe6..d162d6befc 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -5,10 +5,10 @@ use libc::c_char; use log::*; use solana_rbpf::{EbpfVmRaw, MemoryRegion}; use solana_sdk::account::KeyedAccount; +use solana_sdk::instruction::InstructionError; use solana_sdk::loader_instruction::LoaderInstruction; use solana_sdk::pubkey::Pubkey; use solana_sdk::solana_entrypoint; -use solana_sdk::transaction::InstructionError; use std::ffi::CStr; use std::io::prelude::*; use std::io::{Error, ErrorKind}; diff --git a/programs/budget_api/src/budget_instruction.rs b/programs/budget_api/src/budget_instruction.rs index 4b1b8825c0..5be7b38121 100644 --- a/programs/budget_api/src/budget_instruction.rs +++ b/programs/budget_api/src/budget_instruction.rs @@ -2,8 +2,8 @@ use crate::budget_expr::BudgetExpr; use crate::id; use chrono::prelude::{DateTime, Utc}; use serde_derive::{Deserialize, Serialize}; +use solana_sdk::instruction::{AccountMeta, Instruction}; use solana_sdk::pubkey::Pubkey; -use solana_sdk::transaction::{AccountMeta, Instruction}; /// A smart contract. #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] diff --git a/programs/budget_api/src/budget_processor.rs b/programs/budget_api/src/budget_processor.rs index a32ccaf27a..48a24e0f54 100644 --- a/programs/budget_api/src/budget_processor.rs +++ b/programs/budget_api/src/budget_processor.rs @@ -6,8 +6,8 @@ use bincode::{deserialize, serialize}; use chrono::prelude::{DateTime, Utc}; use log::*; use solana_sdk::account::KeyedAccount; +use solana_sdk::instruction::InstructionError; use solana_sdk::pubkey::Pubkey; -use solana_sdk::transaction::InstructionError; /// Process a Witness Signature. Any payment plans waiting on this signature /// will progress one step. @@ -149,8 +149,9 @@ mod tests { use solana_runtime::bank::Bank; use solana_runtime::bank_client::BankClient; use solana_sdk::genesis_block::GenesisBlock; + use solana_sdk::instruction::InstructionError; use solana_sdk::signature::{Keypair, KeypairUtil}; - use solana_sdk::transaction::{InstructionError, Transaction, TransactionError}; + use solana_sdk::transaction::{Transaction, TransactionError}; fn create_bank(lamports: u64) -> (Bank, Keypair) { let (genesis_block, mint_keypair) = GenesisBlock::new(lamports); diff --git a/programs/budget_api/src/budget_state.rs b/programs/budget_api/src/budget_state.rs index 77dbb84aaf..cf840e85f5 100644 --- a/programs/budget_api/src/budget_state.rs +++ b/programs/budget_api/src/budget_state.rs @@ -2,7 +2,7 @@ use crate::budget_expr::BudgetExpr; use bincode::{self, deserialize, serialize_into}; use serde_derive::{Deserialize, Serialize}; -use solana_sdk::transaction::InstructionError; +use solana_sdk::instruction::InstructionError; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum BudgetError { diff --git a/programs/config_api/src/config_instruction.rs b/programs/config_api/src/config_instruction.rs index f3fdca44de..228611af03 100644 --- a/programs/config_api/src/config_instruction.rs +++ b/programs/config_api/src/config_instruction.rs @@ -1,8 +1,8 @@ use crate::id; use crate::ConfigState; +use solana_sdk::instruction::{AccountMeta, Instruction}; use solana_sdk::pubkey::Pubkey; use solana_sdk::system_instruction::SystemInstruction; -use solana_sdk::transaction::{AccountMeta, Instruction}; pub struct ConfigInstruction {} diff --git a/programs/config_api/src/config_processor.rs b/programs/config_api/src/config_processor.rs index c24dd7a199..8bece35eea 100644 --- a/programs/config_api/src/config_processor.rs +++ b/programs/config_api/src/config_processor.rs @@ -2,8 +2,8 @@ use log::*; use solana_sdk::account::KeyedAccount; +use solana_sdk::instruction::InstructionError; use solana_sdk::pubkey::Pubkey; -use solana_sdk::transaction::InstructionError; pub fn process_instruction( _program_id: &Pubkey, diff --git a/programs/exchange_api/src/exchange_instruction.rs b/programs/exchange_api/src/exchange_instruction.rs index 9203e75cfe..9040781e3b 100644 --- a/programs/exchange_api/src/exchange_instruction.rs +++ b/programs/exchange_api/src/exchange_instruction.rs @@ -3,8 +3,8 @@ use crate::exchange_state::*; use crate::id; use serde_derive::{Deserialize, Serialize}; +use solana_sdk::instruction::{AccountMeta, Instruction}; use solana_sdk::pubkey::Pubkey; -use solana_sdk::transaction::{AccountMeta, Instruction}; #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub struct TradeRequestInfo { diff --git a/programs/exchange_api/src/exchange_processor.rs b/programs/exchange_api/src/exchange_processor.rs index 5bda46cb89..33f5647afe 100644 --- a/programs/exchange_api/src/exchange_processor.rs +++ b/programs/exchange_api/src/exchange_processor.rs @@ -5,8 +5,8 @@ use crate::exchange_state::*; use crate::id; use log::*; use solana_sdk::account::KeyedAccount; +use solana_sdk::instruction::InstructionError; use solana_sdk::pubkey::Pubkey; -use solana_sdk::transaction::InstructionError; use std::cmp; pub struct ExchangeProcessor {} diff --git a/programs/failure_program/src/lib.rs b/programs/failure_program/src/lib.rs index 8cf8b9a963..afb5abf98e 100644 --- a/programs/failure_program/src/lib.rs +++ b/programs/failure_program/src/lib.rs @@ -1,7 +1,7 @@ use solana_sdk::account::KeyedAccount; +use solana_sdk::instruction::InstructionError; use solana_sdk::pubkey::Pubkey; use solana_sdk::solana_entrypoint; -use solana_sdk::transaction::InstructionError; solana_entrypoint!(entrypoint); fn entrypoint( diff --git a/programs/failure_program/tests/failure.rs b/programs/failure_program/tests/failure.rs index 5f2784feac..11f3c0ad2e 100644 --- a/programs/failure_program/tests/failure.rs +++ b/programs/failure_program/tests/failure.rs @@ -2,8 +2,9 @@ use solana_runtime::bank::Bank; use solana_runtime::bank_client::BankClient; use solana_runtime::loader_utils::{create_invoke_instruction, load_program}; use solana_sdk::genesis_block::GenesisBlock; +use solana_sdk::instruction::InstructionError; use solana_sdk::native_loader; -use solana_sdk::transaction::{InstructionError, TransactionError}; +use solana_sdk::transaction::TransactionError; #[test] fn test_program_native_failure() { diff --git a/programs/noop_program/src/lib.rs b/programs/noop_program/src/lib.rs index 2af2d24373..344c868fad 100644 --- a/programs/noop_program/src/lib.rs +++ b/programs/noop_program/src/lib.rs @@ -1,8 +1,8 @@ use log::*; use solana_sdk::account::KeyedAccount; +use solana_sdk::instruction::InstructionError; use solana_sdk::pubkey::Pubkey; use solana_sdk::solana_entrypoint; -use solana_sdk::transaction::InstructionError; solana_entrypoint!(entrypoint); fn entrypoint( diff --git a/programs/storage_api/src/storage_processor.rs b/programs/storage_api/src/storage_processor.rs index f4dce68068..cf360c606c 100644 --- a/programs/storage_api/src/storage_processor.rs +++ b/programs/storage_api/src/storage_processor.rs @@ -5,8 +5,8 @@ use crate::*; use log::*; use solana_sdk::account::KeyedAccount; +use solana_sdk::instruction::InstructionError; use solana_sdk::pubkey::Pubkey; -use solana_sdk::transaction::InstructionError; pub const TOTAL_VALIDATOR_REWARDS: u64 = 1000; pub const TOTAL_REPLICATOR_REWARDS: u64 = 1000; @@ -179,10 +179,11 @@ mod tests { use solana_sdk::account::{create_keyed_accounts, Account}; use solana_sdk::genesis_block::GenesisBlock; use solana_sdk::hash::{hash, Hash}; + use solana_sdk::instruction::CompiledInstruction; use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::{Keypair, KeypairUtil, Signature}; use solana_sdk::system_transaction::SystemTransaction; - use solana_sdk::transaction::{CompiledInstruction, Transaction}; + use solana_sdk::transaction::Transaction; fn test_transaction( tx: &Transaction, diff --git a/programs/token_api/src/token_processor.rs b/programs/token_api/src/token_processor.rs index f98b08dd7f..8389d8b3b1 100644 --- a/programs/token_api/src/token_processor.rs +++ b/programs/token_api/src/token_processor.rs @@ -2,8 +2,8 @@ use crate::token_state::TokenState; use bincode::serialize; use log::*; use solana_sdk::account::KeyedAccount; +use solana_sdk::instruction::InstructionError; use solana_sdk::pubkey::Pubkey; -use solana_sdk::transaction::InstructionError; pub fn process_instruction( program_id: &Pubkey, diff --git a/programs/vote_api/src/vote_instruction.rs b/programs/vote_api/src/vote_instruction.rs index e7b7642522..5e1c23cc93 100644 --- a/programs/vote_api/src/vote_instruction.rs +++ b/programs/vote_api/src/vote_instruction.rs @@ -1,7 +1,7 @@ use crate::id; use serde_derive::{Deserialize, Serialize}; +use solana_sdk::instruction::{AccountMeta, Instruction}; use solana_sdk::pubkey::Pubkey; -use solana_sdk::transaction::{AccountMeta, Instruction}; #[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone)] pub struct Vote { diff --git a/programs/vote_api/src/vote_processor.rs b/programs/vote_api/src/vote_processor.rs index ed295ec1f7..ea586522b0 100644 --- a/programs/vote_api/src/vote_processor.rs +++ b/programs/vote_api/src/vote_processor.rs @@ -6,8 +6,8 @@ use crate::vote_state; use bincode::deserialize; use log::*; use solana_sdk::account::KeyedAccount; +use solana_sdk::instruction::InstructionError; use solana_sdk::pubkey::Pubkey; -use solana_sdk::transaction::InstructionError; pub fn process_instruction( _program_id: &Pubkey, @@ -51,10 +51,11 @@ mod tests { use solana_runtime::bank::{Bank, Result}; use solana_runtime::bank_client::BankClient; use solana_sdk::genesis_block::GenesisBlock; + use solana_sdk::instruction::{AccountMeta, Instruction, InstructionError}; use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::system_instruction::SystemInstruction; - use solana_sdk::transaction::{AccountMeta, Instruction, InstructionError, TransactionError}; + use solana_sdk::transaction::TransactionError; fn create_bank(lamports: u64) -> (Bank, Keypair) { let (genesis_block, mint_keypair) = GenesisBlock::new(lamports); diff --git a/programs/vote_api/src/vote_state.rs b/programs/vote_api/src/vote_state.rs index 8a95f107ed..b7435c8382 100644 --- a/programs/vote_api/src/vote_state.rs +++ b/programs/vote_api/src/vote_state.rs @@ -7,8 +7,8 @@ use bincode::{deserialize, serialize_into, serialized_size, ErrorKind}; use log::*; use serde_derive::{Deserialize, Serialize}; use solana_sdk::account::{Account, KeyedAccount}; +use solana_sdk::instruction::InstructionError; use solana_sdk::pubkey::Pubkey; -use solana_sdk::transaction::InstructionError; use std::collections::VecDeque; // Maximum number of votes to keep around diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index 47a7e40f43..1c447e9c17 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -991,9 +991,8 @@ mod tests { use rand::{thread_rng, Rng}; use solana_sdk::account::Account; use solana_sdk::hash::Hash; - use solana_sdk::signature::Keypair; - use solana_sdk::signature::KeypairUtil; - use solana_sdk::transaction::CompiledInstruction; + use solana_sdk::instruction::CompiledInstruction; + use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::transaction::Transaction; fn cleanup_paths(paths: &str) { diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 62d228a05b..b25b0eecf1 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -928,11 +928,11 @@ mod tests { use bincode::serialize; use solana_sdk::genesis_block::{GenesisBlock, BOOTSTRAP_LEADER_LAMPORTS}; use solana_sdk::hash; + use solana_sdk::instruction::{CompiledInstruction, InstructionError}; use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::system_instruction::SystemInstruction; use solana_sdk::system_program; use solana_sdk::system_transaction::SystemTransaction; - use solana_sdk::transaction::{CompiledInstruction, InstructionError}; #[test] fn test_bank_new() { diff --git a/runtime/src/bank_client.rs b/runtime/src/bank_client.rs index b66f2f2782..2a4ef1c5f0 100644 --- a/runtime/src/bank_client.rs +++ b/runtime/src/bank_client.rs @@ -1,9 +1,10 @@ use crate::bank::Bank; +use solana_sdk::instruction::Instruction; use solana_sdk::pubkey::Pubkey; use solana_sdk::script::Script; use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::system_instruction::SystemInstruction; -use solana_sdk::transaction::{Instruction, Transaction, TransactionError}; +use solana_sdk::transaction::{Transaction, TransactionError}; pub struct BankClient<'a> { bank: &'a Bank, @@ -67,7 +68,7 @@ impl<'a> BankClient<'a> { mod tests { use super::*; use solana_sdk::genesis_block::GenesisBlock; - use solana_sdk::transaction::AccountMeta; + use solana_sdk::instruction::AccountMeta; #[test] fn test_bank_client_new_with_keypairs() { diff --git a/runtime/src/loader_utils.rs b/runtime/src/loader_utils.rs index 943e59eb19..b4251b986d 100644 --- a/runtime/src/loader_utils.rs +++ b/runtime/src/loader_utils.rs @@ -1,11 +1,11 @@ use crate::bank::Bank; use crate::bank_client::BankClient; use serde::Serialize; +use solana_sdk::instruction::{AccountMeta, Instruction}; use solana_sdk::loader_instruction::LoaderInstruction; use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::system_instruction::SystemInstruction; -use solana_sdk::transaction::{AccountMeta, Instruction}; pub fn load_program( bank: &Bank, diff --git a/runtime/src/native_loader.rs b/runtime/src/native_loader.rs index 278a201e73..90752d60a9 100644 --- a/runtime/src/native_loader.rs +++ b/runtime/src/native_loader.rs @@ -6,10 +6,10 @@ use libloading::os::unix::*; use libloading::os::windows::*; use log::*; use solana_sdk::account::KeyedAccount; +use solana_sdk::instruction::InstructionError; use solana_sdk::loader_instruction::LoaderInstruction; use solana_sdk::native_program; use solana_sdk::pubkey::Pubkey; -use solana_sdk::transaction::InstructionError; use std::env; use std::path::PathBuf; use std::str; diff --git a/runtime/src/runtime.rs b/runtime/src/runtime.rs index de9b96d38d..0a013dc47c 100644 --- a/runtime/src/runtime.rs +++ b/runtime/src/runtime.rs @@ -1,8 +1,9 @@ use crate::native_loader; use solana_sdk::account::{create_keyed_accounts, Account, KeyedAccount}; +use solana_sdk::instruction::InstructionError; use solana_sdk::pubkey::Pubkey; use solana_sdk::system_program; -use solana_sdk::transaction::{InstructionError, Transaction, TransactionError}; +use solana_sdk::transaction::{Transaction, TransactionError}; /// Return true if the slice has any duplicate elements pub fn has_duplicates(xs: &[T]) -> bool { diff --git a/runtime/src/system_program.rs b/runtime/src/system_program.rs index ed24ad1ac1..435d18db55 100644 --- a/runtime/src/system_program.rs +++ b/runtime/src/system_program.rs @@ -1,10 +1,10 @@ use bincode::serialize; use log::*; use solana_sdk::account::KeyedAccount; +use solana_sdk::instruction::InstructionError; use solana_sdk::pubkey::Pubkey; use solana_sdk::system_instruction::{SystemError, SystemInstruction}; use solana_sdk::system_program; -use solana_sdk::transaction::InstructionError; const FROM_ACCOUNT_INDEX: usize = 0; const TO_ACCOUNT_INDEX: usize = 1; @@ -108,11 +108,12 @@ mod tests { use crate::bank_client::BankClient; use solana_sdk::account::Account; use solana_sdk::genesis_block::GenesisBlock; + use solana_sdk::instruction::{AccountMeta, Instruction, InstructionError}; use solana_sdk::script::Script; use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::system_instruction::SystemInstruction; use solana_sdk::system_program; - use solana_sdk::transaction::{AccountMeta, Instruction, InstructionError, TransactionError}; + use solana_sdk::transaction::TransactionError; #[test] fn test_create_system_account() { diff --git a/sdk/src/instruction.rs b/sdk/src/instruction.rs new file mode 100644 index 0000000000..8aa4e42bc6 --- /dev/null +++ b/sdk/src/instruction.rs @@ -0,0 +1,149 @@ +//! Defines a composable Instruction type and a memory-efficient CompiledInstruction. + +use crate::pubkey::Pubkey; +use crate::shortvec::{deserialize_vec_bytes, encode_len, serialize_vec_bytes}; +use crate::system_instruction::SystemError; +use bincode::{serialize, Error}; +use serde::Serialize; +use std::io::{Cursor, Read, Write}; +use std::mem::size_of; + +/// Reasons the runtime might have rejected an instruction. +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum InstructionError { + /// Deprecated! Use CustomError instead! + /// The program instruction returned an error + GenericError, + + /// The arguments provided to a program instruction where invalid + InvalidArgument, + + /// An instruction's data contents was invalid + InvalidInstructionData, + + /// An account's data contents was invalid + InvalidAccountData, + + /// An account's data was too small + AccountDataTooSmall, + + /// The account did not have the expected program id + IncorrectProgramId, + + /// A signature was required but not found + MissingRequiredSignature, + + /// An initialize instruction was sent to an account that has already been initialized. + AccountAlreadyInitialized, + + /// An attempt to operate on an account that hasn't been initialized. + UninitializedAccount, + + /// Program's instruction lamport balance does not equal the balance after the instruction + UnbalancedInstruction, + + /// Program modified an account's program id + ModifiedProgramId, + + /// Program spent the lamports of an account that doesn't belong to it + ExternalAccountLamportSpend, + + /// Program modified the data of an account that doesn't belong to it + ExternalAccountDataModified, + + /// An account was referenced more than once in a single instruction + DuplicateAccountIndex, + + /// CustomError allows on-chain programs to implement program-specific error types and see + /// them returned by the Solana runtime. A CustomError may be any type that is serialized + /// to a Vec of bytes, max length 32 bytes. Any CustomError Vec greater than this length will + /// be truncated by the runtime. + CustomError(Vec), +} + +impl InstructionError { + pub fn new_result_with_negative_lamports() -> Self { + let serialized_error = + bincode::serialize(&SystemError::ResultWithNegativeLamports).unwrap(); + InstructionError::CustomError(serialized_error) + } +} + +/// An instruction to execute a program +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub struct GenericInstruction { + /// Index into the transaction program ids array indicating the program account that executes this instruction + pub program_ids_index: P, + /// Ordered indices into the transaction keys array indicating which accounts to pass to the program + pub accounts: Vec, + /// The program input data + pub data: Vec, +} + +impl GenericInstruction { + pub fn new(program_ids_index: P, data: &T, accounts: Vec) -> Self { + let data = serialize(data).unwrap(); + Self { + program_ids_index, + data, + accounts, + } + } +} + +/// Account metadata used to define Instructions +#[derive(Debug)] +pub struct AccountMeta { + /// An account's public key + pub pubkey: Pubkey, + /// True if an Instruciton requires a Transaction signature matching `pubkey`. + pub is_signer: bool, +} + +impl AccountMeta { + pub fn new(pubkey: Pubkey, is_signer: bool) -> Self { + Self { pubkey, is_signer } + } +} + +pub type Instruction = GenericInstruction; +pub type CompiledInstruction = GenericInstruction; + +impl CompiledInstruction { + 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 { + 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(CompiledInstruction { + program_ids_index, + accounts, + data, + }) + } + + pub fn serialized_size(&self) -> Result { + let mut buf = [0; size_of::() + 1]; + let mut wr = Cursor::new(&mut buf[..]); + let mut size = size_of::(); + + let len = self.accounts.len(); + encode_len(&mut wr, len)?; + size += wr.position() as usize + (len * size_of::()); + + let len = self.data.len(); + wr.set_position(0); + encode_len(&mut wr, len)?; + size += wr.position() as usize + (len * size_of::()); + + Ok(size as u64) + } +} diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index bc1e642d68..725213a497 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -2,6 +2,7 @@ pub mod account; pub mod bpf_loader; pub mod genesis_block; pub mod hash; +pub mod instruction; pub mod loader_instruction; pub mod native_loader; pub mod native_program; diff --git a/sdk/src/loader_instruction.rs b/sdk/src/loader_instruction.rs index 09b6465f5b..f020474a59 100644 --- a/sdk/src/loader_instruction.rs +++ b/sdk/src/loader_instruction.rs @@ -1,5 +1,5 @@ +use crate::instruction::{AccountMeta, Instruction}; use crate::pubkey::Pubkey; -use crate::transaction::{AccountMeta, Instruction}; #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub enum LoaderInstruction { diff --git a/sdk/src/native_program.rs b/sdk/src/native_program.rs index 86c28cc918..88fcb4f26b 100644 --- a/sdk/src/native_program.rs +++ b/sdk/src/native_program.rs @@ -1,6 +1,6 @@ use crate::account::KeyedAccount; +use crate::instruction::InstructionError; use crate::pubkey::Pubkey; -use crate::transaction::InstructionError; // All native programs export a symbol named process() pub const ENTRYPOINT: &str = "process"; @@ -24,7 +24,7 @@ macro_rules! solana_entrypoint( keyed_accounts: &mut [solana_sdk::account::KeyedAccount], data: &[u8], tick_height: u64 - ) -> Result<(), solana_sdk::transaction::InstructionError> { + ) -> Result<(), solana_sdk::instruction::InstructionError> { $entrypoint(program_id, keyed_accounts, data, tick_height) } ) @@ -40,7 +40,7 @@ macro_rules! process_instruction_entrypoint( keyed_accounts: &mut [solana_sdk::account::KeyedAccount], data: &[u8], tick_height: u64, - ) -> Result<(), solana_sdk::transaction::InstructionError> { + ) -> Result<(), solana_sdk::instruction::InstructionError> { solana_logger::setup(); log::trace!("process_instruction: {:?}", data); diff --git a/sdk/src/script.rs b/sdk/src/script.rs index f034fbd023..2301ca8666 100644 --- a/sdk/src/script.rs +++ b/sdk/src/script.rs @@ -1,8 +1,9 @@ //! A library for building scripts and compiling them into transactions. use crate::hash::Hash; +use crate::instruction::{CompiledInstruction, Instruction}; use crate::pubkey::Pubkey; -use crate::transaction::{CompiledInstruction, Instruction, Transaction}; +use crate::transaction::Transaction; use itertools::Itertools; fn position(keys: &[Pubkey], key: &Pubkey) -> u8 { @@ -104,8 +105,8 @@ impl Script { #[cfg(test)] mod tests { use super::*; + use crate::instruction::AccountMeta; use crate::signature::{Keypair, KeypairUtil}; - use crate::transaction::AccountMeta; #[test] fn test_transaction_builder_unique_program_ids() { diff --git a/sdk/src/system_instruction.rs b/sdk/src/system_instruction.rs index 5a115e2cd0..ea25aafc36 100644 --- a/sdk/src/system_instruction.rs +++ b/sdk/src/system_instruction.rs @@ -1,6 +1,6 @@ +use crate::instruction::{AccountMeta, Instruction}; use crate::pubkey::Pubkey; use crate::system_program; -use crate::transaction::{AccountMeta, Instruction}; #[derive(Serialize, Debug, Clone, PartialEq)] pub enum SystemError { diff --git a/sdk/src/transaction.rs b/sdk/src/transaction.rs index 000e8cf423..11b86ecc43 100644 --- a/sdk/src/transaction.rs +++ b/sdk/src/transaction.rs @@ -1,162 +1,19 @@ -//! The `transaction` module provides functionality for creating log transactions. +//! Defines a Transaction type to package an atomic sequence of instructions. use crate::hash::{Hash, Hasher}; +use crate::instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError}; use crate::packet::PACKET_DATA_SIZE; use crate::pubkey::Pubkey; use crate::script::Script; -use crate::shortvec::{ - deserialize_vec_bytes, deserialize_vec_with, encode_len, serialize_vec_bytes, - serialize_vec_with, -}; +use crate::shortvec::{deserialize_vec_with, encode_len, serialize_vec_with}; use crate::signature::{KeypairUtil, Signature}; -use crate::system_instruction::SystemError; -use bincode::{serialize, Error}; +use bincode::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; -/// Reasons the runtime might have rejected an instruction. -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum InstructionError { - /// Deprecated! Use CustomError instead! - /// The program instruction returned an error - GenericError, - - /// The arguments provided to a program instruction where invalid - InvalidArgument, - - /// An instruction's data contents was invalid - InvalidInstructionData, - - /// An account's data contents was invalid - InvalidAccountData, - - /// An account's data was too small - AccountDataTooSmall, - - /// The account did not have the expected program id - IncorrectProgramId, - - /// A signature was required but not found - MissingRequiredSignature, - - /// An initialize instruction was sent to an account that has already been initialized. - AccountAlreadyInitialized, - - /// An attempt to operate on an account that hasn't been initialized. - UninitializedAccount, - - /// Program's instruction lamport balance does not equal the balance after the instruction - UnbalancedInstruction, - - /// Program modified an account's program id - ModifiedProgramId, - - /// Program spent the lamports of an account that doesn't belong to it - ExternalAccountLamportSpend, - - /// Program modified the data of an account that doesn't belong to it - ExternalAccountDataModified, - - /// An account was referenced more than once in a single instruction - DuplicateAccountIndex, - - /// CustomError allows on-chain programs to implement program-specific error types and see - /// them returned by the Solana runtime. A CustomError may be any type that is serialized - /// to a Vec of bytes, max length 32 bytes. Any CustomError Vec greater than this length will - /// be truncated by the runtime. - CustomError(Vec), -} - -impl InstructionError { - pub fn new_result_with_negative_lamports() -> Self { - let serialized_error = - bincode::serialize(&SystemError::ResultWithNegativeLamports).unwrap(); - InstructionError::CustomError(serialized_error) - } -} - -/// An instruction to execute a program -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct GenericInstruction { - /// Index into the transaction program ids array indicating the program account that executes this instruction - pub program_ids_index: P, - /// Ordered indices into the transaction keys array indicating which accounts to pass to the program - pub accounts: Vec, - /// The program input data - pub data: Vec, -} - -impl GenericInstruction { - pub fn new(program_ids_index: P, data: &T, accounts: Vec) -> Self { - let data = serialize(data).unwrap(); - Self { - program_ids_index, - data, - accounts, - } - } -} - -/// Account metadata used to define Instructions -#[derive(Debug)] -pub struct AccountMeta { - /// An account's public key - pub pubkey: Pubkey, - /// True if an Instruciton requires a Transaction signature matching `pubkey`. - pub is_signer: bool, -} - -impl AccountMeta { - pub fn new(pubkey: Pubkey, is_signer: bool) -> Self { - Self { pubkey, is_signer } - } -} - -pub type Instruction = GenericInstruction; -pub type CompiledInstruction = GenericInstruction; - -impl CompiledInstruction { - 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 { - 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(CompiledInstruction { - program_ids_index, - accounts, - data, - }) - } - - pub fn serialized_size(&self) -> Result { - let mut buf = [0; size_of::() + 1]; - let mut wr = Cursor::new(&mut buf[..]); - let mut size = size_of::(); - - let len = self.accounts.len(); - encode_len(&mut wr, len)?; - size += wr.position() as usize + (len * size_of::()); - - let len = self.data.len(); - wr.set_position(0); - encode_len(&mut wr, len)?; - size += wr.position() as usize + (len * size_of::()); - - Ok(size as u64) - } -} - /// Reasons a transaction might be rejected. #[derive(Debug, PartialEq, Eq, Clone)] pub enum TransactionError { @@ -553,7 +410,7 @@ impl<'de> Deserialize<'de> for Transaction { mod tests { use super::*; use crate::signature::Keypair; - use bincode::deserialize; + use bincode::{deserialize, serialize}; #[test] fn test_refs() {