Improve Wallet coverage (#2385)
* Add trait for RpcRequestHandler trait for RpcClient and add MockRpcClient for unit tests * Add request_airdrop integration test * Add timestamp_tx, witness_tx, and cancel_tx to wallet integration tests; add wallet integration tests to test-stable * Add test cases * Ignore plentiful sleeps in unit tests
This commit is contained in:
parent
780360834d
commit
8af61f561b
|
@ -28,10 +28,10 @@ for program in programs/native/*; do
|
|||
done
|
||||
|
||||
# Run integration tests serially
|
||||
for test in tests/*.rs; do
|
||||
for test in tests/*.rs wallet/tests/*.rs; do
|
||||
test=${test##*/} # basename x
|
||||
test=${test%.rs} # basename x .rs
|
||||
_ cargo test --verbose --features="$FEATURES" --test="$test" -- --test-threads=1 --nocapture
|
||||
_ cargo test --all --verbose --features="$FEATURES" --test="$test" -- --test-threads=1 --nocapture
|
||||
done
|
||||
|
||||
echo --- ci/localnet-sanity.sh
|
||||
|
|
|
@ -53,6 +53,7 @@ pub mod replicator;
|
|||
pub mod result;
|
||||
pub mod retransmit_stage;
|
||||
pub mod rpc;
|
||||
pub mod rpc_mock;
|
||||
pub mod rpc_pubsub;
|
||||
pub mod rpc_request;
|
||||
pub mod runtime;
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::db_ledger::DbLedger;
|
|||
use crate::gossip_service::GossipService;
|
||||
use crate::leader_scheduler::LeaderScheduler;
|
||||
use crate::result::Result;
|
||||
use crate::rpc_request::{RpcClient, RpcRequest};
|
||||
use crate::rpc_request::{RpcClient, RpcRequest, RpcRequestHandler};
|
||||
use crate::service::Service;
|
||||
use crate::storage_stage::ENTRIES_PER_SEGMENT;
|
||||
use crate::streamer::BlobReceiver;
|
||||
|
@ -144,12 +144,12 @@ impl Replicator {
|
|||
RpcClient::new_from_socket(rpc_peers[node_idx].rpc)
|
||||
};
|
||||
|
||||
storage_last_id = RpcRequest::GetStorageMiningLastId
|
||||
.make_rpc_request(&rpc_client, 2, None)
|
||||
storage_last_id = rpc_client
|
||||
.make_rpc_request(2, RpcRequest::GetStorageMiningLastId, None)
|
||||
.expect("rpc request")
|
||||
.to_string();
|
||||
storage_entry_height = RpcRequest::GetStorageMiningEntryHeight
|
||||
.make_rpc_request(&rpc_client, 2, None)
|
||||
storage_entry_height = rpc_client
|
||||
.make_rpc_request(2, RpcRequest::GetStorageMiningEntryHeight, None)
|
||||
.expect("rpc request")
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
// Implementation of RpcRequestHandler trait for testing Rpc requests without i/o
|
||||
|
||||
use crate::rpc_request::{RpcRequest, RpcRequestHandler};
|
||||
use serde_json::{self, Number, Value};
|
||||
use solana_sdk::hash::Hash;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||
use solana_sdk::system_transaction::SystemTransaction;
|
||||
use solana_sdk::transaction::Transaction;
|
||||
use std::error;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::net::SocketAddr;
|
||||
|
||||
pub const PUBKEY: &str = "7RoSF9fUmdphVCpabEoefH81WwrW7orsWonXWqTXkKV8";
|
||||
pub const SIGNATURE: &str =
|
||||
"43yNSFC6fYTuPgTNFFhF4axw7AfWxB2BPdurme8yrsWEYwm8299xh8n6TAHjGymiSub1XtyxTNyd9GBfY2hxoBw8";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MockRpcClient {
|
||||
pub addr: String,
|
||||
}
|
||||
|
||||
impl MockRpcClient {
|
||||
pub fn new(addr: String) -> Self {
|
||||
MockRpcClient { addr }
|
||||
}
|
||||
}
|
||||
|
||||
impl RpcRequestHandler for MockRpcClient {
|
||||
fn make_rpc_request(
|
||||
&self,
|
||||
_id: u64,
|
||||
request: RpcRequest,
|
||||
params: Option<Value>,
|
||||
) -> Result<Value, Box<dyn error::Error>> {
|
||||
if self.addr == "fails" {
|
||||
return Ok(Value::Null);
|
||||
}
|
||||
let val = match request {
|
||||
RpcRequest::ConfirmTransaction => {
|
||||
if let Some(Value::Array(param_array)) = params {
|
||||
if let Value::String(param_string) = ¶m_array[0] {
|
||||
Value::Bool(param_string == SIGNATURE)
|
||||
} else {
|
||||
Value::Null
|
||||
}
|
||||
} else {
|
||||
Value::Null
|
||||
}
|
||||
}
|
||||
RpcRequest::GetBalance => {
|
||||
let n = if self.addr == "airdrop" { 0 } else { 50 };
|
||||
Value::Number(Number::from(n))
|
||||
}
|
||||
RpcRequest::GetLastId => Value::String(PUBKEY.to_string()),
|
||||
RpcRequest::GetSignatureStatus => {
|
||||
let str = if self.addr == "account_in_use" {
|
||||
"AccountInUse"
|
||||
} else if self.addr == "bad_sig_status" {
|
||||
"Nonexistent"
|
||||
} else {
|
||||
"Confirmed"
|
||||
};
|
||||
Value::String(str.to_string())
|
||||
}
|
||||
RpcRequest::GetTransactionCount => Value::Number(Number::from(1234)),
|
||||
RpcRequest::SendTransaction => Value::String(SIGNATURE.to_string()),
|
||||
_ => Value::Null,
|
||||
};
|
||||
Ok(val)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_airdrop_transaction(
|
||||
_drone_addr: &SocketAddr,
|
||||
_id: &Pubkey,
|
||||
tokens: u64,
|
||||
_last_id: Hash,
|
||||
) -> Result<Transaction, Error> {
|
||||
if tokens == 0 {
|
||||
Err(Error::new(ErrorKind::Other, "Airdrop failed"))?
|
||||
}
|
||||
let key = Keypair::new();
|
||||
let to = Keypair::new().pubkey();
|
||||
let last_id = Hash::default();
|
||||
let tx = Transaction::system_new(&key, to, 50, last_id);
|
||||
Ok(tx)
|
||||
}
|
|
@ -6,6 +6,7 @@ use std::thread::sleep;
|
|||
use std::time::Duration;
|
||||
use std::{error, fmt};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RpcClient {
|
||||
pub client: reqwest::Client,
|
||||
pub addr: String,
|
||||
|
@ -35,55 +36,22 @@ impl RpcClient {
|
|||
addr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rpc_request_str(rpc_addr: SocketAddr) -> String {
|
||||
format!("http://{}", rpc_addr)
|
||||
}
|
||||
|
||||
pub enum RpcRequest {
|
||||
ConfirmTransaction,
|
||||
GetAccountInfo,
|
||||
GetBalance,
|
||||
GetConfirmationTime,
|
||||
GetLastId,
|
||||
GetSignatureStatus,
|
||||
GetTransactionCount,
|
||||
RequestAirdrop,
|
||||
SendTransaction,
|
||||
RegisterNode,
|
||||
SignVote,
|
||||
DeregisterNode,
|
||||
GetStorageMiningLastId,
|
||||
GetStorageMiningEntryHeight,
|
||||
GetStoragePubkeysForEntryHeight,
|
||||
}
|
||||
|
||||
impl RpcRequest {
|
||||
pub fn make_rpc_request(
|
||||
&self,
|
||||
client: &RpcClient,
|
||||
id: u64,
|
||||
params: Option<Value>,
|
||||
) -> Result<Value, Box<dyn error::Error>> {
|
||||
self.retry_make_rpc_request(client, id, params, 0)
|
||||
}
|
||||
|
||||
pub fn retry_make_rpc_request(
|
||||
&self,
|
||||
client: &RpcClient,
|
||||
id: u64,
|
||||
request: &RpcRequest,
|
||||
params: Option<Value>,
|
||||
mut retries: usize,
|
||||
) -> Result<Value, Box<dyn error::Error>> {
|
||||
let request = self.build_request_json(id, params);
|
||||
let request_json = request.build_request_json(id, params);
|
||||
|
||||
loop {
|
||||
match client
|
||||
match self
|
||||
.client
|
||||
.post(&client.addr)
|
||||
.post(&self.addr)
|
||||
.header(CONTENT_TYPE, "application/json")
|
||||
.body(request.to_string())
|
||||
.body(request_json.to_string())
|
||||
.send()
|
||||
{
|
||||
Ok(mut response) => {
|
||||
|
@ -111,7 +79,52 @@ impl RpcRequest {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rpc_request_str(rpc_addr: SocketAddr) -> String {
|
||||
format!("http://{}", rpc_addr)
|
||||
}
|
||||
|
||||
pub trait RpcRequestHandler {
|
||||
fn make_rpc_request(
|
||||
&self,
|
||||
id: u64,
|
||||
request: RpcRequest,
|
||||
params: Option<Value>,
|
||||
) -> Result<Value, Box<dyn error::Error>>;
|
||||
}
|
||||
|
||||
impl RpcRequestHandler for RpcClient {
|
||||
fn make_rpc_request(
|
||||
&self,
|
||||
id: u64,
|
||||
request: RpcRequest,
|
||||
params: Option<Value>,
|
||||
) -> Result<Value, Box<dyn error::Error>> {
|
||||
self.retry_make_rpc_request(id, &request, params, 0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum RpcRequest {
|
||||
ConfirmTransaction,
|
||||
GetAccountInfo,
|
||||
GetBalance,
|
||||
GetConfirmationTime,
|
||||
GetLastId,
|
||||
GetSignatureStatus,
|
||||
GetTransactionCount,
|
||||
RequestAirdrop,
|
||||
SendTransaction,
|
||||
RegisterNode,
|
||||
SignVote,
|
||||
DeregisterNode,
|
||||
GetStorageMiningLastId,
|
||||
GetStorageMiningEntryHeight,
|
||||
GetStoragePubkeysForEntryHeight,
|
||||
}
|
||||
|
||||
impl RpcRequest {
|
||||
fn build_request_json(&self, id: u64, params: Option<Value>) -> Value {
|
||||
let jsonrpc = "2.0";
|
||||
let method = match self {
|
||||
|
@ -251,15 +264,15 @@ mod tests {
|
|||
let rpc_addr = receiver.recv().unwrap();
|
||||
let rpc_client = RpcClient::new_from_socket(rpc_addr);
|
||||
|
||||
let balance = RpcRequest::GetBalance.make_rpc_request(
|
||||
&rpc_client,
|
||||
let balance = rpc_client.make_rpc_request(
|
||||
1,
|
||||
RpcRequest::GetBalance,
|
||||
Some(json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"])),
|
||||
);
|
||||
assert!(balance.is_ok());
|
||||
assert_eq!(balance.unwrap().as_u64().unwrap(), 50);
|
||||
|
||||
let last_id = RpcRequest::GetLastId.make_rpc_request(&rpc_client, 2, None);
|
||||
let last_id = rpc_client.make_rpc_request(2, RpcRequest::GetLastId, None);
|
||||
assert!(last_id.is_ok());
|
||||
assert_eq!(
|
||||
last_id.unwrap().as_str().unwrap(),
|
||||
|
@ -268,7 +281,7 @@ mod tests {
|
|||
|
||||
// Send erroneous parameter
|
||||
let last_id =
|
||||
RpcRequest::GetLastId.make_rpc_request(&rpc_client, 3, Some(json!("paramter")));
|
||||
rpc_client.make_rpc_request(3, RpcRequest::GetLastId, Some(json!("paramter")));
|
||||
assert_eq!(last_id.is_err(), true);
|
||||
}
|
||||
|
||||
|
@ -302,9 +315,9 @@ mod tests {
|
|||
let rpc_addr = receiver.recv().unwrap();
|
||||
let rpc_client = RpcClient::new_from_socket(rpc_addr);
|
||||
|
||||
let balance = RpcRequest::GetBalance.retry_make_rpc_request(
|
||||
&rpc_client,
|
||||
let balance = rpc_client.retry_make_rpc_request(
|
||||
1,
|
||||
&RpcRequest::GetBalance,
|
||||
Some(json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhw"])),
|
||||
10,
|
||||
);
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::cluster_info::{ClusterInfo, ClusterInfoError, NodeInfo};
|
|||
use crate::gossip_service::GossipService;
|
||||
use crate::packet::PACKET_DATA_SIZE;
|
||||
use crate::result::{Error, Result};
|
||||
use crate::rpc_request::{RpcClient, RpcRequest};
|
||||
use crate::rpc_request::{RpcClient, RpcRequest, RpcRequestHandler};
|
||||
use bincode::serialize;
|
||||
use bs58;
|
||||
use hashbrown::HashMap;
|
||||
|
@ -149,7 +149,9 @@ impl ThinClient {
|
|||
|
||||
pub fn get_account_userdata(&mut self, pubkey: &Pubkey) -> io::Result<Option<Vec<u8>>> {
|
||||
let params = json!([format!("{}", pubkey)]);
|
||||
let resp = RpcRequest::GetAccountInfo.make_rpc_request(&self.rpc_client, 1, Some(params));
|
||||
let resp = self
|
||||
.rpc_client
|
||||
.make_rpc_request(1, RpcRequest::GetAccountInfo, Some(params));
|
||||
if let Ok(account_json) = resp {
|
||||
let account: Account =
|
||||
serde_json::from_value(account_json).expect("deserialize account");
|
||||
|
@ -167,7 +169,9 @@ impl ThinClient {
|
|||
pub fn get_balance(&mut self, pubkey: &Pubkey) -> io::Result<u64> {
|
||||
trace!("get_balance sending request to {}", self.rpc_addr);
|
||||
let params = json!([format!("{}", pubkey)]);
|
||||
let resp = RpcRequest::GetAccountInfo.make_rpc_request(&self.rpc_client, 1, Some(params));
|
||||
let resp = self
|
||||
.rpc_client
|
||||
.make_rpc_request(1, RpcRequest::GetAccountInfo, Some(params));
|
||||
if let Ok(account_json) = resp {
|
||||
let account: Account =
|
||||
serde_json::from_value(account_json).expect("deserialize account");
|
||||
|
@ -193,7 +197,9 @@ impl ThinClient {
|
|||
let mut done = false;
|
||||
while !done {
|
||||
debug!("get_confirmation_time send_to {}", &self.rpc_addr);
|
||||
let resp = RpcRequest::GetConfirmationTime.make_rpc_request(&self.rpc_client, 1, None);
|
||||
let resp = self
|
||||
.rpc_client
|
||||
.make_rpc_request(1, RpcRequest::GetConfirmationTime, None);
|
||||
|
||||
if let Ok(value) = resp {
|
||||
done = true;
|
||||
|
@ -212,7 +218,9 @@ impl ThinClient {
|
|||
debug!("transaction_count");
|
||||
let mut tries_left = 5;
|
||||
while tries_left > 0 {
|
||||
let resp = RpcRequest::GetTransactionCount.make_rpc_request(&self.rpc_client, 1, None);
|
||||
let resp = self
|
||||
.rpc_client
|
||||
.make_rpc_request(1, RpcRequest::GetTransactionCount, None);
|
||||
|
||||
if let Ok(value) = resp {
|
||||
debug!("transaction_count recv_response: {:?}", value);
|
||||
|
@ -233,7 +241,9 @@ impl ThinClient {
|
|||
let mut done = false;
|
||||
while !done {
|
||||
debug!("get_last_id send_to {}", &self.rpc_addr);
|
||||
let resp = RpcRequest::GetLastId.make_rpc_request(&self.rpc_client, 1, None);
|
||||
let resp = self
|
||||
.rpc_client
|
||||
.make_rpc_request(1, RpcRequest::GetLastId, None);
|
||||
|
||||
if let Ok(value) = resp {
|
||||
done = true;
|
||||
|
@ -309,9 +319,9 @@ impl ThinClient {
|
|||
let now = Instant::now();
|
||||
let mut done = false;
|
||||
while !done {
|
||||
let resp = RpcRequest::ConfirmTransaction.make_rpc_request(
|
||||
&self.rpc_client,
|
||||
let resp = self.rpc_client.make_rpc_request(
|
||||
1,
|
||||
RpcRequest::ConfirmTransaction,
|
||||
Some(params.clone()),
|
||||
);
|
||||
|
||||
|
|
|
@ -48,24 +48,27 @@ impl VoteSigner for RemoteVoteSigner {
|
|||
msg: &[u8],
|
||||
) -> jsonrpc_core::Result<Pubkey> {
|
||||
let params = json!([pubkey, sig, msg]);
|
||||
let resp = RpcRequest::RegisterNode
|
||||
.retry_make_rpc_request(&self.rpc_client, 1, Some(params), 5)
|
||||
let resp = self
|
||||
.rpc_client
|
||||
.retry_make_rpc_request(1, &RpcRequest::RegisterNode, Some(params), 5)
|
||||
.unwrap();
|
||||
let vote_account: Pubkey = serde_json::from_value(resp).unwrap();
|
||||
Ok(vote_account)
|
||||
}
|
||||
fn sign(&self, pubkey: Pubkey, sig: &Signature, msg: &[u8]) -> jsonrpc_core::Result<Signature> {
|
||||
let params = json!([pubkey, sig, msg]);
|
||||
let resp = RpcRequest::SignVote
|
||||
.make_rpc_request(&self.rpc_client, 1, Some(params))
|
||||
let resp = self
|
||||
.rpc_client
|
||||
.retry_make_rpc_request(1, &RpcRequest::SignVote, Some(params), 0)
|
||||
.unwrap();
|
||||
let vote_signature: Signature = serde_json::from_value(resp).unwrap();
|
||||
Ok(vote_signature)
|
||||
}
|
||||
fn deregister(&self, pubkey: Pubkey, sig: &Signature, msg: &[u8]) -> jsonrpc_core::Result<()> {
|
||||
let params = json!([pubkey, sig, msg]);
|
||||
let _resp = RpcRequest::DeregisterNode
|
||||
.retry_make_rpc_request(&self.rpc_client, 1, Some(params), 5)
|
||||
let _resp = self
|
||||
.rpc_client
|
||||
.retry_make_rpc_request(1, &RpcRequest::DeregisterNode, Some(params), 5)
|
||||
.unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -156,15 +156,15 @@ fn test_replicator_startup() {
|
|||
// chacha is not enabled
|
||||
#[cfg(feature = "chacha")]
|
||||
{
|
||||
use solana::rpc_request::{RpcClient, RpcRequest};
|
||||
use solana::rpc_request::{RpcClient, RpcRequest, RpcRequestHandler};
|
||||
use std::thread::sleep;
|
||||
|
||||
let rpc_client = RpcClient::new_from_socket(validator_node_info.rpc);
|
||||
let mut non_zero_pubkeys = false;
|
||||
for _ in 0..30 {
|
||||
let params = json!([0]);
|
||||
let pubkeys = RpcRequest::GetStoragePubkeysForEntryHeight
|
||||
.make_rpc_request(&rpc_client, 1, Some(params))
|
||||
let pubkeys = rpc_client
|
||||
.make_rpc_request(1, RpcRequest::GetStoragePubkeysForEntryHeight, Some(params))
|
||||
.unwrap();
|
||||
info!("pubkeys: {:?}", pubkeys);
|
||||
if pubkeys.as_array().unwrap().len() != 0 {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
pub mod wallet;
|
|
@ -1,9 +1,7 @@
|
|||
mod wallet;
|
||||
|
||||
use crate::wallet::{parse_command, process_command, WalletConfig, WalletError};
|
||||
use clap::{crate_version, App, Arg, ArgMatches, SubCommand};
|
||||
use solana::socketaddr;
|
||||
use solana_sdk::signature::{gen_keypair_file, read_keypair, KeypairUtil};
|
||||
use solana_wallet::wallet::{parse_command, process_command, WalletConfig, WalletError};
|
||||
use std::error;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
|
@ -53,6 +51,7 @@ pub fn parse_args(matches: &ArgMatches<'_>) -> Result<WalletConfig, Box<dyn erro
|
|||
timeout,
|
||||
proxy,
|
||||
drone_port: None,
|
||||
rpc_client: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,320 @@
|
|||
use chrono::prelude::*;
|
||||
use serde_json::{json, Value};
|
||||
use solana::bank::Bank;
|
||||
use solana::cluster_info::Node;
|
||||
use solana::db_ledger::create_tmp_ledger_with_mint;
|
||||
use solana::fullnode::Fullnode;
|
||||
use solana::leader_scheduler::LeaderScheduler;
|
||||
use solana::mint::Mint;
|
||||
use solana::rpc_request::{RpcClient, RpcRequest, RpcRequestHandler};
|
||||
use solana::vote_signer_proxy::VoteSignerProxy;
|
||||
use solana_drone::drone::run_local_drone;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||
use solana_vote_signer::rpc::LocalVoteSigner;
|
||||
use solana_wallet::wallet::{
|
||||
process_command, request_and_confirm_airdrop, WalletCommand, WalletConfig,
|
||||
};
|
||||
use std::fs::remove_dir_all;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
fn check_balance(expected_balance: u64, client: &RpcClient, params: Value) {
|
||||
let balance = client
|
||||
.make_rpc_request(1, RpcRequest::GetBalance, Some(params))
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
assert_eq!(balance, expected_balance);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wallet_timestamp_tx() {
|
||||
let leader_keypair = Arc::new(Keypair::new());
|
||||
let leader = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||
let leader_data = leader.info.clone();
|
||||
|
||||
let alice = Mint::new(10_000);
|
||||
let mut bank = Bank::new(&alice);
|
||||
let bob_pubkey = Keypair::new().pubkey();
|
||||
let ledger_path = create_tmp_ledger_with_mint("thin_client", &alice);
|
||||
let entry_height = alice.create_entries().len() as u64;
|
||||
|
||||
let leader_scheduler = Arc::new(RwLock::new(LeaderScheduler::from_bootstrap_leader(
|
||||
leader_data.id,
|
||||
)));
|
||||
bank.leader_scheduler = leader_scheduler;
|
||||
let vote_account_keypair = Arc::new(Keypair::new());
|
||||
let vote_signer =
|
||||
VoteSignerProxy::new(&vote_account_keypair, Box::new(LocalVoteSigner::default()));
|
||||
let last_id = bank.last_id();
|
||||
let server = Fullnode::new_with_bank(
|
||||
leader_keypair,
|
||||
Arc::new(vote_signer),
|
||||
bank,
|
||||
None,
|
||||
entry_height,
|
||||
&last_id,
|
||||
leader,
|
||||
None,
|
||||
&ledger_path,
|
||||
false,
|
||||
None,
|
||||
);
|
||||
sleep(Duration::from_millis(900));
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_drone(alice.keypair(), sender);
|
||||
let drone_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_from_socket(leader_data.rpc);
|
||||
|
||||
let mut config_payer = WalletConfig::default();
|
||||
config_payer.network = leader_data.gossip;
|
||||
config_payer.drone_port = Some(drone_addr.port());
|
||||
|
||||
let mut config_witness = WalletConfig::default();
|
||||
config_witness.network = leader_data.gossip;
|
||||
config_witness.drone_port = Some(drone_addr.port());
|
||||
|
||||
assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
|
||||
|
||||
request_and_confirm_airdrop(&rpc_client, &drone_addr, &config_payer.id.pubkey(), 50).unwrap();
|
||||
let params = json!([format!("{}", config_payer.id.pubkey())]);
|
||||
check_balance(50, &rpc_client, params);
|
||||
|
||||
// Make transaction (from config_payer to bob_pubkey) requiring timestamp from config_witness
|
||||
let date_string = "\"2018-09-19T17:30:59Z\"";
|
||||
let dt: DateTime<Utc> = serde_json::from_str(&date_string).unwrap();
|
||||
config_payer.command = WalletCommand::Pay(
|
||||
10,
|
||||
bob_pubkey,
|
||||
Some(dt),
|
||||
Some(config_witness.id.pubkey()),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
let sig_response = process_command(&config_payer);
|
||||
assert!(sig_response.is_ok());
|
||||
|
||||
let object: Value = serde_json::from_str(&sig_response.unwrap()).unwrap();
|
||||
let process_id_str = object.get("processId").unwrap().as_str().unwrap();
|
||||
let process_id_vec = bs58::decode(process_id_str)
|
||||
.into_vec()
|
||||
.expect("base58-encoded public key");
|
||||
let process_id = Pubkey::new(&process_id_vec);
|
||||
|
||||
let params = json!([format!("{}", config_payer.id.pubkey())]);
|
||||
check_balance(39, &rpc_client, params); // config_payer balance
|
||||
let params = json!([format!("{}", process_id)]);
|
||||
check_balance(11, &rpc_client, params); // contract balance
|
||||
let params = json!([format!("{}", bob_pubkey)]);
|
||||
check_balance(0, &rpc_client, params); // recipient balance
|
||||
|
||||
// Sign transaction by config_witness
|
||||
config_witness.command = WalletCommand::TimeElapsed(bob_pubkey, process_id, dt);
|
||||
let sig_response = process_command(&config_witness);
|
||||
assert!(sig_response.is_ok());
|
||||
|
||||
let params = json!([format!("{}", config_payer.id.pubkey())]);
|
||||
check_balance(39, &rpc_client, params); // config_payer balance
|
||||
let params = json!([format!("{}", process_id)]);
|
||||
check_balance(1, &rpc_client, params); // contract balance
|
||||
let params = json!([format!("{}", bob_pubkey)]);
|
||||
check_balance(10, &rpc_client, params); // recipient balance
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wallet_witness_tx() {
|
||||
let leader_keypair = Arc::new(Keypair::new());
|
||||
let leader = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||
let leader_data = leader.info.clone();
|
||||
|
||||
let alice = Mint::new(10_000);
|
||||
let mut bank = Bank::new(&alice);
|
||||
let bob_pubkey = Keypair::new().pubkey();
|
||||
let ledger_path = create_tmp_ledger_with_mint("thin_client", &alice);
|
||||
let entry_height = alice.create_entries().len() as u64;
|
||||
|
||||
let leader_scheduler = Arc::new(RwLock::new(LeaderScheduler::from_bootstrap_leader(
|
||||
leader_data.id,
|
||||
)));
|
||||
bank.leader_scheduler = leader_scheduler;
|
||||
let vote_account_keypair = Arc::new(Keypair::new());
|
||||
let vote_signer =
|
||||
VoteSignerProxy::new(&vote_account_keypair, Box::new(LocalVoteSigner::default()));
|
||||
let last_id = bank.last_id();
|
||||
let server = Fullnode::new_with_bank(
|
||||
leader_keypair,
|
||||
Arc::new(vote_signer),
|
||||
bank,
|
||||
None,
|
||||
entry_height,
|
||||
&last_id,
|
||||
leader,
|
||||
None,
|
||||
&ledger_path,
|
||||
false,
|
||||
None,
|
||||
);
|
||||
sleep(Duration::from_millis(900));
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_drone(alice.keypair(), sender);
|
||||
let drone_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_from_socket(leader_data.rpc);
|
||||
|
||||
let mut config_payer = WalletConfig::default();
|
||||
config_payer.network = leader_data.gossip;
|
||||
config_payer.drone_port = Some(drone_addr.port());
|
||||
|
||||
let mut config_witness = WalletConfig::default();
|
||||
config_witness.network = leader_data.gossip;
|
||||
config_witness.drone_port = Some(drone_addr.port());
|
||||
|
||||
assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
|
||||
|
||||
request_and_confirm_airdrop(&rpc_client, &drone_addr, &config_payer.id.pubkey(), 50).unwrap();
|
||||
|
||||
// Make transaction (from config_payer to bob_pubkey) requiring witness signature from config_witness
|
||||
config_payer.command = WalletCommand::Pay(
|
||||
10,
|
||||
bob_pubkey,
|
||||
None,
|
||||
None,
|
||||
Some(vec![config_witness.id.pubkey()]),
|
||||
None,
|
||||
);
|
||||
let sig_response = process_command(&config_payer);
|
||||
assert!(sig_response.is_ok());
|
||||
|
||||
let object: Value = serde_json::from_str(&sig_response.unwrap()).unwrap();
|
||||
let process_id_str = object.get("processId").unwrap().as_str().unwrap();
|
||||
let process_id_vec = bs58::decode(process_id_str)
|
||||
.into_vec()
|
||||
.expect("base58-encoded public key");
|
||||
let process_id = Pubkey::new(&process_id_vec);
|
||||
|
||||
let params = json!([format!("{}", config_payer.id.pubkey())]);
|
||||
check_balance(39, &rpc_client, params); // config_payer balance
|
||||
let params = json!([format!("{}", process_id)]);
|
||||
check_balance(11, &rpc_client, params); // contract balance
|
||||
let params = json!([format!("{}", bob_pubkey)]);
|
||||
check_balance(0, &rpc_client, params); // recipient balance
|
||||
|
||||
// Sign transaction by config_witness
|
||||
config_witness.command = WalletCommand::Witness(bob_pubkey, process_id);
|
||||
let sig_response = process_command(&config_witness);
|
||||
assert!(sig_response.is_ok());
|
||||
|
||||
let params = json!([format!("{}", config_payer.id.pubkey())]);
|
||||
check_balance(39, &rpc_client, params); // config_payer balance
|
||||
let params = json!([format!("{}", process_id)]);
|
||||
check_balance(1, &rpc_client, params); // contract balance
|
||||
let params = json!([format!("{}", bob_pubkey)]);
|
||||
check_balance(10, &rpc_client, params); // recipient balance
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wallet_cancel_tx() {
|
||||
let leader_keypair = Arc::new(Keypair::new());
|
||||
let leader = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||
let leader_data = leader.info.clone();
|
||||
|
||||
let alice = Mint::new(10_000);
|
||||
let mut bank = Bank::new(&alice);
|
||||
let bob_pubkey = Keypair::new().pubkey();
|
||||
let ledger_path = create_tmp_ledger_with_mint("thin_client", &alice);
|
||||
let entry_height = alice.create_entries().len() as u64;
|
||||
|
||||
let leader_scheduler = Arc::new(RwLock::new(LeaderScheduler::from_bootstrap_leader(
|
||||
leader_data.id,
|
||||
)));
|
||||
bank.leader_scheduler = leader_scheduler;
|
||||
let vote_account_keypair = Arc::new(Keypair::new());
|
||||
let vote_signer =
|
||||
VoteSignerProxy::new(&vote_account_keypair, Box::new(LocalVoteSigner::default()));
|
||||
let last_id = bank.last_id();
|
||||
let server = Fullnode::new_with_bank(
|
||||
leader_keypair,
|
||||
Arc::new(vote_signer),
|
||||
bank,
|
||||
None,
|
||||
entry_height,
|
||||
&last_id,
|
||||
leader,
|
||||
None,
|
||||
&ledger_path,
|
||||
false,
|
||||
None,
|
||||
);
|
||||
sleep(Duration::from_millis(900));
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_drone(alice.keypair(), sender);
|
||||
let drone_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_from_socket(leader_data.rpc);
|
||||
|
||||
let mut config_payer = WalletConfig::default();
|
||||
config_payer.network = leader_data.gossip;
|
||||
config_payer.drone_port = Some(drone_addr.port());
|
||||
|
||||
let mut config_witness = WalletConfig::default();
|
||||
config_witness.network = leader_data.gossip;
|
||||
config_witness.drone_port = Some(drone_addr.port());
|
||||
|
||||
assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
|
||||
|
||||
request_and_confirm_airdrop(&rpc_client, &drone_addr, &config_payer.id.pubkey(), 50).unwrap();
|
||||
|
||||
// Make transaction (from config_payer to bob_pubkey) requiring witness signature from config_witness
|
||||
config_payer.command = WalletCommand::Pay(
|
||||
10,
|
||||
bob_pubkey,
|
||||
None,
|
||||
None,
|
||||
Some(vec![config_witness.id.pubkey()]),
|
||||
Some(config_payer.id.pubkey()),
|
||||
);
|
||||
let sig_response = process_command(&config_payer);
|
||||
assert!(sig_response.is_ok());
|
||||
|
||||
let object: Value = serde_json::from_str(&sig_response.unwrap()).unwrap();
|
||||
let process_id_str = object.get("processId").unwrap().as_str().unwrap();
|
||||
let process_id_vec = bs58::decode(process_id_str)
|
||||
.into_vec()
|
||||
.expect("base58-encoded public key");
|
||||
let process_id = Pubkey::new(&process_id_vec);
|
||||
|
||||
let params = json!([format!("{}", config_payer.id.pubkey())]);
|
||||
check_balance(39, &rpc_client, params); // config_payer balance
|
||||
let params = json!([format!("{}", process_id)]);
|
||||
check_balance(11, &rpc_client, params); // contract balance
|
||||
let params = json!([format!("{}", bob_pubkey)]);
|
||||
check_balance(0, &rpc_client, params); // recipient balance
|
||||
|
||||
// Sign transaction by config_witness
|
||||
config_payer.command = WalletCommand::Cancel(process_id);
|
||||
let sig_response = process_command(&config_payer);
|
||||
assert!(sig_response.is_ok());
|
||||
|
||||
let params = json!([format!("{}", config_payer.id.pubkey())]);
|
||||
check_balance(49, &rpc_client, params); // config_payer balance
|
||||
let params = json!([format!("{}", process_id)]);
|
||||
check_balance(1, &rpc_client, params); // contract balance
|
||||
let params = json!([format!("{}", bob_pubkey)]);
|
||||
check_balance(0, &rpc_client, params); // recipient balance
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
use serde_json::json;
|
||||
use solana::bank::Bank;
|
||||
use solana::cluster_info::Node;
|
||||
use solana::db_ledger::create_tmp_ledger_with_mint;
|
||||
use solana::fullnode::Fullnode;
|
||||
use solana::leader_scheduler::LeaderScheduler;
|
||||
use solana::mint::Mint;
|
||||
use solana::rpc_request::{RpcClient, RpcRequest, RpcRequestHandler};
|
||||
use solana::vote_signer_proxy::VoteSignerProxy;
|
||||
use solana_drone::drone::run_local_drone;
|
||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||
use solana_vote_signer::rpc::LocalVoteSigner;
|
||||
use solana_wallet::wallet::{process_command, WalletCommand, WalletConfig};
|
||||
use std::fs::remove_dir_all;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
fn test_wallet_request_airdrop() {
|
||||
let leader_keypair = Arc::new(Keypair::new());
|
||||
let leader = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||
let leader_data = leader.info.clone();
|
||||
|
||||
let alice = Mint::new(10_000);
|
||||
let mut bank = Bank::new(&alice);
|
||||
let ledger_path = create_tmp_ledger_with_mint("thin_client", &alice);
|
||||
let entry_height = alice.create_entries().len() as u64;
|
||||
|
||||
let leader_scheduler = Arc::new(RwLock::new(LeaderScheduler::from_bootstrap_leader(
|
||||
leader_data.id,
|
||||
)));
|
||||
bank.leader_scheduler = leader_scheduler;
|
||||
let vote_account_keypair = Arc::new(Keypair::new());
|
||||
let vote_signer =
|
||||
VoteSignerProxy::new(&vote_account_keypair, Box::new(LocalVoteSigner::default()));
|
||||
let last_id = bank.last_id();
|
||||
let server = Fullnode::new_with_bank(
|
||||
leader_keypair,
|
||||
Arc::new(vote_signer),
|
||||
bank,
|
||||
None,
|
||||
entry_height,
|
||||
&last_id,
|
||||
leader,
|
||||
None,
|
||||
&ledger_path,
|
||||
false,
|
||||
None,
|
||||
);
|
||||
sleep(Duration::from_millis(900));
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_drone(alice.keypair(), sender);
|
||||
let drone_addr = receiver.recv().unwrap();
|
||||
|
||||
let mut bob_config = WalletConfig::default();
|
||||
bob_config.network = leader_data.gossip;
|
||||
bob_config.drone_port = Some(drone_addr.port());
|
||||
bob_config.command = WalletCommand::Airdrop(50);
|
||||
|
||||
let sig_response = process_command(&bob_config);
|
||||
assert!(sig_response.is_ok());
|
||||
|
||||
let rpc_client = RpcClient::new_from_socket(leader_data.rpc);
|
||||
|
||||
let params = json!([format!("{}", bob_config.id.pubkey())]);
|
||||
let balance = rpc_client
|
||||
.make_rpc_request(1, RpcRequest::GetBalance, Some(params))
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
assert_eq!(balance, 50);
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
Loading…
Reference in New Issue