From d96a6b42a59ea76f5b2334fafbb91de0bf2f2612 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Fri, 16 Nov 2018 08:04:46 -0800 Subject: [PATCH] Move drone into its own crate --- Cargo.toml | 6 +- benches/bank.rs | 3 +- benches/banking_stage.rs | 2 +- benches/ledger.rs | 3 +- ci/docker-solana/.gitignore | 1 + ci/docker-solana/build.sh | 5 +- ci/publish-crate.sh | 2 +- ci/publish-solana-tar.sh | 3 +- ci/test-stable-perf.sh | 1 + ci/test-stable.sh | 2 +- drone/Cargo.toml | 29 +++ {src => drone/src}/bin/drone.rs | 23 +- {src => drone/src}/drone.rs | 44 +++- drone/src/lib.rs | 14 ++ multinode-demo/common.sh | 5 +- net/net.sh | 6 +- sdk/Cargo.toml | 5 +- {src => sdk/src}/hash.rs | 0 sdk/src/lib.rs | 10 + sdk/src/packet.rs | 2 + sdk/src/signature.rs | 80 ++++++ sdk/src/system_instruction.rs | 28 +++ sdk/src/transaction.rs | 334 +++++++++++++++++++++++++ src/bank.rs | 13 +- src/banking_stage.rs | 2 +- src/bin/bench-tps.rs | 5 +- src/bin/replicator.rs | 3 +- src/bloom.rs | 2 +- src/budget_program.rs | 2 +- src/budget_transaction.rs | 16 +- src/chacha_cuda.rs | 4 +- src/cluster_info.rs | 4 +- src/compute_leader_finality_service.rs | 2 +- src/crds.rs | 2 +- src/crds_gossip.rs | 2 +- src/crds_gossip_pull.rs | 2 +- src/crds_gossip_push.rs | 2 +- src/crds_traits_impls.rs | 2 +- src/entry.rs | 4 +- src/fullnode.rs | 2 +- src/leader_scheduler.rs | 4 +- src/ledger.rs | 8 +- src/lib.rs | 3 +- src/loader_transaction.rs | 2 +- src/mint.rs | 15 +- src/packet.rs | 8 +- src/poh.rs | 4 +- src/poh_recorder.rs | 4 +- src/replicate_stage.rs | 4 +- src/replicator.rs | 4 +- src/rpc.rs | 4 +- src/signature.rs | 77 +----- src/sigverify.rs | 5 +- src/storage_program.rs | 2 +- src/storage_stage.rs | 4 +- src/storage_transaction.rs | 2 +- src/system_program.rs | 36 +-- src/system_transaction.rs | 26 +- src/thin_client.rs | 6 +- src/tpu.rs | 2 +- src/transaction.rs | 330 +----------------------- src/tvu.rs | 4 +- src/vote_stage.rs | 2 +- src/vote_transaction.rs | 2 +- src/wallet.rs | 6 +- src/window_service.rs | 2 +- tests/multinode.rs | 2 +- 67 files changed, 678 insertions(+), 567 deletions(-) create mode 100644 drone/Cargo.toml rename {src => drone/src}/bin/drone.rs (92%) rename {src => drone/src}/drone.rs (92%) create mode 100644 drone/src/lib.rs rename {src => sdk/src}/hash.rs (100%) create mode 100644 sdk/src/packet.rs create mode 100644 sdk/src/signature.rs create mode 100644 sdk/src/system_instruction.rs create mode 100644 sdk/src/transaction.rs diff --git a/Cargo.toml b/Cargo.toml index 749ea8239b..68ea3686bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,10 +21,6 @@ path = "src/bin/bench-streamer.rs" name = "solana-bench-tps" path = "src/bin/bench-tps.rs" -[[bin]] -name = "solana-drone" -path = "src/bin/drone.rs" - [[bin]] required-features = ["chacha"] name = "solana-replicator" @@ -113,6 +109,7 @@ tokio = "0.1" tokio-codec = "0.1" untrusted = "0.6.2" solana-bpfloader = { path = "programs/native/bpf_loader", version = "0.11.0" } +solana-drone = { path = "drone", version = "0.11.0" } solana-erc20 = { path = "programs/native/erc20", version = "0.11.0" } solana-lualoader = { path = "programs/native/lua_loader", version = "0.11.0" } solana-noop = { path = "programs/native/noop", version = "0.11.0" } @@ -139,6 +136,7 @@ name = "chacha" [workspace] members = [ ".", + "drone", "metrics", "sdk", "programs/bpf/rust/noop", diff --git a/benches/bank.rs b/benches/bank.rs index ac2896d7e9..28ee689dbe 100644 --- a/benches/bank.rs +++ b/benches/bank.rs @@ -2,14 +2,15 @@ extern crate bincode; extern crate rayon; extern crate solana; +extern crate solana_sdk; extern crate test; use solana::bank::*; -use solana::hash::hash; use solana::mint::Mint; use solana::signature::{Keypair, KeypairUtil}; use solana::system_transaction::SystemTransaction; use solana::transaction::Transaction; +use solana_sdk::hash::hash; use test::Bencher; #[bench] diff --git a/benches/banking_stage.rs b/benches/banking_stage.rs index bde3370782..d37c84ea98 100644 --- a/benches/banking_stage.rs +++ b/benches/banking_stage.rs @@ -11,12 +11,12 @@ use rayon::prelude::*; use solana::bank::{Bank, MAX_ENTRY_IDS}; use solana::banking_stage::{BankingStage, NUM_THREADS}; use solana::entry::Entry; -use solana::hash::hash; use solana::mint::Mint; use solana::packet::to_packets_chunked; use solana::signature::{KeypairUtil, Signature}; use solana::system_transaction::SystemTransaction; use solana::transaction::Transaction; +use solana_sdk::hash::hash; use solana_sdk::pubkey::Pubkey; use std::iter; use std::sync::mpsc::{channel, Receiver}; diff --git a/benches/ledger.rs b/benches/ledger.rs index c2311b2f9d..8b3849843c 100644 --- a/benches/ledger.rs +++ b/benches/ledger.rs @@ -1,13 +1,14 @@ #![feature(test)] extern crate solana; +extern crate solana_sdk; extern crate test; use solana::entry::reconstruct_entries_from_blobs; -use solana::hash::{hash, Hash}; use solana::ledger::{next_entries, Block}; use solana::signature::{Keypair, KeypairUtil}; use solana::system_transaction::SystemTransaction; use solana::transaction::Transaction; +use solana_sdk::hash::{hash, Hash}; use test::Bencher; #[bench] diff --git a/ci/docker-solana/.gitignore b/ci/docker-solana/.gitignore index 4c224402db..79163e181b 100644 --- a/ci/docker-solana/.gitignore +++ b/ci/docker-solana/.gitignore @@ -1 +1,2 @@ cargo-install/ +usr/ diff --git a/ci/docker-solana/build.sh b/ci/docker-solana/build.sh index 662c1f7ed3..ba5967200a 100755 --- a/ci/docker-solana/build.sh +++ b/ci/docker-solana/build.sh @@ -18,8 +18,11 @@ if [[ -z $CHANNEL ]]; then fi rm -rf usr/ -../docker-run.sh solanalabs/rust:1.30.0 \ +../docker-run.sh solanalabs/rust:1.30.1 bash -c " + set -ex + cargo install --path drone --root ci/docker-solana/usr cargo install --path . --root ci/docker-solana/usr +" cp -f entrypoint.sh usr/bin/solana-entrypoint.sh ../../scripts/install-native-programs.sh usr/bin/ diff --git a/ci/publish-crate.sh b/ci/publish-crate.sh index ae13ac42b1..2f7686fd47 100755 --- a/ci/publish-crate.sh +++ b/ci/publish-crate.sh @@ -19,7 +19,7 @@ if [[ -n $CI ]]; then fi # shellcheck disable=2044 # Disable 'For loops over find output are fragile...' -for Cargo_toml in {sdk,metrics,programs/native/{bpf_loader,lua_loader,noop},.}/Cargo.toml; do +for Cargo_toml in {sdk,metrics,drone,programs/native/{bpf_loader,lua_loader,noop},.}/Cargo.toml; do # TODO: Ensure the published version matches the contents of BUILDKITE_TAG ( set -x diff --git a/ci/publish-solana-tar.sh b/ci/publish-solana-tar.sh index fbc070827f..be056775ae 100755 --- a/ci/publish-solana-tar.sh +++ b/ci/publish-solana-tar.sh @@ -43,7 +43,8 @@ echo --- Creating tarball git rev-parse HEAD ) > solana-release/version.txt - cargo install --root solana-release + cargo install --path drone --root solana-release + cargo install --path . --root solana-release ./scripts/install-native-programs.sh solana-release/bin ./fetch-perf-libs.sh diff --git a/ci/test-stable-perf.sh b/ci/test-stable-perf.sh index b5ab63b3eb..a226d070ef 100755 --- a/ci/test-stable-perf.sh +++ b/ci/test-stable-perf.sh @@ -25,6 +25,7 @@ _() { } FEATURES=cuda,erasure,chacha +_ cargo build --all --verbose --features="$FEATURES" _ cargo test --verbose --features="$FEATURES" --lib # Run integration tests serially diff --git a/ci/test-stable.sh b/ci/test-stable.sh index b29ee3e586..d8943fa242 100755 --- a/ci/test-stable.sh +++ b/ci/test-stable.sh @@ -25,7 +25,7 @@ maybe_install() { } _ cargo fmt -- --check -_ cargo build --verbose +_ cargo build --all --verbose _ cargo test --verbose --lib _ cargo clippy -- --deny=warnings || true diff --git a/drone/Cargo.toml b/drone/Cargo.toml new file mode 100644 index 0000000000..c848050579 --- /dev/null +++ b/drone/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "solana-drone" +version = "0.11.0" +description = "Solana Drone" +authors = ["Solana Maintainers "] +repository = "https://github.com/solana-labs/solana" +license = "Apache-2.0" + +[dependencies] +bincode = "1.0.0" +bytes = "0.4" +byteorder = "1.2.1" +clap = "2.31" +log = "0.4.2" +serde = "1.0.27" +serde_derive = "1.0.27" +solana-sdk = { path = "../sdk", version = "0.11.0" } +solana-metrics = { path = "../metrics", version = "0.11.0" } +tokio = "0.1" +tokio-codec = "0.1" + +[lib] +name = "solana_drone" +crate-type = ["lib"] + +[[bin]] +name = "solana-drone" +path = "src/bin/drone.rs" + diff --git a/src/bin/drone.rs b/drone/src/bin/drone.rs similarity index 92% rename from src/bin/drone.rs rename to drone/src/bin/drone.rs index a335b6d3b4..a61153bfa6 100644 --- a/src/bin/drone.rs +++ b/drone/src/bin/drone.rs @@ -4,9 +4,10 @@ extern crate bytes; #[macro_use] extern crate clap; extern crate log; -extern crate serde_json; -extern crate solana; +#[macro_use] +extern crate solana_drone; extern crate solana_metrics; +extern crate solana_sdk; extern crate tokio; extern crate tokio_codec; @@ -14,9 +15,9 @@ use bincode::{deserialize, serialize}; use byteorder::{ByteOrder, LittleEndian}; use bytes::Bytes; use clap::{App, Arg}; -use solana::drone::{Drone, DroneRequest, DRONE_PORT}; -use solana::logger; -use solana::signature::read_keypair; +use solana_drone::drone::{Drone, DroneRequest, DRONE_PORT}; +//use solana::logger; +use solana_sdk::signature::read_keypair; use std::error; use std::io; use std::net::{Ipv4Addr, SocketAddr}; @@ -26,18 +27,8 @@ use tokio::net::TcpListener; use tokio::prelude::*; use tokio_codec::{BytesCodec, Decoder}; -macro_rules! socketaddr { - ($ip:expr, $port:expr) => { - SocketAddr::from((Ipv4Addr::from($ip), $port)) - }; - ($str:expr) => {{ - let a: SocketAddr = $str.parse().unwrap(); - a - }}; -} - fn main() -> Result<(), Box> { - logger::setup(); + //logger::setup(); solana_metrics::set_panic_hook("drone"); let matches = App::new("drone") .version(crate_version!()) diff --git a/src/drone.rs b/drone/src/drone.rs similarity index 92% rename from src/drone.rs rename to drone/src/drone.rs index e903af3024..b0a5ac73a4 100644 --- a/src/drone.rs +++ b/drone/src/drone.rs @@ -7,13 +7,14 @@ use bincode::{deserialize, serialize}; use byteorder::{ByteOrder, LittleEndian}; use bytes::Bytes; -use hash::Hash; - -use packet::PACKET_DATA_SIZE; -use signature::Keypair; use solana_metrics; use solana_metrics::influxdb; +use solana_sdk::hash::Hash; +use solana_sdk::packet::PACKET_DATA_SIZE; use solana_sdk::pubkey::Pubkey; +use solana_sdk::signature::Keypair; +use solana_sdk::system_instruction::{SystemInstruction, SYSTEM_PROGRAM_ID}; +use solana_sdk::transaction::Transaction; use std::io; use std::io::{Error, ErrorKind}; use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream}; @@ -21,12 +22,21 @@ use std::sync::mpsc::Sender; use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; -use system_transaction::SystemTransaction; use tokio; use tokio::net::TcpListener; use tokio::prelude::*; use tokio_codec::{BytesCodec, Decoder}; -use transaction::Transaction; + +#[macro_export] +macro_rules! socketaddr { + ($ip:expr, $port:expr) => { + SocketAddr::from((Ipv4Addr::from($ip), $port)) + }; + ($str:expr) => {{ + let a: SocketAddr = $str.parse().unwrap(); + a + }}; +} pub const TIME_SLICE: u64 = 60; pub const REQUEST_CAP: u64 = 500_000_000; @@ -124,9 +134,23 @@ impl Drone { ); info!("Requesting airdrop of {} to {:?}", tokens, to); - let mut tx = Transaction::system_new(&self.mint_keypair, to, tokens, last_id); - tx.sign(&[&self.mint_keypair], last_id); - Ok(tx) + + let create_instruction = SystemInstruction::CreateAccount { + tokens, + space: 0, + program_id: Pubkey::default(), + }; + let mut transaction = Transaction::new( + &self.mint_keypair, + &[to], + Pubkey::new(&SYSTEM_PROGRAM_ID), + &create_instruction, + last_id, + 0, /*fee*/ + ); + + transaction.sign(&[&self.mint_keypair], last_id); + Ok(transaction) } else { Err(Error::new(ErrorKind::Other, "token limit reached")) } @@ -276,7 +300,7 @@ mod tests { use logger; use mint::Mint; use netutil::get_ip_addr; - use signature::{Keypair, KeypairUtil}; + use solana_sdk::signature::{Keypair, KeypairUtil}; use std::fs::remove_dir_all; use std::net::{SocketAddr, UdpSocket}; use std::sync::{Arc, RwLock}; diff --git a/drone/src/lib.rs b/drone/src/lib.rs new file mode 100644 index 0000000000..5973e7534b --- /dev/null +++ b/drone/src/lib.rs @@ -0,0 +1,14 @@ +pub mod drone; + +extern crate bincode; +extern crate byteorder; +extern crate bytes; +#[macro_use] +extern crate log; +extern crate serde; +#[macro_use] +extern crate serde_derive; +extern crate solana_metrics; +extern crate solana_sdk; +extern crate tokio; +extern crate tokio_codec; diff --git a/multinode-demo/common.sh b/multinode-demo/common.sh index ea4acee18a..8b1816a92c 100644 --- a/multinode-demo/common.sh +++ b/multinode-demo/common.sh @@ -57,10 +57,13 @@ else program=${BASH_REMATCH[1]} features="--features=cuda" fi + if [[ "$program" = drone ]]; then + maybe_package="--package solana-drone" + fi if [[ -z $DEBUG ]]; then maybe_release=--release fi - printf "cargo run $maybe_release --bin solana-%s %s -- " "$program" "$features" + printf "cargo run $maybe_release $maybe_package --bin solana-%s %s -- " "$program" "$features" } if [[ -n $SOLANA_CUDA ]]; then # shellcheck disable=2154 # 'here' is referenced but not assigned diff --git a/net/net.sh b/net/net.sh index 8a61838b45..a2dc49a40f 100755 --- a/net/net.sh +++ b/net/net.sh @@ -136,7 +136,11 @@ build() { # shellcheck source=/dev/null source target/perf-libs/env.sh fi - $MAYBE_DOCKER cargo install --features="$cargoFeatures" --root farf + $MAYBE_DOCKER bash -c " + set -ex + cargo install --path drone --features=$cargoFeatures --root farf + cargo install --path . --features=$cargoFeatures --root farf + " ./scripts/install-native-programs.sh farf/ ) echo "Build took $SECONDS seconds" diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index a51819d897..ce11cbef40 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -11,7 +11,10 @@ bincode = "1.0.0" bs58 = "0.2.0" generic-array = { version = "0.12.0", default-features = false, features = ["serde"] } log = "0.4.2" +ring = "0.13.2" +sha2 = "0.8.0" serde = "1.0.27" serde_derive = "1.0.27" - +serde_json = "1.0.10" +untrusted = "0.6.2" diff --git a/src/hash.rs b/sdk/src/hash.rs similarity index 100% rename from src/hash.rs rename to sdk/src/hash.rs diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 5ba110f6ba..ba47799246 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -1,12 +1,22 @@ pub mod account; +pub mod hash; pub mod loader_instruction; pub mod native_program; +pub mod packet; pub mod pubkey; +pub mod signature; +pub mod system_instruction; pub mod timing; +pub mod transaction; extern crate bincode; extern crate bs58; extern crate generic_array; extern crate log; +extern crate ring; +extern crate serde; #[macro_use] extern crate serde_derive; +extern crate serde_json; +extern crate sha2; +extern crate untrusted; diff --git a/sdk/src/packet.rs b/sdk/src/packet.rs new file mode 100644 index 0000000000..a28761155b --- /dev/null +++ b/sdk/src/packet.rs @@ -0,0 +1,2 @@ +/// Maximum over-the-wire size of a Transaction +pub const PACKET_DATA_SIZE: usize = 512; diff --git a/sdk/src/signature.rs b/sdk/src/signature.rs new file mode 100644 index 0000000000..0cfcca4260 --- /dev/null +++ b/sdk/src/signature.rs @@ -0,0 +1,80 @@ +//! The `signature` module provides functionality for public, and private keys. + +use bs58; +use generic_array::typenum::U64; +use generic_array::GenericArray; +use pubkey::Pubkey; +use ring::signature::Ed25519KeyPair; +use ring::{rand, signature}; +use serde_json; +use std::error; +use std::fmt; +use std::fs::File; +use untrusted::Input; + +pub type Keypair = Ed25519KeyPair; + +#[derive(Serialize, Deserialize, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct Signature(GenericArray); + +impl Signature { + pub fn new(signature_slice: &[u8]) -> Self { + Signature(GenericArray::clone_from_slice(&signature_slice)) + } + + pub fn verify(&self, pubkey_bytes: &[u8], message_bytes: &[u8]) -> bool { + let pubkey = Input::from(pubkey_bytes); + let message = Input::from(message_bytes); + let signature = Input::from(self.0.as_slice()); + signature::verify(&signature::ED25519, pubkey, message, signature).is_ok() + } +} + +impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl fmt::Debug for Signature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", bs58::encode(self.0).into_string()) + } +} + +impl fmt::Display for Signature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", bs58::encode(self.0).into_string()) + } +} + +pub trait KeypairUtil { + fn new() -> Self; + fn pubkey(&self) -> Pubkey; +} + +impl KeypairUtil for Ed25519KeyPair { + /// Return a new ED25519 keypair + fn new() -> Self { + let rng = rand::SystemRandom::new(); + let pkcs8_bytes = Ed25519KeyPair::generate_pkcs8(&rng).expect("generate_pkcs8"); + Ed25519KeyPair::from_pkcs8(Input::from(&pkcs8_bytes)).expect("from_pcks8") + } + + /// Return the public key for the given keypair + fn pubkey(&self) -> Pubkey { + Pubkey::new(self.public_key_bytes()) + } +} + +pub fn read_pkcs8(path: &str) -> Result, Box> { + let file = File::open(path.to_string())?; + let pkcs8: Vec = serde_json::from_reader(file)?; + Ok(pkcs8) +} + +pub fn read_keypair(path: &str) -> Result> { + let pkcs8 = read_pkcs8(path)?; + let keypair = Ed25519KeyPair::from_pkcs8(Input::from(&pkcs8))?; + Ok(keypair) +} diff --git a/sdk/src/system_instruction.rs b/sdk/src/system_instruction.rs new file mode 100644 index 0000000000..865c518bc3 --- /dev/null +++ b/sdk/src/system_instruction.rs @@ -0,0 +1,28 @@ +use pubkey::Pubkey; + +pub const SYSTEM_PROGRAM_ID: [u8; 32] = [0u8; 32]; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum SystemInstruction { + /// Create a new account + /// * Transaction::keys[0] - source + /// * Transaction::keys[1] - new account key + /// * tokens - number of tokens to transfer to the new account + /// * space - memory to allocate if greater then zero + /// * program_id - the program id of the new account + CreateAccount { + tokens: u64, + space: u64, + program_id: Pubkey, + }, + /// Assign account to a program + /// * Transaction::keys[0] - account to assign + Assign { program_id: Pubkey }, + /// Move tokens + /// * Transaction::keys[0] - source + /// * Transaction::keys[1] - destination + Move { tokens: u64 }, + + /// Spawn a new program from an account + Spawn, +} diff --git a/sdk/src/transaction.rs b/sdk/src/transaction.rs new file mode 100644 index 0000000000..e65bda52de --- /dev/null +++ b/sdk/src/transaction.rs @@ -0,0 +1,334 @@ +//! The `transaction` module provides functionality for creating log transactions. + +use bincode::serialize; +use hash::{Hash, Hasher}; +use pubkey::Pubkey; +use serde::Serialize; +use signature::{Keypair, KeypairUtil, Signature}; +use std::mem::size_of; + +pub const SIG_OFFSET: usize = size_of::(); + +/// An instruction to execute a program under the `program_id` of `program_ids_index` with the +/// specified accounts and userdata +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub struct Instruction { + /// The program code that executes this transaction is identified by the program_id. + /// this is an offset into the Transaction::program_ids field + pub program_ids_index: u8, + /// Indices into the keys array of which accounts to load + pub accounts: Vec, + /// Userdata to be stored in the account + pub userdata: Vec, +} + +impl Instruction { + pub fn new(program_ids_index: u8, userdata: &T, accounts: Vec) -> Self { + let userdata = serialize(userdata).unwrap(); + Instruction { + program_ids_index, + userdata, + accounts, + } + } +} + +/// An atomic transaction +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub struct Transaction { + /// A set of digital signature of `account_keys`, `program_ids`, `last_id`, `fee` and `instructions`, signed by the first + /// signatures.len() keys of account_keys + pub signatures: Vec, + + /// The `Pubkeys` that are executing this transaction userdata. The meaning of each key is + /// program-specific. + /// * account_keys[0] - Typically this is the `caller` public key. `signature` is verified with account_keys[0]. + /// In the future which key pays the fee and which keys have signatures would be configurable. + /// * account_keys[1] - Typically this is the program context or the recipient of the tokens + pub account_keys: Vec, + + /// The ID of a recent ledger entry. + pub last_id: Hash, + + /// The number of tokens paid for processing and storage of this transaction. + pub fee: u64, + + /// Keys identifying programs in the instructions vector. + pub program_ids: Vec, + /// Programs that will be executed in sequence and commited in one atomic transaction if all + /// succeed. + pub instructions: Vec, +} + +impl Transaction { + pub fn new( + from_keypair: &Keypair, + transaction_keys: &[Pubkey], + program_id: Pubkey, + userdata: &T, + last_id: 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, userdata, accounts)]; + Self::new_with_instructions( + &[from_keypair], + transaction_keys, + last_id, + fee, + program_ids, + instructions, + ) + } + /// Create a signed transaction + /// * `from_keypair` - The key used to sign the transaction. This key is stored as keys[0] + /// * `account_keys` - The keys for the transaction. These are the program state + /// instances or token recipient keys. + /// * `last_id` - The PoH hash. + /// * `fee` - The transaction fee. + /// * `program_ids` - The keys that identify programs used in the `instruction` vector. + /// * `instructions` - The programs and their arguments that the transaction will execute atomically + pub fn new_with_instructions( + from_keypairs: &[&Keypair], + keys: &[Pubkey], + last_id: Hash, + fee: u64, + program_ids: Vec, + instructions: Vec, + ) -> 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, + last_id: Hash::default(), + fee, + program_ids, + instructions, + }; + tx.sign(from_keypairs, last_id); + tx + } + pub fn userdata(&self, instruction_index: usize) -> &[u8] { + &self.instructions[instruction_index].userdata + } + fn key_index(&self, instruction_index: usize, accounts_index: usize) -> Option { + 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 signed_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] + } + /// Get the transaction data to sign. + pub fn get_sign_data(&self) -> Vec { + let mut data = serialize(&self.account_keys).expect("serialize account_keys"); + + let last_id_data = serialize(&self.last_id).expect("serialize last_id"); + data.extend_from_slice(&last_id_data); + + let fee_data = serialize(&self.fee).expect("serialize fee"); + data.extend_from_slice(&fee_data); + + let program_ids = serialize(&self.program_ids).expect("serialize program_ids"); + data.extend_from_slice(&program_ids); + + let instructions = serialize(&self.instructions).expect("serialize instructions"); + data.extend_from_slice(&instructions); + data + } + + /// Sign this transaction. + pub fn sign(&mut self, keypairs: &[&Keypair], last_id: Hash) { + self.last_id = last_id; + let sign_data = self.get_sign_data(); + self.signatures = keypairs + .iter() + .map(|keypair| Signature::new(&keypair.sign(&sign_data).as_ref())) + .collect(); + } + + /// Verify only the transaction signature. + pub fn verify_signature(&self) -> bool { + self.signatures + .iter() + .all(|s| s.verify(&self.from().as_ref(), &self.get_sign_data())) + } + + /// Verify that references in the instructions are valid + 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] + } + + // a hash of a slice of transactions only needs to hash the signatures + pub fn hash(transactions: &[Transaction]) -> Hash { + let mut hasher = Hasher::default(); + transactions + .iter() + .for_each(|tx| hasher.hash(&tx.signatures[0].as_ref())); + hasher.result() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use bincode::serialize; + + #[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], + Default::default(), + 0, + vec![prog1, prog2], + instructions, + ); + assert!(tx.verify_refs()); + + assert_eq!(tx.key(0, 0), Some(&key.pubkey())); + assert_eq!(tx.signed_key(0, 0), Some(&key.pubkey())); + + assert_eq!(tx.key(1, 0), Some(&key.pubkey())); + assert_eq!(tx.signed_key(1, 0), Some(&key.pubkey())); + + assert_eq!(tx.key(0, 1), Some(&key1)); + assert_eq!(tx.signed_key(0, 1), None); + + assert_eq!(tx.key(1, 1), Some(&key2)); + assert_eq!(tx.signed_key(1, 1), None); + + assert_eq!(tx.key(2, 0), None); + assert_eq!(tx.signed_key(2, 0), None); + + assert_eq!(tx.key(0, 2), None); + assert_eq!(tx.signed_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], + &[], + Default::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], + &[], + Default::default(), + 0, + vec![Default::default()], + instructions, + ); + assert_eq!(*tx.program_id(0), Default::default()); + assert!(!tx.verify_refs()); + } + + /// Detect binary changes in the serialized contract userdata, which could have a downstream + /// affect on SDKs and DApps + #[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, + ])).expect("fu"); + 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![ + 1, 0, 0, 0, 0, 0, 0, 0, 213, 248, 255, 179, 219, 217, 130, 31, 27, 85, 33, 217, 62, + 28, 180, 204, 186, 141, 178, 150, 153, 184, 205, 87, 123, 128, 101, 254, 222, 111, + 152, 17, 153, 210, 169, 1, 81, 208, 254, 64, 229, 205, 145, 10, 213, 241, 255, 31, + 184, 52, 242, 148, 213, 131, 241, 165, 144, 181, 18, 4, 58, 171, 44, 11, 3, 0, 0, + 0, 0, 0, 0, 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, 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, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 + ], + ); + } +} diff --git a/src/bank.rs b/src/bank.rs index 952b0f270b..cb0eeebccb 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -9,7 +9,6 @@ use bpf_loader; use budget_program::BudgetState; use counter::Counter; use entry::Entry; -use hash::{hash, Hash}; use itertools::Itertools; use jsonrpc_macros::pubsub::Sink; use leader_scheduler::LeaderScheduler; @@ -25,7 +24,9 @@ use rpc::RpcSignatureStatus; use signature::Keypair; use signature::Signature; use solana_sdk::account::{create_keyed_accounts, Account, KeyedAccount}; +use solana_sdk::hash::{hash, Hash}; use solana_sdk::pubkey::Pubkey; +use solana_sdk::system_instruction::SystemInstruction; use solana_sdk::timing::{duration_as_us, timestamp}; use std; use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; @@ -1229,15 +1230,15 @@ impl Bank { let tx = &entry1.transactions[0]; assert!(SystemProgram::check_id(tx.program_id(0)), "Invalid ledger"); assert!(SystemProgram::check_id(tx.program_id(1)), "Invalid ledger"); - let mut instruction: SystemProgram = deserialize(tx.userdata(0)).unwrap(); - let mint_deposit = if let SystemProgram::Move { tokens } = instruction { + let mut instruction: SystemInstruction = deserialize(tx.userdata(0)).unwrap(); + let mint_deposit = if let SystemInstruction::Move { tokens } = instruction { Some(tokens) } else { None }.expect("invalid ledger, needs to start with mint deposit"); instruction = deserialize(tx.userdata(1)).unwrap(); - let leader_payment = if let SystemProgram::Move { tokens } = instruction { + let leader_payment = if let SystemInstruction::Move { tokens } = instruction { Some(tokens) } else { None @@ -1495,11 +1496,11 @@ mod tests { use budget_program::BudgetState; use entry::next_entry; use entry::Entry; - use hash::hash; use jsonrpc_macros::pubsub::{Subscriber, SubscriptionId}; use ledger; use signature::Keypair; use signature::{GenKeys, KeypairUtil}; + use solana_sdk::hash::hash; use std; use system_transaction::SystemTransaction; use tokio::prelude::{Async, Stream}; @@ -1573,7 +1574,7 @@ mod tests { let key1 = Keypair::new().pubkey(); let key2 = Keypair::new().pubkey(); let bank = Bank::new(&mint); - let spend = SystemProgram::Move { tokens: 1 }; + let spend = SystemInstruction::Move { tokens: 1 }; let instructions = vec![ Instruction { program_ids_index: 0, diff --git a/src/banking_stage.rs b/src/banking_stage.rs index cc2d81540f..b96b38c629 100644 --- a/src/banking_stage.rs +++ b/src/banking_stage.rs @@ -7,7 +7,6 @@ use bincode::deserialize; use compute_leader_finality_service::ComputeLeaderFinalityService; use counter::Counter; use entry::Entry; -use hash::Hash; use log::Level; use packet::Packets; use poh_recorder::{PohRecorder, PohRecorderError}; @@ -15,6 +14,7 @@ use poh_service::{Config, PohService}; use result::{Error, Result}; use service::Service; use sigverify_stage::VerifiedPackets; +use solana_sdk::hash::Hash; use solana_sdk::timing; use std::net::SocketAddr; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/src/bin/bench-tps.rs b/src/bin/bench-tps.rs index b40e75888d..09745b2366 100644 --- a/src/bin/bench-tps.rs +++ b/src/bin/bench-tps.rs @@ -8,6 +8,7 @@ extern crate log; extern crate serde_json; #[macro_use] extern crate solana; +extern crate solana_drone; extern crate solana_metrics; extern crate solana_sdk; @@ -17,8 +18,6 @@ use rand::{thread_rng, Rng}; use rayon::prelude::*; use solana::client::mk_client; use solana::cluster_info::{ClusterInfo, NodeInfo}; -use solana::drone::{request_airdrop_transaction, DRONE_PORT}; -use solana::hash::Hash; use solana::logger; use solana::ncp::Ncp; use solana::service::Service; @@ -27,7 +26,9 @@ use solana::system_transaction::SystemTransaction; use solana::thin_client::{poll_gossip_for_leader, ThinClient}; use solana::transaction::Transaction; use solana::window::default_window; +use solana_drone::drone::{request_airdrop_transaction, DRONE_PORT}; use solana_metrics::influxdb; +use solana_sdk::hash::Hash; use solana_sdk::timing::timestamp; use solana_sdk::timing::{duration_as_ms, duration_as_s}; use std::cmp; diff --git a/src/bin/replicator.rs b/src/bin/replicator.rs index 8f55aee42a..165fa1c89b 100644 --- a/src/bin/replicator.rs +++ b/src/bin/replicator.rs @@ -4,12 +4,12 @@ extern crate getopts; extern crate serde_json; #[macro_use] extern crate solana; +extern crate solana_drone; use clap::{App, Arg}; use solana::chacha::{chacha_cbc_encrypt_file, CHACHA_BLOCK_SIZE}; use solana::client::mk_client; use solana::cluster_info::Node; -use solana::drone::{request_airdrop_transaction, DRONE_PORT}; use solana::fullnode::Config; use solana::ledger::LEDGER_DATA_FILE; use solana::logger; @@ -17,6 +17,7 @@ use solana::replicator::{sample_file, Replicator}; use solana::signature::{Keypair, KeypairUtil}; use solana::storage_transaction::StorageTransaction; use solana::transaction::Transaction; +use solana_drone::drone::{request_airdrop_transaction, DRONE_PORT}; use std::fs::File; use std::net::{Ipv4Addr, SocketAddr}; use std::path::Path; diff --git a/src/bloom.rs b/src/bloom.rs index b2d7f07bfc..98cbeeebff 100644 --- a/src/bloom.rs +++ b/src/bloom.rs @@ -59,7 +59,7 @@ impl Bloom { #[cfg(test)] mod test { use super::*; - use hash::{hash, Hash}; + use solana_sdk::hash::{hash, Hash}; #[test] fn test_bloom_filter() { diff --git a/src/budget_program.rs b/src/budget_program.rs index a21eba5d45..16603ddfcb 100644 --- a/src/budget_program.rs +++ b/src/budget_program.rs @@ -254,9 +254,9 @@ mod test { use budget_program::{BudgetError, BudgetState}; use budget_transaction::BudgetTransaction; use chrono::prelude::{DateTime, NaiveDate, Utc}; - use hash::Hash; use signature::{GenKeys, Keypair, KeypairUtil}; use solana_sdk::account::Account; + use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; use transaction::Transaction; diff --git a/src/budget_transaction.rs b/src/budget_transaction.rs index 6fa3ebb199..7f664890cd 100644 --- a/src/budget_transaction.rs +++ b/src/budget_transaction.rs @@ -5,11 +5,11 @@ use budget_expr::{BudgetExpr, Condition}; use budget_instruction::Instruction; use budget_program::BudgetState; use chrono::prelude::*; -use hash::Hash; use payment_plan::Payment; use signature::{Keypair, KeypairUtil}; +use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; -use system_program::SystemProgram; +use solana_sdk::system_instruction::{SystemInstruction, SYSTEM_PROGRAM_ID}; use transaction::{self, Transaction}; pub trait BudgetTransaction { @@ -60,7 +60,7 @@ pub trait BudgetTransaction { ) -> Self; fn instruction(&self, program_index: usize) -> Option; - fn system_instruction(&self, program_index: usize) -> Option; + fn system_instruction(&self, program_index: usize) -> Option; fn verify_plan(&self) -> bool; } @@ -77,7 +77,7 @@ impl BudgetTransaction for Transaction { let contract = Keypair::new().pubkey(); let keys = vec![from_keypair.pubkey(), contract]; - let system_instruction = SystemProgram::Move { tokens }; + let system_instruction = SystemInstruction::Move { tokens }; let payment = Payment { tokens: tokens - fee, @@ -85,7 +85,7 @@ impl BudgetTransaction for Transaction { }; let budget_instruction = Instruction::NewBudget(BudgetExpr::Pay(payment)); - let program_ids = vec![SystemProgram::id(), BudgetState::id()]; + let program_ids = vec![Pubkey::new(&SYSTEM_PROGRAM_ID), BudgetState::id()]; let instructions = vec![ transaction::Instruction::new(0, &system_instruction, vec![0, 1]), @@ -206,13 +206,13 @@ impl BudgetTransaction for Transaction { deserialize(&self.userdata(instruction_index)).ok() } - fn system_instruction(&self, instruction_index: usize) -> Option { + fn system_instruction(&self, instruction_index: usize) -> Option { deserialize(&self.userdata(instruction_index)).ok() } /// Verify only the payment plan. fn verify_plan(&self) -> bool { - if let Some(SystemProgram::Move { tokens }) = self.system_instruction(0) { + if let Some(SystemInstruction::Move { tokens }) = self.system_instruction(0) { if let Some(Instruction::NewBudget(expr)) = self.instruction(1) { if !(self.fee <= tokens && expr.verify(tokens - self.fee)) { return false; @@ -284,7 +284,7 @@ mod tests { let pubkey = keypair.pubkey(); let mut tx = Transaction::budget_new(&keypair, pubkey, 42, zero); let mut system_instruction = tx.system_instruction(0).unwrap(); - if let SystemProgram::Move { ref mut tokens } = system_instruction { + if let SystemInstruction::Move { ref mut tokens } = system_instruction { *tokens = 1_000_000; // <-- attack, part 1! let mut instruction = tx.instruction(1).unwrap(); if let Instruction::NewBudget(ref mut expr) = instruction { diff --git a/src/chacha_cuda.rs b/src/chacha_cuda.rs index 2a9a163aab..b9dfb31042 100644 --- a/src/chacha_cuda.rs +++ b/src/chacha_cuda.rs @@ -1,7 +1,7 @@ use chacha::{CHACHA_BLOCK_SIZE, CHACHA_KEY_SIZE}; -use hash::Hash; use ledger::LedgerWindow; use sigverify::{chacha_cbc_encrypt_many_sample, chacha_end_sha_state, chacha_init_sha_state}; +use solana_sdk::hash::Hash; use std::io; use std::mem::size_of; @@ -102,10 +102,10 @@ pub fn chacha_cbc_encrypt_file_many_keys( mod tests { use chacha::chacha_cbc_encrypt_file; use chacha_cuda::chacha_cbc_encrypt_file_many_keys; - use hash::Hash; use ledger::LedgerWriter; use ledger::{get_tmp_ledger_path, make_tiny_test_entries, LEDGER_DATA_FILE}; use replicator::sample_file; + use solana_sdk::hash::Hash; use std::fs::{remove_dir_all, remove_file}; use std::path::Path; diff --git a/src/cluster_info.rs b/src/cluster_info.rs index 0c98146409..e3f64875ca 100644 --- a/src/cluster_info.rs +++ b/src/cluster_info.rs @@ -19,7 +19,6 @@ use counter::Counter; use crds_gossip::CrdsGossip; use crds_gossip_pull::CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS; use crds_value::{CrdsValue, CrdsValueLabel, LeaderId}; -use hash::Hash; use ledger::LedgerWindow; use log::Level; use netutil::{bind_in_range, bind_to, find_available_port_in_range, multi_bind_in_range}; @@ -29,6 +28,7 @@ use rayon::prelude::*; use result::Result; use rpc::RPC_PORT; use signature::{Keypair, KeypairUtil}; +use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; use solana_sdk::timing::{duration_as_ms, timestamp}; use std::collections::HashMap; @@ -1046,12 +1046,12 @@ mod tests { use super::*; use crds_value::CrdsValueLabel; use entry::Entry; - use hash::{hash, Hash}; use ledger::{get_tmp_ledger_path, LedgerWindow, LedgerWriter}; use logger; use packet::SharedBlob; use result::Error; use signature::{Keypair, KeypairUtil}; + use solana_sdk::hash::{hash, Hash}; use std::fs::remove_dir_all; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::sync::{Arc, RwLock}; diff --git a/src/compute_leader_finality_service.rs b/src/compute_leader_finality_service.rs index 933da63da3..0ab54e76e3 100644 --- a/src/compute_leader_finality_service.rs +++ b/src/compute_leader_finality_service.rs @@ -136,10 +136,10 @@ pub mod tests { use bank::Bank; use bincode::serialize; use compute_leader_finality_service::ComputeLeaderFinalityService; - use hash::hash; use logger; use mint::Mint; use signature::{Keypair, KeypairUtil}; + use solana_sdk::hash::hash; use std::sync::Arc; use std::thread::sleep; use std::time::Duration; diff --git a/src/crds.rs b/src/crds.rs index cf054017f8..82e40320e0 100644 --- a/src/crds.rs +++ b/src/crds.rs @@ -26,8 +26,8 @@ use bincode::serialize; use crds_value::{CrdsValue, CrdsValueLabel}; -use hash::{hash, Hash}; use indexmap::map::IndexMap; +use solana_sdk::hash::{hash, Hash}; use solana_sdk::pubkey::Pubkey; use std::cmp; diff --git a/src/crds_gossip.rs b/src/crds_gossip.rs index 07937a69de..57fb21bbe1 100644 --- a/src/crds_gossip.rs +++ b/src/crds_gossip.rs @@ -9,7 +9,7 @@ use crds_gossip_error::CrdsGossipError; use crds_gossip_pull::CrdsGossipPull; use crds_gossip_push::{CrdsGossipPush, CRDS_GOSSIP_NUM_ACTIVE}; use crds_value::CrdsValue; -use hash::Hash; +use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; pub struct CrdsGossip { diff --git a/src/crds_gossip_pull.rs b/src/crds_gossip_pull.rs index 2555aa56e1..2b77fbfa1b 100644 --- a/src/crds_gossip_pull.rs +++ b/src/crds_gossip_pull.rs @@ -14,10 +14,10 @@ use bloom::Bloom; use crds::Crds; use crds_gossip_error::CrdsGossipError; use crds_value::{CrdsValue, CrdsValueLabel}; -use hash::Hash; use packet::BLOB_DATA_SIZE; use rand; use rand::distributions::{Distribution, Weighted, WeightedChoice}; +use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; use std::cmp; use std::collections::HashMap; diff --git a/src/crds_gossip_push.rs b/src/crds_gossip_push.rs index 79d2e1efae..afdd872737 100644 --- a/src/crds_gossip_push.rs +++ b/src/crds_gossip_push.rs @@ -13,10 +13,10 @@ use bloom::Bloom; use crds::{Crds, VersionedCrdsValue}; use crds_gossip_error::CrdsGossipError; use crds_value::{CrdsValue, CrdsValueLabel}; -use hash::Hash; use indexmap::map::IndexMap; use packet::BLOB_DATA_SIZE; use rand::{self, Rng}; +use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; use std::cmp; use std::collections::HashMap; diff --git a/src/crds_traits_impls.rs b/src/crds_traits_impls.rs index b2c9db2142..382a8d50f6 100644 --- a/src/crds_traits_impls.rs +++ b/src/crds_traits_impls.rs @@ -1,5 +1,5 @@ use bloom::BloomHashIndex; -use hash::Hash; +use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; fn slice_hash(slice: &[u8], hash_index: u64) -> u64 { diff --git a/src/entry.rs b/src/entry.rs index 10b1bc483f..503c4922c2 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -3,10 +3,10 @@ //! transactions within it. Entries cannot be reordered, and its field `num_hashes` //! represents an approximate amount of time since the last Entry was created. use bincode::{deserialize, serialize_into, serialized_size}; -use hash::Hash; use packet::{SharedBlob, BLOB_DATA_SIZE}; use poh::Poh; use result::Result; +use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; use std::io::Cursor; use std::mem::size_of; @@ -275,8 +275,8 @@ mod tests { use budget_transaction::BudgetTransaction; use chrono::prelude::*; use entry::Entry; - use hash::hash; use signature::{Keypair, KeypairUtil}; + use solana_sdk::hash::hash; use system_transaction::SystemTransaction; use transaction::Transaction; diff --git a/src/fullnode.rs b/src/fullnode.rs index 137bf3860a..b65e17325e 100644 --- a/src/fullnode.rs +++ b/src/fullnode.rs @@ -3,7 +3,6 @@ use bank::Bank; use broadcast_stage::BroadcastStage; use cluster_info::{ClusterInfo, Node, NodeInfo}; -use hash::Hash; use leader_scheduler::LeaderScheduler; use ledger::read_ledger; use ncp::Ncp; @@ -11,6 +10,7 @@ use rpc::JsonRpcService; use rpc_pubsub::PubSubService; use service::Service; use signature::{Keypair, KeypairUtil}; +use solana_sdk::hash::Hash; use solana_sdk::timing::timestamp; use std::net::UdpSocket; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; diff --git a/src/leader_scheduler.rs b/src/leader_scheduler.rs index b8f278d267..b991948dcc 100644 --- a/src/leader_scheduler.rs +++ b/src/leader_scheduler.rs @@ -6,9 +6,9 @@ use bank::Bank; use bincode::serialize; use byteorder::{LittleEndian, ReadBytesExt}; use entry::Entry; -use hash::{hash, Hash}; use ledger::create_ticks; use signature::{Keypair, KeypairUtil}; +use solana_sdk::hash::{hash, Hash}; use solana_sdk::pubkey::Pubkey; use std::collections::HashSet; use std::io::Cursor; @@ -493,13 +493,13 @@ pub fn make_active_set_entries( #[cfg(test)] mod tests { use bank::Bank; - use hash::Hash; use leader_scheduler::{ LeaderScheduler, LeaderSchedulerConfig, DEFAULT_BOOTSTRAP_HEIGHT, DEFAULT_LEADER_ROTATION_INTERVAL, DEFAULT_SEED_ROTATION_INTERVAL, }; use mint::Mint; use signature::{Keypair, KeypairUtil}; + use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; use std::collections::HashSet; use std::hash::Hash as StdHash; diff --git a/src/ledger.rs b/src/ledger.rs index f42042e52e..e37314dc2a 100644 --- a/src/ledger.rs +++ b/src/ledger.rs @@ -8,14 +8,14 @@ use budget_transaction::BudgetTransaction; #[cfg(test)] use chrono::prelude::Utc; use entry::Entry; -#[cfg(test)] -use hash::hash; -use hash::Hash; use log::Level::Trace; use mint::Mint; use packet::{SharedBlob, BLOB_DATA_SIZE}; use rayon::prelude::*; use signature::{Keypair, KeypairUtil}; +#[cfg(test)] +use solana_sdk::hash::hash; +use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; use std::fs::{create_dir_all, remove_dir_all, File, OpenOptions}; use std::io::prelude::*; @@ -672,9 +672,9 @@ mod tests { use bincode::{deserialize, serialized_size}; use budget_transaction::BudgetTransaction; use entry::{next_entry, reconstruct_entries_from_blobs, Entry}; - use hash::hash; use packet::{to_blobs, BLOB_DATA_SIZE, PACKET_DATA_SIZE}; use signature::{Keypair, KeypairUtil}; + use solana_sdk::hash::hash; use std; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use transaction::Transaction; diff --git a/src/lib.rs b/src/lib.rs index 9c7916ca68..b8d156c2b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,13 +36,11 @@ pub mod budget_program; pub mod cluster_info; pub mod compute_leader_finality_service; pub mod db_ledger; -pub mod drone; pub mod entry; #[cfg(feature = "erasure")] pub mod erasure; pub mod fetch_stage; pub mod fullnode; -pub mod hash; pub mod leader_scheduler; pub mod ledger; pub mod ledger_write_stage; @@ -122,6 +120,7 @@ extern crate serde_json; extern crate serde_cbor; extern crate sha2; extern crate socket2; +extern crate solana_drone; extern crate solana_jsonrpc_core as jsonrpc_core; extern crate solana_jsonrpc_http_server as jsonrpc_http_server; #[macro_use] diff --git a/src/loader_transaction.rs b/src/loader_transaction.rs index 6cf7cd3de8..10bc3eecb9 100644 --- a/src/loader_transaction.rs +++ b/src/loader_transaction.rs @@ -1,7 +1,7 @@ //! The `dynamic_transaction` module provides functionality for loading and calling a program -use hash::Hash; use signature::{Keypair, KeypairUtil}; +use solana_sdk::hash::Hash; use solana_sdk::loader_instruction::LoaderInstruction; use solana_sdk::pubkey::Pubkey; use transaction::Transaction; diff --git a/src/mint.rs b/src/mint.rs index e14fac16b4..87f8fdf2ee 100644 --- a/src/mint.rs +++ b/src/mint.rs @@ -1,9 +1,9 @@ //! The `mint` module is a library for generating the chain's genesis block. use entry::Entry; -use hash::{hash, Hash}; use ring::rand::SystemRandom; use signature::{Keypair, KeypairUtil}; +use solana_sdk::hash::{hash, Hash}; use solana_sdk::pubkey::Pubkey; use system_transaction::SystemTransaction; use transaction::Transaction; @@ -108,6 +108,7 @@ mod tests { use super::*; use bincode::deserialize; use ledger::Block; + use solana_sdk::system_instruction::SystemInstruction; use system_program::SystemProgram; #[test] @@ -116,8 +117,8 @@ mod tests { let tx = transactions.next().unwrap(); assert_eq!(tx.instructions.len(), 1); assert!(SystemProgram::check_id(tx.program_id(0))); - let instruction: SystemProgram = deserialize(tx.userdata(0)).unwrap(); - if let SystemProgram::Move { tokens } = instruction { + let instruction: SystemInstruction = deserialize(tx.userdata(0)).unwrap(); + if let SystemInstruction::Move { tokens } = instruction { assert_eq!(tokens, 100); } assert_eq!(transactions.next(), None); @@ -134,12 +135,12 @@ mod tests { assert_eq!(tx.instructions.len(), 2); assert!(SystemProgram::check_id(tx.program_id(0))); assert!(SystemProgram::check_id(tx.program_id(1))); - let instruction: SystemProgram = deserialize(tx.userdata(0)).unwrap(); - if let SystemProgram::Move { tokens } = instruction { + let instruction: SystemInstruction = deserialize(tx.userdata(0)).unwrap(); + if let SystemInstruction::Move { tokens } = instruction { assert_eq!(tokens, 100); } - let instruction: SystemProgram = deserialize(tx.userdata(1)).unwrap(); - if let SystemProgram::Move { tokens } = instruction { + let instruction: SystemInstruction = deserialize(tx.userdata(1)).unwrap(); + if let SystemInstruction::Move { tokens } = instruction { assert_eq!(tokens, 1); } assert_eq!(transactions.next(), None); diff --git a/src/packet.rs b/src/packet.rs index 150eee8e49..f9b102d81f 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -5,13 +5,14 @@ use counter::Counter; #[cfg(test)] use entry::Entry; #[cfg(test)] -use hash::Hash; -#[cfg(test)] use ledger::Block; use log::Level; use recvmmsg::{recv_mmsg, NUM_RCVMMSGS}; use result::{Error, Result}; use serde::Serialize; +#[cfg(test)] +use solana_sdk::hash::Hash; +pub use solana_sdk::packet::PACKET_DATA_SIZE; use solana_sdk::pubkey::Pubkey; use std::fmt; use std::io; @@ -27,7 +28,6 @@ pub type SharedBlobs = Vec; pub const NUM_PACKETS: usize = 1024 * 8; pub const BLOB_SIZE: usize = (64 * 1024 - 128); // wikipedia says there should be 20b for ipv4 headers pub const BLOB_DATA_SIZE: usize = BLOB_SIZE - (BLOB_HEADER_SIZE * 2); -pub const PACKET_DATA_SIZE: usize = 512; pub const NUM_BLOBS: usize = (NUM_PACKETS * PACKET_DATA_SIZE) / BLOB_SIZE; #[derive(Clone, Default, Debug, PartialEq)] @@ -457,12 +457,12 @@ pub fn make_consecutive_blobs( #[cfg(test)] mod tests { - use hash::Hash; use packet::{ to_packets, Blob, Meta, Packet, Packets, SharedBlob, SharedPackets, NUM_PACKETS, PACKET_DATA_SIZE, }; use signature::{Keypair, KeypairUtil}; + use solana_sdk::hash::Hash; use std::io; use std::io::Write; use std::net::UdpSocket; diff --git a/src/poh.rs b/src/poh.rs index 934c29998c..1b1a908b98 100644 --- a/src/poh.rs +++ b/src/poh.rs @@ -1,6 +1,6 @@ //! The `Poh` module provides an object for generating a Proof of History. //! It records Hashes items on behalf of its users. -use hash::{hash, hashv, Hash}; +use solana_sdk::hash::{hash, hashv, Hash}; pub struct Poh { prev_id: Hash, @@ -96,8 +96,8 @@ pub fn verify(initial: Hash, entries: &[PohEntry]) -> bool { #[cfg(test)] mod tests { - use hash::Hash; use poh::{self, PohEntry}; + use solana_sdk::hash::Hash; #[test] #[should_panic] diff --git a/src/poh_recorder.rs b/src/poh_recorder.rs index a1b1c8368a..0ac484c8c0 100644 --- a/src/poh_recorder.rs +++ b/src/poh_recorder.rs @@ -3,9 +3,9 @@ //! use bank::Bank; use entry::Entry; -use hash::Hash; use poh::Poh; use result::{Error, Result}; +use solana_sdk::hash::Hash; use std::sync::mpsc::Sender; use std::sync::{Arc, Mutex}; use transaction::Transaction; @@ -118,8 +118,8 @@ impl PohRecorder { #[cfg(test)] mod tests { use super::*; - use hash::hash; use mint::Mint; + use solana_sdk::hash::hash; use std::sync::mpsc::channel; use std::sync::Arc; use system_transaction::test_tx; diff --git a/src/replicate_stage.rs b/src/replicate_stage.rs index e689240f8d..4ec71f23a0 100644 --- a/src/replicate_stage.rs +++ b/src/replicate_stage.rs @@ -4,7 +4,7 @@ use bank::Bank; use cluster_info::ClusterInfo; use counter::Counter; use entry::{EntryReceiver, EntrySender}; -use hash::Hash; +use solana_sdk::hash::Hash; use ledger::Block; use log::Level; @@ -246,7 +246,6 @@ mod test { use cluster_info::{ClusterInfo, Node}; use entry::Entry; use fullnode::Fullnode; - use hash::Hash; use leader_scheduler::{make_active_set_entries, LeaderScheduler, LeaderSchedulerConfig}; use ledger::{create_ticks, create_tmp_sample_ledger, LedgerWriter}; use logger; @@ -255,6 +254,7 @@ mod test { use result::Error; use service::Service; use signature::{Keypair, KeypairUtil}; + use solana_sdk::hash::Hash; use std::fs::remove_dir_all; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::channel; diff --git a/src/replicator.rs b/src/replicator.rs index d007a9ae2a..86548aaa85 100644 --- a/src/replicator.rs +++ b/src/replicator.rs @@ -1,9 +1,9 @@ use blob_fetch_stage::BlobFetchStage; use cluster_info::{ClusterInfo, Node, NodeInfo}; -use hash::{Hash, Hasher}; use leader_scheduler::LeaderScheduler; use ncp::Ncp; use service::Service; +use solana_sdk::hash::{Hash, Hasher}; use std::fs::File; use std::io; use std::io::BufReader; @@ -168,13 +168,13 @@ mod tests { use client::mk_client; use cluster_info::Node; use fullnode::Fullnode; - use hash::Hash; use leader_scheduler::LeaderScheduler; use ledger::{create_tmp_genesis, get_tmp_ledger_path, read_ledger}; use logger; use replicator::sample_file; use replicator::Replicator; use signature::{Keypair, KeypairUtil}; + use solana_sdk::hash::Hash; use std::fs::File; use std::fs::{create_dir_all, remove_dir_all, remove_file}; use std::io::Write; diff --git a/src/rpc.rs b/src/rpc.rs index 9b3a74780d..8c05b88bc7 100644 --- a/src/rpc.rs +++ b/src/rpc.rs @@ -4,12 +4,12 @@ use bank::{Bank, BankError}; use bincode::{deserialize, serialize}; use bs58; use cluster_info::ClusterInfo; -use drone::{request_airdrop_transaction, DRONE_PORT}; use jsonrpc_core::*; use jsonrpc_http_server::*; use packet::PACKET_DATA_SIZE; use service::Service; use signature::Signature; +use solana_drone::drone::{request_airdrop_transaction, DRONE_PORT}; use solana_sdk::account::Account; use solana_sdk::pubkey::Pubkey; use std::mem; @@ -363,7 +363,6 @@ mod tests { use bincode::serialize; use cluster_info::{Node, NodeInfo}; use fullnode::Fullnode; - use hash::{hash, Hash}; use jsonrpc_core::Response; use leader_scheduler::LeaderScheduler; use ledger::create_tmp_ledger_with_mint; @@ -371,6 +370,7 @@ mod tests { use reqwest; use reqwest::header::CONTENT_TYPE; use signature::{Keypair, KeypairUtil}; + use solana_sdk::hash::{hash, Hash}; use std::fs::remove_dir_all; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use system_transaction::SystemTransaction; diff --git a/src/signature.rs b/src/signature.rs index 17c24b345d..fa283ff885 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -1,72 +1,10 @@ //! The `signature` module provides functionality for public, and private keys. -use bs58; -use generic_array::typenum::U64; -use generic_array::GenericArray; use rand::{ChaChaRng, Rng, SeedableRng}; use rayon::prelude::*; -use ring::signature::Ed25519KeyPair; -use ring::{rand, signature}; -use serde_json; -use solana_sdk::pubkey::Pubkey; -use std::error; -use std::fmt; -use std::fs::File; use untrusted::Input; -pub type Keypair = Ed25519KeyPair; - -#[derive(Serialize, Deserialize, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub struct Signature(GenericArray); - -impl Signature { - pub fn new(signature_slice: &[u8]) -> Self { - Signature(GenericArray::clone_from_slice(&signature_slice)) - } - pub fn verify(&self, pubkey_bytes: &[u8], message_bytes: &[u8]) -> bool { - let pubkey = Input::from(pubkey_bytes); - let message = Input::from(message_bytes); - let signature = Input::from(self.0.as_slice()); - signature::verify(&signature::ED25519, pubkey, message, signature).is_ok() - } -} - -impl AsRef<[u8]> for Signature { - fn as_ref(&self) -> &[u8] { - &self.0[..] - } -} - -impl fmt::Debug for Signature { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", bs58::encode(self.0).into_string()) - } -} - -impl fmt::Display for Signature { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", bs58::encode(self.0).into_string()) - } -} - -pub trait KeypairUtil { - fn new() -> Self; - fn pubkey(&self) -> Pubkey; -} - -impl KeypairUtil for Ed25519KeyPair { - /// Return a new ED25519 keypair - fn new() -> Self { - let rng = rand::SystemRandom::new(); - let pkcs8_bytes = Ed25519KeyPair::generate_pkcs8(&rng).expect("generate_pkcs8"); - Ed25519KeyPair::from_pkcs8(Input::from(&pkcs8_bytes)).expect("from_pcks8") - } - - /// Return the public key for the given keypair - fn pubkey(&self) -> Pubkey { - Pubkey::new(self.public_key_bytes()) - } -} +pub use solana_sdk::signature::*; pub struct GenKeys { generator: ChaChaRng, @@ -96,21 +34,10 @@ impl GenKeys { } } -pub fn read_pkcs8(path: &str) -> Result, Box> { - let file = File::open(path.to_string())?; - let pkcs8: Vec = serde_json::from_reader(file)?; - Ok(pkcs8) -} - -pub fn read_keypair(path: &str) -> Result> { - let pkcs8 = read_pkcs8(path)?; - let keypair = Ed25519KeyPair::from_pkcs8(Input::from(&pkcs8))?; - Ok(keypair) -} - #[cfg(test)] mod tests { use super::*; + pub use solana_sdk::pubkey::Pubkey; use std::collections::HashSet; #[test] diff --git a/src/sigverify.rs b/src/sigverify.rs index 1d73b61a76..301b18bf2f 100644 --- a/src/sigverify.rs +++ b/src/sigverify.rs @@ -324,10 +324,11 @@ pub fn make_packet_from_transaction(tx: Transaction) -> Packet { mod tests { use bincode::serialize; use budget_program::BudgetState; - use hash::Hash; use packet::{Packet, SharedPackets}; use signature::{Keypair, KeypairUtil}; use sigverify; + use solana_sdk::hash::Hash; + use solana_sdk::system_instruction::SystemInstruction; use system_program::SystemProgram; use system_transaction::{memfind, test_tx}; use transaction; @@ -426,7 +427,7 @@ mod tests { let keys = vec![keypair0.pubkey(), keypair1.pubkey()]; - let system_instruction = SystemProgram::Move { tokens }; + let system_instruction = SystemInstruction::Move { tokens }; let program_ids = vec![SystemProgram::id(), BudgetState::id()]; diff --git a/src/storage_program.rs b/src/storage_program.rs index dd18914276..bced49441a 100644 --- a/src/storage_program.rs +++ b/src/storage_program.rs @@ -3,8 +3,8 @@ //! and give reward for good proofs. use bincode::deserialize; -use hash::Hash; use solana_sdk::account::Account; +use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; use transaction::Transaction; diff --git a/src/storage_stage.rs b/src/storage_stage.rs index db6f1be291..5199c56351 100644 --- a/src/storage_stage.rs +++ b/src/storage_stage.rs @@ -5,12 +5,12 @@ #[cfg(all(feature = "chacha", feature = "cuda"))] use chacha_cuda::chacha_cbc_encrypt_file_many_keys; use entry::EntryReceiver; -use hash::Hash; use rand::{ChaChaRng, Rng, SeedableRng}; use result::{Error, Result}; use service::Service; use signature::Keypair; use signature::Signature; +use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; use std::mem::size_of; use std::sync::atomic::{AtomicBool, Ordering}; @@ -260,12 +260,12 @@ impl Service for StorageStage { #[cfg(test)] mod tests { use entry::Entry; - use hash::Hash; use ledger::make_tiny_test_entries; use ledger::{create_tmp_sample_ledger, LedgerWriter}; use logger; use service::Service; use signature::{Keypair, KeypairUtil}; + use solana_sdk::hash::Hash; use std::cmp::{max, min}; use std::fs::remove_dir_all; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/src/storage_transaction.rs b/src/storage_transaction.rs index b99a7f388b..70682c04f2 100644 --- a/src/storage_transaction.rs +++ b/src/storage_transaction.rs @@ -1,5 +1,5 @@ -use hash::Hash; use signature::{Keypair, KeypairUtil}; +use solana_sdk::hash::Hash; use storage_program::StorageProgram; use transaction::Transaction; diff --git a/src/system_program.rs b/src/system_program.rs index ec8f853d20..ce9698a1f7 100644 --- a/src/system_program.rs +++ b/src/system_program.rs @@ -3,6 +3,7 @@ use bincode::deserialize; use solana_sdk::account::Account; use solana_sdk::pubkey::Pubkey; +use solana_sdk::system_instruction::SystemInstruction; use std; use transaction::Transaction; @@ -22,30 +23,7 @@ impl std::error::Error for Error {} pub type Result = std::result::Result; -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum SystemProgram { - /// Create a new account - /// * Transaction::keys[0] - source - /// * Transaction::keys[1] - new account key - /// * tokens - number of tokens to transfer to the new account - /// * space - memory to allocate if greater then zero - /// * program_id - the program id of the new account - CreateAccount { - tokens: u64, - space: u64, - program_id: Pubkey, - }, - /// Assign account to a program - /// * Transaction::keys[0] - account to assign - Assign { program_id: Pubkey }, - /// Move tokens - /// * Transaction::keys[0] - source - /// * Transaction::keys[1] - destination - Move { tokens: u64 }, - - /// Spawn a new program from an account - Spawn, -} +pub struct SystemProgram {} pub const SYSTEM_PROGRAM_ID: [u8; 32] = [0u8; 32]; @@ -68,7 +46,7 @@ impl SystemProgram { if let Ok(syscall) = deserialize(tx.userdata(pix)) { trace!("process_transaction: {:?}", syscall); match syscall { - SystemProgram::CreateAccount { + SystemInstruction::CreateAccount { tokens, space, program_id, @@ -95,13 +73,13 @@ impl SystemProgram { accounts[1].executable = false; accounts[1].loader = Pubkey::default(); } - SystemProgram::Assign { program_id } => { + SystemInstruction::Assign { program_id } => { if !Self::check_id(&accounts[0].owner) { Err(Error::AssignOfUnownedAccount)?; } accounts[0].owner = program_id; } - SystemProgram::Move { tokens } => { + SystemInstruction::Move { tokens } => { //bank should be verifying correctness if tokens > accounts[0].tokens { info!("Insufficient tokens in account[0]"); @@ -110,7 +88,7 @@ impl SystemProgram { accounts[0].tokens -= tokens; accounts[1].tokens += tokens; } - SystemProgram::Spawn => { + SystemInstruction::Spawn => { if !accounts[0].executable || accounts[0].loader != Pubkey::default() { Err(Error::AccountNotFinalized)?; } @@ -128,9 +106,9 @@ impl SystemProgram { #[cfg(test)] mod test { use super::*; - use hash::Hash; use signature::{Keypair, KeypairUtil}; use solana_sdk::account::Account; + use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; use system_program::SystemProgram; use system_transaction::SystemTransaction; diff --git a/src/system_transaction.rs b/src/system_transaction.rs index 63216726fe..fcd0cc29e7 100644 --- a/src/system_transaction.rs +++ b/src/system_transaction.rs @@ -1,9 +1,11 @@ //! The `system_transaction` module provides functionality for creating system transactions. -use hash::Hash; use signature::{Keypair, KeypairUtil}; +use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; +use solana_sdk::system_instruction::SystemInstruction; use system_program::SystemProgram; + use transaction::{Instruction, Transaction}; pub trait SystemTransaction { @@ -40,7 +42,7 @@ pub trait SystemTransaction { } impl SystemTransaction for Transaction { - /// Create and sign new SystemProgram::CreateAccount transaction + /// Create and sign new SystemInstruction::CreateAccount transaction fn system_create( from_keypair: &Keypair, to: Pubkey, @@ -50,7 +52,7 @@ impl SystemTransaction for Transaction { program_id: Pubkey, fee: u64, ) -> Self { - let create = SystemProgram::CreateAccount { + let create = SystemInstruction::CreateAccount { tokens, //TODO, the tokens to allocate might need to be higher then 0 in the future space, program_id, @@ -64,9 +66,9 @@ impl SystemTransaction for Transaction { fee, ) } - /// Create and sign new SystemProgram::Assign transaction + /// Create and sign new SystemInstruction::Assign transaction fn system_assign(from_keypair: &Keypair, last_id: Hash, program_id: Pubkey, fee: u64) -> Self { - let assign = SystemProgram::Assign { program_id }; + let assign = SystemInstruction::Assign { program_id }; Transaction::new( from_keypair, &[], @@ -76,11 +78,11 @@ impl SystemTransaction for Transaction { fee, ) } - /// Create and sign new SystemProgram::CreateAccount transaction with some defaults + /// Create and sign new SystemInstruction::CreateAccount transaction with some defaults fn system_new(from_keypair: &Keypair, to: Pubkey, tokens: u64, last_id: Hash) -> Self { Transaction::system_create(from_keypair, to, last_id, tokens, 0, Pubkey::default(), 0) } - /// Create and sign new SystemProgram::Move transaction + /// Create and sign new SystemInstruction::Move transaction fn system_move( from_keypair: &Keypair, to: Pubkey, @@ -88,7 +90,7 @@ impl SystemTransaction for Transaction { last_id: Hash, fee: u64, ) -> Self { - let move_tokens = SystemProgram::Move { tokens }; + let move_tokens = SystemInstruction::Move { tokens }; Transaction::new( from_keypair, &[to], @@ -98,13 +100,13 @@ impl SystemTransaction for Transaction { fee, ) } - /// Create and sign new SystemProgram::Move transaction to many destinations + /// Create and sign new SystemInstruction::Move transaction to many destinations fn system_move_many(from: &Keypair, moves: &[(Pubkey, u64)], last_id: Hash, fee: u64) -> Self { let instructions: Vec<_> = moves .iter() .enumerate() .map(|(i, (_, amount))| { - let spend = SystemProgram::Move { tokens: *amount }; + let spend = SystemInstruction::Move { tokens: *amount }; Instruction::new(0, &spend, vec![0, i as u8 + 1]) }).collect(); let to_keys: Vec<_> = moves.iter().map(|(to_key, _)| *to_key).collect(); @@ -118,9 +120,9 @@ impl SystemTransaction for Transaction { instructions, ) } - /// Create and sign new SystemProgram::Spawn transaction + /// Create and sign new SystemInstruction::Spawn transaction fn system_spawn(from_keypair: &Keypair, last_id: Hash, fee: u64) -> Self { - let spawn = SystemProgram::Spawn; + let spawn = SystemInstruction::Spawn; Transaction::new(from_keypair, &[], SystemProgram::id(), &spawn, last_id, fee) } } diff --git a/src/thin_client.rs b/src/thin_client.rs index a47970300a..127b5d05a4 100644 --- a/src/thin_client.rs +++ b/src/thin_client.rs @@ -7,7 +7,6 @@ use bank::Bank; use bincode::serialize; use bs58; use cluster_info::{ClusterInfo, ClusterInfoError, NodeInfo}; -use hash::Hash; use log::Level; use ncp::Ncp; use packet::PACKET_DATA_SIZE; @@ -18,6 +17,7 @@ use signature::{Keypair, Signature}; use solana_metrics; use solana_metrics::influxdb; use solana_sdk::account::Account; +use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; use solana_sdk::timing; use std; @@ -417,8 +417,8 @@ mod tests { use logger; use mint::Mint; use signature::{Keypair, KeypairUtil}; + use solana_sdk::system_instruction::SystemInstruction; use std::fs::remove_dir_all; - use system_program::SystemProgram; use vote_program::VoteProgram; use vote_transaction::VoteTransaction; @@ -520,7 +520,7 @@ mod tests { let mut tr2 = Transaction::system_new(&alice.keypair(), bob_pubkey, 501, last_id); let mut instruction2 = deserialize(tr2.userdata(0)).unwrap(); - if let SystemProgram::Move { ref mut tokens } = instruction2 { + if let SystemInstruction::Move { ref mut tokens } = instruction2 { *tokens = 502; } tr2.instructions[0].userdata = serialize(&instruction2).unwrap(); diff --git a/src/tpu.rs b/src/tpu.rs index 3a51699917..9678c6ef11 100644 --- a/src/tpu.rs +++ b/src/tpu.rs @@ -5,11 +5,11 @@ use bank::Bank; use banking_stage::{BankingStage, BankingStageReturnType}; use entry::Entry; use fetch_stage::FetchStage; -use hash::Hash; use ledger_write_stage::LedgerWriteStage; use poh_service::Config; use service::Service; use sigverify_stage::SigVerifyStage; +use solana_sdk::hash::Hash; use std::net::UdpSocket; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::Receiver; diff --git a/src/transaction.rs b/src/transaction.rs index 16395c8ebf..e70dc793af 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -1,329 +1 @@ -//! The `transaction` module provides functionality for creating log transactions. - -use bincode::serialize; -use hash::{Hash, Hasher}; -use serde::Serialize; -use signature::{Keypair, KeypairUtil, Signature}; -use solana_sdk::pubkey::Pubkey; -use std::mem::size_of; - -pub const SIG_OFFSET: usize = size_of::(); - -/// An instruction to execute a program under the `program_id` of `program_ids_index` with the -/// specified accounts and userdata -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct Instruction { - /// The program code that executes this transaction is identified by the program_id. - /// this is an offset into the Transaction::program_ids field - pub program_ids_index: u8, - /// Indices into the keys array of which accounts to load - pub accounts: Vec, - /// Userdata to be stored in the account - pub userdata: Vec, -} - -impl Instruction { - pub fn new(program_ids_index: u8, userdata: &T, accounts: Vec) -> Self { - let userdata = serialize(userdata).unwrap(); - Instruction { - program_ids_index, - userdata, - accounts, - } - } -} - -/// An atomic transaction -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct Transaction { - /// A set of digital signature of `account_keys`, `program_ids`, `last_id`, `fee` and `instructions`, signed by the first - /// signatures.len() keys of account_keys - pub signatures: Vec, - - /// The `Pubkeys` that are executing this transaction userdata. The meaning of each key is - /// program-specific. - /// * account_keys[0] - Typically this is the `caller` public key. `signature` is verified with account_keys[0]. - /// In the future which key pays the fee and which keys have signatures would be configurable. - /// * account_keys[1] - Typically this is the program context or the recipient of the tokens - pub account_keys: Vec, - - /// The ID of a recent ledger entry. - pub last_id: Hash, - - /// The number of tokens paid for processing and storage of this transaction. - pub fee: u64, - - /// Keys identifying programs in the instructions vector. - pub program_ids: Vec, - /// Programs that will be executed in sequence and commited in one atomic transaction if all - /// succeed. - pub instructions: Vec, -} - -impl Transaction { - pub fn new( - from_keypair: &Keypair, - transaction_keys: &[Pubkey], - program_id: Pubkey, - userdata: &T, - last_id: 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, userdata, accounts)]; - Self::new_with_instructions( - &[from_keypair], - transaction_keys, - last_id, - fee, - program_ids, - instructions, - ) - } - /// Create a signed transaction - /// * `from_keypair` - The key used to sign the transaction. This key is stored as keys[0] - /// * `account_keys` - The keys for the transaction. These are the program state - /// instances or token recipient keys. - /// * `last_id` - The PoH hash. - /// * `fee` - The transaction fee. - /// * `program_ids` - The keys that identify programs used in the `instruction` vector. - /// * `instructions` - The programs and their arguments that the transaction will execute atomically - pub fn new_with_instructions( - from_keypairs: &[&Keypair], - keys: &[Pubkey], - last_id: Hash, - fee: u64, - program_ids: Vec, - instructions: Vec, - ) -> 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, - last_id: Hash::default(), - fee, - program_ids, - instructions, - }; - tx.sign(from_keypairs, last_id); - tx - } - pub fn userdata(&self, instruction_index: usize) -> &[u8] { - &self.instructions[instruction_index].userdata - } - fn key_index(&self, instruction_index: usize, accounts_index: usize) -> Option { - 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 signed_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] - } - /// Get the transaction data to sign. - pub fn get_sign_data(&self) -> Vec { - let mut data = serialize(&self.account_keys).expect("serialize account_keys"); - - let last_id_data = serialize(&self.last_id).expect("serialize last_id"); - data.extend_from_slice(&last_id_data); - - let fee_data = serialize(&self.fee).expect("serialize fee"); - data.extend_from_slice(&fee_data); - - let program_ids = serialize(&self.program_ids).expect("serialize program_ids"); - data.extend_from_slice(&program_ids); - - let instructions = serialize(&self.instructions).expect("serialize instructions"); - data.extend_from_slice(&instructions); - data - } - - /// Sign this transaction. - pub fn sign(&mut self, keypairs: &[&Keypair], last_id: Hash) { - self.last_id = last_id; - let sign_data = self.get_sign_data(); - self.signatures = keypairs - .iter() - .map(|keypair| Signature::new(&keypair.sign(&sign_data).as_ref())) - .collect(); - } - - /// Verify only the transaction signature. - pub fn verify_signature(&self) -> bool { - warn!("transaction signature verification called"); - self.signatures - .iter() - .all(|s| s.verify(&self.from().as_ref(), &self.get_sign_data())) - } - - /// Verify that references in the instructions are valid - 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] - } - - // a hash of a slice of transactions only needs to hash the signatures - pub fn hash(transactions: &[Transaction]) -> Hash { - let mut hasher = Hasher::default(); - transactions - .iter() - .for_each(|tx| hasher.hash(&tx.signatures[0].as_ref())); - hasher.result() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use bincode::serialize; - use signature::GenKeys; - - #[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], - Default::default(), - 0, - vec![prog1, prog2], - instructions, - ); - assert!(tx.verify_refs()); - - assert_eq!(tx.key(0, 0), Some(&key.pubkey())); - assert_eq!(tx.signed_key(0, 0), Some(&key.pubkey())); - - assert_eq!(tx.key(1, 0), Some(&key.pubkey())); - assert_eq!(tx.signed_key(1, 0), Some(&key.pubkey())); - - assert_eq!(tx.key(0, 1), Some(&key1)); - assert_eq!(tx.signed_key(0, 1), None); - - assert_eq!(tx.key(1, 1), Some(&key2)); - assert_eq!(tx.signed_key(1, 1), None); - - assert_eq!(tx.key(2, 0), None); - assert_eq!(tx.signed_key(2, 0), None); - - assert_eq!(tx.key(0, 2), None); - assert_eq!(tx.signed_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], - &[], - Default::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], - &[], - Default::default(), - 0, - vec![Default::default()], - instructions, - ); - assert_eq!(*tx.program_id(0), Default::default()); - assert!(!tx.verify_refs()); - } - - /// Detect binary changes in the serialized contract userdata, which could have a downstream - /// affect on SDKs and DApps - #[test] - fn test_sdk_serialize() { - let keypair = &GenKeys::new([0u8; 32]).gen_n_keypairs(1)[0]; - 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![ - 1, 0, 0, 0, 0, 0, 0, 0, 234, 139, 34, 5, 120, 28, 107, 203, 69, 25, 236, 200, 164, - 1, 12, 47, 147, 53, 41, 143, 23, 116, 230, 203, 59, 228, 153, 14, 22, 241, 103, - 226, 186, 169, 181, 65, 49, 215, 44, 2, 61, 214, 113, 216, 184, 206, 147, 104, 140, - 225, 138, 21, 172, 135, 211, 80, 103, 80, 216, 106, 249, 86, 194, 1, 3, 0, 0, 0, 0, - 0, 0, 0, 32, 253, 186, 201, 177, 11, 117, 135, 187, 167, 181, 188, 22, 59, 206, - 105, 231, 150, 215, 30, 78, 212, 76, 16, 252, 180, 72, 134, 137, 247, 161, 68, 32, - 253, 186, 201, 177, 11, 117, 135, 187, 167, 181, 188, 22, 59, 206, 105, 231, 150, - 215, 30, 78, 212, 76, 16, 252, 180, 72, 134, 137, 247, 161, 68, 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, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, - 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 - ], - ); - } -} +pub use solana_sdk::transaction::*; diff --git a/src/tvu.rs b/src/tvu.rs index bf111db791..1a05b43264 100644 --- a/src/tvu.rs +++ b/src/tvu.rs @@ -13,12 +13,12 @@ use bank::Bank; use blob_fetch_stage::BlobFetchStage; use cluster_info::ClusterInfo; -use hash::Hash; use ledger_write_stage::LedgerWriteStage; use replicate_stage::{ReplicateStage, ReplicateStageReturnType}; use retransmit_stage::RetransmitStage; use service::Service; use signature::Keypair; +use solana_sdk::hash::Hash; use std::net::UdpSocket; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, RwLock}; @@ -167,7 +167,6 @@ pub mod tests { use bincode::serialize; use cluster_info::{ClusterInfo, Node}; use entry::Entry; - use hash::Hash; use leader_scheduler::LeaderScheduler; use logger; use mint::Mint; @@ -175,6 +174,7 @@ pub mod tests { use packet::SharedBlob; use service::Service; use signature::{Keypair, KeypairUtil}; + use solana_sdk::hash::Hash; use std::net::UdpSocket; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::channel; diff --git a/src/vote_stage.rs b/src/vote_stage.rs index bd65723b1b..430ed2f04a 100644 --- a/src/vote_stage.rs +++ b/src/vote_stage.rs @@ -4,11 +4,11 @@ use bank::Bank; use bincode::serialize; use cluster_info::ClusterInfo; use counter::Counter; -use hash::Hash; use log::Level; use packet::SharedBlob; use result::{Error, Result}; use signature::Keypair; +use solana_sdk::hash::Hash; use std::net::SocketAddr; use std::sync::atomic::AtomicUsize; use std::sync::{Arc, RwLock}; diff --git a/src/vote_transaction.rs b/src/vote_transaction.rs index 1bfcf33a5f..c53b6dc902 100644 --- a/src/vote_transaction.rs +++ b/src/vote_transaction.rs @@ -3,12 +3,12 @@ #[cfg(test)] use bank::Bank; use bincode::deserialize; -use hash::Hash; #[cfg(test)] use result::Result; use signature::Keypair; #[cfg(test)] use signature::KeypairUtil; +use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; use system_transaction::SystemTransaction; use transaction::Transaction; diff --git a/src/wallet.rs b/src/wallet.rs index bd11d91c64..3fc8560eaf 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -5,10 +5,8 @@ use budget_program::BudgetState; use budget_transaction::BudgetTransaction; use chrono::prelude::*; use clap::ArgMatches; -use drone::{request_airdrop_transaction, DRONE_PORT}; use elf; use fullnode::Config; -use hash::Hash; use loader_transaction::LoaderTransaction; use ring::rand::SystemRandom; use ring::signature::Ed25519KeyPair; @@ -16,6 +14,8 @@ use rpc::RpcSignatureStatus; use rpc_request::RpcRequest; use serde_json; use signature::{Keypair, KeypairUtil, Signature}; +use solana_drone::drone::{request_airdrop_transaction, DRONE_PORT}; +use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; use std::fs::{self, File}; use std::io::Write; @@ -759,12 +759,12 @@ mod tests { use bank::Bank; use clap::{App, Arg, SubCommand}; use cluster_info::Node; - use drone::run_local_drone; use fullnode::Fullnode; use leader_scheduler::LeaderScheduler; use ledger::create_tmp_genesis; use serde_json::Value; use signature::{read_keypair, read_pkcs8, Keypair, KeypairUtil}; + use solana_drone::drone::run_local_drone; use std::fs::remove_dir_all; use std::sync::mpsc::channel; use std::sync::{Arc, RwLock}; diff --git a/src/window_service.rs b/src/window_service.rs index cdede83cbe..81c667d96e 100644 --- a/src/window_service.rs +++ b/src/window_service.rs @@ -354,10 +354,10 @@ pub fn window_service( mod test { use cluster_info::{ClusterInfo, Node}; use entry::Entry; - use hash::Hash; use leader_scheduler::LeaderScheduler; use logger; use packet::{make_consecutive_blobs, SharedBlob, PACKET_DATA_SIZE}; + use solana_sdk::hash::Hash; use std::net::UdpSocket; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::{channel, Receiver}; diff --git a/tests/multinode.rs b/tests/multinode.rs index 337d327b36..d138ef613c 100644 --- a/tests/multinode.rs +++ b/tests/multinode.rs @@ -10,7 +10,6 @@ use solana::blob_fetch_stage::BlobFetchStage; use solana::cluster_info::{ClusterInfo, Node, NodeInfo}; use solana::entry::{reconstruct_entries_from_blobs, Entry}; use solana::fullnode::{Fullnode, FullnodeReturnType}; -use solana::hash::Hash; use solana::leader_scheduler::{make_active_set_entries, LeaderScheduler, LeaderSchedulerConfig}; use solana::ledger::{ create_tmp_genesis, create_tmp_sample_ledger, get_tmp_ledger_path, read_ledger, LedgerWindow, @@ -28,6 +27,7 @@ use solana::system_transaction::SystemTransaction; use solana::thin_client::{retry_get_balance, ThinClient}; use solana::transaction::Transaction; use solana::window::default_window; +use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; use solana_sdk::timing::{duration_as_ms, duration_as_s}; use std::collections::{HashSet, VecDeque};