Client app
This commit is contained in:
parent
aff4e24775
commit
2a4d470039
@ -1,15 +1,28 @@
|
|||||||
extern crate ethcore_util as util;
|
extern crate ethcore_util as util;
|
||||||
|
extern crate ethcore;
|
||||||
|
extern crate rustc_serialize;
|
||||||
|
|
||||||
use std::io::*;
|
use std::io::*;
|
||||||
|
use std::env;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use rustc_serialize::hex::FromHex;
|
||||||
|
use util::hash::*;
|
||||||
use util::network::{NetworkService};
|
use util::network::{NetworkService};
|
||||||
|
use ethcore::client::Client;
|
||||||
|
use ethcore::sync::EthSync;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _service = NetworkService::start().unwrap();
|
let mut service = NetworkService::start().unwrap();
|
||||||
|
let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap();
|
||||||
|
let mut dir = env::temp_dir();
|
||||||
|
dir.push(H32::random().hex());
|
||||||
|
let client = Arc::new(Client::new(&genesis, &dir));
|
||||||
|
let sync = Box::new(EthSync::new(client));
|
||||||
|
service.register_protocol(sync, "eth", &[62u8, 63u8]).expect("Error registering eth protocol handler");
|
||||||
loop {
|
loop {
|
||||||
let mut cmd = String::new();
|
let mut cmd = String::new();
|
||||||
stdin().read_line(&mut cmd).unwrap();
|
stdin().read_line(&mut cmd).unwrap();
|
||||||
if cmd == "quit" || cmd == "exit" || cmd == "q" {
|
if cmd == "quit\n" || cmd == "exit\n" || cmd == "q\n" {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
//! Fast access to blockchain data.
|
//! Fast access to blockchain data.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
use std::sync::RwLock;
|
||||||
use rocksdb::{DB, WriteBatch, Writable};
|
use rocksdb::{DB, WriteBatch, Writable};
|
||||||
use heapsize::HeapSizeOf;
|
use heapsize::HeapSizeOf;
|
||||||
use util::hash::*;
|
use util::hash::*;
|
||||||
@ -62,17 +62,17 @@ impl BestBlock {
|
|||||||
///
|
///
|
||||||
/// **Does not do input data verification.**
|
/// **Does not do input data verification.**
|
||||||
pub struct BlockChain {
|
pub struct BlockChain {
|
||||||
best_block: RefCell<BestBlock>,
|
best_block: RwLock<BestBlock>,
|
||||||
|
|
||||||
// block cache
|
// block cache
|
||||||
blocks: RefCell<HashMap<H256, Bytes>>,
|
blocks: RwLock<HashMap<H256, Bytes>>,
|
||||||
|
|
||||||
// extra caches
|
// extra caches
|
||||||
block_details: RefCell<HashMap<H256, BlockDetails>>,
|
block_details: RwLock<HashMap<H256, BlockDetails>>,
|
||||||
block_hashes: RefCell<HashMap<U256, H256>>,
|
block_hashes: RwLock<HashMap<U256, H256>>,
|
||||||
transaction_addresses: RefCell<HashMap<H256, TransactionAddress>>,
|
transaction_addresses: RwLock<HashMap<H256, TransactionAddress>>,
|
||||||
block_logs: RefCell<HashMap<H256, BlockLogBlooms>>,
|
block_logs: RwLock<HashMap<H256, BlockLogBlooms>>,
|
||||||
blocks_blooms: RefCell<HashMap<H256, BlocksBlooms>>,
|
blocks_blooms: RwLock<HashMap<H256, BlocksBlooms>>,
|
||||||
|
|
||||||
extras_db: DB,
|
extras_db: DB,
|
||||||
blocks_db: DB
|
blocks_db: DB
|
||||||
@ -117,13 +117,13 @@ impl BlockChain {
|
|||||||
let blocks_db = DB::open_default(blocks_path.to_str().unwrap()).unwrap();
|
let blocks_db = DB::open_default(blocks_path.to_str().unwrap()).unwrap();
|
||||||
|
|
||||||
let bc = BlockChain {
|
let bc = BlockChain {
|
||||||
best_block: RefCell::new(BestBlock::new()),
|
best_block: RwLock::new(BestBlock::new()),
|
||||||
blocks: RefCell::new(HashMap::new()),
|
blocks: RwLock::new(HashMap::new()),
|
||||||
block_details: RefCell::new(HashMap::new()),
|
block_details: RwLock::new(HashMap::new()),
|
||||||
block_hashes: RefCell::new(HashMap::new()),
|
block_hashes: RwLock::new(HashMap::new()),
|
||||||
transaction_addresses: RefCell::new(HashMap::new()),
|
transaction_addresses: RwLock::new(HashMap::new()),
|
||||||
block_logs: RefCell::new(HashMap::new()),
|
block_logs: RwLock::new(HashMap::new()),
|
||||||
blocks_blooms: RefCell::new(HashMap::new()),
|
blocks_blooms: RwLock::new(HashMap::new()),
|
||||||
extras_db: extras_db,
|
extras_db: extras_db,
|
||||||
blocks_db: blocks_db
|
blocks_db: blocks_db
|
||||||
};
|
};
|
||||||
@ -158,7 +158,7 @@ impl BlockChain {
|
|||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut best_block = bc.best_block.borrow_mut();
|
let mut best_block = bc.best_block.write().unwrap();
|
||||||
best_block.number = bc.block_number(&best_block_hash).unwrap();
|
best_block.number = bc.block_number(&best_block_hash).unwrap();
|
||||||
best_block.total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty;
|
best_block.total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty;
|
||||||
best_block.hash = best_block_hash;
|
best_block.hash = best_block_hash;
|
||||||
@ -272,7 +272,7 @@ impl BlockChain {
|
|||||||
// create views onto rlp
|
// create views onto rlp
|
||||||
let block = BlockView::new(bytes);
|
let block = BlockView::new(bytes);
|
||||||
let header = block.header_view();
|
let header = block.header_view();
|
||||||
let hash = block.sha3();
|
let hash = header.sha3();
|
||||||
|
|
||||||
if self.is_known(&hash) {
|
if self.is_known(&hash) {
|
||||||
return;
|
return;
|
||||||
@ -283,13 +283,13 @@ impl BlockChain {
|
|||||||
let (batch, new_best) = self.block_to_extras_insert_batch(bytes);
|
let (batch, new_best) = self.block_to_extras_insert_batch(bytes);
|
||||||
|
|
||||||
// update best block
|
// update best block
|
||||||
let mut best_block = self.best_block.borrow_mut();
|
let mut best_block = self.best_block.write().unwrap();
|
||||||
if let Some(b) = new_best {
|
if let Some(b) = new_best {
|
||||||
*best_block = b;
|
*best_block = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update caches
|
// update caches
|
||||||
let mut write = self.block_details.borrow_mut();
|
let mut write = self.block_details.write().unwrap();
|
||||||
write.remove(&header.parent_hash());
|
write.remove(&header.parent_hash());
|
||||||
|
|
||||||
// update extras database
|
// update extras database
|
||||||
@ -425,17 +425,17 @@ impl BlockChain {
|
|||||||
|
|
||||||
/// Get best block hash.
|
/// Get best block hash.
|
||||||
pub fn best_block_hash(&self) -> H256 {
|
pub fn best_block_hash(&self) -> H256 {
|
||||||
self.best_block.borrow().hash.clone()
|
self.best_block.read().unwrap().hash.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get best block number.
|
/// Get best block number.
|
||||||
pub fn best_block_number(&self) -> U256 {
|
pub fn best_block_number(&self) -> U256 {
|
||||||
self.best_block.borrow().number
|
self.best_block.read().unwrap().number
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get best block total difficulty.
|
/// Get best block total difficulty.
|
||||||
pub fn best_block_total_difficulty(&self) -> U256 {
|
pub fn best_block_total_difficulty(&self) -> U256 {
|
||||||
self.best_block.borrow().total_difficulty
|
self.best_block.read().unwrap().total_difficulty
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the number of given block's hash.
|
/// Get the number of given block's hash.
|
||||||
@ -448,9 +448,10 @@ impl BlockChain {
|
|||||||
self.query_extras(hash, &self.block_logs)
|
self.query_extras(hash, &self.block_logs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block(&self, hash: &H256) -> Option<Bytes> {
|
/// Get raw block data
|
||||||
|
pub fn block(&self, hash: &H256) -> Option<Bytes> {
|
||||||
{
|
{
|
||||||
let read = self.blocks.borrow();
|
let read = self.blocks.read().unwrap();
|
||||||
match read.get(hash) {
|
match read.get(hash) {
|
||||||
Some(v) => return Some(v.clone()),
|
Some(v) => return Some(v.clone()),
|
||||||
None => ()
|
None => ()
|
||||||
@ -463,7 +464,7 @@ impl BlockChain {
|
|||||||
match opt {
|
match opt {
|
||||||
Some(b) => {
|
Some(b) => {
|
||||||
let bytes: Bytes = b.to_vec();
|
let bytes: Bytes = b.to_vec();
|
||||||
let mut write = self.blocks.borrow_mut();
|
let mut write = self.blocks.write().unwrap();
|
||||||
write.insert(hash.clone(), bytes.clone());
|
write.insert(hash.clone(), bytes.clone());
|
||||||
Some(bytes)
|
Some(bytes)
|
||||||
},
|
},
|
||||||
@ -471,11 +472,11 @@ impl BlockChain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_extras<K, T>(&self, hash: &K, cache: &RefCell<HashMap<K, T>>) -> Option<T> where
|
fn query_extras<K, T>(&self, hash: &K, cache: &RwLock<HashMap<K, T>>) -> Option<T> where
|
||||||
T: Clone + Decodable + ExtrasIndexable,
|
T: Clone + Decodable + ExtrasIndexable,
|
||||||
K: ExtrasSliceConvertable + Eq + Hash + Clone {
|
K: ExtrasSliceConvertable + Eq + Hash + Clone {
|
||||||
{
|
{
|
||||||
let read = cache.borrow();
|
let read = cache.read().unwrap();
|
||||||
match read.get(hash) {
|
match read.get(hash) {
|
||||||
Some(v) => return Some(v.clone()),
|
Some(v) => return Some(v.clone()),
|
||||||
None => ()
|
None => ()
|
||||||
@ -483,17 +484,17 @@ impl BlockChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.extras_db.get_extras(hash).map(| t: T | {
|
self.extras_db.get_extras(hash).map(| t: T | {
|
||||||
let mut write = cache.borrow_mut();
|
let mut write = cache.write().unwrap();
|
||||||
write.insert(hash.clone(), t.clone());
|
write.insert(hash.clone(), t.clone());
|
||||||
t
|
t
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_extras_exist<K, T>(&self, hash: &K, cache: &RefCell<HashMap<K, T>>) -> bool where
|
fn query_extras_exist<K, T>(&self, hash: &K, cache: &RwLock<HashMap<K, T>>) -> bool where
|
||||||
K: ExtrasSliceConvertable + Eq + Hash + Clone,
|
K: ExtrasSliceConvertable + Eq + Hash + Clone,
|
||||||
T: ExtrasIndexable {
|
T: ExtrasIndexable {
|
||||||
{
|
{
|
||||||
let read = cache.borrow();
|
let read = cache.read().unwrap();
|
||||||
match read.get(hash) {
|
match read.get(hash) {
|
||||||
Some(_) => return true,
|
Some(_) => return true,
|
||||||
None => ()
|
None => ()
|
||||||
@ -506,21 +507,21 @@ impl BlockChain {
|
|||||||
/// Get current cache size.
|
/// Get current cache size.
|
||||||
pub fn cache_size(&self) -> CacheSize {
|
pub fn cache_size(&self) -> CacheSize {
|
||||||
CacheSize {
|
CacheSize {
|
||||||
blocks: self.blocks.heap_size_of_children(),
|
blocks: self.blocks.read().unwrap().heap_size_of_children(),
|
||||||
block_details: self.block_details.heap_size_of_children(),
|
block_details: self.block_details.read().unwrap().heap_size_of_children(),
|
||||||
transaction_addresses: self.transaction_addresses.heap_size_of_children(),
|
transaction_addresses: self.transaction_addresses.read().unwrap().heap_size_of_children(),
|
||||||
block_logs: self.block_logs.heap_size_of_children(),
|
block_logs: self.block_logs.read().unwrap().heap_size_of_children(),
|
||||||
blocks_blooms: self.blocks_blooms.heap_size_of_children()
|
blocks_blooms: self.blocks_blooms.read().unwrap().heap_size_of_children()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to squeeze the cache if its too big.
|
/// Tries to squeeze the cache if its too big.
|
||||||
pub fn squeeze_to_fit(&self, size: CacheSize) {
|
pub fn squeeze_to_fit(&self, size: CacheSize) {
|
||||||
self.blocks.borrow_mut().squeeze(size.blocks);
|
self.blocks.write().unwrap().squeeze(size.blocks);
|
||||||
self.block_details.borrow_mut().squeeze(size.block_details);
|
self.block_details.write().unwrap().squeeze(size.block_details);
|
||||||
self.transaction_addresses.borrow_mut().squeeze(size.transaction_addresses);
|
self.transaction_addresses.write().unwrap().squeeze(size.transaction_addresses);
|
||||||
self.block_logs.borrow_mut().squeeze(size.block_logs);
|
self.block_logs.write().unwrap().squeeze(size.block_logs);
|
||||||
self.blocks_blooms.borrow_mut().squeeze(size.blocks_blooms);
|
self.blocks_blooms.write().unwrap().squeeze(size.blocks_blooms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
src/eth.rs
20
src/eth.rs
@ -27,8 +27,8 @@ pub struct BlockChainInfo {
|
|||||||
pub total_difficulty: U256,
|
pub total_difficulty: U256,
|
||||||
pub pending_total_difficulty: U256,
|
pub pending_total_difficulty: U256,
|
||||||
pub genesis_hash: H256,
|
pub genesis_hash: H256,
|
||||||
pub last_block_hash: H256,
|
pub best_block_hash: H256,
|
||||||
pub last_block_number: BlockNumber
|
pub best_block_number: BlockNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BlockQueueStatus {
|
pub struct BlockQueueStatus {
|
||||||
@ -37,21 +37,21 @@ pub struct BlockQueueStatus {
|
|||||||
|
|
||||||
pub type TreeRoute = ::blockchain::TreeRoute;
|
pub type TreeRoute = ::blockchain::TreeRoute;
|
||||||
|
|
||||||
pub type BlockNumber = u32;
|
pub type BlockNumber = u64;
|
||||||
|
|
||||||
pub trait BlockChainClient : Sync {
|
pub trait BlockChainClient : Sync {
|
||||||
fn block_header(&self, h: &H256) -> Option<Bytes>;
|
fn block_header(&self, hash: &H256) -> Option<Bytes>;
|
||||||
fn block_body(&self, h: &H256) -> Option<Bytes>;
|
fn block_body(&self, hash: &H256) -> Option<Bytes>;
|
||||||
fn block(&self, h: &H256) -> Option<Bytes>;
|
fn block(&self, hash: &H256) -> Option<Bytes>;
|
||||||
fn block_status(&self, h: &H256) -> BlockStatus;
|
fn block_status(&self, hash: &H256) -> BlockStatus;
|
||||||
fn block_header_at(&self, n: BlockNumber) -> Option<Bytes>;
|
fn block_header_at(&self, n: BlockNumber) -> Option<Bytes>;
|
||||||
fn block_body_at(&self, n: BlockNumber) -> Option<Bytes>;
|
fn block_body_at(&self, n: BlockNumber) -> Option<Bytes>;
|
||||||
fn block_at(&self, n: BlockNumber) -> Option<Bytes>;
|
fn block_at(&self, n: BlockNumber) -> Option<Bytes>;
|
||||||
fn block_status_at(&self, n: BlockNumber) -> BlockStatus;
|
fn block_status_at(&self, n: BlockNumber) -> BlockStatus;
|
||||||
fn tree_route(&self, from: &H256, to: &H256) -> TreeRoute;
|
fn tree_route(&self, from: &H256, to: &H256) -> TreeRoute;
|
||||||
fn state_data(&self, h: &H256) -> Option<Bytes>;
|
fn state_data(&self, hash: &H256) -> Option<Bytes>;
|
||||||
fn block_receipts(&self, h: &H256) -> Option<Bytes>;
|
fn block_receipts(&self, hash: &H256) -> Option<Bytes>;
|
||||||
fn import_block(&mut self, b: &[u8]) -> ImportResult;
|
fn import_block(&mut self, byte: &[u8]) -> ImportResult;
|
||||||
fn queue_status(&self) -> BlockQueueStatus;
|
fn queue_status(&self) -> BlockQueueStatus;
|
||||||
fn clear_queue(&mut self);
|
fn clear_queue(&mut self);
|
||||||
fn info(&self) -> BlockChainInfo;
|
fn info(&self) -> BlockChainInfo;
|
||||||
|
@ -104,6 +104,8 @@ pub mod genesis;
|
|||||||
pub mod views;
|
pub mod views;
|
||||||
pub mod blockchain;
|
pub mod blockchain;
|
||||||
pub mod extras;
|
pub mod extras;
|
||||||
|
pub mod client;
|
||||||
|
|
||||||
pub mod eth;
|
pub mod eth;
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ impl ChainSync {
|
|||||||
self.highest_block = 0;
|
self.highest_block = 0;
|
||||||
self.have_common_block = false;
|
self.have_common_block = false;
|
||||||
io.chain().clear_queue();
|
io.chain().clear_queue();
|
||||||
self.starting_block = io.chain().info().last_block_number;
|
self.starting_block = io.chain().info().best_block_number;
|
||||||
self.state = SyncState::NotSynced;
|
self.state = SyncState::NotSynced;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,7 +516,7 @@ impl ChainSync {
|
|||||||
if !self.have_common_block {
|
if !self.have_common_block {
|
||||||
// download backwards until common block is found 1 header at a time
|
// download backwards until common block is found 1 header at a time
|
||||||
let chain_info = io.chain().info();
|
let chain_info = io.chain().info();
|
||||||
start = chain_info.last_block_number as usize;
|
start = chain_info.best_block_number as usize;
|
||||||
if !self.headers.is_empty() {
|
if !self.headers.is_empty() {
|
||||||
start = min(start, self.headers.range_iter().next().unwrap().0 as usize - 1);
|
start = min(start, self.headers.range_iter().next().unwrap().0 as usize - 1);
|
||||||
}
|
}
|
||||||
@ -724,7 +724,7 @@ impl ChainSync {
|
|||||||
packet.append(&(PROTOCOL_VERSION as u32));
|
packet.append(&(PROTOCOL_VERSION as u32));
|
||||||
packet.append(&0u32); //TODO: network id
|
packet.append(&0u32); //TODO: network id
|
||||||
packet.append(&chain.total_difficulty);
|
packet.append(&chain.total_difficulty);
|
||||||
packet.append(&chain.last_block_hash);
|
packet.append(&chain.best_block_hash);
|
||||||
packet.append(&chain.genesis_hash);
|
packet.append(&chain.genesis_hash);
|
||||||
//TODO: handle timeout for status request
|
//TODO: handle timeout for status request
|
||||||
match io.send(*peer_id, STATUS_PACKET, packet.out()) {
|
match io.send(*peer_id, STATUS_PACKET, packet.out()) {
|
||||||
@ -742,7 +742,7 @@ impl ChainSync {
|
|||||||
let max_headers: usize = r.val_at(1);
|
let max_headers: usize = r.val_at(1);
|
||||||
let skip: usize = r.val_at(2);
|
let skip: usize = r.val_at(2);
|
||||||
let reverse: bool = r.val_at(3);
|
let reverse: bool = r.val_at(3);
|
||||||
let last = io.chain().info().last_block_number;
|
let last = io.chain().info().best_block_number;
|
||||||
let mut number = if r.at(0).size() == 32 {
|
let mut number = if r.at(0).size() == 32 {
|
||||||
// id is a hash
|
// id is a hash
|
||||||
let hash: H256 = r.val_at(0);
|
let hash: H256 = r.val_at(0);
|
||||||
|
@ -63,6 +63,13 @@ pub struct EthSync {
|
|||||||
pub use self::chain::SyncStatus;
|
pub use self::chain::SyncStatus;
|
||||||
|
|
||||||
impl EthSync {
|
impl EthSync {
|
||||||
|
pub fn new(chain: Arc<BlockChainClient+Send+Sized>) -> EthSync {
|
||||||
|
EthSync {
|
||||||
|
chain: chain,
|
||||||
|
sync: ChainSync::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_syncing(&self) -> bool {
|
pub fn is_syncing(&self) -> bool {
|
||||||
self.sync.is_syncing()
|
self.sync.is_syncing()
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ impl<K, V> RangeCollection<K, V> for Vec<(K, Vec<V>)> where K: Ord + PartialEq +
|
|||||||
fn test_range() {
|
fn test_range() {
|
||||||
use std::cmp::{Ordering};
|
use std::cmp::{Ordering};
|
||||||
|
|
||||||
let mut ranges: Vec<(u32, Vec<char>)> = Vec::new();
|
let mut ranges: Vec<(u64, Vec<char>)> = Vec::new();
|
||||||
assert_eq!(ranges.range_iter().next(), None);
|
assert_eq!(ranges.range_iter().next(), None);
|
||||||
assert_eq!(ranges.find_item(&1), None);
|
assert_eq!(ranges.find_item(&1), None);
|
||||||
assert!(!ranges.have_item(&1));
|
assert!(!ranges.have_item(&1));
|
||||||
|
@ -169,8 +169,8 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
total_difficulty: self.difficulty,
|
total_difficulty: self.difficulty,
|
||||||
pending_total_difficulty: self.difficulty,
|
pending_total_difficulty: self.difficulty,
|
||||||
genesis_hash: self.genesis_hash.clone(),
|
genesis_hash: self.genesis_hash.clone(),
|
||||||
last_block_hash: self.last_hash.clone(),
|
best_block_hash: self.last_hash.clone(),
|
||||||
last_block_number: self.blocks.len() as BlockNumber - 1,
|
best_block_number: self.blocks.len() as BlockNumber - 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user