Compare commits
27 Commits
foo4
...
v0.7.0-rc.
Author | SHA1 | Date | |
---|---|---|---|
28d24497a3 | |||
05cea4c1da | |||
260f5edfd6 | |||
7105136595 | |||
54db379bf2 | |||
effbf0b978 | |||
8e7a2a9587 | |||
18e6ff4167 | |||
fa1cdaa91a | |||
b538b67524 | |||
2b0f6355af | |||
11b9a0323d | |||
710fa822a0 | |||
aaf6ce5aea | |||
34ea483736 | |||
a3ff40476e | |||
4cca3ff454 | |||
3d9acdd970 | |||
428f220b88 | |||
10add6a8ac | |||
f06a8dceda | |||
545f4f1c87 | |||
77543d83ff | |||
eb6a30cb7c | |||
97372b8e63 | |||
cea29ed772 | |||
b5006b8f2b |
@ -37,10 +37,6 @@ path = "src/bin/fullnode-config.rs"
|
||||
name = "solana-genesis"
|
||||
path = "src/bin/genesis.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "solana-mint"
|
||||
path = "src/bin/mint.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "solana-drone"
|
||||
path = "src/bin/drone.rs"
|
||||
@ -85,6 +81,7 @@ futures = "0.1.21"
|
||||
clap = "2.31"
|
||||
reqwest = "0.8.6"
|
||||
influx_db_client = "0.3.4"
|
||||
dirs = "1.0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.2"
|
||||
|
@ -3,7 +3,7 @@ steps:
|
||||
name: "stable [public]"
|
||||
env:
|
||||
CARGO_TARGET_CACHE_NAME: "stable"
|
||||
timeout_in_minutes: 20
|
||||
timeout_in_minutes: 30
|
||||
- command: "ci/shellcheck.sh"
|
||||
name: "shellcheck [public]"
|
||||
timeout_in_minutes: 20
|
||||
@ -36,3 +36,9 @@ steps:
|
||||
- trigger: "solana-snap"
|
||||
branches: "!pull/*"
|
||||
async: true
|
||||
build:
|
||||
message: "${BUILDKITE_MESSAGE}"
|
||||
commit: "${BUILDKITE_COMMIT}"
|
||||
branch: "${BUILDKITE_BRANCH}"
|
||||
env:
|
||||
TRIGGERED_BUILDKITE_TAG: "${BUILDKITE_TAG}"
|
||||
|
80
ci/refresh-testnet.sh
Executable file
80
ci/refresh-testnet.sh
Executable file
@ -0,0 +1,80 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Refreshes the Solana software running on the Testnet full nodes
|
||||
#
|
||||
# This script must be run by a user/machine that has successfully authenticated
|
||||
# with GCP and has sufficient permission.
|
||||
#
|
||||
|
||||
if [[ -z $SOLANA_METRICS_CONFIG ]]; then
|
||||
echo Error: SOLANA_METRICS_CONFIG environment variable is unset
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Default to --edge channel. To select the beta channel:
|
||||
# export SOLANA_METRICS_CONFIG=--beta
|
||||
if [[ -z $SOLANA_SNAP_CHANNEL ]]; then
|
||||
SOLANA_SNAP_CHANNEL=--edge
|
||||
fi
|
||||
|
||||
vmlist=(testnet-solana-com:us-west1-b) # Leader is hard coded as the first entry
|
||||
|
||||
echo "--- Available validators"
|
||||
gcloud compute instances list --filter="labels.testnet-mode=validator"
|
||||
while read -r vmName vmZone status; do
|
||||
if [[ $status != RUNNING ]]; then
|
||||
echo "Warning: $vmName is not RUNNING, ignoring it."
|
||||
continue
|
||||
fi
|
||||
vmlist+=("$vmName:$vmZone")
|
||||
done < <(gcloud compute instances list --filter="labels.testnet-mode=validator" --format 'value(name,zone,status)')
|
||||
|
||||
|
||||
echo "--- Refreshing"
|
||||
leader=true
|
||||
for info in "${vmlist[@]}"; do
|
||||
vmName=${info%:*}
|
||||
vmZone=${info#*:}
|
||||
echo "Starting refresh for $vmName"
|
||||
|
||||
(
|
||||
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
|
||||
set -x
|
||||
sudo snap remove solana
|
||||
sudo snap install solana $SOLANA_SNAP_CHANNEL --devmode
|
||||
sudo snap set solana $nodeConfig
|
||||
snap info solana
|
||||
sudo snap logs solana -n200
|
||||
EOF
|
||||
set -x
|
||||
gcloud compute scp --zone "$vmZone" "autogen-refresh-$vmName.sh" "$vmName":
|
||||
gcloud compute ssh "$vmName" --zone "$vmZone" \
|
||||
--ssh-flag="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -t" \
|
||||
--command="bash ./autogen-refresh-$vmName.sh"
|
||||
) > "log-$vmName.txt" 2>&1 &
|
||||
|
||||
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
|
||||
|
||||
echo Waiting for validators...
|
||||
wait
|
||||
|
||||
for info in "${vmlist[@]}"; do
|
||||
vmName=${info%:*}
|
||||
cat "log-$vmName.txt"
|
||||
done
|
||||
|
||||
echo "--- done"
|
||||
exit 0
|
@ -7,7 +7,11 @@ if [[ -z $BUILDKITE_BRANCH ]] || ./ci/is-pr.sh; then
|
||||
DRYRUN="echo"
|
||||
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
|
||||
else
|
||||
SNAP_CHANNEL=beta
|
||||
|
@ -23,9 +23,9 @@ fi
|
||||
|
||||
client_json="$SOLANA_CONFIG_CLIENT_DIR"/client.json
|
||||
if [[ ! -r $client_json ]]; then
|
||||
$solana_mint <<<0 > "$client_json"
|
||||
$solana_keygen -o "$client_json"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086 # $solana_client_demo should not be quoted
|
||||
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
|
||||
|
@ -53,7 +53,7 @@ solana_fullnode=$(solana_program fullnode)
|
||||
solana_fullnode_config=$(solana_program fullnode-config)
|
||||
solana_fullnode_cuda=$(solana_program fullnode-cuda)
|
||||
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_BACKTRACE=1
|
||||
@ -107,15 +107,19 @@ tune_networking() {
|
||||
# Reference: https://medium.com/@CameronSparr/increase-os-udp-buffers-to-improve-performance-51d167bb1360
|
||||
[[ $(uname) = Linux ]] && (
|
||||
set -x
|
||||
# TODO: Check values and warn instead, it's a little rude to set them here.
|
||||
sudo sysctl -w net.core.rmem_max=26214400 1>/dev/null 2>/dev/null
|
||||
sudo sysctl -w net.core.rmem_default=26214400 1>/dev/null 2>/dev/null
|
||||
# test the existence of the sysctls before trying to set them
|
||||
sysctl net.core.rmem_max 2>/dev/null 1>/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_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
|
||||
declare url="$1"
|
||||
|
@ -38,4 +38,4 @@ $rsync -vPz "$rsync_leader_url"/config/leader.json "$SOLANA_CONFIG_DIR"/
|
||||
|
||||
# shellcheck disable=SC2086 # $solana_drone should not be quoted
|
||||
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
|
||||
|
@ -25,9 +25,15 @@ fi
|
||||
|
||||
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
|
||||
exec $program \
|
||||
-l "$SOLANA_CONFIG_DIR"/leader.json \
|
||||
< <(shopt -s nullglob && cat "$SOLANA_CONFIG_DIR"/genesis.log \
|
||||
"$SOLANA_CONFIG_DIR"/tx-*.log) \
|
||||
> "$SOLANA_CONFIG_DIR"/tx-"$(date -u +%Y%m%d%H%M%S%N)".log
|
||||
--identity "$SOLANA_CONFIG_DIR"/leader.json \
|
||||
--ledger "$SOLANA_CONFIG_DIR"/ledger.log
|
||||
|
@ -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
|
@ -71,6 +71,8 @@ done
|
||||
|
||||
leader_address_args=("$ip_address_arg")
|
||||
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
|
||||
|
||||
@ -78,25 +80,26 @@ echo "Cleaning $SOLANA_CONFIG_DIR"
|
||||
rm -rvf "$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
|
||||
rm -rvf "$SOLANA_CONFIG_PRIVATE_DIR"
|
||||
mkdir -p "$SOLANA_CONFIG_PRIVATE_DIR"
|
||||
|
||||
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"
|
||||
$solana_genesis < "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json > "$SOLANA_CONFIG_DIR"/genesis.log
|
||||
echo "Creating $SOLANA_CONFIG_DIR/ledger.log"
|
||||
$solana_genesis --tokens="$num_tokens" < "$mint_path" > "$SOLANA_CONFIG_DIR"/ledger.log
|
||||
|
||||
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
|
||||
|
||||
|
||||
if $node_type_validator; then
|
||||
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
|
||||
|
||||
ls -lh "$SOLANA_CONFIG_DIR"/
|
||||
|
@ -73,8 +73,24 @@ ls -lh "$SOLANA_LEADER_CONFIG_DIR"
|
||||
|
||||
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
|
||||
exec $program \
|
||||
-l "$SOLANA_CONFIG_DIR"/validator.json -t "$leader_address:$leader_port" \
|
||||
< <(shopt -s nullglob && cat "$SOLANA_LEADER_CONFIG_DIR"/genesis.log \
|
||||
"$SOLANA_LEADER_CONFIG_DIR"/tx-*.log)
|
||||
--identity "$SOLANA_CONFIG_DIR"/validator.json \
|
||||
--testnet "$leader_address:$leader_port" \
|
||||
--ledger "$SOLANA_LEADER_CONFIG_DIR"/ledger.log
|
||||
|
@ -36,12 +36,12 @@ if [[ ! -r "$SOLANA_CONFIG_CLIENT_DIR"/leader.json ]]; then
|
||||
)
|
||||
fi
|
||||
|
||||
client_json="$SOLANA_CONFIG_CLIENT_DIR"/client.json
|
||||
if [[ ! -r $client_json ]]; then
|
||||
$solana_mint <<<0 > "$client_json"
|
||||
client_id_path="$SOLANA_CONFIG_CLIENT_DIR"/id.json
|
||||
if [[ ! -r $client_id_path ]]; then
|
||||
$solana_keygen -o "$client_id_path"
|
||||
fi
|
||||
|
||||
set -x
|
||||
# shellcheck disable=SC2086 # $solana_wallet should not be quoted
|
||||
exec $solana_wallet \
|
||||
-l "$SOLANA_CONFIG_CLIENT_DIR"/leader.json -m "$client_json" "$@"
|
||||
-l "$SOLANA_CONFIG_CLIENT_DIR"/leader.json -k "$client_id_path" "$@"
|
||||
|
@ -37,16 +37,26 @@ apps:
|
||||
plugs:
|
||||
- network
|
||||
- network-bind
|
||||
- home
|
||||
genesis:
|
||||
command: solana-genesis
|
||||
mint:
|
||||
command: solana-mint
|
||||
keygen:
|
||||
command: solana-keygen
|
||||
plugs:
|
||||
- home
|
||||
client-demo:
|
||||
command: solana-client-demo
|
||||
plugs:
|
||||
- network
|
||||
- network-bind
|
||||
- home
|
||||
wallet:
|
||||
# TODO: Merge wallet.sh functionality into solana-wallet proper
|
||||
command: wallet.sh
|
||||
#command: solana-wallet
|
||||
plugs:
|
||||
- network
|
||||
- home
|
||||
|
||||
daemon-validator:
|
||||
daemon: simple
|
||||
|
@ -12,11 +12,10 @@ use solana::crdt::{Crdt, NodeInfo};
|
||||
use solana::drone::DroneRequest;
|
||||
use solana::fullnode::Config;
|
||||
use solana::hash::Hash;
|
||||
use solana::mint::Mint;
|
||||
use solana::nat::{udp_public_bind, udp_random_bind};
|
||||
use solana::ncp::Ncp;
|
||||
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::thin_client::ThinClient;
|
||||
use solana::timing::{duration_as_ms, duration_as_s};
|
||||
@ -77,7 +76,7 @@ fn sample_tx_count(
|
||||
fn generate_and_send_txs(
|
||||
client: &mut ThinClient,
|
||||
tx_clients: &[ThinClient],
|
||||
id: &Mint,
|
||||
id: &KeyPair,
|
||||
keypairs: &[KeyPair],
|
||||
leader: &NodeInfo,
|
||||
txs: i64,
|
||||
@ -91,7 +90,7 @@ fn generate_and_send_txs(
|
||||
let transactions: Vec<_> = if !reclaim {
|
||||
keypairs
|
||||
.par_iter()
|
||||
.map(|keypair| Transaction::new(&id.keypair(), keypair.pubkey(), 1, *last_id))
|
||||
.map(|keypair| Transaction::new(&id, keypair.pubkey(), 1, *last_id))
|
||||
.collect()
|
||||
} else {
|
||||
keypairs
|
||||
@ -164,12 +163,13 @@ fn main() {
|
||||
.help("/path/to/leader.json"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mint")
|
||||
.short("m")
|
||||
.long("mint")
|
||||
Arg::with_name("keypair")
|
||||
.short("k")
|
||||
.long("keypair")
|
||||
.value_name("PATH")
|
||||
.takes_value(true)
|
||||
.help("/path/to/mint.json"),
|
||||
.default_value("~/.config/solana/id.json")
|
||||
.help("/path/to/id.json"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("num_nodes")
|
||||
@ -205,13 +205,7 @@ fn main() {
|
||||
leader = NodeInfo::new_leader(&server_addr);
|
||||
};
|
||||
|
||||
let id: Mint;
|
||||
if let Some(m) = matches.value_of("mint") {
|
||||
id = read_mint(m).expect("client mint");
|
||||
} else {
|
||||
eprintln!("No mint found!");
|
||||
exit(1);
|
||||
};
|
||||
let id = read_keypair(matches.value_of("keypair").unwrap()).expect("client keypair");
|
||||
|
||||
if let Some(t) = matches.value_of("threads") {
|
||||
threads = t.to_string().parse().expect("integer");
|
||||
@ -259,7 +253,7 @@ fn main() {
|
||||
println!("Got last ID {:?}", last_id);
|
||||
|
||||
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);
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
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(
|
||||
drone_addr: &SocketAddr,
|
||||
id: &Mint,
|
||||
id: &KeyPair,
|
||||
tokens: u64,
|
||||
) -> Result<(), Box<error::Error>> {
|
||||
let mut stream = TcpStream::connect(drone_addr)?;
|
||||
|
@ -12,11 +12,9 @@ use clap::{App, Arg};
|
||||
use solana::crdt::NodeInfo;
|
||||
use solana::drone::{Drone, DroneRequest};
|
||||
use solana::fullnode::Config;
|
||||
use solana::mint::Mint;
|
||||
use std::error;
|
||||
use solana::signature::read_keypair;
|
||||
use std::fs::File;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::process::exit;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use tokio::net::TcpListener;
|
||||
@ -35,11 +33,12 @@ fn main() {
|
||||
.help("/path/to/leader.json"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mint")
|
||||
.short("m")
|
||||
.long("mint")
|
||||
Arg::with_name("keypair")
|
||||
.short("k")
|
||||
.long("keypair")
|
||||
.value_name("PATH")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.help("/path/to/mint.json"),
|
||||
)
|
||||
.arg(
|
||||
@ -68,13 +67,9 @@ fn main() {
|
||||
leader = NodeInfo::new_leader(&server_addr);
|
||||
};
|
||||
|
||||
let mint: Mint;
|
||||
if let Some(m) = matches.value_of("mint") {
|
||||
mint = read_mint(m).expect("client mint");
|
||||
} else {
|
||||
eprintln!("No mint found!");
|
||||
exit(1);
|
||||
};
|
||||
let mint_keypair =
|
||||
read_keypair(matches.value_of("keypair").expect("keypair")).expect("client keypair");
|
||||
|
||||
let time_slice: Option<u64>;
|
||||
if let Some(t) = matches.value_of("time") {
|
||||
time_slice = Some(t.to_string().parse().expect("integer"));
|
||||
@ -88,8 +83,6 @@ fn main() {
|
||||
request_cap = None;
|
||||
}
|
||||
|
||||
let mint_keypair = mint.keypair();
|
||||
|
||||
let drone_addr: SocketAddr = "0.0.0.0:9900".parse().unwrap();
|
||||
|
||||
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));
|
||||
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)
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
extern crate clap;
|
||||
extern crate dirs;
|
||||
extern crate serde_json;
|
||||
extern crate solana;
|
||||
|
||||
@ -6,6 +7,7 @@ use clap::{App, Arg};
|
||||
use solana::crdt::{get_ip_addr, parse_port_or_addr};
|
||||
use solana::fullnode::Config;
|
||||
use solana::nat::get_public_ip_addr;
|
||||
use solana::signature::read_pkcs8;
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
@ -18,6 +20,14 @@ fn main() {
|
||||
.takes_value(false)
|
||||
.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::with_name("public")
|
||||
.short("p")
|
||||
@ -54,9 +64,18 @@ fn main() {
|
||||
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
|
||||
// port range that we open on aws
|
||||
let config = Config::new(&bind_addr);
|
||||
let config = Config::new(&bind_addr, pkcs8);
|
||||
let stdout = io::stdout();
|
||||
serde_json::to_writer(stdout, &config).expect("serialize");
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
extern crate atty;
|
||||
extern crate clap;
|
||||
extern crate env_logger;
|
||||
extern crate getopts;
|
||||
@ -6,10 +5,9 @@ extern crate log;
|
||||
extern crate serde_json;
|
||||
extern crate solana;
|
||||
|
||||
use atty::{is, Stream};
|
||||
use clap::{App, Arg};
|
||||
use solana::crdt::{NodeInfo, TestNode};
|
||||
use solana::fullnode::{Config, FullNode, InFile, OutFile};
|
||||
use solana::fullnode::{Config, FullNode, LedgerFile};
|
||||
use solana::service::Service;
|
||||
use solana::signature::{KeyPair, KeyPairUtil};
|
||||
use std::fs::File;
|
||||
@ -22,8 +20,8 @@ fn main() -> () {
|
||||
let matches = App::new("fullnode")
|
||||
.arg(
|
||||
Arg::with_name("identity")
|
||||
.short("l")
|
||||
.long("local")
|
||||
.short("i")
|
||||
.long("identity")
|
||||
.value_name("FILE")
|
||||
.takes_value(true)
|
||||
.help("run with the identity found in FILE"),
|
||||
@ -34,27 +32,23 @@ fn main() -> () {
|
||||
.long("testnet")
|
||||
.value_name("HOST:PORT")
|
||||
.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::with_name("output")
|
||||
.short("o")
|
||||
.long("output")
|
||||
Arg::with_name("ledger")
|
||||
.short("L")
|
||||
.long("ledger")
|
||||
.value_name("FILE")
|
||||
.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();
|
||||
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 mut keypair = KeyPair::new();
|
||||
let mut repl_data = NodeInfo::new_leader_with_pubkey(keypair.pubkey(), &bind_addr);
|
||||
if let Some(l) = matches.value_of("identity") {
|
||||
let path = l.to_string();
|
||||
if let Some(i) = matches.value_of("identity") {
|
||||
let path = i.to_string();
|
||||
if let Ok(file) = File::open(path.clone()) {
|
||||
let parse: serde_json::Result<Config> = serde_json::from_reader(file);
|
||||
if let Ok(data) = parse {
|
||||
@ -69,27 +63,22 @@ fn main() -> () {
|
||||
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 fullnode = if let Some(t) = matches.value_of("testnet") {
|
||||
let testnet_address_string = t.to_string();
|
||||
let testnet_addr = testnet_address_string.parse().unwrap();
|
||||
FullNode::new(
|
||||
node,
|
||||
false,
|
||||
InFile::StdIn,
|
||||
Some(keypair),
|
||||
Some(testnet_addr),
|
||||
None,
|
||||
)
|
||||
|
||||
FullNode::new(node, false, ledger, Some(keypair), Some(testnet_addr))
|
||||
} else {
|
||||
node.data.leader_id = node.data.id;
|
||||
|
||||
let outfile = if let Some(o) = matches.value_of("output") {
|
||||
OutFile::Path(o.to_string())
|
||||
} else {
|
||||
OutFile::StdOut
|
||||
};
|
||||
FullNode::new(node, true, InFile::StdIn, None, None, Some(outfile))
|
||||
FullNode::new(node, true, ledger, None, None)
|
||||
};
|
||||
fullnode.join().expect("join");
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
//! A command-line executable for generating the chain's genesis block.
|
||||
|
||||
extern crate atty;
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
extern crate serde_json;
|
||||
extern crate solana;
|
||||
|
||||
use atty::{is, Stream};
|
||||
use clap::{App, Arg};
|
||||
use solana::entry_writer::EntryWriter;
|
||||
use solana::mint::Mint;
|
||||
use std::error;
|
||||
@ -12,6 +15,20 @@ use std::io::{stdin, stdout, Read};
|
||||
use std::process::exit;
|
||||
|
||||
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) {
|
||||
eprintln!("nothing found on stdin, expected a json file");
|
||||
exit(1);
|
||||
@ -24,7 +41,9 @@ fn main() -> Result<(), Box<error::Error>> {
|
||||
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();
|
||||
EntryWriter::write_entries(&mut writer, mint.create_entries())?;
|
||||
Ok(())
|
||||
|
@ -1,14 +1,49 @@
|
||||
extern crate clap;
|
||||
extern crate dirs;
|
||||
extern crate ring;
|
||||
extern crate serde_json;
|
||||
|
||||
use clap::{App, Arg};
|
||||
use ring::rand::SystemRandom;
|
||||
use ring::signature::Ed25519KeyPair;
|
||||
use std::error;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
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 pkcs8_bytes = Ed25519KeyPair::generate_pkcs8(&rnd)?;
|
||||
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(())
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -2,6 +2,7 @@ extern crate atty;
|
||||
extern crate bincode;
|
||||
extern crate bs58;
|
||||
extern crate clap;
|
||||
extern crate dirs;
|
||||
extern crate env_logger;
|
||||
extern crate serde_json;
|
||||
extern crate solana;
|
||||
@ -11,8 +12,7 @@ use clap::{App, Arg, SubCommand};
|
||||
use solana::crdt::NodeInfo;
|
||||
use solana::drone::DroneRequest;
|
||||
use solana::fullnode::Config;
|
||||
use solana::mint::Mint;
|
||||
use solana::signature::{PublicKey, Signature};
|
||||
use solana::signature::{read_keypair, KeyPair, KeyPairUtil, PublicKey, Signature};
|
||||
use solana::thin_client::ThinClient;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
@ -20,7 +20,6 @@ use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream, UdpSocket};
|
||||
use std::process::exit;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
@ -57,7 +56,7 @@ impl error::Error for WalletError {
|
||||
|
||||
struct WalletConfig {
|
||||
leader: NodeInfo,
|
||||
id: Mint,
|
||||
id: KeyPair,
|
||||
drone_addr: SocketAddr,
|
||||
command: WalletCommand,
|
||||
}
|
||||
@ -67,7 +66,7 @@ impl Default for WalletConfig {
|
||||
let default_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8000);
|
||||
WalletConfig {
|
||||
leader: NodeInfo::new_leader(&default_addr),
|
||||
id: Mint::new(0),
|
||||
id: KeyPair::new(),
|
||||
drone_addr: default_addr,
|
||||
command: WalletCommand::Balance,
|
||||
}
|
||||
@ -85,12 +84,12 @@ fn parse_args() -> Result<WalletConfig, Box<error::Error>> {
|
||||
.help("/path/to/leader.json"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mint")
|
||||
.short("m")
|
||||
.long("mint")
|
||||
Arg::with_name("keypair")
|
||||
.short("k")
|
||||
.long("keypair")
|
||||
.value_name("PATH")
|
||||
.takes_value(true)
|
||||
.help("/path/to/mint.json"),
|
||||
.help("/path/to/id.json"),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("airdrop")
|
||||
@ -101,6 +100,7 @@ fn parse_args() -> Result<WalletConfig, Box<error::Error>> {
|
||||
.long("tokens")
|
||||
.value_name("NUMBER")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.help("The number of tokens to request"),
|
||||
),
|
||||
)
|
||||
@ -122,7 +122,6 @@ fn parse_args() -> Result<WalletConfig, Box<error::Error>> {
|
||||
.long("to")
|
||||
.value_name("PUBKEY")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.help("The pubkey of recipient"),
|
||||
),
|
||||
)
|
||||
@ -149,24 +148,27 @@ fn parse_args() -> Result<WalletConfig, Box<error::Error>> {
|
||||
leader = NodeInfo::new_leader(&server_addr);
|
||||
};
|
||||
|
||||
let id: Mint;
|
||||
if let Some(m) = matches.value_of("mint") {
|
||||
id = read_mint(m)?;
|
||||
let mut path = dirs::home_dir().expect("home directory");
|
||||
let id_path = if matches.is_present("keypair") {
|
||||
matches.value_of("keypair").unwrap()
|
||||
} else {
|
||||
eprintln!("No mint found!");
|
||||
exit(1);
|
||||
path.extend(&[".config", "solana", "id.json"]);
|
||||
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;
|
||||
drone_addr.set_port(9900);
|
||||
|
||||
let command = match matches.subcommand() {
|
||||
("airdrop", Some(airdrop_matches)) => {
|
||||
let tokens = if airdrop_matches.is_present("tokens") {
|
||||
airdrop_matches.value_of("tokens").unwrap().parse()?
|
||||
} else {
|
||||
id.tokens
|
||||
};
|
||||
let tokens = airdrop_matches.value_of("tokens").unwrap().parse()?;
|
||||
Ok(WalletCommand::AirDrop(tokens))
|
||||
}
|
||||
("pay", Some(pay_matches)) => {
|
||||
@ -184,11 +186,7 @@ fn parse_args() -> Result<WalletConfig, Box<error::Error>> {
|
||||
id.pubkey()
|
||||
};
|
||||
|
||||
let tokens = if pay_matches.is_present("tokens") {
|
||||
pay_matches.value_of("tokens").unwrap().parse()?
|
||||
} else {
|
||||
id.tokens
|
||||
};
|
||||
let tokens = pay_matches.value_of("tokens").unwrap().parse()?;
|
||||
|
||||
Ok(WalletCommand::Pay(tokens, to))
|
||||
}
|
||||
@ -264,7 +262,7 @@ fn process_command(
|
||||
// If client has positive balance, spend tokens in {balance} number of transactions
|
||||
WalletCommand::Pay(tokens, to) => {
|
||||
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());
|
||||
}
|
||||
// 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))
|
||||
}
|
||||
|
||||
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> {
|
||||
let requests_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(
|
||||
drone_addr: &SocketAddr,
|
||||
id: &Mint,
|
||||
id: &KeyPair,
|
||||
tokens: u64,
|
||||
) -> Result<(), Box<error::Error>> {
|
||||
let mut stream = TcpStream::connect(drone_addr)?;
|
||||
|
@ -7,13 +7,12 @@ use entry_writer;
|
||||
use ledger::Block;
|
||||
use ncp::Ncp;
|
||||
use packet::BlobRecycler;
|
||||
use ring::rand::SystemRandom;
|
||||
use rpu::Rpu;
|
||||
use service::Service;
|
||||
use signature::{KeyPair, KeyPairUtil};
|
||||
use std::collections::VecDeque;
|
||||
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::net::SocketAddr;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
@ -31,13 +30,8 @@ pub struct FullNode {
|
||||
thread_hdls: Vec<JoinHandle<()>>,
|
||||
}
|
||||
|
||||
pub enum InFile {
|
||||
StdIn,
|
||||
Path(String),
|
||||
}
|
||||
|
||||
pub enum OutFile {
|
||||
StdOut,
|
||||
pub enum LedgerFile {
|
||||
StdInOut,
|
||||
Path(String),
|
||||
}
|
||||
|
||||
@ -50,11 +44,7 @@ pub struct Config {
|
||||
|
||||
/// Structure to be replicated by the network
|
||||
impl Config {
|
||||
pub fn new(bind_addr: &SocketAddr) -> Self {
|
||||
let rnd = SystemRandom::new();
|
||||
let pkcs8 = KeyPair::generate_pkcs8(&rnd)
|
||||
.expect("generate_pkcs8 in mint pub fn new")
|
||||
.to_vec();
|
||||
pub fn new(bind_addr: &SocketAddr, pkcs8: Vec<u8>) -> Self {
|
||||
let keypair =
|
||||
KeyPair::from_pkcs8(Input::from(&pkcs8)).expect("from_pkcs8 in fullnode::Config new");
|
||||
let pubkey = keypair.pubkey();
|
||||
@ -71,16 +61,24 @@ impl FullNode {
|
||||
pub fn new(
|
||||
mut node: TestNode,
|
||||
leader: bool,
|
||||
infile: InFile,
|
||||
ledger: LedgerFile,
|
||||
keypair_for_validator: Option<KeyPair>,
|
||||
network_entry_for_validator: Option<SocketAddr>,
|
||||
outfile_for_leader: Option<OutFile>,
|
||||
) -> FullNode {
|
||||
info!("creating bank...");
|
||||
let bank = Bank::default();
|
||||
let infile: Box<Read> = match infile {
|
||||
InFile::Path(path) => Box::new(File::open(path).unwrap()),
|
||||
InFile::StdIn => Box::new(stdin()),
|
||||
let (infile, outfile): (Box<Read>, Box<Write + Send>) = match ledger {
|
||||
LedgerFile::Path(path) => (
|
||||
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 entries = entry_writer::read_entries(reader).map(|e| e.expect("failed to parse entry"));
|
||||
@ -122,17 +120,6 @@ impl FullNode {
|
||||
server
|
||||
} else {
|
||||
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(
|
||||
bank,
|
||||
@ -142,7 +129,7 @@ impl FullNode {
|
||||
None,
|
||||
node,
|
||||
exit.clone(),
|
||||
outfile_for_leader,
|
||||
outfile,
|
||||
);
|
||||
info!(
|
||||
"leader ready... local request address: {} (advertising {})",
|
||||
|
15
src/mint.rs
15
src/mint.rs
@ -15,11 +15,7 @@ pub struct Mint {
|
||||
}
|
||||
|
||||
impl Mint {
|
||||
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();
|
||||
pub fn new_with_pkcs8(tokens: i64, pkcs8: Vec<u8>) -> Self {
|
||||
let keypair =
|
||||
KeyPair::from_pkcs8(Input::from(&pkcs8)).expect("from_pkcs8 in mint pub fn new");
|
||||
let pubkey = keypair.pubkey();
|
||||
@ -29,6 +25,15 @@ impl Mint {
|
||||
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 {
|
||||
hash(&self.pkcs8)
|
||||
}
|
||||
|
@ -8,8 +8,11 @@ use ring::error::Unspecified;
|
||||
use ring::rand::SecureRandom;
|
||||
use ring::signature::Ed25519KeyPair;
|
||||
use ring::{rand, signature};
|
||||
use serde_json;
|
||||
use std::cell::RefCell;
|
||||
use untrusted;
|
||||
use std::error;
|
||||
use std::fs::File;
|
||||
use untrusted::Input;
|
||||
|
||||
pub type KeyPair = Ed25519KeyPair;
|
||||
pub type PublicKey = GenericArray<u8, U32>;
|
||||
@ -24,10 +27,8 @@ impl KeyPairUtil for Ed25519KeyPair {
|
||||
/// Return a new ED25519 keypair
|
||||
fn new() -> Self {
|
||||
let rng = rand::SystemRandom::new();
|
||||
let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(&rng)
|
||||
.expect("generate_pkcs8 in signature pb fn new");
|
||||
signature::Ed25519KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8_bytes))
|
||||
.expect("from_pcks8 in signature pb fn 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
|
||||
@ -42,9 +43,9 @@ pub trait SignatureUtil {
|
||||
|
||||
impl SignatureUtil for GenericArray<u8, U64> {
|
||||
fn verify(&self, peer_public_key_bytes: &[u8], msg_bytes: &[u8]) -> bool {
|
||||
let peer_public_key = untrusted::Input::from(peer_public_key_bytes);
|
||||
let msg = untrusted::Input::from(msg_bytes);
|
||||
let sig = untrusted::Input::from(self);
|
||||
let peer_public_key = Input::from(peer_public_key_bytes);
|
||||
let msg = Input::from(msg_bytes);
|
||||
let sig = Input::from(self);
|
||||
signature::verify(&signature::ED25519, peer_public_key, msg, sig).is_ok()
|
||||
}
|
||||
}
|
||||
@ -77,7 +78,7 @@ impl GenKeys {
|
||||
.into_par_iter()
|
||||
.map(|seed| {
|
||||
let pkcs8 = GenKeys::new(seed).new_key();
|
||||
KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8)).unwrap()
|
||||
KeyPair::from_pkcs8(Input::from(&pkcs8)).unwrap()
|
||||
})
|
||||
.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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -7,7 +7,7 @@ extern crate solana;
|
||||
use solana::crdt::TestNode;
|
||||
use solana::crdt::{Crdt, NodeInfo};
|
||||
use solana::entry_writer::EntryWriter;
|
||||
use solana::fullnode::{FullNode, InFile, OutFile};
|
||||
use solana::fullnode::{FullNode, LedgerFile};
|
||||
use solana::logger;
|
||||
use solana::mint::Mint;
|
||||
use solana::ncp::Ncp;
|
||||
@ -94,8 +94,7 @@ fn test_multi_node_validator_catchup_from_zero() {
|
||||
let server = FullNode::new(
|
||||
leader,
|
||||
true,
|
||||
InFile::Path(ledger_path.clone()),
|
||||
None,
|
||||
LedgerFile::Path(ledger_path.clone()),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
@ -106,10 +105,9 @@ fn test_multi_node_validator_catchup_from_zero() {
|
||||
let mut val = FullNode::new(
|
||||
validator,
|
||||
false,
|
||||
InFile::Path(ledger_path.clone()),
|
||||
LedgerFile::Path(ledger_path.clone()),
|
||||
Some(keypair),
|
||||
Some(leader_data.contact_info.ncp),
|
||||
None,
|
||||
);
|
||||
nodes.push(val);
|
||||
}
|
||||
@ -141,10 +139,9 @@ fn test_multi_node_validator_catchup_from_zero() {
|
||||
let val = FullNode::new(
|
||||
validator,
|
||||
false,
|
||||
InFile::Path(ledger_path.clone()),
|
||||
LedgerFile::Path(ledger_path.clone()),
|
||||
Some(keypair),
|
||||
Some(leader_data.contact_info.ncp),
|
||||
None,
|
||||
);
|
||||
nodes.push(val);
|
||||
//contains the leader and new node
|
||||
@ -196,8 +193,7 @@ fn test_multi_node_basic() {
|
||||
let server = FullNode::new(
|
||||
leader,
|
||||
true,
|
||||
InFile::Path(ledger_path.clone()),
|
||||
None,
|
||||
LedgerFile::Path(ledger_path.clone()),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
@ -208,10 +204,9 @@ fn test_multi_node_basic() {
|
||||
let val = FullNode::new(
|
||||
validator,
|
||||
false,
|
||||
InFile::Path(ledger_path.clone()),
|
||||
LedgerFile::Path(ledger_path.clone()),
|
||||
Some(keypair),
|
||||
Some(leader_data.contact_info.ncp),
|
||||
None,
|
||||
);
|
||||
nodes.push(val);
|
||||
}
|
||||
@ -251,10 +246,9 @@ fn test_boot_validator_from_file() {
|
||||
let leader_fullnode = FullNode::new(
|
||||
leader,
|
||||
true,
|
||||
InFile::Path(ledger_path.clone()),
|
||||
LedgerFile::Path(ledger_path.clone()),
|
||||
None,
|
||||
None,
|
||||
Some(OutFile::Path(ledger_path.clone())),
|
||||
);
|
||||
let leader_balance =
|
||||
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(
|
||||
validator,
|
||||
false,
|
||||
InFile::Path(ledger_path.clone()),
|
||||
LedgerFile::Path(ledger_path.clone()),
|
||||
Some(keypair),
|
||||
Some(leader_data.contact_info.ncp),
|
||||
None,
|
||||
);
|
||||
|
||||
let mut client = mk_client(&validator_data);
|
||||
let getbal = retry_get_balance(&mut client, &bob_pubkey, 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(
|
||||
leader,
|
||||
true,
|
||||
InFile::Path(ledger_path.to_string()),
|
||||
LedgerFile::Path(ledger_path.to_string()),
|
||||
None,
|
||||
None,
|
||||
Some(OutFile::Path(ledger_path.to_string())),
|
||||
);
|
||||
(leader_data, leader_fullnode)
|
||||
}
|
||||
@ -342,10 +333,9 @@ fn test_leader_restart_validator_start_from_old_ledger() {
|
||||
let val_fullnode = FullNode::new(
|
||||
validator,
|
||||
false,
|
||||
InFile::Path(stale_ledger_path.clone()),
|
||||
LedgerFile::Path(stale_ledger_path.clone()),
|
||||
Some(keypair),
|
||||
Some(leader_data.contact_info.ncp),
|
||||
None,
|
||||
);
|
||||
|
||||
// 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(
|
||||
leader,
|
||||
true,
|
||||
InFile::Path(ledger_path.clone()),
|
||||
LedgerFile::Path(ledger_path.clone()),
|
||||
None,
|
||||
None,
|
||||
Some(OutFile::Path(ledger_path.clone())),
|
||||
);
|
||||
info!("{:x} LEADER", leader_data.debug_id());
|
||||
let leader_balance =
|
||||
@ -412,10 +401,9 @@ fn test_multi_node_dynamic_network() {
|
||||
let val = FullNode::new(
|
||||
validator,
|
||||
false,
|
||||
InFile::Path(ledger_path.clone()),
|
||||
LedgerFile::Path(ledger_path.clone()),
|
||||
Some(keypair),
|
||||
Some(leader_data.contact_info.ncp),
|
||||
Some(OutFile::Path(ledger_path.clone())),
|
||||
);
|
||||
info!("started[{}/{}] {:x}", n, N, rd.debug_id());
|
||||
(rd, val)
|
||||
|
Reference in New Issue
Block a user