Started putting in place the adapter between the chain and p2p modules to forward blocks and transactions. Cleaned up chain store references.

This commit is contained in:
Ignotus Peverell 2016-12-18 15:51:54 -08:00
parent 2e6d3d9fdb
commit e688ff99e6
No known key found for this signature in database
GPG key ID: 99CD25F39F8F8211
15 changed files with 137 additions and 61 deletions

View file

@ -14,6 +14,8 @@
//! Implementation of the chain block acceptance (or refusal) pipeline. //! Implementation of the chain block acceptance (or refusal) pipeline.
use std::sync::{Arc, Mutex};
use secp; use secp;
use time; use time;
@ -36,9 +38,9 @@ bitflags! {
/// Contextual information required to process a new block and either reject or /// Contextual information required to process a new block and either reject or
/// accept it. /// accept it.
pub struct BlockContext<'a> { pub struct BlockContext {
opts: Options, opts: Options,
store: &'a ChainStore, store: Arc<ChainStore>,
head: Tip, head: Tip,
tip: Option<Tip>, tip: Option<Tip>,
} }
@ -59,7 +61,7 @@ pub enum Error {
StoreErr(types::Error), StoreErr(types::Error),
} }
pub fn process_block(b: &Block, store: &ChainStore, opts: Options) -> Result<(), Error> { pub fn process_block(b: &Block, store: Arc<ChainStore>, opts: Options) -> Result<(), Error> {
// TODO should just take a promise for a block with a full header so we don't // TODO should just take a promise for a block with a full header so we don't
// spend resources reading the full block when its header is invalid // spend resources reading the full block when its header is invalid

View file

@ -36,6 +36,9 @@ pub struct ChainKVStore {
db: grin_store::Store, db: grin_store::Store,
} }
unsafe impl Sync for ChainKVStore {}
unsafe impl Send for ChainKVStore {}
impl ChainKVStore { impl ChainKVStore {
pub fn new(root_path: String) -> Result<ChainKVStore, Error> { pub fn new(root_path: String) -> Result<ChainKVStore, Error> {
let db = try!(grin_store::Store::open(format!("{}/{}", root_path, STORE_SUBPATH).as_str()) let db = try!(grin_store::Store::open(format!("{}/{}", root_path, STORE_SUBPATH).as_str())

View file

@ -133,7 +133,7 @@ pub enum Error {
/// Trait the chain pipeline requires an implementor for in order to process /// Trait the chain pipeline requires an implementor for in order to process
/// blocks. /// blocks.
pub trait ChainStore: Send { pub trait ChainStore: Send + Sync {
/// Get the tip that's also the head of the chain /// Get the tip that's also the head of the chain
fn head(&self) -> Result<Tip, Error>; fn head(&self) -> Result<Tip, Error>;

View file

@ -17,6 +17,7 @@ extern crate grin_chain;
extern crate rand; extern crate rand;
extern crate secp256k1zkp as secp; extern crate secp256k1zkp as secp;
use std::sync::Arc;
use rand::os::OsRng; use rand::os::OsRng;
use grin_chain::types::*; use grin_chain::types::*;
@ -26,7 +27,6 @@ use grin_core::consensus;
#[test] #[test]
fn mine_empty_chain() { fn mine_empty_chain() {
let curve = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new().unwrap();
let store = grin_chain::store::ChainKVStore::new(".grin".to_string()).unwrap(); let store = grin_chain::store::ChainKVStore::new(".grin".to_string()).unwrap();
@ -42,6 +42,7 @@ fn mine_empty_chain() {
let mut prev = gen; let mut prev = gen;
let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit); let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
let reward_key = secp::key::SecretKey::new(&secp, &mut rng); let reward_key = secp::key::SecretKey::new(&secp, &mut rng);
let arc_store = Arc::new(store);
for n in 1..4 { for n in 1..4 {
let mut b = core::Block::new(&prev.header, vec![], reward_key).unwrap(); let mut b = core::Block::new(&prev.header, vec![], reward_key).unwrap();
@ -55,10 +56,10 @@ fn mine_empty_chain() {
b.header.pow = proof; b.header.pow = proof;
b.header.nonce = nonce; b.header.nonce = nonce;
b.header.target = diff_target; b.header.target = diff_target;
grin_chain::pipe::process_block(&b, &store, grin_chain::pipe::EASY_POW).unwrap(); grin_chain::pipe::process_block(&b, arc_store.clone(), grin_chain::pipe::EASY_POW).unwrap();
// checking our new head // checking our new head
let head = store.head().unwrap(); let head = arc_store.clone().head().unwrap();
assert_eq!(head.height, n); assert_eq!(head.height, n);
assert_eq!(head.last_block_h, b.hash()); assert_eq!(head.last_block_h, b.hash());

42
grin/src/adapters.rs Normal file
View file

@ -0,0 +1,42 @@
// 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.
use std::sync::{Arc, Mutex};
use chain;
use core::core;
use p2p::NetAdapter;
pub struct NetToChainAdapter {
chain_store: Arc<chain::ChainStore>,
}
impl NetAdapter for NetToChainAdapter {
fn transaction_received(&self, tx: core::Transaction) {
unimplemented!();
}
fn block_received(&self, b: core::Block) {
// if let Err(e) = chain::process_block(&b, self.chain_store,
// chain::pipe::NONE) {
// debug!("Block {} refused by chain: {}", b.hash(), e);
// }
unimplemented!();
}
}
impl NetToChainAdapter {
pub fn new(chain_store: Arc<chain::ChainStore>) -> NetToChainAdapter {
NetToChainAdapter { chain_store: chain_store }
}
}

View file

@ -35,6 +35,7 @@ extern crate grin_p2p as p2p;
extern crate grin_store as store; extern crate grin_store as store;
extern crate secp256k1zkp as secp; extern crate secp256k1zkp as secp;
mod adapters;
mod miner; mod miner;
mod server; mod server;

View file

@ -30,15 +30,13 @@ use secp;
pub struct Miner { pub struct Miner {
chain_head: Arc<Mutex<chain::Tip>>, chain_head: Arc<Mutex<chain::Tip>>,
chain_store: Arc<Mutex<chain::ChainStore>>, chain_store: Arc<chain::ChainStore>,
} }
impl Miner { impl Miner {
/// Creates a new Miner. Needs references to the chain state and its /// Creates a new Miner. Needs references to the chain state and its
/// storage. /// storage.
pub fn new(chain_head: Arc<Mutex<chain::Tip>>, pub fn new(chain_head: Arc<Mutex<chain::Tip>>, chain_store: Arc<chain::ChainStore>) -> Miner {
chain_store: Arc<Mutex<chain::ChainStore>>)
-> Miner {
Miner { Miner {
chain_head: chain_head, chain_head: chain_head,
chain_store: chain_store, chain_store: chain_store,
@ -54,7 +52,7 @@ impl Miner {
let head: core::BlockHeader; let head: core::BlockHeader;
let mut latest_hash: Hash; let mut latest_hash: Hash;
{ {
head = self.chain_store.lock().unwrap().head_header().unwrap(); head = self.chain_store.head_header().unwrap();
latest_hash = self.chain_head.lock().unwrap().last_block_h; latest_hash = self.chain_head.lock().unwrap().last_block_h;
} }
let b = self.build_block(&head); let b = self.build_block(&head);
@ -86,9 +84,7 @@ impl Miner {
// if we found a solution, push our block out // if we found a solution, push our block out
if let Some(proof) = sol { if let Some(proof) = sol {
info!("Found valid proof of work, adding block {}.", b.hash()); info!("Found valid proof of work, adding block {}.", b.hash());
if let Err(e) = chain::process_block(&b, if let Err(e) = chain::process_block(&b, self.chain_store.clone(), chain::NONE) {
self.chain_store.lock().unwrap().deref(),
chain::NONE) {
error!("Error validating mined block: {:?}", e); error!("Error validating mined block: {:?}", e);
} }
} else { } else {

View file

@ -23,6 +23,7 @@ use std::thread;
use futures::Future; use futures::Future;
use tokio_core::reactor; use tokio_core::reactor;
use adapters::NetToChainAdapter;
use chain; use chain;
use chain::ChainStore; use chain::ChainStore;
use core; use core;
@ -72,7 +73,7 @@ pub struct Server {
/// the reference copy of the current chain state /// the reference copy of the current chain state
chain_head: Arc<Mutex<chain::Tip>>, chain_head: Arc<Mutex<chain::Tip>>,
/// data store access /// data store access
chain_store: Arc<Mutex<chain::ChainStore>>, chain_store: Arc<chain::ChainStore>,
} }
impl Server { impl Server {
@ -82,7 +83,8 @@ impl Server {
let mut evtlp = reactor::Core::new().unwrap(); let mut evtlp = reactor::Core::new().unwrap();
let handle = evtlp.handle(); let handle = evtlp.handle();
let server = Arc::new(p2p::Server::new(config.p2p_config)); let net_adapter = Arc::new(NetToChainAdapter::new(chain_store.clone()));
let server = Arc::new(p2p::Server::new(config.p2p_config, net_adapter));
evtlp.run(server.start(handle.clone())).unwrap(); evtlp.run(server.start(handle.clone())).unwrap();
warn!("Grin server started."); warn!("Grin server started.");
@ -91,7 +93,7 @@ impl Server {
evt_handle: handle.clone(), evt_handle: handle.clone(),
p2p: server, p2p: server,
chain_head: Arc::new(Mutex::new(head)), chain_head: Arc::new(Mutex::new(head)),
chain_store: Arc::new(Mutex::new(chain_store)), chain_store: chain_store,
}) })
} }
@ -121,7 +123,7 @@ pub struct ServerFut {
/// the reference copy of the current chain state /// the reference copy of the current chain state
chain_head: Arc<Mutex<chain::Tip>>, chain_head: Arc<Mutex<chain::Tip>>,
/// data store access /// data store access
chain_store: Arc<Mutex<chain::ChainStore>>, chain_store: Arc<chain::ChainStore>,
} }
impl ServerFut { impl ServerFut {
@ -129,7 +131,8 @@ impl ServerFut {
pub fn start(config: ServerConfig, evt_handle: &reactor::Handle) -> Result<Server, Error> { pub fn start(config: ServerConfig, evt_handle: &reactor::Handle) -> Result<Server, Error> {
let (chain_store, head) = try!(store_head(&config)); let (chain_store, head) = try!(store_head(&config));
let server = Arc::new(p2p::Server::new(config.p2p_config)); let net_adapter = Arc::new(NetToChainAdapter::new(chain_store.clone()));
let server = Arc::new(p2p::Server::new(config.p2p_config, net_adapter));
evt_handle.spawn(server.start(evt_handle.clone()).map_err(|_| ())); evt_handle.spawn(server.start(evt_handle.clone()).map_err(|_| ()));
warn!("Grin server started."); warn!("Grin server started.");
@ -138,7 +141,7 @@ impl ServerFut {
evt_handle: evt_handle.clone(), evt_handle: evt_handle.clone(),
p2p: server, p2p: server,
chain_head: Arc::new(Mutex::new(head)), chain_head: Arc::new(Mutex::new(head)),
chain_store: Arc::new(Mutex::new(chain_store)), chain_store: chain_store,
}) })
} }
@ -160,7 +163,8 @@ impl ServerFut {
// Helper function to create the chain storage and check if it already has a // Helper function to create the chain storage and check if it already has a
// genesis block // genesis block
fn store_head(config: &ServerConfig) -> Result<(chain::store::ChainKVStore, chain::Tip), Error> { fn store_head(config: &ServerConfig)
-> Result<(Arc<chain::store::ChainKVStore>, chain::Tip), Error> {
let chain_store = try!(chain::store::ChainKVStore::new(config.db_root.clone()) let chain_store = try!(chain::store::ChainKVStore::new(config.db_root.clone())
.map_err(&Error::StoreErr)); .map_err(&Error::StoreErr));
@ -178,5 +182,5 @@ fn store_head(config: &ServerConfig) -> Result<(chain::store::ChainKVStore, chai
} }
Err(e) => return Err(Error::StoreErr(e)), Err(e) => return Err(Error::StoreErr(e)),
}; };
Ok((chain_store, head)) Ok((Arc::new(chain_store), head))
} }

View file

@ -44,4 +44,4 @@ mod types;
pub use server::{Server, DummyAdapter}; pub use server::{Server, DummyAdapter};
pub use peer::Peer; pub use peer::Peer;
pub use types::P2PConfig; pub use types::{P2PConfig, NetAdapter};

View file

@ -57,7 +57,10 @@ impl Peer {
Box::new(hs_peer) Box::new(hs_peer)
} }
pub fn run(&self, conn: TcpStream, na: Arc<NetAdapter>) -> Box<Future<Item = (), Error = Error>> { pub fn run(&self,
conn: TcpStream,
na: Arc<NetAdapter>)
-> Box<Future<Item = (), Error = Error>> {
self.proto.handle(conn, na) self.proto.handle(conn, na)
} }

View file

@ -136,7 +136,9 @@ impl ProtocolV1 {
}) })
.and_then(move |(reader, header)| { .and_then(move |(reader, header)| {
// now that we have a size, proceed with the body // now that we have a size, proceed with the body
read_exact(reader, vec![0u8; header.msg_len as usize]).map(|(reader, buf)| { (reader, header, buf) }).map_err(|e| ser::Error::IOErr(e)) read_exact(reader, vec![0u8; header.msg_len as usize])
.map(|(reader, buf)| (reader, header, buf))
.map_err(|e| ser::Error::IOErr(e))
}) })
.map(move |(reader, header, buf)| { .map(move |(reader, header, buf)| {
// add the count of bytes received // add the count of bytes received
@ -192,7 +194,11 @@ impl ProtocolV1 {
} }
} }
fn handle_payload(adapter: Arc<NetAdapter>, header: &MsgHeader, buf: Vec<u8>, sender: &mut UnboundedSender<Vec<u8>>) -> Result<(), ser::Error> { fn handle_payload(adapter: Arc<NetAdapter>,
header: &MsgHeader,
buf: Vec<u8>,
sender: &mut UnboundedSender<Vec<u8>>)
-> Result<(), ser::Error> {
match header.msg_type { match header.msg_type {
Type::Ping => { Type::Ping => {
let data = try!(ser::ser_vec(&MsgHeader::new(Type::Pong, 0))); let data = try!(ser::ser_vec(&MsgHeader::new(Type::Pong, 0)));

View file

@ -45,6 +45,7 @@ impl NetAdapter for DummyAdapter {
pub struct Server { pub struct Server {
config: P2PConfig, config: P2PConfig,
peers: Arc<RwLock<Vec<Arc<Peer>>>>, peers: Arc<RwLock<Vec<Arc<Peer>>>>,
adapter: Arc<NetAdapter>,
stop: RefCell<Option<futures::sync::oneshot::Sender<()>>>, stop: RefCell<Option<futures::sync::oneshot::Sender<()>>>,
} }
@ -54,10 +55,11 @@ unsafe impl Send for Server {}
// TODO TLS // TODO TLS
impl Server { impl Server {
/// Creates a new idle p2p server with no peers /// Creates a new idle p2p server with no peers
pub fn new(config: P2PConfig) -> Server { pub fn new(config: P2PConfig, adapter: Arc<NetAdapter>) -> Server {
Server { Server {
config: config, config: config,
peers: Arc::new(RwLock::new(Vec::new())), peers: Arc::new(RwLock::new(Vec::new())),
adapter: adapter,
stop: RefCell::new(None), stop: RefCell::new(None),
} }
} }
@ -71,10 +73,12 @@ impl Server {
let hs = Arc::new(Handshake::new()); let hs = Arc::new(Handshake::new());
let peers = self.peers.clone(); let peers = self.peers.clone();
let adapter = self.adapter.clone();
// main peer acceptance future handling handshake // main peer acceptance future handling handshake
let hp = h.clone(); let hp = h.clone();
let peers = socket.incoming().map_err(|e| Error::IOErr(e)).map(move |(conn, addr)| { let peers = socket.incoming().map_err(|e| Error::IOErr(e)).map(move |(conn, addr)| {
let adapter = adapter.clone();
let peers = peers.clone(); let peers = peers.clone();
// accept the peer and add it to the server map // accept the peer and add it to the server map
@ -84,7 +88,7 @@ impl Server {
let timed_peer = with_timeout(Box::new(peer_accept), &hp); let timed_peer = with_timeout(Box::new(peer_accept), &hp);
// run the main peer protocol // run the main peer protocol
timed_peer.and_then(|(conn, peer)| peer.clone().run(conn, Arc::new(DummyAdapter {}))) timed_peer.and_then(move |(conn, peer)| peer.clone().run(conn, adapter))
}); });
// spawn each peer future to its own task // spawn each peer future to its own task
@ -120,6 +124,8 @@ impl Server {
h: reactor::Handle) h: reactor::Handle)
-> Box<Future<Item = (), Error = Error>> { -> Box<Future<Item = (), Error = Error>> {
let peers = self.peers.clone(); let peers = self.peers.clone();
let adapter = self.adapter.clone();
let socket = TcpStream::connect(&addr, &h).map_err(|e| Error::IOErr(e)); let socket = TcpStream::connect(&addr, &h).map_err(|e| Error::IOErr(e));
let request = socket.and_then(move |socket| { let request = socket.and_then(move |socket| {
let peers = peers.clone(); let peers = peers.clone();
@ -129,7 +135,7 @@ impl Server {
let peer_connect = add_to_peers(peers, Peer::connect(socket, &Handshake::new())); let peer_connect = add_to_peers(peers, Peer::connect(socket, &Handshake::new()));
with_timeout(Box::new(peer_connect), &h) with_timeout(Box::new(peer_connect), &h)
}) })
.and_then(|(socket, peer)| peer.run(socket, Arc::new(DummyAdapter {}))); .and_then(move |(socket, peer)| peer.run(socket, adapter));
Box::new(request) Box::new(request)
} }

View file

@ -66,7 +66,10 @@ pub trait Protocol {
/// be known already, usually passed during construction. Will typically /// be known already, usually passed during construction. Will typically
/// block so needs to be called withing a coroutine. Should also be called /// block so needs to be called withing a coroutine. Should also be called
/// only once. /// only once.
fn handle(&self, conn: TcpStream, na: Arc<NetAdapter>) -> Box<Future<Item = (), Error = Error>>; fn handle(&self,
conn: TcpStream,
na: Arc<NetAdapter>)
-> Box<Future<Item = (), Error = Error>>;
/// Sends a ping message to the remote peer. /// Sends a ping message to the remote peer.
fn send_ping(&self) -> Result<(), Error>; fn send_ping(&self) -> Result<(), Error>;

View file

@ -37,7 +37,8 @@ fn peer_handshake() {
let mut evtlp = Core::new().unwrap(); let mut evtlp = Core::new().unwrap();
let handle = evtlp.handle(); let handle = evtlp.handle();
let p2p_conf = p2p::P2PConfig::default(); let p2p_conf = p2p::P2PConfig::default();
let server = p2p::Server::new(p2p_conf); let net_adapter = Arc::new(p2p::DummyAdapter{});
let server = p2p::Server::new(p2p_conf, net_adapter.clone());
let run_server = server.start(handle.clone()); let run_server = server.start(handle.clone());
let phandle = handle.clone(); let phandle = handle.clone();
@ -51,7 +52,7 @@ fn peer_handshake() {
socket.and_then(move |socket| { socket.and_then(move |socket| {
Peer::connect(socket, &p2p::handshake::Handshake::new()) Peer::connect(socket, &p2p::handshake::Handshake::new())
}).and_then(move |(socket, peer)| { }).and_then(move |(socket, peer)| {
rhandle.spawn(peer.run(socket, Arc::new(p2p::DummyAdapter {})).map_err(|e| { rhandle.spawn(peer.run(socket, net_adapter.clone()).map_err(|e| {
panic!("Client run failed: {}", e); panic!("Client run failed: {}", e);
})); }));
peer.send_ping().unwrap(); peer.send_ping().unwrap();

View file

@ -50,6 +50,9 @@ pub struct Store {
rdb: RwLock<DB>, rdb: RwLock<DB>,
} }
unsafe impl Sync for Store {}
unsafe impl Send for Store {}
impl Store { impl Store {
/// Opens a new RocksDB at the specified location. /// Opens a new RocksDB at the specified location.
pub fn open(path: &str) -> Result<Store, Error> { pub fn open(path: &str) -> Result<Store, Error> {
@ -90,8 +93,13 @@ impl Store {
self.get_ser_limited(key, 0) self.get_ser_limited(key, 0)
} }
/// Gets a `Readable` value from the db, provided its key, allowing to extract only partial data. The underlying Readable size must align accordingly. Encapsulates serialization. /// Gets a `Readable` value from the db, provided its key, allowing to
pub fn get_ser_limited<T: ser::Readable<T>>(&self, key: &[u8], len: usize) -> Result<Option<T>, Error> { /// extract only partial data. The underlying Readable size must align
/// accordingly. Encapsulates serialization.
pub fn get_ser_limited<T: ser::Readable<T>>(&self,
key: &[u8],
len: usize)
-> Result<Option<T>, Error> {
let data = try!(self.get(key)); let data = try!(self.get(key));
match data { match data {
Some(val) => { Some(val) => {