Compare commits

..

27 Commits

Author SHA1 Message Date
Michael Vines
28d24497a3 Wait for the leader to initialize before starting the validators 2018-07-13 12:32:24 -07:00
Michael Vines
05cea4c1da dedup 2018-07-13 11:48:17 -07:00
Michael Vines
260f5edfd6 Use correct leader.json 2018-07-13 11:48:17 -07:00
Michael Vines
7105136595 Enable CUDA for the leader node 2018-07-13 11:36:12 -07:00
Michael Vines
54db379bf2 Refresh in parallel 2018-07-13 11:19:31 -07:00
Michael Vines
effbf0b978 Add script to refresh testnet nodes 2018-07-13 11:19:31 -07:00
Michael Vines
8e7a2a9587 Validators now request an airdrop of 1 token before starting up 2018-07-13 10:02:19 -07:00
Michael Vines
18e6ff4167 Fail gracefully when keypair file is unreadable 2018-07-13 10:00:55 -07:00
Michael Vines
fa1cdaa91a Add home plugs to enable Snap access to ~/.config/solana/id.json 2018-07-13 09:32:37 -07:00
Michael Vines
b538b67524 Bump timeout for stable build
When the CI build machine caches are empty stable occasionally needs more than 20m
2018-07-13 09:17:45 -07:00
Michael Vines
2b0f6355af Tagged snap builds now correctly publish to the beta channel 2018-07-12 23:43:59 -07:00
Rob Walker
11b9a0323d fixups 2018-07-12 22:51:55 -07:00
Rob Walker
710fa822a0 fixups 2018-07-12 22:51:55 -07:00
Rob Walker
aaf6ce5aea fixups 2018-07-12 22:51:55 -07:00
Rob Walker
34ea483736 step two: supply a ledger file argument to fullnode in the demo
(also whack unused "myip.sh", even though it was pretty)
2018-07-12 22:51:55 -07:00
Rob Walker
a3ff40476e Banish stdin/stdout for ledger
step one: accept a "ledger file" argument instead of "outfile"
2018-07-12 22:51:55 -07:00
Greg Fitzgerald
4cca3ff454 Fix keypair option in scripts
Thanks @CriesofCarrots!
2018-07-12 21:50:28 -06:00
Greg Fitzgerald
3d9acdd970 Fix nightly 2018-07-12 21:50:28 -06:00
Greg Fitzgerald
428f220b88 Battle shellcheck 2018-07-12 21:50:28 -06:00
Greg Fitzgerald
10add6a8ac Cleanup setup.sh 2018-07-12 21:50:28 -06:00
Greg Fitzgerald
f06a8dceda Fix keygen docs
Thanks @rob-solana
2018-07-12 21:50:28 -06:00
Greg Fitzgerald
545f4f1c87 Pass the owner's keypair to fullnode-config 2018-07-12 21:50:28 -06:00
Greg Fitzgerald
77543d83ff Fix default keypair paths 2018-07-12 21:50:28 -06:00
Greg Fitzgerald
eb6a30cb7c In Wallet, make --tokens required and --to optional 2018-07-12 21:50:28 -06:00
Greg Fitzgerald
97372b8e63 Add --outfile option to solana-keygen 2018-07-12 21:50:28 -06:00
Greg Fitzgerald
cea29ed772 More keygen 2018-07-12 21:50:28 -06:00
Greg Fitzgerald
b5006b8f2b Migrate to solana-keygen
Most of #593
2018-07-12 21:50:28 -06:00
25 changed files with 327 additions and 308 deletions

View File

@@ -37,10 +37,6 @@ path = "src/bin/fullnode-config.rs"
name = "solana-genesis" name = "solana-genesis"
path = "src/bin/genesis.rs" path = "src/bin/genesis.rs"
[[bin]]
name = "solana-mint"
path = "src/bin/mint.rs"
[[bin]] [[bin]]
name = "solana-drone" name = "solana-drone"
path = "src/bin/drone.rs" path = "src/bin/drone.rs"
@@ -85,6 +81,7 @@ futures = "0.1.21"
clap = "2.31" clap = "2.31"
reqwest = "0.8.6" reqwest = "0.8.6"
influx_db_client = "0.3.4" influx_db_client = "0.3.4"
dirs = "1.0.2"
[dev-dependencies] [dev-dependencies]
criterion = "0.2" criterion = "0.2"

View File

@@ -1,4 +1,38 @@
steps: steps:
- command: "ci/docker-run.sh rust ci/test-stable.sh"
name: "stable [public]"
env:
CARGO_TARGET_CACHE_NAME: "stable"
timeout_in_minutes: 30
- command: "ci/shellcheck.sh"
name: "shellcheck [public]"
timeout_in_minutes: 20
- command: "ci/docker-run.sh solanalabs/rust-nightly ci/test-nightly.sh"
name: "nightly [public]"
env:
CARGO_TARGET_CACHE_NAME: "nightly"
timeout_in_minutes: 30
- command: "ci/test-stable-perf.sh"
name: "stable-perf [public]"
env:
CARGO_TARGET_CACHE_NAME: "stable-perf"
timeout_in_minutes: 20
retry:
automatic:
- exit_status: "*"
limit: 2
agents:
- "queue=cuda"
- command: "ci/pr-snap.sh"
timeout_in_minutes: 20
name: "snap [public]"
- wait
- command: "ci/publish-crate.sh"
timeout_in_minutes: 20
name: "publish crate [public]"
- command: "ci/hoover.sh"
timeout_in_minutes: 20
name: "clean agent [public]"
- trigger: "solana-snap" - trigger: "solana-snap"
branches: "!pull/*" branches: "!pull/*"
async: true async: true
@@ -7,5 +41,4 @@ steps:
commit: "${BUILDKITE_COMMIT}" commit: "${BUILDKITE_COMMIT}"
branch: "${BUILDKITE_BRANCH}" branch: "${BUILDKITE_BRANCH}"
env: env:
BUILDKITE_TAG: "${BUILDKITE_TAG}" TRIGGERED_BUILDKITE_TAG: "${BUILDKITE_TAG}"
PARENT_BUILDKITE_TAG: "${BUILDKITE_TAG}"

View File

@@ -31,19 +31,24 @@ done < <(gcloud compute instances list --filter="labels.testnet-mode=validator"
echo "--- Refreshing" echo "--- Refreshing"
mode=leader+drone leader=true
for info in "${vmlist[@]}"; do for info in "${vmlist[@]}"; do
vmName=${info%:*} vmName=${info%:*}
vmZone=${info#*:} vmZone=${info#*:}
echo "Starting refresh for $vmName" echo "Starting refresh for $vmName"
( (
echo "--- Processing $vmName in zone $vmZone as $mode" echo "--- Processing $vmName in zone $vmZone"
if $leader; then
nodeConfig="mode=leader+drone enable-cuda=1 metrics-config=$SOLANA_METRICS_CONFIG"
else
nodeConfig="mode=validator metrics-config=$SOLANA_METRICS_CONFIG"
fi
cat > "autogen-refresh-$vmName.sh" <<EOF cat > "autogen-refresh-$vmName.sh" <<EOF
set -x set -x
sudo snap remove solana sudo snap remove solana
sudo snap install solana $SOLANA_SNAP_CHANNEL --devmode sudo snap install solana $SOLANA_SNAP_CHANNEL --devmode
sudo snap set solana mode=$mode metrics-config=$SOLANA_METRICS_CONFIG sudo snap set solana $nodeConfig
snap info solana snap info solana
sudo snap logs solana -n200 sudo snap logs solana -n200
EOF EOF
@@ -53,10 +58,17 @@ EOF
--ssh-flag="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -t" \ --ssh-flag="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -t" \
--command="bash ./autogen-refresh-$vmName.sh" --command="bash ./autogen-refresh-$vmName.sh"
) > "log-$vmName.txt" 2>&1 & ) > "log-$vmName.txt" 2>&1 &
mode=validator
if $leader; then
echo Waiting for leader...
# Wait for the leader to initialize before starting the validators
# TODO: Remove this limitation eventually.
wait
fi
leader=false
done done
echo "Waiting..." echo Waiting for validators...
wait wait
for info in "${vmlist[@]}"; do for info in "${vmlist[@]}"; do

View File

@@ -7,7 +7,11 @@ if [[ -z $BUILDKITE_BRANCH ]] || ./ci/is-pr.sh; then
DRYRUN="echo" DRYRUN="echo"
fi fi
if [[ -z "$BUILDKITE_TAG" ]]; then # BUILDKITE_TAG is the normal environment variable set by Buildkite. However
# when this script is run from a triggered pipeline, TRIGGERED_BUILDKITE_TAG is
# used instead of BUILDKITE_TAG (due to Buildkite limitations that prevents
# BUILDKITE_TAG from propagating through to triggered pipelines)
if [[ -z "$BUILDKITE_TAG" && -z "$TRIGGERED_BUILDKITE_TAG" ]]; then
SNAP_CHANNEL=edge SNAP_CHANNEL=edge
else else
SNAP_CHANNEL=beta SNAP_CHANNEL=beta

View File

@@ -23,9 +23,9 @@ fi
client_json="$SOLANA_CONFIG_CLIENT_DIR"/client.json client_json="$SOLANA_CONFIG_CLIENT_DIR"/client.json
if [[ ! -r $client_json ]]; then if [[ ! -r $client_json ]]; then
$solana_mint <<<0 > "$client_json" $solana_keygen -o "$client_json"
fi fi
# shellcheck disable=SC2086 # $solana_client_demo should not be quoted # shellcheck disable=SC2086 # $solana_client_demo should not be quoted
exec $solana_client_demo \ exec $solana_client_demo \
-n "$count" -l "$SOLANA_CONFIG_CLIENT_DIR"/leader.json -m "$SOLANA_CONFIG_CLIENT_DIR"/client.json -n "$count" -l "$SOLANA_CONFIG_CLIENT_DIR"/leader.json -k "$SOLANA_CONFIG_CLIENT_DIR"/client.json

View File

@@ -53,7 +53,7 @@ solana_fullnode=$(solana_program fullnode)
solana_fullnode_config=$(solana_program fullnode-config) solana_fullnode_config=$(solana_program fullnode-config)
solana_fullnode_cuda=$(solana_program fullnode-cuda) solana_fullnode_cuda=$(solana_program fullnode-cuda)
solana_genesis=$(solana_program genesis) solana_genesis=$(solana_program genesis)
solana_mint=$(solana_program mint) solana_keygen=$(solana_program keygen)
export RUST_LOG=${RUST_LOG:-solana=info} # if RUST_LOG is unset, default to info export RUST_LOG=${RUST_LOG:-solana=info} # if RUST_LOG is unset, default to info
export RUST_BACKTRACE=1 export RUST_BACKTRACE=1
@@ -107,15 +107,19 @@ tune_networking() {
# Reference: https://medium.com/@CameronSparr/increase-os-udp-buffers-to-improve-performance-51d167bb1360 # Reference: https://medium.com/@CameronSparr/increase-os-udp-buffers-to-improve-performance-51d167bb1360
[[ $(uname) = Linux ]] && ( [[ $(uname) = Linux ]] && (
set -x set -x
# TODO: Check values and warn instead, it's a little rude to set them here. # test the existence of the sysctls before trying to set them
sudo sysctl -w net.core.rmem_max=26214400 1>/dev/null 2>/dev/null sysctl net.core.rmem_max 2>/dev/null 1>/dev/null &&
sudo sysctl -w net.core.rmem_default=26214400 1>/dev/null 2>/dev/null sudo sysctl -w net.core.rmem_max=26214400 1>/dev/null 2>/dev/null
sysctl net.core.rmem_default 2>/dev/null 1>/dev/null &&
sudo sysctl -w net.core.rmem_default=26214400 1>/dev/null 2>/dev/null
) )
return 0
} }
SOLANA_CONFIG_DIR=${SNAP_DATA:-$PWD}/config SOLANA_CONFIG_DIR=${SNAP_DATA:-$PWD}/config
SOLANA_CONFIG_PRIVATE_DIR=${SNAP_DATA:-$PWD}/config-private SOLANA_CONFIG_PRIVATE_DIR=${SNAP_DATA:-$PWD}/config-private
SOLANA_CONFIG_CLIENT_DIR=${SNAP_USER_DATA:-$PWD}/config-client-client SOLANA_CONFIG_CLIENT_DIR=${SNAP_USER_DATA:-$PWD}/config-client
rsync_url() { # adds the 'rsync://` prefix to URLs that need it rsync_url() { # adds the 'rsync://` prefix to URLs that need it
declare url="$1" declare url="$1"

View File

@@ -38,4 +38,4 @@ $rsync -vPz "$rsync_leader_url"/config/leader.json "$SOLANA_CONFIG_DIR"/
# shellcheck disable=SC2086 # $solana_drone should not be quoted # shellcheck disable=SC2086 # $solana_drone should not be quoted
exec $solana_drone \ exec $solana_drone \
-l "$SOLANA_CONFIG_DIR"/leader.json -m "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json -l "$SOLANA_CONFIG_DIR"/leader.json -k "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json

View File

@@ -25,9 +25,15 @@ fi
tune_networking tune_networking
# migrate from old ledger format? why not...
if [[ ! -f "$SOLANA_CONFIG_DIR"/ledger.log &&
-f "$SOLANA_CONFIG_DIR"/genesis.log ]]; then
(shopt -s nullglob &&
cat "$SOLANA_CONFIG_DIR"/genesis.log \
"$SOLANA_CONFIG_DIR"/tx-*.log) > "$SOLANA_CONFIG_DIR"/ledger.log
fi
# shellcheck disable=SC2086 # $program should not be quoted # shellcheck disable=SC2086 # $program should not be quoted
exec $program \ exec $program \
-l "$SOLANA_CONFIG_DIR"/leader.json \ --identity "$SOLANA_CONFIG_DIR"/leader.json \
< <(shopt -s nullglob && cat "$SOLANA_CONFIG_DIR"/genesis.log \ --ledger "$SOLANA_CONFIG_DIR"/ledger.log
"$SOLANA_CONFIG_DIR"/tx-*.log) \
> "$SOLANA_CONFIG_DIR"/tx-"$(date -u +%Y%m%d%H%M%S%N)".log

View File

@@ -1,59 +0,0 @@
#!/bin/bash
function myip()
{
# shellcheck disable=SC2207
declare ipaddrs=(
# query interwebs
$(curl -s ifconfig.co)
# machine's interfaces
$(ifconfig |
awk '/inet addr:/ {gsub("addr:","",$2); print $2; next}
/inet6 addr:/ {gsub("/.*", "", $3); print $3; next}
/inet(6)? / {print $2}'
)
)
if (( ! ${#ipaddrs[*]} ))
then
echo "
myip: error: I'm having trouble determining what our IP address is...
Are we connected to a network?
"
return 1
fi
declare prompt="
Please choose the IP address you want to advertise to the network:
0) ${ipaddrs[0]} <====== this one was returned by the interwebs...
"
for ((i=1; i < ${#ipaddrs[*]}; i++))
do
prompt+=" $i) ${ipaddrs[i]}
"
done
while read -r -p "${prompt}
please enter a number [0 for default]: " which
do
[[ -z ${which} ]] && break;
[[ ${which} =~ [0-9]+ ]] && (( which < ${#ipaddrs[*]} )) && break;
echo "Ug. invalid entry \"${which}\"...
"
sleep 1
done
which=${which:-0}
echo "${ipaddrs[which]}"
}
if [[ ${0} == "${BASH_SOURCE[0]}" ]]
then
myip "$@"
fi

View File

@@ -71,6 +71,8 @@ done
leader_address_args=("$ip_address_arg") leader_address_args=("$ip_address_arg")
validator_address_args=("$ip_address_arg" -b 9000) validator_address_args=("$ip_address_arg" -b 9000)
id_path="$SOLANA_CONFIG_PRIVATE_DIR"/id.json
mint_path="$SOLANA_CONFIG_PRIVATE_DIR"/mint.json
set -e set -e
@@ -78,25 +80,26 @@ echo "Cleaning $SOLANA_CONFIG_DIR"
rm -rvf "$SOLANA_CONFIG_DIR" rm -rvf "$SOLANA_CONFIG_DIR"
mkdir -p "$SOLANA_CONFIG_DIR" mkdir -p "$SOLANA_CONFIG_DIR"
rm -rvf "$SOLANA_CONFIG_PRIVATE_DIR"
mkdir -p "$SOLANA_CONFIG_PRIVATE_DIR"
$solana_keygen -o "$id_path"
if $node_type_leader; then if $node_type_leader; then
rm -rvf "$SOLANA_CONFIG_PRIVATE_DIR"
mkdir -p "$SOLANA_CONFIG_PRIVATE_DIR"
echo "Creating $SOLANA_CONFIG_DIR/mint.json with $num_tokens tokens" echo "Creating $SOLANA_CONFIG_DIR/mint.json with $num_tokens tokens"
$solana_mint <<<"$num_tokens" > "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json $solana_keygen -o "$mint_path"
echo "Creating $SOLANA_CONFIG_DIR/genesis.log" echo "Creating $SOLANA_CONFIG_DIR/ledger.log"
$solana_genesis < "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json > "$SOLANA_CONFIG_DIR"/genesis.log $solana_genesis --tokens="$num_tokens" < "$mint_path" > "$SOLANA_CONFIG_DIR"/ledger.log
echo "Creating $SOLANA_CONFIG_DIR/leader.json" echo "Creating $SOLANA_CONFIG_DIR/leader.json"
$solana_fullnode_config "${leader_address_args[@]}" > "$SOLANA_CONFIG_DIR"/leader.json $solana_fullnode_config --keypair="$id_path" "${leader_address_args[@]}" > "$SOLANA_CONFIG_DIR"/leader.json
fi fi
if $node_type_validator; then if $node_type_validator; then
echo "Creating $SOLANA_CONFIG_DIR/validator.json" echo "Creating $SOLANA_CONFIG_DIR/validator.json"
$solana_fullnode_config "${validator_address_args[@]}" > "$SOLANA_CONFIG_DIR"/validator.json $solana_fullnode_config --keypair="$id_path" "${validator_address_args[@]}" > "$SOLANA_CONFIG_DIR"/validator.json
fi fi
ls -lh "$SOLANA_CONFIG_DIR"/ ls -lh "$SOLANA_CONFIG_DIR"/

View File

@@ -73,8 +73,24 @@ ls -lh "$SOLANA_LEADER_CONFIG_DIR"
tune_networking tune_networking
# migrate from old ledger format? why not...
if [[ ! -f "$SOLANA_LEADER_CONFIG_DIR"/ledger.log &&
-f "$SOLANA_LEADER_CONFIG_DIR"/genesis.log ]]; then
(shopt -s nullglob &&
cat "$SOLANA_LEADER_CONFIG_DIR"/genesis.log \
"$SOLANA_LEADER_CONFIG_DIR"/tx-*.log) > "$SOLANA_LEADER_CONFIG_DIR"/ledger.log
fi
# Ensure the validator has at least 1 token before connecting to the network
# TODO: Remove this workaround
while ! $solana_wallet \
-l "$SOLANA_LEADER_CONFIG_DIR"/leader.json \
-k "$SOLANA_CONFIG_PRIVATE_DIR"/id.json airdrop --tokens 1; do
sleep 1
done
# shellcheck disable=SC2086 # $program should not be quoted # shellcheck disable=SC2086 # $program should not be quoted
exec $program \ exec $program \
-l "$SOLANA_CONFIG_DIR"/validator.json -t "$leader_address:$leader_port" \ --identity "$SOLANA_CONFIG_DIR"/validator.json \
< <(shopt -s nullglob && cat "$SOLANA_LEADER_CONFIG_DIR"/genesis.log \ --testnet "$leader_address:$leader_port" \
"$SOLANA_LEADER_CONFIG_DIR"/tx-*.log) --ledger "$SOLANA_LEADER_CONFIG_DIR"/ledger.log

View File

@@ -36,12 +36,12 @@ if [[ ! -r "$SOLANA_CONFIG_CLIENT_DIR"/leader.json ]]; then
) )
fi fi
client_json="$SOLANA_CONFIG_CLIENT_DIR"/client.json client_id_path="$SOLANA_CONFIG_CLIENT_DIR"/id.json
if [[ ! -r $client_json ]]; then if [[ ! -r $client_id_path ]]; then
$solana_mint <<<0 > "$client_json" $solana_keygen -o "$client_id_path"
fi fi
set -x set -x
# shellcheck disable=SC2086 # $solana_wallet should not be quoted # shellcheck disable=SC2086 # $solana_wallet should not be quoted
exec $solana_wallet \ exec $solana_wallet \
-l "$SOLANA_CONFIG_CLIENT_DIR"/leader.json -m "$client_json" "$@" -l "$SOLANA_CONFIG_CLIENT_DIR"/leader.json -k "$client_id_path" "$@"

View File

@@ -37,16 +37,26 @@ apps:
plugs: plugs:
- network - network
- network-bind - network-bind
- home
genesis: genesis:
command: solana-genesis command: solana-genesis
mint: keygen:
command: solana-mint command: solana-keygen
plugs:
- home
client-demo: client-demo:
command: solana-client-demo command: solana-client-demo
plugs:
- network
- network-bind
- home
wallet: wallet:
# TODO: Merge wallet.sh functionality into solana-wallet proper # TODO: Merge wallet.sh functionality into solana-wallet proper
command: wallet.sh command: wallet.sh
#command: solana-wallet #command: solana-wallet
plugs:
- network
- home
daemon-validator: daemon-validator:
daemon: simple daemon: simple

View File

@@ -12,11 +12,10 @@ use solana::crdt::{Crdt, NodeInfo};
use solana::drone::DroneRequest; use solana::drone::DroneRequest;
use solana::fullnode::Config; use solana::fullnode::Config;
use solana::hash::Hash; use solana::hash::Hash;
use solana::mint::Mint;
use solana::nat::{udp_public_bind, udp_random_bind}; use solana::nat::{udp_public_bind, udp_random_bind};
use solana::ncp::Ncp; use solana::ncp::Ncp;
use solana::service::Service; use solana::service::Service;
use solana::signature::{GenKeys, KeyPair, KeyPairUtil}; use solana::signature::{read_keypair, GenKeys, KeyPair, KeyPairUtil};
use solana::streamer::default_window; use solana::streamer::default_window;
use solana::thin_client::ThinClient; use solana::thin_client::ThinClient;
use solana::timing::{duration_as_ms, duration_as_s}; use solana::timing::{duration_as_ms, duration_as_s};
@@ -77,7 +76,7 @@ fn sample_tx_count(
fn generate_and_send_txs( fn generate_and_send_txs(
client: &mut ThinClient, client: &mut ThinClient,
tx_clients: &[ThinClient], tx_clients: &[ThinClient],
id: &Mint, id: &KeyPair,
keypairs: &[KeyPair], keypairs: &[KeyPair],
leader: &NodeInfo, leader: &NodeInfo,
txs: i64, txs: i64,
@@ -91,7 +90,7 @@ fn generate_and_send_txs(
let transactions: Vec<_> = if !reclaim { let transactions: Vec<_> = if !reclaim {
keypairs keypairs
.par_iter() .par_iter()
.map(|keypair| Transaction::new(&id.keypair(), keypair.pubkey(), 1, *last_id)) .map(|keypair| Transaction::new(&id, keypair.pubkey(), 1, *last_id))
.collect() .collect()
} else { } else {
keypairs keypairs
@@ -164,12 +163,13 @@ fn main() {
.help("/path/to/leader.json"), .help("/path/to/leader.json"),
) )
.arg( .arg(
Arg::with_name("mint") Arg::with_name("keypair")
.short("m") .short("k")
.long("mint") .long("keypair")
.value_name("PATH") .value_name("PATH")
.takes_value(true) .takes_value(true)
.help("/path/to/mint.json"), .default_value("~/.config/solana/id.json")
.help("/path/to/id.json"),
) )
.arg( .arg(
Arg::with_name("num_nodes") Arg::with_name("num_nodes")
@@ -205,13 +205,7 @@ fn main() {
leader = NodeInfo::new_leader(&server_addr); leader = NodeInfo::new_leader(&server_addr);
}; };
let id: Mint; let id = read_keypair(matches.value_of("keypair").unwrap()).expect("client keypair");
if let Some(m) = matches.value_of("mint") {
id = read_mint(m).expect("client mint");
} else {
eprintln!("No mint found!");
exit(1);
};
if let Some(t) = matches.value_of("threads") { if let Some(t) = matches.value_of("threads") {
threads = t.to_string().parse().expect("integer"); threads = t.to_string().parse().expect("integer");
@@ -259,7 +253,7 @@ fn main() {
println!("Got last ID {:?}", last_id); println!("Got last ID {:?}", last_id);
let mut seed = [0u8; 32]; let mut seed = [0u8; 32];
seed.copy_from_slice(&id.keypair().public_key_bytes()[..32]); seed.copy_from_slice(&id.public_key_bytes()[..32]);
let rnd = GenKeys::new(seed); let rnd = GenKeys::new(seed);
println!("Creating keypairs..."); println!("Creating keypairs...");
@@ -433,15 +427,9 @@ fn read_leader(path: &str) -> Config {
serde_json::from_reader(file).unwrap_or_else(|_| panic!("failed to parse {}", path)) serde_json::from_reader(file).unwrap_or_else(|_| panic!("failed to parse {}", path))
} }
fn read_mint(path: &str) -> Result<Mint, Box<error::Error>> {
let file = File::open(path.to_string())?;
let mint = serde_json::from_reader(file)?;
Ok(mint)
}
fn request_airdrop( fn request_airdrop(
drone_addr: &SocketAddr, drone_addr: &SocketAddr,
id: &Mint, id: &KeyPair,
tokens: u64, tokens: u64,
) -> Result<(), Box<error::Error>> { ) -> Result<(), Box<error::Error>> {
let mut stream = TcpStream::connect(drone_addr)?; let mut stream = TcpStream::connect(drone_addr)?;

View File

@@ -12,11 +12,9 @@ use clap::{App, Arg};
use solana::crdt::NodeInfo; use solana::crdt::NodeInfo;
use solana::drone::{Drone, DroneRequest}; use solana::drone::{Drone, DroneRequest};
use solana::fullnode::Config; use solana::fullnode::Config;
use solana::mint::Mint; use solana::signature::read_keypair;
use std::error;
use std::fs::File; use std::fs::File;
use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::process::exit;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
use tokio::net::TcpListener; use tokio::net::TcpListener;
@@ -35,11 +33,12 @@ fn main() {
.help("/path/to/leader.json"), .help("/path/to/leader.json"),
) )
.arg( .arg(
Arg::with_name("mint") Arg::with_name("keypair")
.short("m") .short("k")
.long("mint") .long("keypair")
.value_name("PATH") .value_name("PATH")
.takes_value(true) .takes_value(true)
.required(true)
.help("/path/to/mint.json"), .help("/path/to/mint.json"),
) )
.arg( .arg(
@@ -68,13 +67,9 @@ fn main() {
leader = NodeInfo::new_leader(&server_addr); leader = NodeInfo::new_leader(&server_addr);
}; };
let mint: Mint; let mint_keypair =
if let Some(m) = matches.value_of("mint") { read_keypair(matches.value_of("keypair").expect("keypair")).expect("client keypair");
mint = read_mint(m).expect("client mint");
} else {
eprintln!("No mint found!");
exit(1);
};
let time_slice: Option<u64>; let time_slice: Option<u64>;
if let Some(t) = matches.value_of("time") { if let Some(t) = matches.value_of("time") {
time_slice = Some(t.to_string().parse().expect("integer")); time_slice = Some(t.to_string().parse().expect("integer"));
@@ -88,8 +83,6 @@ fn main() {
request_cap = None; request_cap = None;
} }
let mint_keypair = mint.keypair();
let drone_addr: SocketAddr = "0.0.0.0:9900".parse().unwrap(); let drone_addr: SocketAddr = "0.0.0.0:9900".parse().unwrap();
let drone = Arc::new(Mutex::new(Drone::new( let drone = Arc::new(Mutex::new(Drone::new(
@@ -152,9 +145,3 @@ fn read_leader(path: &str) -> Config {
let file = File::open(path).unwrap_or_else(|_| panic!("file not found: {}", path)); let file = File::open(path).unwrap_or_else(|_| panic!("file not found: {}", path));
serde_json::from_reader(file).unwrap_or_else(|_| panic!("failed to parse {}", path)) serde_json::from_reader(file).unwrap_or_else(|_| panic!("failed to parse {}", path))
} }
fn read_mint(path: &str) -> Result<Mint, Box<error::Error>> {
let file = File::open(path.to_string())?;
let mint = serde_json::from_reader(file)?;
Ok(mint)
}

View File

@@ -1,4 +1,5 @@
extern crate clap; extern crate clap;
extern crate dirs;
extern crate serde_json; extern crate serde_json;
extern crate solana; extern crate solana;
@@ -6,6 +7,7 @@ use clap::{App, Arg};
use solana::crdt::{get_ip_addr, parse_port_or_addr}; use solana::crdt::{get_ip_addr, parse_port_or_addr};
use solana::fullnode::Config; use solana::fullnode::Config;
use solana::nat::get_public_ip_addr; use solana::nat::get_public_ip_addr;
use solana::signature::read_pkcs8;
use std::io; use std::io;
use std::net::SocketAddr; use std::net::SocketAddr;
@@ -18,6 +20,14 @@ fn main() {
.takes_value(false) .takes_value(false)
.help("detect network address from local machine configuration"), .help("detect network address from local machine configuration"),
) )
.arg(
Arg::with_name("keypair")
.short("k")
.long("keypair")
.value_name("PATH")
.takes_value(true)
.help("/path/to/id.json"),
)
.arg( .arg(
Arg::with_name("public") Arg::with_name("public")
.short("p") .short("p")
@@ -54,9 +64,18 @@ fn main() {
bind_addr bind_addr
}; };
let mut path = dirs::home_dir().expect("home directory");
let id_path = if matches.is_present("keypair") {
matches.value_of("keypair").unwrap()
} else {
path.extend(&[".config", "solana", "id.json"]);
path.to_str().unwrap()
};
let pkcs8 = read_pkcs8(id_path).expect("client keypair");
// we need all the receiving sockets to be bound within the expected // we need all the receiving sockets to be bound within the expected
// port range that we open on aws // port range that we open on aws
let config = Config::new(&bind_addr); let config = Config::new(&bind_addr, pkcs8);
let stdout = io::stdout(); let stdout = io::stdout();
serde_json::to_writer(stdout, &config).expect("serialize"); serde_json::to_writer(stdout, &config).expect("serialize");
} }

View File

@@ -1,4 +1,3 @@
extern crate atty;
extern crate clap; extern crate clap;
extern crate env_logger; extern crate env_logger;
extern crate getopts; extern crate getopts;
@@ -6,10 +5,9 @@ extern crate log;
extern crate serde_json; extern crate serde_json;
extern crate solana; extern crate solana;
use atty::{is, Stream};
use clap::{App, Arg}; use clap::{App, Arg};
use solana::crdt::{NodeInfo, TestNode}; use solana::crdt::{NodeInfo, TestNode};
use solana::fullnode::{Config, FullNode, InFile, OutFile}; use solana::fullnode::{Config, FullNode, LedgerFile};
use solana::service::Service; use solana::service::Service;
use solana::signature::{KeyPair, KeyPairUtil}; use solana::signature::{KeyPair, KeyPairUtil};
use std::fs::File; use std::fs::File;
@@ -22,8 +20,8 @@ fn main() -> () {
let matches = App::new("fullnode") let matches = App::new("fullnode")
.arg( .arg(
Arg::with_name("identity") Arg::with_name("identity")
.short("l") .short("i")
.long("local") .long("identity")
.value_name("FILE") .value_name("FILE")
.takes_value(true) .takes_value(true)
.help("run with the identity found in FILE"), .help("run with the identity found in FILE"),
@@ -34,27 +32,23 @@ fn main() -> () {
.long("testnet") .long("testnet")
.value_name("HOST:PORT") .value_name("HOST:PORT")
.takes_value(true) .takes_value(true)
.help("testnet; connect to the network at this gossip entry point"), .help("connect to the network at this gossip entry point"),
) )
.arg( .arg(
Arg::with_name("output") Arg::with_name("ledger")
.short("o") .short("L")
.long("output") .long("ledger")
.value_name("FILE") .value_name("FILE")
.takes_value(true) .takes_value(true)
.help("output log to FILE, defaults to stdout (ignored by validators)"), .help("use FILE as persistent ledger (defaults to stdin/stdout)"),
) )
.get_matches(); .get_matches();
if is(Stream::Stdin) {
eprintln!("nothing found on stdin, expected a log file");
exit(1);
}
let bind_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8000); let bind_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8000);
let mut keypair = KeyPair::new(); let mut keypair = KeyPair::new();
let mut repl_data = NodeInfo::new_leader_with_pubkey(keypair.pubkey(), &bind_addr); let mut repl_data = NodeInfo::new_leader_with_pubkey(keypair.pubkey(), &bind_addr);
if let Some(l) = matches.value_of("identity") { if let Some(i) = matches.value_of("identity") {
let path = l.to_string(); let path = i.to_string();
if let Ok(file) = File::open(path.clone()) { if let Ok(file) = File::open(path.clone()) {
let parse: serde_json::Result<Config> = serde_json::from_reader(file); let parse: serde_json::Result<Config> = serde_json::from_reader(file);
if let Ok(data) = parse { if let Ok(data) = parse {
@@ -69,27 +63,22 @@ fn main() -> () {
exit(1); exit(1);
} }
} }
let ledger = if let Some(l) = matches.value_of("ledger") {
LedgerFile::Path(l.to_string())
} else {
LedgerFile::StdInOut
};
let mut node = TestNode::new_with_bind_addr(repl_data, bind_addr); let mut node = TestNode::new_with_bind_addr(repl_data, bind_addr);
let fullnode = if let Some(t) = matches.value_of("testnet") { let fullnode = if let Some(t) = matches.value_of("testnet") {
let testnet_address_string = t.to_string(); let testnet_address_string = t.to_string();
let testnet_addr = testnet_address_string.parse().unwrap(); let testnet_addr = testnet_address_string.parse().unwrap();
FullNode::new(
node, FullNode::new(node, false, ledger, Some(keypair), Some(testnet_addr))
false,
InFile::StdIn,
Some(keypair),
Some(testnet_addr),
None,
)
} else { } else {
node.data.leader_id = node.data.id; node.data.leader_id = node.data.id;
let outfile = if let Some(o) = matches.value_of("output") { FullNode::new(node, true, ledger, None, None)
OutFile::Path(o.to_string())
} else {
OutFile::StdOut
};
FullNode::new(node, true, InFile::StdIn, None, None, Some(outfile))
}; };
fullnode.join().expect("join"); fullnode.join().expect("join");
} }

View File

@@ -1,10 +1,13 @@
//! A command-line executable for generating the chain's genesis block. //! A command-line executable for generating the chain's genesis block.
extern crate atty; extern crate atty;
#[macro_use]
extern crate clap;
extern crate serde_json; extern crate serde_json;
extern crate solana; extern crate solana;
use atty::{is, Stream}; use atty::{is, Stream};
use clap::{App, Arg};
use solana::entry_writer::EntryWriter; use solana::entry_writer::EntryWriter;
use solana::mint::Mint; use solana::mint::Mint;
use std::error; use std::error;
@@ -12,6 +15,20 @@ use std::io::{stdin, stdout, Read};
use std::process::exit; use std::process::exit;
fn main() -> Result<(), Box<error::Error>> { fn main() -> Result<(), Box<error::Error>> {
let matches = App::new("solana-genesis")
.arg(
Arg::with_name("tokens")
.short("t")
.long("tokens")
.value_name("NUMBER")
.takes_value(true)
.required(true)
.help("Number of tokens with which to initialize mint"),
)
.get_matches();
let tokens = value_t_or_exit!(matches, "tokens", i64);
if is(Stream::Stdin) { if is(Stream::Stdin) {
eprintln!("nothing found on stdin, expected a json file"); eprintln!("nothing found on stdin, expected a json file");
exit(1); exit(1);
@@ -24,7 +41,9 @@ fn main() -> Result<(), Box<error::Error>> {
exit(1); exit(1);
} }
let mint: Mint = serde_json::from_str(&buffer)?; let pkcs8: Vec<u8> = serde_json::from_str(&buffer)?;
let mint = Mint::new_with_pkcs8(tokens, pkcs8);
let mut writer = stdout(); let mut writer = stdout();
EntryWriter::write_entries(&mut writer, mint.create_entries())?; EntryWriter::write_entries(&mut writer, mint.create_entries())?;
Ok(()) Ok(())

View File

@@ -1,14 +1,49 @@
extern crate clap;
extern crate dirs;
extern crate ring; extern crate ring;
extern crate serde_json; extern crate serde_json;
use clap::{App, Arg};
use ring::rand::SystemRandom; use ring::rand::SystemRandom;
use ring::signature::Ed25519KeyPair; use ring::signature::Ed25519KeyPair;
use std::error; use std::error;
use std::fs::{self, File};
use std::io::Write;
use std::path::Path;
fn main() -> Result<(), Box<error::Error>> { fn main() -> Result<(), Box<error::Error>> {
let matches = App::new("solana-keygen")
.arg(
Arg::with_name("outfile")
.short("o")
.long("outfile")
.value_name("PATH")
.takes_value(true)
.help("path to generated file"),
)
.get_matches();
let rnd = SystemRandom::new(); let rnd = SystemRandom::new();
let pkcs8_bytes = Ed25519KeyPair::generate_pkcs8(&rnd)?; let pkcs8_bytes = Ed25519KeyPair::generate_pkcs8(&rnd)?;
let serialized = serde_json::to_string(&pkcs8_bytes.to_vec())?; let serialized = serde_json::to_string(&pkcs8_bytes.to_vec())?;
println!("{}", serialized);
let mut path = dirs::home_dir().expect("home directory");
let outfile = if matches.is_present("outfile") {
matches.value_of("outfile").unwrap()
} else {
path.extend(&[".config", "solana", "id.json"]);
path.to_str().unwrap()
};
if outfile == "-" {
println!("{}", serialized);
} else {
if let Some(outdir) = Path::new(outfile).parent() {
fs::create_dir_all(outdir)?;
}
let mut f = File::create(outfile)?;
f.write_all(&serialized.into_bytes())?;
}
Ok(()) Ok(())
} }

View File

@@ -1,29 +0,0 @@
extern crate atty;
extern crate serde_json;
extern crate solana;
use atty::{is, Stream};
use solana::mint::Mint;
use std::io;
use std::process::exit;
fn main() {
let mut input_text = String::new();
if is(Stream::Stdin) {
eprintln!("nothing found on stdin, expected a token number");
exit(1);
}
io::stdin().read_line(&mut input_text).unwrap();
let trimmed = input_text.trim();
let tokens = trimmed.parse::<i64>().unwrap_or_else(|e| {
eprintln!("{}", e);
exit(1);
});
let mint = Mint::new(tokens);
let serialized = serde_json::to_string(&mint).unwrap_or_else(|e| {
eprintln!("failed to serialize: {}", e);
exit(1);
});
println!("{}", serialized);
}

View File

@@ -2,6 +2,7 @@ extern crate atty;
extern crate bincode; extern crate bincode;
extern crate bs58; extern crate bs58;
extern crate clap; extern crate clap;
extern crate dirs;
extern crate env_logger; extern crate env_logger;
extern crate serde_json; extern crate serde_json;
extern crate solana; extern crate solana;
@@ -11,8 +12,7 @@ use clap::{App, Arg, SubCommand};
use solana::crdt::NodeInfo; use solana::crdt::NodeInfo;
use solana::drone::DroneRequest; use solana::drone::DroneRequest;
use solana::fullnode::Config; use solana::fullnode::Config;
use solana::mint::Mint; use solana::signature::{read_keypair, KeyPair, KeyPairUtil, PublicKey, Signature};
use solana::signature::{PublicKey, Signature};
use solana::thin_client::ThinClient; use solana::thin_client::ThinClient;
use std::error; use std::error;
use std::fmt; use std::fmt;
@@ -20,7 +20,6 @@ use std::fs::File;
use std::io; use std::io;
use std::io::prelude::*; use std::io::prelude::*;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream, UdpSocket}; use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream, UdpSocket};
use std::process::exit;
use std::thread::sleep; use std::thread::sleep;
use std::time::Duration; use std::time::Duration;
@@ -57,7 +56,7 @@ impl error::Error for WalletError {
struct WalletConfig { struct WalletConfig {
leader: NodeInfo, leader: NodeInfo,
id: Mint, id: KeyPair,
drone_addr: SocketAddr, drone_addr: SocketAddr,
command: WalletCommand, command: WalletCommand,
} }
@@ -67,7 +66,7 @@ impl Default for WalletConfig {
let default_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8000); let default_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8000);
WalletConfig { WalletConfig {
leader: NodeInfo::new_leader(&default_addr), leader: NodeInfo::new_leader(&default_addr),
id: Mint::new(0), id: KeyPair::new(),
drone_addr: default_addr, drone_addr: default_addr,
command: WalletCommand::Balance, command: WalletCommand::Balance,
} }
@@ -85,12 +84,12 @@ fn parse_args() -> Result<WalletConfig, Box<error::Error>> {
.help("/path/to/leader.json"), .help("/path/to/leader.json"),
) )
.arg( .arg(
Arg::with_name("mint") Arg::with_name("keypair")
.short("m") .short("k")
.long("mint") .long("keypair")
.value_name("PATH") .value_name("PATH")
.takes_value(true) .takes_value(true)
.help("/path/to/mint.json"), .help("/path/to/id.json"),
) )
.subcommand( .subcommand(
SubCommand::with_name("airdrop") SubCommand::with_name("airdrop")
@@ -101,6 +100,7 @@ fn parse_args() -> Result<WalletConfig, Box<error::Error>> {
.long("tokens") .long("tokens")
.value_name("NUMBER") .value_name("NUMBER")
.takes_value(true) .takes_value(true)
.required(true)
.help("The number of tokens to request"), .help("The number of tokens to request"),
), ),
) )
@@ -122,7 +122,6 @@ fn parse_args() -> Result<WalletConfig, Box<error::Error>> {
.long("to") .long("to")
.value_name("PUBKEY") .value_name("PUBKEY")
.takes_value(true) .takes_value(true)
.required(true)
.help("The pubkey of recipient"), .help("The pubkey of recipient"),
), ),
) )
@@ -149,24 +148,27 @@ fn parse_args() -> Result<WalletConfig, Box<error::Error>> {
leader = NodeInfo::new_leader(&server_addr); leader = NodeInfo::new_leader(&server_addr);
}; };
let id: Mint; let mut path = dirs::home_dir().expect("home directory");
if let Some(m) = matches.value_of("mint") { let id_path = if matches.is_present("keypair") {
id = read_mint(m)?; matches.value_of("keypair").unwrap()
} else { } else {
eprintln!("No mint found!"); path.extend(&[".config", "solana", "id.json"]);
exit(1); path.to_str().unwrap()
}; };
let id = read_keypair(id_path).or_else(|err| {
display_actions();
Err(WalletError::BadParameter(format!(
"{}: Unable to open keypair file: {}",
err, id_path
)))
})?;
let mut drone_addr = leader.contact_info.tpu; let mut drone_addr = leader.contact_info.tpu;
drone_addr.set_port(9900); drone_addr.set_port(9900);
let command = match matches.subcommand() { let command = match matches.subcommand() {
("airdrop", Some(airdrop_matches)) => { ("airdrop", Some(airdrop_matches)) => {
let tokens = if airdrop_matches.is_present("tokens") { let tokens = airdrop_matches.value_of("tokens").unwrap().parse()?;
airdrop_matches.value_of("tokens").unwrap().parse()?
} else {
id.tokens
};
Ok(WalletCommand::AirDrop(tokens)) Ok(WalletCommand::AirDrop(tokens))
} }
("pay", Some(pay_matches)) => { ("pay", Some(pay_matches)) => {
@@ -184,11 +186,7 @@ fn parse_args() -> Result<WalletConfig, Box<error::Error>> {
id.pubkey() id.pubkey()
}; };
let tokens = if pay_matches.is_present("tokens") { let tokens = pay_matches.value_of("tokens").unwrap().parse()?;
pay_matches.value_of("tokens").unwrap().parse()?
} else {
id.tokens
};
Ok(WalletCommand::Pay(tokens, to)) Ok(WalletCommand::Pay(tokens, to))
} }
@@ -264,7 +262,7 @@ fn process_command(
// If client has positive balance, spend tokens in {balance} number of transactions // If client has positive balance, spend tokens in {balance} number of transactions
WalletCommand::Pay(tokens, to) => { WalletCommand::Pay(tokens, to) => {
let last_id = client.get_last_id(); let last_id = client.get_last_id();
let sig = client.transfer(tokens, &config.id.keypair(), to, &last_id)?; let sig = client.transfer(tokens, &config.id, to, &last_id)?;
println!("{}", bs58::encode(sig).into_string()); println!("{}", bs58::encode(sig).into_string());
} }
// Confirm the last client transaction by signature // Confirm the last client transaction by signature
@@ -295,12 +293,6 @@ fn read_leader(path: &str) -> Config {
serde_json::from_reader(file).unwrap_or_else(|_| panic!("failed to parse {}", path)) serde_json::from_reader(file).unwrap_or_else(|_| panic!("failed to parse {}", path))
} }
fn read_mint(path: &str) -> Result<Mint, Box<error::Error>> {
let file = File::open(path.to_string())?;
let mint = serde_json::from_reader(file)?;
Ok(mint)
}
fn mk_client(r: &NodeInfo) -> io::Result<ThinClient> { fn mk_client(r: &NodeInfo) -> io::Result<ThinClient> {
let requests_socket = UdpSocket::bind("0.0.0.0:0").unwrap(); let requests_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
let transactions_socket = UdpSocket::bind("0.0.0.0:0").unwrap(); let transactions_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
@@ -318,7 +310,7 @@ fn mk_client(r: &NodeInfo) -> io::Result<ThinClient> {
fn request_airdrop( fn request_airdrop(
drone_addr: &SocketAddr, drone_addr: &SocketAddr,
id: &Mint, id: &KeyPair,
tokens: u64, tokens: u64,
) -> Result<(), Box<error::Error>> { ) -> Result<(), Box<error::Error>> {
let mut stream = TcpStream::connect(drone_addr)?; let mut stream = TcpStream::connect(drone_addr)?;

View File

@@ -7,13 +7,12 @@ use entry_writer;
use ledger::Block; use ledger::Block;
use ncp::Ncp; use ncp::Ncp;
use packet::BlobRecycler; use packet::BlobRecycler;
use ring::rand::SystemRandom;
use rpu::Rpu; use rpu::Rpu;
use service::Service; use service::Service;
use signature::{KeyPair, KeyPairUtil}; use signature::{KeyPair, KeyPairUtil};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::io::{sink, stdin, stdout, BufReader}; use std::io::{stdin, stdout, BufReader};
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::net::SocketAddr; use std::net::SocketAddr;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
@@ -31,13 +30,8 @@ pub struct FullNode {
thread_hdls: Vec<JoinHandle<()>>, thread_hdls: Vec<JoinHandle<()>>,
} }
pub enum InFile { pub enum LedgerFile {
StdIn, StdInOut,
Path(String),
}
pub enum OutFile {
StdOut,
Path(String), Path(String),
} }
@@ -50,11 +44,7 @@ pub struct Config {
/// Structure to be replicated by the network /// Structure to be replicated by the network
impl Config { impl Config {
pub fn new(bind_addr: &SocketAddr) -> Self { pub fn new(bind_addr: &SocketAddr, pkcs8: Vec<u8>) -> Self {
let rnd = SystemRandom::new();
let pkcs8 = KeyPair::generate_pkcs8(&rnd)
.expect("generate_pkcs8 in mint pub fn new")
.to_vec();
let keypair = let keypair =
KeyPair::from_pkcs8(Input::from(&pkcs8)).expect("from_pkcs8 in fullnode::Config new"); KeyPair::from_pkcs8(Input::from(&pkcs8)).expect("from_pkcs8 in fullnode::Config new");
let pubkey = keypair.pubkey(); let pubkey = keypair.pubkey();
@@ -71,16 +61,24 @@ impl FullNode {
pub fn new( pub fn new(
mut node: TestNode, mut node: TestNode,
leader: bool, leader: bool,
infile: InFile, ledger: LedgerFile,
keypair_for_validator: Option<KeyPair>, keypair_for_validator: Option<KeyPair>,
network_entry_for_validator: Option<SocketAddr>, network_entry_for_validator: Option<SocketAddr>,
outfile_for_leader: Option<OutFile>,
) -> FullNode { ) -> FullNode {
info!("creating bank..."); info!("creating bank...");
let bank = Bank::default(); let bank = Bank::default();
let infile: Box<Read> = match infile { let (infile, outfile): (Box<Read>, Box<Write + Send>) = match ledger {
InFile::Path(path) => Box::new(File::open(path).unwrap()), LedgerFile::Path(path) => (
InFile::StdIn => Box::new(stdin()), Box::new(File::open(path.clone()).expect("opening ledger file")),
Box::new(
OpenOptions::new()
.create(true)
.append(true)
.open(path)
.expect("opening ledger file"),
),
),
LedgerFile::StdInOut => (Box::new(stdin()), Box::new(stdout())),
}; };
let reader = BufReader::new(infile); let reader = BufReader::new(infile);
let entries = entry_writer::read_entries(reader).map(|e| e.expect("failed to parse entry")); let entries = entry_writer::read_entries(reader).map(|e| e.expect("failed to parse entry"));
@@ -122,17 +120,6 @@ impl FullNode {
server server
} else { } else {
node.data.leader_id = node.data.id; node.data.leader_id = node.data.id;
let outfile_for_leader: Box<Write + Send> = match outfile_for_leader {
Some(OutFile::Path(file)) => Box::new(
OpenOptions::new()
.create(true)
.append(true)
.open(file)
.expect("opening ledger file"),
),
Some(OutFile::StdOut) => Box::new(stdout()),
None => Box::new(sink()),
};
let server = FullNode::new_leader( let server = FullNode::new_leader(
bank, bank,
@@ -142,7 +129,7 @@ impl FullNode {
None, None,
node, node,
exit.clone(), exit.clone(),
outfile_for_leader, outfile,
); );
info!( info!(
"leader ready... local request address: {} (advertising {})", "leader ready... local request address: {} (advertising {})",

View File

@@ -15,11 +15,7 @@ pub struct Mint {
} }
impl Mint { impl Mint {
pub fn new(tokens: i64) -> Self { pub fn new_with_pkcs8(tokens: i64, pkcs8: Vec<u8>) -> Self {
let rnd = SystemRandom::new();
let pkcs8 = KeyPair::generate_pkcs8(&rnd)
.expect("generate_pkcs8 in mint pub fn new")
.to_vec();
let keypair = let keypair =
KeyPair::from_pkcs8(Input::from(&pkcs8)).expect("from_pkcs8 in mint pub fn new"); KeyPair::from_pkcs8(Input::from(&pkcs8)).expect("from_pkcs8 in mint pub fn new");
let pubkey = keypair.pubkey(); let pubkey = keypair.pubkey();
@@ -29,6 +25,15 @@ impl Mint {
tokens, tokens,
} }
} }
pub fn new(tokens: i64) -> Self {
let rnd = SystemRandom::new();
let pkcs8 = KeyPair::generate_pkcs8(&rnd)
.expect("generate_pkcs8 in mint pub fn new")
.to_vec();
Self::new_with_pkcs8(tokens, pkcs8)
}
pub fn seed(&self) -> Hash { pub fn seed(&self) -> Hash {
hash(&self.pkcs8) hash(&self.pkcs8)
} }

View File

@@ -8,8 +8,11 @@ use ring::error::Unspecified;
use ring::rand::SecureRandom; use ring::rand::SecureRandom;
use ring::signature::Ed25519KeyPair; use ring::signature::Ed25519KeyPair;
use ring::{rand, signature}; use ring::{rand, signature};
use serde_json;
use std::cell::RefCell; use std::cell::RefCell;
use untrusted; use std::error;
use std::fs::File;
use untrusted::Input;
pub type KeyPair = Ed25519KeyPair; pub type KeyPair = Ed25519KeyPair;
pub type PublicKey = GenericArray<u8, U32>; pub type PublicKey = GenericArray<u8, U32>;
@@ -24,10 +27,8 @@ impl KeyPairUtil for Ed25519KeyPair {
/// Return a new ED25519 keypair /// Return a new ED25519 keypair
fn new() -> Self { fn new() -> Self {
let rng = rand::SystemRandom::new(); let rng = rand::SystemRandom::new();
let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(&rng) let pkcs8_bytes = Ed25519KeyPair::generate_pkcs8(&rng).expect("generate_pkcs8");
.expect("generate_pkcs8 in signature pb fn new"); Ed25519KeyPair::from_pkcs8(Input::from(&pkcs8_bytes)).expect("from_pcks8")
signature::Ed25519KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8_bytes))
.expect("from_pcks8 in signature pb fn new")
} }
/// Return the public key for the given keypair /// Return the public key for the given keypair
@@ -42,9 +43,9 @@ pub trait SignatureUtil {
impl SignatureUtil for GenericArray<u8, U64> { impl SignatureUtil for GenericArray<u8, U64> {
fn verify(&self, peer_public_key_bytes: &[u8], msg_bytes: &[u8]) -> bool { fn verify(&self, peer_public_key_bytes: &[u8], msg_bytes: &[u8]) -> bool {
let peer_public_key = untrusted::Input::from(peer_public_key_bytes); let peer_public_key = Input::from(peer_public_key_bytes);
let msg = untrusted::Input::from(msg_bytes); let msg = Input::from(msg_bytes);
let sig = untrusted::Input::from(self); let sig = Input::from(self);
signature::verify(&signature::ED25519, peer_public_key, msg, sig).is_ok() signature::verify(&signature::ED25519, peer_public_key, msg, sig).is_ok()
} }
} }
@@ -77,7 +78,7 @@ impl GenKeys {
.into_par_iter() .into_par_iter()
.map(|seed| { .map(|seed| {
let pkcs8 = GenKeys::new(seed).new_key(); let pkcs8 = GenKeys::new(seed).new_key();
KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8)).unwrap() KeyPair::from_pkcs8(Input::from(&pkcs8)).unwrap()
}) })
.collect() .collect()
} }
@@ -91,6 +92,18 @@ impl SecureRandom for GenKeys {
} }
} }
pub fn read_pkcs8(path: &str) -> Result<Vec<u8>, Box<error::Error>> {
let file = File::open(path.to_string())?;
let pkcs8: Vec<u8> = serde_json::from_reader(file)?;
Ok(pkcs8)
}
pub fn read_keypair(path: &str) -> Result<KeyPair, Box<error::Error>> {
let pkcs8 = read_pkcs8(path)?;
let keypair = Ed25519KeyPair::from_pkcs8(Input::from(&pkcs8))?;
Ok(keypair)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@@ -7,7 +7,7 @@ extern crate solana;
use solana::crdt::TestNode; use solana::crdt::TestNode;
use solana::crdt::{Crdt, NodeInfo}; use solana::crdt::{Crdt, NodeInfo};
use solana::entry_writer::EntryWriter; use solana::entry_writer::EntryWriter;
use solana::fullnode::{FullNode, InFile, OutFile}; use solana::fullnode::{FullNode, LedgerFile};
use solana::logger; use solana::logger;
use solana::mint::Mint; use solana::mint::Mint;
use solana::ncp::Ncp; use solana::ncp::Ncp;
@@ -94,8 +94,7 @@ fn test_multi_node_validator_catchup_from_zero() {
let server = FullNode::new( let server = FullNode::new(
leader, leader,
true, true,
InFile::Path(ledger_path.clone()), LedgerFile::Path(ledger_path.clone()),
None,
None, None,
None, None,
); );
@@ -106,10 +105,9 @@ fn test_multi_node_validator_catchup_from_zero() {
let mut val = FullNode::new( let mut val = FullNode::new(
validator, validator,
false, false,
InFile::Path(ledger_path.clone()), LedgerFile::Path(ledger_path.clone()),
Some(keypair), Some(keypair),
Some(leader_data.contact_info.ncp), Some(leader_data.contact_info.ncp),
None,
); );
nodes.push(val); nodes.push(val);
} }
@@ -141,10 +139,9 @@ fn test_multi_node_validator_catchup_from_zero() {
let val = FullNode::new( let val = FullNode::new(
validator, validator,
false, false,
InFile::Path(ledger_path.clone()), LedgerFile::Path(ledger_path.clone()),
Some(keypair), Some(keypair),
Some(leader_data.contact_info.ncp), Some(leader_data.contact_info.ncp),
None,
); );
nodes.push(val); nodes.push(val);
//contains the leader and new node //contains the leader and new node
@@ -196,8 +193,7 @@ fn test_multi_node_basic() {
let server = FullNode::new( let server = FullNode::new(
leader, leader,
true, true,
InFile::Path(ledger_path.clone()), LedgerFile::Path(ledger_path.clone()),
None,
None, None,
None, None,
); );
@@ -208,10 +204,9 @@ fn test_multi_node_basic() {
let val = FullNode::new( let val = FullNode::new(
validator, validator,
false, false,
InFile::Path(ledger_path.clone()), LedgerFile::Path(ledger_path.clone()),
Some(keypair), Some(keypair),
Some(leader_data.contact_info.ncp), Some(leader_data.contact_info.ncp),
None,
); );
nodes.push(val); nodes.push(val);
} }
@@ -251,10 +246,9 @@ fn test_boot_validator_from_file() {
let leader_fullnode = FullNode::new( let leader_fullnode = FullNode::new(
leader, leader,
true, true,
InFile::Path(ledger_path.clone()), LedgerFile::Path(ledger_path.clone()),
None, None,
None, None,
Some(OutFile::Path(ledger_path.clone())),
); );
let leader_balance = let leader_balance =
send_tx_and_retry_get_balance(&leader_data, &alice, &bob_pubkey, Some(500)).unwrap(); send_tx_and_retry_get_balance(&leader_data, &alice, &bob_pubkey, Some(500)).unwrap();
@@ -269,12 +263,10 @@ fn test_boot_validator_from_file() {
let val_fullnode = FullNode::new( let val_fullnode = FullNode::new(
validator, validator,
false, false,
InFile::Path(ledger_path.clone()), LedgerFile::Path(ledger_path.clone()),
Some(keypair), Some(keypair),
Some(leader_data.contact_info.ncp), Some(leader_data.contact_info.ncp),
None,
); );
let mut client = mk_client(&validator_data); let mut client = mk_client(&validator_data);
let getbal = retry_get_balance(&mut client, &bob_pubkey, Some(leader_balance)); let getbal = retry_get_balance(&mut client, &bob_pubkey, Some(leader_balance));
assert!(getbal == Some(leader_balance)); assert!(getbal == Some(leader_balance));
@@ -290,10 +282,9 @@ fn create_leader(ledger_path: &str) -> (NodeInfo, FullNode) {
let leader_fullnode = FullNode::new( let leader_fullnode = FullNode::new(
leader, leader,
true, true,
InFile::Path(ledger_path.to_string()), LedgerFile::Path(ledger_path.to_string()),
None, None,
None, None,
Some(OutFile::Path(ledger_path.to_string())),
); );
(leader_data, leader_fullnode) (leader_data, leader_fullnode)
} }
@@ -342,10 +333,9 @@ fn test_leader_restart_validator_start_from_old_ledger() {
let val_fullnode = FullNode::new( let val_fullnode = FullNode::new(
validator, validator,
false, false,
InFile::Path(stale_ledger_path.clone()), LedgerFile::Path(stale_ledger_path.clone()),
Some(keypair), Some(keypair),
Some(leader_data.contact_info.ncp), Some(leader_data.contact_info.ncp),
None,
); );
// trigger broadcast, validator should catch up from leader, whose window contains // trigger broadcast, validator should catch up from leader, whose window contains
@@ -386,10 +376,9 @@ fn test_multi_node_dynamic_network() {
let server = FullNode::new( let server = FullNode::new(
leader, leader,
true, true,
InFile::Path(ledger_path.clone()), LedgerFile::Path(ledger_path.clone()),
None, None,
None, None,
Some(OutFile::Path(ledger_path.clone())),
); );
info!("{:x} LEADER", leader_data.debug_id()); info!("{:x} LEADER", leader_data.debug_id());
let leader_balance = let leader_balance =
@@ -412,10 +401,9 @@ fn test_multi_node_dynamic_network() {
let val = FullNode::new( let val = FullNode::new(
validator, validator,
false, false,
InFile::Path(ledger_path.clone()), LedgerFile::Path(ledger_path.clone()),
Some(keypair), Some(keypair),
Some(leader_data.contact_info.ncp), Some(leader_data.contact_info.ncp),
Some(OutFile::Path(ledger_path.clone())),
); );
info!("started[{}/{}] {:x}", n, N, rd.debug_id()); info!("started[{}/{}] {:x}", n, N, rd.debug_id());
(rd, val) (rd, val)