2016-11-30 05:51:36 +03:00
|
|
|
// Copyright 2016 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.
|
|
|
|
|
|
|
|
extern crate grin_grin as grin;
|
|
|
|
extern crate grin_core as core;
|
|
|
|
extern crate grin_p2p as p2p;
|
|
|
|
extern crate grin_chain as chain;
|
2016-12-15 03:10:39 +03:00
|
|
|
|
2016-11-30 05:51:36 +03:00
|
|
|
extern crate env_logger;
|
2016-12-15 03:10:39 +03:00
|
|
|
extern crate futures;
|
|
|
|
extern crate tokio_core;
|
2017-02-19 05:42:34 +03:00
|
|
|
extern crate tokio_timer;
|
2016-11-30 05:51:36 +03:00
|
|
|
|
|
|
|
use std::io;
|
2016-12-14 06:21:49 +03:00
|
|
|
use std::thread;
|
2016-11-30 05:51:36 +03:00
|
|
|
use std::time;
|
2017-02-19 05:42:34 +03:00
|
|
|
use std::default::Default;
|
2016-11-30 05:51:36 +03:00
|
|
|
|
2016-12-23 23:15:36 +03:00
|
|
|
use futures::{Future, Poll, Async};
|
|
|
|
use futures::task::park;
|
2016-12-15 03:10:39 +03:00
|
|
|
use tokio_core::reactor;
|
2017-02-19 05:42:34 +03:00
|
|
|
use tokio_timer::Timer;
|
2016-12-15 03:10:39 +03:00
|
|
|
|
2017-02-19 05:42:34 +03:00
|
|
|
/// Create a network of 5 servers and mine a block, verifying that the block
|
|
|
|
/// gets propagated to all.
|
2016-11-30 05:51:36 +03:00
|
|
|
#[test]
|
2017-02-08 00:52:17 +03:00
|
|
|
fn simulate_block_propagation() {
|
|
|
|
env_logger::init();
|
2016-11-30 05:51:36 +03:00
|
|
|
|
2016-12-15 03:10:39 +03:00
|
|
|
let mut evtlp = reactor::Core::new().unwrap();
|
|
|
|
let handle = evtlp.handle();
|
|
|
|
|
2016-12-14 06:21:49 +03:00
|
|
|
// instantiates 5 servers on different ports
|
|
|
|
let mut servers = vec![];
|
|
|
|
for n in 0..5 {
|
2016-12-23 23:15:36 +03:00
|
|
|
let s = grin::Server::future(
|
2016-11-30 05:51:36 +03:00
|
|
|
grin::ServerConfig{
|
2017-02-08 00:52:17 +03:00
|
|
|
db_root: format!("target/grin-prop-{}", n),
|
2016-12-21 04:39:02 +03:00
|
|
|
cuckoo_size: 12,
|
2017-02-19 05:42:34 +03:00
|
|
|
p2p_config: p2p::P2PConfig{port: 10000+n, ..p2p::P2PConfig::default()},
|
|
|
|
..Default::default()
|
2016-12-15 03:10:39 +03:00
|
|
|
}, &handle).unwrap();
|
2016-11-30 05:51:36 +03:00
|
|
|
servers.push(s);
|
2016-12-14 06:21:49 +03:00
|
|
|
}
|
2016-11-30 05:51:36 +03:00
|
|
|
|
2016-12-14 06:21:49 +03:00
|
|
|
// everyone connects to everyone else
|
|
|
|
for n in 0..5 {
|
|
|
|
for m in 0..5 {
|
|
|
|
if m == n { continue }
|
|
|
|
let addr = format!("{}:{}", "127.0.0.1", 10000+m);
|
|
|
|
servers[n].connect_peer(addr.parse().unwrap()).unwrap();
|
2016-11-30 05:51:36 +03:00
|
|
|
}
|
2016-12-14 06:21:49 +03:00
|
|
|
}
|
2016-11-30 05:51:36 +03:00
|
|
|
|
2016-12-21 04:39:02 +03:00
|
|
|
// start mining
|
|
|
|
servers[0].start_miner();
|
2016-12-23 23:15:36 +03:00
|
|
|
let original_height = servers[0].head().height;
|
2016-12-21 04:39:02 +03:00
|
|
|
|
2017-01-28 06:17:28 +03:00
|
|
|
// monitor for a change of head on a different server and check whether
|
|
|
|
// chain height has changed
|
2016-12-23 23:15:36 +03:00
|
|
|
evtlp.run(change(&servers[4]).and_then(|tip| {
|
|
|
|
assert!(tip.height == original_height+1);
|
|
|
|
Ok(())
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2017-02-19 05:42:34 +03:00
|
|
|
/// Creates 2 different disconnected servers, mine a few blocks on one, connect
|
|
|
|
/// them and check that the 2nd gets all the blocks
|
2017-02-08 00:52:17 +03:00
|
|
|
#[test]
|
|
|
|
fn simulate_full_sync() {
|
|
|
|
env_logger::init();
|
|
|
|
|
|
|
|
let mut evtlp = reactor::Core::new().unwrap();
|
|
|
|
let handle = evtlp.handle();
|
|
|
|
|
|
|
|
// instantiates 2 servers on different ports
|
|
|
|
let mut servers = vec![];
|
|
|
|
for n in 0..2 {
|
|
|
|
let s = grin::Server::future(
|
|
|
|
grin::ServerConfig{
|
|
|
|
db_root: format!("target/grin-sync-{}", n),
|
|
|
|
cuckoo_size: 12,
|
2017-02-19 05:42:34 +03:00
|
|
|
p2p_config: p2p::P2PConfig{port: 11000+n, ..p2p::P2PConfig::default()},
|
|
|
|
..Default::default()
|
2017-02-08 00:52:17 +03:00
|
|
|
}, &handle).unwrap();
|
|
|
|
servers.push(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
// mine a few blocks on server 1
|
|
|
|
servers[0].start_miner();
|
|
|
|
thread::sleep(time::Duration::from_secs(15));
|
|
|
|
|
|
|
|
// connect 1 and 2
|
|
|
|
let addr = format!("{}:{}", "127.0.0.1", 11001);
|
|
|
|
servers[0].connect_peer(addr.parse().unwrap()).unwrap();
|
|
|
|
|
|
|
|
// 2 should get blocks
|
|
|
|
evtlp.run(change(&servers[1]));
|
|
|
|
}
|
|
|
|
|
2017-02-19 05:42:34 +03:00
|
|
|
/// Creates 5 servers, one being a seed and check that through peer address
|
|
|
|
/// messages they all end up connected.
|
|
|
|
#[test]
|
|
|
|
fn simulate_seeding() {
|
|
|
|
env_logger::init();
|
|
|
|
|
|
|
|
let mut evtlp = reactor::Core::new().unwrap();
|
|
|
|
let handle = evtlp.handle();
|
|
|
|
|
|
|
|
// instantiates 5 servers on different ports, with 0 as a seed
|
|
|
|
let mut servers = vec![];
|
|
|
|
for n in 0..5 {
|
|
|
|
let s = grin::Server::future(
|
|
|
|
grin::ServerConfig{
|
|
|
|
db_root: format!("target/grin-seed-{}", n),
|
|
|
|
cuckoo_size: 12,
|
|
|
|
p2p_config: p2p::P2PConfig{port: 12000+n, ..p2p::P2PConfig::default()},
|
2017-02-19 22:08:57 +03:00
|
|
|
seeding_type: grin::Seeding::List(vec!["127.0.0.1:12000".to_string()]),
|
2017-02-19 05:42:34 +03:00
|
|
|
..Default::default()
|
|
|
|
}, &handle).unwrap();
|
|
|
|
servers.push(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
// wait a bit and check all servers are now connected
|
|
|
|
evtlp.run(Timer::default().sleep(time::Duration::from_secs(30)).and_then(|_| {
|
|
|
|
for s in servers {
|
|
|
|
// occasionally 2 peers will connect to each other at the same time
|
|
|
|
assert!(s.peer_count() >= 4);
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2016-12-23 23:15:36 +03:00
|
|
|
// Builds the change future, monitoring for a change of head on the provided server
|
|
|
|
fn change<'a>(s: &'a grin::Server) -> HeadChange<'a> {
|
|
|
|
let start_head = s.head();
|
|
|
|
HeadChange {
|
|
|
|
server: s,
|
|
|
|
original: start_head,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-24 01:34:02 +03:00
|
|
|
/// Future that monitors when a server has had its head updated. Current
|
|
|
|
/// implementation isn't optimized, only use for tests.
|
2016-12-23 23:15:36 +03:00
|
|
|
struct HeadChange<'a> {
|
|
|
|
server: &'a grin::Server,
|
|
|
|
original: chain::Tip,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Future for HeadChange<'a> {
|
|
|
|
type Item = chain::Tip;
|
|
|
|
type Error = ();
|
|
|
|
|
|
|
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
|
|
|
let new_head = self.server.head();
|
|
|
|
if new_head.last_block_h != self.original.last_block_h {
|
|
|
|
Ok(Async::Ready(new_head))
|
|
|
|
} else {
|
|
|
|
// egregious polling, asking the task to schedule us every iteration
|
|
|
|
park().unpark();
|
|
|
|
Ok(Async::NotReady)
|
|
|
|
}
|
|
|
|
}
|
2016-11-30 05:51:36 +03:00
|
|
|
}
|