mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-21 11:31:08 +03:00
5e57e9c8e9
It produces 1000+ otputs on a fast machine (?) and generates invalid URL as result (too many paramaters). We don't care about sending all outputs in this test, we just need something.
484 lines
15 KiB
Rust
484 lines
15 KiB
Rust
// Copyright 2018 The Grin Developers
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#[macro_use]
|
|
extern crate slog;
|
|
|
|
extern crate grin_api as api;
|
|
extern crate grin_chain as chain;
|
|
extern crate grin_config as config;
|
|
extern crate grin_core as core;
|
|
extern crate grin_p2p as p2p;
|
|
extern crate grin_servers as servers;
|
|
extern crate grin_util as util;
|
|
extern crate grin_wallet as wallet;
|
|
|
|
mod framework;
|
|
|
|
use std::sync::{Arc, Mutex};
|
|
use std::{thread, time};
|
|
|
|
use core::global::{self, ChainTypes};
|
|
|
|
use framework::{LocalServerContainer, LocalServerContainerConfig};
|
|
use util::{init_test_logger, LOGGER};
|
|
|
|
#[test]
|
|
fn simple_server_wallet() {
|
|
init_test_logger();
|
|
info!(LOGGER, "starting simple_server_wallet");
|
|
let test_name_dir = "test_servers";
|
|
core::global::set_mining_mode(core::global::ChainTypes::AutomatedTesting);
|
|
framework::clean_all_output(test_name_dir);
|
|
|
|
// Run a separate coinbase wallet for coinbase transactions
|
|
let mut coinbase_config = LocalServerContainerConfig::default();
|
|
coinbase_config.name = String::from("coinbase_wallet_api");
|
|
coinbase_config.wallet_validating_node_url = String::from("http://127.0.0.1:40001");
|
|
coinbase_config.wallet_port = 50002;
|
|
let coinbase_wallet = Arc::new(Mutex::new(
|
|
LocalServerContainer::new(coinbase_config).unwrap(),
|
|
));
|
|
|
|
let _ = thread::spawn(move || {
|
|
let mut w = coinbase_wallet.lock().unwrap();
|
|
w.run_wallet(0);
|
|
});
|
|
|
|
// Wait for the wallet to start
|
|
thread::sleep(time::Duration::from_millis(1000));
|
|
|
|
let mut server_config = LocalServerContainerConfig::default();
|
|
server_config.name = String::from("api_server_one");
|
|
server_config.p2p_server_port = 40000;
|
|
server_config.api_server_port = 40001;
|
|
server_config.start_miner = true;
|
|
server_config.start_wallet = false;
|
|
server_config.coinbase_wallet_address =
|
|
String::from(format!("http://{}:{}", server_config.base_addr, 50002));
|
|
let mut server_one = LocalServerContainer::new(server_config.clone()).unwrap();
|
|
|
|
// Spawn server and let it run for a bit
|
|
let _ = thread::spawn(move || server_one.run_server(120));
|
|
|
|
//Wait for chain to build
|
|
thread::sleep(time::Duration::from_millis(5000));
|
|
|
|
// Starting tests
|
|
let base_addr = server_config.base_addr;
|
|
let api_server_port = server_config.api_server_port;
|
|
|
|
warn!(LOGGER, "Testing chain handler");
|
|
let tip = get_tip(&base_addr, api_server_port);
|
|
assert!(tip.is_ok());
|
|
|
|
warn!(LOGGER, "Testing status handler");
|
|
let status = get_status(&base_addr, api_server_port);
|
|
assert!(status.is_ok());
|
|
|
|
// Be sure that at least a block is mined by Travis
|
|
let mut current_tip = get_tip(&base_addr, api_server_port).unwrap();
|
|
while current_tip.height == 0 {
|
|
thread::sleep(time::Duration::from_millis(1000));
|
|
current_tip = get_tip(&base_addr, api_server_port).unwrap();
|
|
}
|
|
|
|
warn!(LOGGER, "Testing block handler");
|
|
let last_block_by_height = get_block_by_height(&base_addr, api_server_port, current_tip.height);
|
|
assert!(last_block_by_height.is_ok());
|
|
let last_block_by_height_compact =
|
|
get_block_by_height_compact(&base_addr, api_server_port, current_tip.height);
|
|
assert!(last_block_by_height_compact.is_ok());
|
|
|
|
let block_hash = current_tip.last_block_pushed;
|
|
let last_block_by_hash = get_block_by_hash(&base_addr, api_server_port, &block_hash);
|
|
assert!(last_block_by_hash.is_ok());
|
|
let last_block_by_hash_compact =
|
|
get_block_by_hash_compact(&base_addr, api_server_port, &block_hash);
|
|
assert!(last_block_by_hash_compact.is_ok());
|
|
|
|
warn!(LOGGER, "Testing chain output handler");
|
|
let start_height = 0;
|
|
let end_height = current_tip.height;
|
|
let outputs_by_height =
|
|
get_outputs_by_height(&base_addr, api_server_port, start_height, end_height);
|
|
assert!(outputs_by_height.is_ok());
|
|
let ids = get_ids_from_block_outputs(outputs_by_height.unwrap());
|
|
let outputs_by_ids1 = get_outputs_by_ids1(&base_addr, api_server_port, ids.clone());
|
|
assert!(outputs_by_ids1.is_ok());
|
|
let outputs_by_ids2 = get_outputs_by_ids2(&base_addr, api_server_port, ids.clone());
|
|
assert!(outputs_by_ids2.is_ok());
|
|
|
|
warn!(LOGGER, "Testing txhashset handler");
|
|
let roots = get_txhashset_roots(&base_addr, api_server_port);
|
|
assert!(roots.is_ok());
|
|
let last_10_outputs = get_txhashset_lastoutputs(&base_addr, api_server_port, 0);
|
|
assert!(last_10_outputs.is_ok());
|
|
let last_5_outputs = get_txhashset_lastoutputs(&base_addr, api_server_port, 5);
|
|
assert!(last_5_outputs.is_ok());
|
|
let last_10_rangeproofs = get_txhashset_lastrangeproofs(&base_addr, api_server_port, 0);
|
|
assert!(last_10_rangeproofs.is_ok());
|
|
let last_5_rangeproofs = get_txhashset_lastrangeproofs(&base_addr, api_server_port, 5);
|
|
assert!(last_5_rangeproofs.is_ok());
|
|
let last_10_kernels = gettxhashset_lastkernels(&base_addr, api_server_port, 0);
|
|
assert!(last_10_kernels.is_ok());
|
|
let last_5_kernels = gettxhashset_lastkernels(&base_addr, api_server_port, 5);
|
|
assert!(last_5_kernels.is_ok());
|
|
|
|
//let some more mining happen, make sure nothing pukes
|
|
thread::sleep(time::Duration::from_millis(5000));
|
|
}
|
|
|
|
/// Creates 2 servers and test P2P API
|
|
#[test]
|
|
fn test_p2p() {
|
|
init_test_logger();
|
|
info!(LOGGER, "starting test_p2p");
|
|
global::set_mining_mode(ChainTypes::AutomatedTesting);
|
|
|
|
let test_name_dir = "test_servers";
|
|
framework::clean_all_output(test_name_dir);
|
|
|
|
// Spawn server and let it run for a bit
|
|
let mut server_config_one = LocalServerContainerConfig::default();
|
|
server_config_one.name = String::from("p2p_server_one");
|
|
server_config_one.p2p_server_port = 40002;
|
|
server_config_one.api_server_port = 40003;
|
|
server_config_one.start_miner = false;
|
|
server_config_one.start_wallet = false;
|
|
server_config_one.is_seeding = true;
|
|
let mut server_one = LocalServerContainer::new(server_config_one.clone()).unwrap();
|
|
let _ = thread::spawn(move || server_one.run_server(120));
|
|
|
|
thread::sleep(time::Duration::from_millis(1000));
|
|
|
|
// Spawn server and let it run for a bit
|
|
let mut server_config_two = LocalServerContainerConfig::default();
|
|
server_config_two.name = String::from("p2p_server_two");
|
|
server_config_two.p2p_server_port = 40004;
|
|
server_config_two.api_server_port = 40005;
|
|
server_config_two.start_miner = false;
|
|
server_config_two.start_wallet = false;
|
|
server_config_two.is_seeding = false;
|
|
let mut server_two = LocalServerContainer::new(server_config_two.clone()).unwrap();
|
|
server_two.add_peer(format!(
|
|
"{}:{}",
|
|
server_config_one.base_addr, server_config_one.p2p_server_port
|
|
));
|
|
let _ = thread::spawn(move || server_two.run_server(120));
|
|
|
|
// Let them do the handshake
|
|
thread::sleep(time::Duration::from_millis(2000));
|
|
|
|
// Starting tests
|
|
warn!(LOGGER, "Starting P2P Tests");
|
|
let base_addr = server_config_one.base_addr;
|
|
let api_server_port = server_config_one.api_server_port;
|
|
|
|
// Check that peer all is also working
|
|
let mut peers_all = get_all_peers(&base_addr, api_server_port);
|
|
assert!(peers_all.is_ok());
|
|
let pall = peers_all.unwrap();
|
|
assert_eq!(pall.len(), 2);
|
|
|
|
// Check that when we get peer connected the peer is here
|
|
let peers_connected = get_connected_peers(&base_addr, api_server_port);
|
|
assert!(peers_connected.is_ok());
|
|
let pc = peers_connected.unwrap();
|
|
assert_eq!(pc.len(), 1);
|
|
|
|
// Check that the peer status is Healthy
|
|
let addr = format!(
|
|
"{}:{}",
|
|
server_config_two.base_addr, server_config_two.p2p_server_port
|
|
);
|
|
let peer = get_peer(&base_addr, api_server_port, &addr);
|
|
assert!(peer.is_ok());
|
|
assert_eq!(peer.unwrap().flags, p2p::State::Healthy);
|
|
|
|
// Ban the peer
|
|
let ban_result = ban_peer(&base_addr, api_server_port, &addr);
|
|
assert!(ban_result.is_ok());
|
|
thread::sleep(time::Duration::from_millis(2000));
|
|
|
|
// Check its status is banned with get peer
|
|
let peer = get_peer(&base_addr, api_server_port, &addr);
|
|
assert!(peer.is_ok());
|
|
assert_eq!(peer.unwrap().flags, p2p::State::Banned);
|
|
|
|
// Check from peer all
|
|
peers_all = get_all_peers(&base_addr, api_server_port);
|
|
assert!(peers_all.is_ok());
|
|
assert_eq!(peers_all.unwrap().len(), 2);
|
|
|
|
// Unban
|
|
let unban_result = unban_peer(&base_addr, api_server_port, &addr);
|
|
assert!(unban_result.is_ok());
|
|
|
|
// Check from peer connected
|
|
let peers_connected = get_connected_peers(&base_addr, api_server_port);
|
|
assert!(peers_connected.is_ok());
|
|
assert_eq!(peers_connected.unwrap().len(), 0);
|
|
|
|
// Check its status is healthy with get peer
|
|
let peer = get_peer(&base_addr, api_server_port, &addr);
|
|
assert!(peer.is_ok());
|
|
assert_eq!(peer.unwrap().flags, p2p::State::Healthy);
|
|
}
|
|
|
|
// Tip handler function
|
|
fn get_tip(base_addr: &String, api_server_port: u16) -> Result<api::Tip, Error> {
|
|
let url = format!("http://{}:{}/v1/chain", base_addr, api_server_port);
|
|
api::client::get::<api::Tip>(url.as_str()).map_err(|e| Error::API(e))
|
|
}
|
|
|
|
// Status handler function
|
|
fn get_status(base_addr: &String, api_server_port: u16) -> Result<api::Status, Error> {
|
|
let url = format!("http://{}:{}/v1/status", base_addr, api_server_port);
|
|
api::client::get::<api::Status>(url.as_str()).map_err(|e| Error::API(e))
|
|
}
|
|
|
|
// Block handler functions
|
|
fn get_block_by_height(
|
|
base_addr: &String,
|
|
api_server_port: u16,
|
|
height: u64,
|
|
) -> Result<api::BlockPrintable, Error> {
|
|
let url = format!(
|
|
"http://{}:{}/v1/blocks/{}",
|
|
base_addr, api_server_port, height
|
|
);
|
|
api::client::get::<api::BlockPrintable>(url.as_str()).map_err(|e| Error::API(e))
|
|
}
|
|
|
|
fn get_block_by_height_compact(
|
|
base_addr: &String,
|
|
api_server_port: u16,
|
|
height: u64,
|
|
) -> Result<api::CompactBlockPrintable, Error> {
|
|
let url = format!(
|
|
"http://{}:{}/v1/blocks/{}?compact",
|
|
base_addr, api_server_port, height
|
|
);
|
|
api::client::get::<api::CompactBlockPrintable>(url.as_str()).map_err(|e| Error::API(e))
|
|
}
|
|
|
|
fn get_block_by_hash(
|
|
base_addr: &String,
|
|
api_server_port: u16,
|
|
block_hash: &String,
|
|
) -> Result<api::BlockPrintable, Error> {
|
|
let url = format!(
|
|
"http://{}:{}/v1/blocks/{}",
|
|
base_addr, api_server_port, block_hash
|
|
);
|
|
api::client::get::<api::BlockPrintable>(url.as_str()).map_err(|e| Error::API(e))
|
|
}
|
|
|
|
fn get_block_by_hash_compact(
|
|
base_addr: &String,
|
|
api_server_port: u16,
|
|
block_hash: &String,
|
|
) -> Result<api::CompactBlockPrintable, Error> {
|
|
let url = format!(
|
|
"http://{}:{}/v1/blocks/{}?compact",
|
|
base_addr, api_server_port, block_hash
|
|
);
|
|
api::client::get::<api::CompactBlockPrintable>(url.as_str()).map_err(|e| Error::API(e))
|
|
}
|
|
|
|
// Chain output handler functions
|
|
fn get_outputs_by_ids1(
|
|
base_addr: &String,
|
|
api_server_port: u16,
|
|
ids: Vec<String>,
|
|
) -> Result<Vec<api::Output>, Error> {
|
|
let url = format!(
|
|
"http://{}:{}/v1/chain/outputs/byids?id={}",
|
|
base_addr,
|
|
api_server_port,
|
|
ids.join(",")
|
|
);
|
|
api::client::get::<Vec<api::Output>>(url.as_str()).map_err(|e| Error::API(e))
|
|
}
|
|
|
|
fn get_outputs_by_ids2(
|
|
base_addr: &String,
|
|
api_server_port: u16,
|
|
ids: Vec<String>,
|
|
) -> Result<Vec<api::Output>, Error> {
|
|
let mut ids_string: String = String::from("");
|
|
for id in ids {
|
|
ids_string = ids_string + "?id=" + &id;
|
|
}
|
|
let ids_string = String::from(&ids_string[1..ids_string.len()]);
|
|
let url = format!(
|
|
"http://{}:{}/v1/chain/outputs/byids?{}",
|
|
base_addr, api_server_port, ids_string
|
|
);
|
|
api::client::get::<Vec<api::Output>>(url.as_str()).map_err(|e| Error::API(e))
|
|
}
|
|
|
|
fn get_outputs_by_height(
|
|
base_addr: &String,
|
|
api_server_port: u16,
|
|
start_height: u64,
|
|
end_height: u64,
|
|
) -> Result<Vec<api::BlockOutputs>, Error> {
|
|
let url = format!(
|
|
"http://{}:{}/v1/chain/outputs/byheight?start_height={}&end_height={}",
|
|
base_addr, api_server_port, start_height, end_height
|
|
);
|
|
api::client::get::<Vec<api::BlockOutputs>>(url.as_str()).map_err(|e| Error::API(e))
|
|
}
|
|
|
|
// TxHashSet handler functions
|
|
fn get_txhashset_roots(base_addr: &String, api_server_port: u16) -> Result<api::TxHashSet, Error> {
|
|
let url = format!(
|
|
"http://{}:{}/v1/txhashset/roots",
|
|
base_addr, api_server_port
|
|
);
|
|
api::client::get::<api::TxHashSet>(url.as_str()).map_err(|e| Error::API(e))
|
|
}
|
|
|
|
fn get_txhashset_lastoutputs(
|
|
base_addr: &String,
|
|
api_server_port: u16,
|
|
n: u64,
|
|
) -> Result<Vec<api::TxHashSetNode>, Error> {
|
|
let url: String;
|
|
if n == 0 {
|
|
url = format!(
|
|
"http://{}:{}/v1/txhashset/lastoutputs",
|
|
base_addr, api_server_port
|
|
);
|
|
} else {
|
|
url = format!(
|
|
"http://{}:{}/v1/txhashset/lastoutputs?n={}",
|
|
base_addr, api_server_port, n
|
|
);
|
|
}
|
|
api::client::get::<Vec<api::TxHashSetNode>>(url.as_str()).map_err(|e| Error::API(e))
|
|
}
|
|
|
|
fn get_txhashset_lastrangeproofs(
|
|
base_addr: &String,
|
|
api_server_port: u16,
|
|
n: u64,
|
|
) -> Result<Vec<api::TxHashSetNode>, Error> {
|
|
let url: String;
|
|
if n == 0 {
|
|
url = format!(
|
|
"http://{}:{}/v1/txhashset/lastrangeproofs",
|
|
base_addr, api_server_port
|
|
);
|
|
} else {
|
|
url = format!(
|
|
"http://{}:{}/v1/txhashset/lastrangeproofs?n={}",
|
|
base_addr, api_server_port, n
|
|
);
|
|
}
|
|
api::client::get::<Vec<api::TxHashSetNode>>(url.as_str()).map_err(|e| Error::API(e))
|
|
}
|
|
|
|
fn gettxhashset_lastkernels(
|
|
base_addr: &String,
|
|
api_server_port: u16,
|
|
n: u64,
|
|
) -> Result<Vec<api::TxHashSetNode>, Error> {
|
|
let url: String;
|
|
if n == 0 {
|
|
url = format!(
|
|
"http://{}:{}/v1/txhashset/lastkernels",
|
|
base_addr, api_server_port
|
|
);
|
|
} else {
|
|
url = format!(
|
|
"http://{}:{}/v1/txhashset/lastkernels?n={}",
|
|
base_addr, api_server_port, n
|
|
);
|
|
}
|
|
api::client::get::<Vec<api::TxHashSetNode>>(url.as_str()).map_err(|e| Error::API(e))
|
|
}
|
|
|
|
// Helper function to get a vec of commitment output ids from a vec of block
|
|
// outputs
|
|
fn get_ids_from_block_outputs(block_outputs: Vec<api::BlockOutputs>) -> Vec<String> {
|
|
let mut ids: Vec<String> = Vec::new();
|
|
for block_output in block_outputs {
|
|
let outputs = &block_output.outputs;
|
|
for output in outputs {
|
|
ids.push(util::to_hex(output.clone().commit.0.to_vec()));
|
|
}
|
|
}
|
|
ids.into_iter().take(100).collect()
|
|
}
|
|
|
|
pub fn ban_peer(base_addr: &String, api_server_port: u16, peer_addr: &String) -> Result<(), Error> {
|
|
let url = format!(
|
|
"http://{}:{}/v1/peers/{}/ban",
|
|
base_addr, api_server_port, peer_addr
|
|
);
|
|
api::client::post_no_ret(url.as_str(), &"").map_err(|e| Error::API(e))
|
|
}
|
|
|
|
pub fn unban_peer(
|
|
base_addr: &String,
|
|
api_server_port: u16,
|
|
peer_addr: &String,
|
|
) -> Result<(), Error> {
|
|
let url = format!(
|
|
"http://{}:{}/v1/peers/{}/unban",
|
|
base_addr, api_server_port, peer_addr
|
|
);
|
|
api::client::post_no_ret(url.as_str(), &"").map_err(|e| Error::API(e))
|
|
}
|
|
|
|
pub fn get_peer(
|
|
base_addr: &String,
|
|
api_server_port: u16,
|
|
peer_addr: &String,
|
|
) -> Result<p2p::PeerData, Error> {
|
|
let url = format!(
|
|
"http://{}:{}/v1/peers/{}",
|
|
base_addr, api_server_port, peer_addr
|
|
);
|
|
api::client::get::<p2p::PeerData>(url.as_str()).map_err(|e| Error::API(e))
|
|
}
|
|
|
|
pub fn get_connected_peers(
|
|
base_addr: &String,
|
|
api_server_port: u16,
|
|
) -> Result<Vec<p2p::PeerInfo>, Error> {
|
|
let url = format!(
|
|
"http://{}:{}/v1/peers/connected",
|
|
base_addr, api_server_port
|
|
);
|
|
api::client::get::<Vec<p2p::PeerInfo>>(url.as_str()).map_err(|e| Error::API(e))
|
|
}
|
|
|
|
pub fn get_all_peers(
|
|
base_addr: &String,
|
|
api_server_port: u16,
|
|
) -> Result<Vec<p2p::PeerData>, Error> {
|
|
let url = format!("http://{}:{}/v1/peers/all", base_addr, api_server_port);
|
|
api::client::get::<Vec<p2p::PeerData>>(url.as_str()).map_err(|e| Error::API(e))
|
|
}
|
|
|
|
/// Error type wrapping underlying module errors.
|
|
#[derive(Debug)]
|
|
pub enum Error {
|
|
/// Error originating from HTTP API calls.
|
|
API(api::Error),
|
|
}
|