Owning views of blockchain data (#3982)
* owning views of blockchain data * port blockchain and client traits to owning views * fix ethcore tests * use strong headers and bodies in ethcore_light * port ethsync to use owning views * port rpc to owning views * port parity informant and blockchain export
This commit is contained in:
parent
592a3ac623
commit
fe1f542c4f
@ -26,6 +26,7 @@ use ethcore::block_status::BlockStatus;
|
|||||||
use ethcore::verification::queue::{HeaderQueue, QueueInfo};
|
use ethcore::verification::queue::{HeaderQueue, QueueInfo};
|
||||||
use ethcore::transaction::{SignedTransaction, PendingTransaction};
|
use ethcore::transaction::{SignedTransaction, PendingTransaction};
|
||||||
use ethcore::blockchain_info::BlockChainInfo;
|
use ethcore::blockchain_info::BlockChainInfo;
|
||||||
|
use ethcore::encoded;
|
||||||
|
|
||||||
use io::IoChannel;
|
use io::IoChannel;
|
||||||
use util::hash::{H256, H256FastMap};
|
use util::hash::{H256, H256FastMap};
|
||||||
@ -90,11 +91,11 @@ impl Provider for Client {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_header(&self, _id: BlockId) -> Option<Bytes> {
|
fn block_header(&self, _id: BlockId) -> Option<encoded::Header> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_body(&self, _id: BlockId) -> Option<Bytes> {
|
fn block_body(&self, _id: BlockId) -> Option<encoded::Body> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +111,7 @@ impl Provider for Client {
|
|||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_proof(&self, _req: request::HeaderProof) -> Option<(Bytes, Vec<Bytes>)> {
|
fn header_proof(&self, _req: request::HeaderProof) -> Option<(encoded::Header, Vec<Bytes>)> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -706,7 +706,7 @@ impl LightProtocol {
|
|||||||
stream.append(&req_id).append(&cur_buffer).begin_list(response.len());
|
stream.append(&req_id).append(&cur_buffer).begin_list(response.len());
|
||||||
|
|
||||||
for header in response {
|
for header in response {
|
||||||
stream.append_raw(&header, 1);
|
stream.append_raw(&header.into_inner(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.out()
|
stream.out()
|
||||||
@ -757,7 +757,7 @@ impl LightProtocol {
|
|||||||
let max_cost = peer.deduct_max(&self.flow_params, request::Kind::Bodies, req.block_hashes.len())?;
|
let max_cost = peer.deduct_max(&self.flow_params, request::Kind::Bodies, req.block_hashes.len())?;
|
||||||
|
|
||||||
let response = self.provider.block_bodies(req);
|
let response = self.provider.block_bodies(req);
|
||||||
let response_len = response.iter().filter(|x| &x[..] != &::rlp::EMPTY_LIST_RLP).count();
|
let response_len = response.iter().filter(|x| x.is_some()).count();
|
||||||
let actual_cost = self.flow_params.compute_cost(request::Kind::Bodies, response_len);
|
let actual_cost = self.flow_params.compute_cost(request::Kind::Bodies, response_len);
|
||||||
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
||||||
|
|
||||||
@ -768,7 +768,10 @@ impl LightProtocol {
|
|||||||
stream.append(&req_id).append(&cur_buffer).begin_list(response.len());
|
stream.append(&req_id).append(&cur_buffer).begin_list(response.len());
|
||||||
|
|
||||||
for body in response {
|
for body in response {
|
||||||
stream.append_raw(&body, 1);
|
match body {
|
||||||
|
Some(body) => stream.append_raw(&body.into_inner(), 1),
|
||||||
|
None => stream.append_empty_data(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.out()
|
stream.out()
|
||||||
|
@ -21,6 +21,7 @@ use ethcore::blockchain_info::BlockChainInfo;
|
|||||||
use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient};
|
use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient};
|
||||||
use ethcore::ids::BlockId;
|
use ethcore::ids::BlockId;
|
||||||
use ethcore::transaction::PendingTransaction;
|
use ethcore::transaction::PendingTransaction;
|
||||||
|
use ethcore::encoded;
|
||||||
use network::{PeerId, NodeId};
|
use network::{PeerId, NodeId};
|
||||||
|
|
||||||
use net::buffer_flow::FlowParams;
|
use net::buffer_flow::FlowParams;
|
||||||
@ -94,11 +95,11 @@ impl Provider for TestProvider {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_header(&self, id: BlockId) -> Option<Bytes> {
|
fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
|
||||||
self.0.client.block_header(id)
|
self.0.client.block_header(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_body(&self, id: BlockId) -> Option<Bytes> {
|
fn block_body(&self, id: BlockId) -> Option<encoded::Body> {
|
||||||
self.0.client.block_body(id)
|
self.0.client.block_body(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +123,7 @@ impl Provider for TestProvider {
|
|||||||
req.account_key.iter().chain(req.account_key.iter()).cloned().collect()
|
req.account_key.iter().chain(req.account_key.iter()).cloned().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_proof(&self, _req: request::HeaderProof) -> Option<(Bytes, Vec<Bytes>)> {
|
fn header_proof(&self, _req: request::HeaderProof) -> Option<(encoded::Header, Vec<Bytes>)> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,7 +274,7 @@ fn get_block_headers() {
|
|||||||
|
|
||||||
response_stream.append(&req_id).append(&new_buf).begin_list(10);
|
response_stream.append(&req_id).append(&new_buf).begin_list(10);
|
||||||
for header in headers {
|
for header in headers {
|
||||||
response_stream.append_raw(&header, 1);
|
response_stream.append_raw(&header.into_inner(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
response_stream.out()
|
response_stream.out()
|
||||||
@ -320,7 +321,7 @@ fn get_block_bodies() {
|
|||||||
|
|
||||||
response_stream.append(&req_id).append(&new_buf).begin_list(10);
|
response_stream.append(&req_id).append(&new_buf).begin_list(10);
|
||||||
for body in bodies {
|
for body in bodies {
|
||||||
response_stream.append_raw(&body, 1);
|
response_stream.append_raw(&body.into_inner(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
response_stream.out()
|
response_stream.out()
|
||||||
|
@ -21,6 +21,7 @@ use ethcore::blockchain_info::BlockChainInfo;
|
|||||||
use ethcore::client::{BlockChainClient, ProvingBlockChainClient};
|
use ethcore::client::{BlockChainClient, ProvingBlockChainClient};
|
||||||
use ethcore::transaction::PendingTransaction;
|
use ethcore::transaction::PendingTransaction;
|
||||||
use ethcore::ids::BlockId;
|
use ethcore::ids::BlockId;
|
||||||
|
use ethcore::encoded;
|
||||||
|
|
||||||
use util::{Bytes, H256};
|
use util::{Bytes, H256};
|
||||||
|
|
||||||
@ -52,9 +53,8 @@ pub trait Provider: Send + Sync {
|
|||||||
///
|
///
|
||||||
/// The returned vector may have any length in the range [0, `max`], but the
|
/// The returned vector may have any length in the range [0, `max`], but the
|
||||||
/// results within must adhere to the `skip` and `reverse` parameters.
|
/// results within must adhere to the `skip` and `reverse` parameters.
|
||||||
fn block_headers(&self, req: request::Headers) -> Vec<Bytes> {
|
fn block_headers(&self, req: request::Headers) -> Vec<encoded::Header> {
|
||||||
use request::HashOrNumber;
|
use request::HashOrNumber;
|
||||||
use ethcore::views::HeaderView;
|
|
||||||
|
|
||||||
if req.max == 0 { return Vec::new() }
|
if req.max == 0 { return Vec::new() }
|
||||||
|
|
||||||
@ -67,9 +67,9 @@ pub trait Provider: Send + Sync {
|
|||||||
return Vec::new();
|
return Vec::new();
|
||||||
}
|
}
|
||||||
Some(header) => {
|
Some(header) => {
|
||||||
let num = HeaderView::new(&header).number();
|
let num = header.number();
|
||||||
let canon_hash = self.block_header(BlockId::Number(num))
|
let canon_hash = self.block_header(BlockId::Number(num))
|
||||||
.map(|h| HeaderView::new(&h).hash());
|
.map(|h| h.hash());
|
||||||
|
|
||||||
if req.max == 1 || canon_hash != Some(hash) {
|
if req.max == 1 || canon_hash != Some(hash) {
|
||||||
// Non-canonical header or single header requested.
|
// Non-canonical header or single header requested.
|
||||||
@ -92,19 +92,18 @@ pub trait Provider: Send + Sync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a block header by id.
|
/// Get a block header by id.
|
||||||
fn block_header(&self, id: BlockId) -> Option<Bytes>;
|
fn block_header(&self, id: BlockId) -> Option<encoded::Header>;
|
||||||
|
|
||||||
/// Provide as many as possible of the requested blocks (minus the headers) encoded
|
/// Provide as many as possible of the requested blocks (minus the headers) encoded
|
||||||
/// in RLP format.
|
/// in RLP format.
|
||||||
fn block_bodies(&self, req: request::Bodies) -> Vec<Bytes> {
|
fn block_bodies(&self, req: request::Bodies) -> Vec<Option<encoded::Body>> {
|
||||||
req.block_hashes.into_iter()
|
req.block_hashes.into_iter()
|
||||||
.map(|hash| self.block_body(BlockId::Hash(hash)))
|
.map(|hash| self.block_body(BlockId::Hash(hash)))
|
||||||
.map(|body| body.unwrap_or_else(|| ::rlp::EMPTY_LIST_RLP.to_vec()))
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a block body by id.
|
/// Get a block body by id.
|
||||||
fn block_body(&self, id: BlockId) -> Option<Bytes>;
|
fn block_body(&self, id: BlockId) -> Option<encoded::Body>;
|
||||||
|
|
||||||
/// Provide the receipts as many as possible of the requested blocks.
|
/// Provide the receipts as many as possible of the requested blocks.
|
||||||
/// Returns a vector of RLP-encoded lists of receipts.
|
/// Returns a vector of RLP-encoded lists of receipts.
|
||||||
@ -169,7 +168,7 @@ pub trait Provider: Send + Sync {
|
|||||||
None => rlp::EMPTY_LIST_RLP.to_vec(),
|
None => rlp::EMPTY_LIST_RLP.to_vec(),
|
||||||
Some((header, proof)) => {
|
Some((header, proof)) => {
|
||||||
let mut stream = RlpStream::new_list(2);
|
let mut stream = RlpStream::new_list(2);
|
||||||
stream.append_raw(&header, 1).begin_list(proof.len());
|
stream.append_raw(&header.into_inner(), 1).begin_list(proof.len());
|
||||||
|
|
||||||
for node in proof {
|
for node in proof {
|
||||||
stream.append_raw(&node, 1);
|
stream.append_raw(&node, 1);
|
||||||
@ -184,7 +183,7 @@ pub trait Provider: Send + Sync {
|
|||||||
/// Provide a header proof from a given Canonical Hash Trie as well as the
|
/// Provide a header proof from a given Canonical Hash Trie as well as the
|
||||||
/// corresponding header. The first element is the block header and the
|
/// corresponding header. The first element is the block header and the
|
||||||
/// second is a merkle proof of the CHT.
|
/// second is a merkle proof of the CHT.
|
||||||
fn header_proof(&self, req: request::HeaderProof) -> Option<(Bytes, Vec<Bytes>)>;
|
fn header_proof(&self, req: request::HeaderProof) -> Option<(encoded::Header, Vec<Bytes>)>;
|
||||||
|
|
||||||
/// Provide pending transactions.
|
/// Provide pending transactions.
|
||||||
fn ready_transactions(&self) -> Vec<PendingTransaction>;
|
fn ready_transactions(&self) -> Vec<PendingTransaction>;
|
||||||
@ -204,11 +203,11 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
|||||||
Some(self.pruning_info().earliest_state)
|
Some(self.pruning_info().earliest_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_header(&self, id: BlockId) -> Option<Bytes> {
|
fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
|
||||||
BlockChainClient::block_header(self, id)
|
BlockChainClient::block_header(self, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_body(&self, id: BlockId) -> Option<Bytes> {
|
fn block_body(&self, id: BlockId) -> Option<encoded::Body> {
|
||||||
BlockChainClient::block_body(self, id)
|
BlockChainClient::block_body(self, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +226,7 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
|||||||
self.code_by_hash(req.account_key, BlockId::Hash(req.block_hash))
|
self.code_by_hash(req.account_key, BlockId::Hash(req.block_hash))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_proof(&self, _req: request::HeaderProof) -> Option<(Bytes, Vec<Bytes>)> {
|
fn header_proof(&self, _req: request::HeaderProof) -> Option<(encoded::Header, Vec<Bytes>)> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ use blockchain::{CacheSize, ImportRoute, Config};
|
|||||||
use db::{self, Writable, Readable, CacheUpdatePolicy};
|
use db::{self, Writable, Readable, CacheUpdatePolicy};
|
||||||
use cache_manager::CacheManager;
|
use cache_manager::CacheManager;
|
||||||
use engines::Engine;
|
use engines::Engine;
|
||||||
|
use encoded;
|
||||||
|
|
||||||
const LOG_BLOOMS_LEVELS: usize = 3;
|
const LOG_BLOOMS_LEVELS: usize = 3;
|
||||||
const LOG_BLOOMS_ELEMENTS_PER_INDEX: usize = 16;
|
const LOG_BLOOMS_ELEMENTS_PER_INDEX: usize = 16;
|
||||||
@ -64,7 +65,7 @@ pub trait BlockProvider {
|
|||||||
self.best_ancient_block().map(|h| self.block_number(&h).expect("Ancient block is always set to an existing block or `None`. Existing block always has a number; qed"))
|
self.best_ancient_block().map(|h| self.block_number(&h).expect("Ancient block is always set to an existing block or `None`. Existing block always has a number; qed"))
|
||||||
}
|
}
|
||||||
/// Get raw block data
|
/// Get raw block data
|
||||||
fn block(&self, hash: &H256) -> Option<Bytes>;
|
fn block(&self, hash: &H256) -> Option<encoded::Block>;
|
||||||
|
|
||||||
/// Get the familial details concerning a block.
|
/// Get the familial details concerning a block.
|
||||||
fn block_details(&self, hash: &H256) -> Option<BlockDetails>;
|
fn block_details(&self, hash: &H256) -> Option<BlockDetails>;
|
||||||
@ -80,25 +81,25 @@ pub trait BlockProvider {
|
|||||||
|
|
||||||
/// Get the partial-header of a block.
|
/// Get the partial-header of a block.
|
||||||
fn block_header(&self, hash: &H256) -> Option<Header> {
|
fn block_header(&self, hash: &H256) -> Option<Header> {
|
||||||
self.block_header_data(hash).map(|header| decode(&header))
|
self.block_header_data(hash).map(|header| header.decode())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the header RLP of a block.
|
/// Get the header RLP of a block.
|
||||||
fn block_header_data(&self, hash: &H256) -> Option<Bytes>;
|
fn block_header_data(&self, hash: &H256) -> Option<encoded::Header>;
|
||||||
|
|
||||||
/// Get the block body (uncles and transactions).
|
/// Get the block body (uncles and transactions).
|
||||||
fn block_body(&self, hash: &H256) -> Option<Bytes>;
|
fn block_body(&self, hash: &H256) -> Option<encoded::Body>;
|
||||||
|
|
||||||
/// Get a list of uncles for a given block.
|
/// Get a list of uncles for a given block.
|
||||||
/// Returns None if block does not exist.
|
/// Returns None if block does not exist.
|
||||||
fn uncles(&self, hash: &H256) -> Option<Vec<Header>> {
|
fn uncles(&self, hash: &H256) -> Option<Vec<Header>> {
|
||||||
self.block_body(hash).map(|bytes| BodyView::new(&bytes).uncles())
|
self.block_body(hash).map(|body| body.uncles())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a list of uncle hashes for a given block.
|
/// Get a list of uncle hashes for a given block.
|
||||||
/// Returns None if block does not exist.
|
/// Returns None if block does not exist.
|
||||||
fn uncle_hashes(&self, hash: &H256) -> Option<Vec<H256>> {
|
fn uncle_hashes(&self, hash: &H256) -> Option<Vec<H256>> {
|
||||||
self.block_body(hash).map(|bytes| BodyView::new(&bytes).uncle_hashes())
|
self.block_body(hash).map(|body| body.uncle_hashes())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the number of given block's hash.
|
/// Get the number of given block's hash.
|
||||||
@ -109,8 +110,8 @@ pub trait BlockProvider {
|
|||||||
/// Get transaction with given transaction hash.
|
/// Get transaction with given transaction hash.
|
||||||
fn transaction(&self, address: &TransactionAddress) -> Option<LocalizedTransaction> {
|
fn transaction(&self, address: &TransactionAddress) -> Option<LocalizedTransaction> {
|
||||||
self.block_body(&address.block_hash)
|
self.block_body(&address.block_hash)
|
||||||
.and_then(|bytes| self.block_number(&address.block_hash)
|
.and_then(|body| self.block_number(&address.block_hash)
|
||||||
.and_then(|n| BodyView::new(&bytes).localized_transaction_at(&address.block_hash, n, address.index)))
|
.and_then(|n| body.view().localized_transaction_at(&address.block_hash, n, address.index)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get transaction receipt.
|
/// Get transaction receipt.
|
||||||
@ -122,8 +123,8 @@ pub trait BlockProvider {
|
|||||||
/// Returns None if block does not exist.
|
/// Returns None if block does not exist.
|
||||||
fn transactions(&self, hash: &H256) -> Option<Vec<LocalizedTransaction>> {
|
fn transactions(&self, hash: &H256) -> Option<Vec<LocalizedTransaction>> {
|
||||||
self.block_body(hash)
|
self.block_body(hash)
|
||||||
.and_then(|bytes| self.block_number(hash)
|
.and_then(|body| self.block_number(hash)
|
||||||
.map(|n| BodyView::new(&bytes).localized_transactions(hash, n)))
|
.map(|n| body.view().localized_transactions(hash, n)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns reference to genesis hash.
|
/// Returns reference to genesis hash.
|
||||||
@ -224,27 +225,27 @@ impl BlockProvider for BlockChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get raw block data
|
/// Get raw block data
|
||||||
fn block(&self, hash: &H256) -> Option<Bytes> {
|
fn block(&self, hash: &H256) -> Option<encoded::Block> {
|
||||||
match (self.block_header_data(hash), self.block_body(hash)) {
|
match (self.block_header_data(hash), self.block_body(hash)) {
|
||||||
(Some(header), Some(body)) => {
|
(Some(header), Some(body)) => {
|
||||||
let mut block = RlpStream::new_list(3);
|
let mut block = RlpStream::new_list(3);
|
||||||
let body_rlp = Rlp::new(&body);
|
let body_rlp = body.rlp();
|
||||||
block.append_raw(&header, 1);
|
block.append_raw(header.rlp().as_raw(), 1);
|
||||||
block.append_raw(body_rlp.at(0).as_raw(), 1);
|
block.append_raw(body_rlp.at(0).as_raw(), 1);
|
||||||
block.append_raw(body_rlp.at(1).as_raw(), 1);
|
block.append_raw(body_rlp.at(1).as_raw(), 1);
|
||||||
Some(block.out())
|
Some(encoded::Block::new(block.out()))
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get block header data
|
/// Get block header data
|
||||||
fn block_header_data(&self, hash: &H256) -> Option<Bytes> {
|
fn block_header_data(&self, hash: &H256) -> Option<encoded::Header> {
|
||||||
// Check cache first
|
// Check cache first
|
||||||
{
|
{
|
||||||
let read = self.block_headers.read();
|
let read = self.block_headers.read();
|
||||||
if let Some(v) = read.get(hash) {
|
if let Some(v) = read.get(hash) {
|
||||||
return Some(v.clone());
|
return Some(encoded::Header::new(v.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,7 +253,9 @@ impl BlockProvider for BlockChain {
|
|||||||
{
|
{
|
||||||
let best_block = self.best_block.read();
|
let best_block = self.best_block.read();
|
||||||
if &best_block.hash == hash {
|
if &best_block.hash == hash {
|
||||||
return Some(Rlp::new(&best_block.block).at(0).as_raw().to_vec());
|
return Some(encoded::Header::new(
|
||||||
|
Rlp::new(&best_block.block).at(0).as_raw().to_vec()
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +268,7 @@ impl BlockProvider for BlockChain {
|
|||||||
let bytes: Bytes = UntrustedRlp::new(&b).decompress(RlpType::Blocks).to_vec();
|
let bytes: Bytes = UntrustedRlp::new(&b).decompress(RlpType::Blocks).to_vec();
|
||||||
let mut write = self.block_headers.write();
|
let mut write = self.block_headers.write();
|
||||||
write.insert(hash.clone(), bytes.clone());
|
write.insert(hash.clone(), bytes.clone());
|
||||||
Some(bytes)
|
Some(encoded::Header::new(bytes))
|
||||||
},
|
},
|
||||||
None => None
|
None => None
|
||||||
};
|
};
|
||||||
@ -275,12 +278,12 @@ impl BlockProvider for BlockChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get block body data
|
/// Get block body data
|
||||||
fn block_body(&self, hash: &H256) -> Option<Bytes> {
|
fn block_body(&self, hash: &H256) -> Option<encoded::Body> {
|
||||||
// Check cache first
|
// Check cache first
|
||||||
{
|
{
|
||||||
let read = self.block_bodies.read();
|
let read = self.block_bodies.read();
|
||||||
if let Some(v) = read.get(hash) {
|
if let Some(v) = read.get(hash) {
|
||||||
return Some(v.clone());
|
return Some(encoded::Body::new(v.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +291,7 @@ impl BlockProvider for BlockChain {
|
|||||||
{
|
{
|
||||||
let best_block = self.best_block.read();
|
let best_block = self.best_block.read();
|
||||||
if &best_block.hash == hash {
|
if &best_block.hash == hash {
|
||||||
return Some(Self::block_to_body(&best_block.block));
|
return Some(encoded::Body::new(Self::block_to_body(&best_block.block)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +304,7 @@ impl BlockProvider for BlockChain {
|
|||||||
let bytes: Bytes = UntrustedRlp::new(&b).decompress(RlpType::Blocks).to_vec();
|
let bytes: Bytes = UntrustedRlp::new(&b).decompress(RlpType::Blocks).to_vec();
|
||||||
let mut write = self.block_bodies.write();
|
let mut write = self.block_bodies.write();
|
||||||
write.insert(hash.clone(), bytes.clone());
|
write.insert(hash.clone(), bytes.clone());
|
||||||
Some(bytes)
|
Some(encoded::Body::new(bytes))
|
||||||
},
|
},
|
||||||
None => None
|
None => None
|
||||||
};
|
};
|
||||||
@ -358,7 +361,7 @@ impl BlockProvider for BlockChain {
|
|||||||
let mut logs = blocks.into_iter()
|
let mut logs = blocks.into_iter()
|
||||||
.filter_map(|number| self.block_hash(number).map(|hash| (number, hash)))
|
.filter_map(|number| self.block_hash(number).map(|hash| (number, hash)))
|
||||||
.filter_map(|(number, hash)| self.block_receipts(&hash).map(|r| (number, hash, r.receipts)))
|
.filter_map(|(number, hash)| self.block_receipts(&hash).map(|r| (number, hash, r.receipts)))
|
||||||
.filter_map(|(number, hash, receipts)| self.block_body(&hash).map(|ref b| (number, hash, receipts, BodyView::new(b).transaction_hashes())))
|
.filter_map(|(number, hash, receipts)| self.block_body(&hash).map(|ref b| (number, hash, receipts, b.transaction_hashes())))
|
||||||
.flat_map(|(number, hash, mut receipts, mut hashes)| {
|
.flat_map(|(number, hash, mut receipts, mut hashes)| {
|
||||||
if receipts.len() != hashes.len() {
|
if receipts.len() != hashes.len() {
|
||||||
warn!("Block {} ({}) has different number of receipts ({}) to transactions ({}). Database corrupt?", number, hash, receipts.len(), hashes.len());
|
warn!("Block {} ({}) has different number of receipts ({}) to transactions ({}). Database corrupt?", number, hash, receipts.len(), hashes.len());
|
||||||
@ -484,7 +487,7 @@ impl BlockChain {
|
|||||||
// Fetch best block details
|
// Fetch best block details
|
||||||
let best_block_number = bc.block_number(&best_block_hash).unwrap();
|
let best_block_number = bc.block_number(&best_block_hash).unwrap();
|
||||||
let best_block_total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty;
|
let best_block_total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty;
|
||||||
let best_block_rlp = bc.block(&best_block_hash).unwrap();
|
let best_block_rlp = bc.block(&best_block_hash).unwrap().into_inner();
|
||||||
|
|
||||||
let raw_first = bc.db.get(db::COL_EXTRA, b"first").unwrap().map(|v| v.to_vec());
|
let raw_first = bc.db.get(db::COL_EXTRA, b"first").unwrap().map(|v| v.to_vec());
|
||||||
let mut best_ancient = bc.db.get(db::COL_EXTRA, b"ancient").unwrap().map(|h| H256::from_slice(&h));
|
let mut best_ancient = bc.db.get(db::COL_EXTRA, b"ancient").unwrap().map(|h| H256::from_slice(&h));
|
||||||
@ -578,7 +581,7 @@ impl BlockChain {
|
|||||||
batch.put(db::COL_EXTRA, b"best", &hash);
|
batch.put(db::COL_EXTRA, b"best", &hash);
|
||||||
|
|
||||||
let best_block_total_difficulty = self.block_details(&hash).unwrap().total_difficulty;
|
let best_block_total_difficulty = self.block_details(&hash).unwrap().total_difficulty;
|
||||||
let best_block_rlp = self.block(&hash).unwrap();
|
let best_block_rlp = self.block(&hash).unwrap().into_inner();
|
||||||
|
|
||||||
let mut best_block = self.best_block.write();
|
let mut best_block = self.best_block.write();
|
||||||
*best_block = BestBlock {
|
*best_block = BestBlock {
|
||||||
@ -862,7 +865,7 @@ impl BlockChain {
|
|||||||
let number = header.number();
|
let number = header.number();
|
||||||
let parent_hash = header.parent_hash();
|
let parent_hash = header.parent_hash();
|
||||||
let parent_details = self.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash));
|
let parent_details = self.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash));
|
||||||
let is_new_best = self.engine.is_new_best_block(self.best_block_total_difficulty(), HeaderView::new(&self.best_block_header()), &parent_details, header);
|
let is_new_best = self.engine.is_new_best_block(self.best_block_total_difficulty(), self.best_block_header().view(), &parent_details, header);
|
||||||
|
|
||||||
BlockInfo {
|
BlockInfo {
|
||||||
hash: hash,
|
hash: hash,
|
||||||
@ -1108,8 +1111,8 @@ impl BlockChain {
|
|||||||
BlockLocation::BranchBecomingCanonChain(ref data) => {
|
BlockLocation::BranchBecomingCanonChain(ref data) => {
|
||||||
let addresses = data.enacted.iter()
|
let addresses = data.enacted.iter()
|
||||||
.flat_map(|hash| {
|
.flat_map(|hash| {
|
||||||
let bytes = self.block_body(hash).expect("Enacted block must be in database.");
|
let body = self.block_body(hash).expect("Enacted block must be in database.");
|
||||||
let hashes = BodyView::new(&bytes).transaction_hashes();
|
let hashes = body.transaction_hashes();
|
||||||
hashes.into_iter()
|
hashes.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, tx_hash)| (tx_hash, Some(TransactionAddress {
|
.map(|(i, tx_hash)| (tx_hash, Some(TransactionAddress {
|
||||||
@ -1129,8 +1132,8 @@ impl BlockChain {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let retracted = data.retracted.iter().flat_map(|hash| {
|
let retracted = data.retracted.iter().flat_map(|hash| {
|
||||||
let bytes = self.block_body(hash).expect("Retracted block must be in database.");
|
let body = self.block_body(hash).expect("Retracted block must be in database.");
|
||||||
let hashes = BodyView::new(&bytes).transaction_hashes();
|
let hashes = body.transaction_hashes();
|
||||||
hashes.into_iter().map(|hash| (hash, None)).collect::<HashMap<H256, Option<TransactionAddress>>>()
|
hashes.into_iter().map(|hash| (hash, None)).collect::<HashMap<H256, Option<TransactionAddress>>>()
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1179,7 +1182,7 @@ impl BlockChain {
|
|||||||
|
|
||||||
let mut blooms: Vec<bc::Bloom> = data.enacted.iter()
|
let mut blooms: Vec<bc::Bloom> = data.enacted.iter()
|
||||||
.map(|hash| self.block_header_data(hash).unwrap())
|
.map(|hash| self.block_header_data(hash).unwrap())
|
||||||
.map(|bytes| HeaderView::new(&bytes).log_bloom())
|
.map(|h| h.log_bloom())
|
||||||
.map(Bloom::from)
|
.map(Bloom::from)
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
.collect();
|
.collect();
|
||||||
@ -1212,9 +1215,10 @@ impl BlockChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get best block header
|
/// Get best block header
|
||||||
pub fn best_block_header(&self) -> Bytes {
|
pub fn best_block_header(&self) -> encoded::Header {
|
||||||
let block = self.best_block.read();
|
let block = self.best_block.read();
|
||||||
BlockView::new(&block.block).header_view().rlp().as_raw().to_vec()
|
let raw = BlockView::new(&block.block).header_view().rlp().as_raw().to_vec();
|
||||||
|
encoded::Header::new(raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get current cache size.
|
/// Get current cache size.
|
||||||
|
@ -32,7 +32,7 @@ use util::kvdb::*;
|
|||||||
|
|
||||||
// other
|
// other
|
||||||
use io::*;
|
use io::*;
|
||||||
use views::{HeaderView, BodyView, BlockView};
|
use views::BlockView;
|
||||||
use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError};
|
use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError};
|
||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
use state::{State, CleanupMode};
|
use state::{State, CleanupMode};
|
||||||
@ -67,10 +67,11 @@ use evm::{Factory as EvmFactory, Schedule};
|
|||||||
use miner::{Miner, MinerService};
|
use miner::{Miner, MinerService};
|
||||||
use snapshot::{self, io as snapshot_io};
|
use snapshot::{self, io as snapshot_io};
|
||||||
use factory::Factories;
|
use factory::Factories;
|
||||||
use rlp::{decode, View, UntrustedRlp};
|
use rlp::{View, UntrustedRlp};
|
||||||
use state_db::StateDB;
|
use state_db::StateDB;
|
||||||
use rand::OsRng;
|
use rand::OsRng;
|
||||||
use client::registry::Registry;
|
use client::registry::Registry;
|
||||||
|
use encoded;
|
||||||
|
|
||||||
// re-export
|
// re-export
|
||||||
pub use types::blockchain_info::BlockChainInfo;
|
pub use types::blockchain_info::BlockChainInfo;
|
||||||
@ -303,17 +304,16 @@ impl Client {
|
|||||||
|
|
||||||
/// The env info as of the best block.
|
/// The env info as of the best block.
|
||||||
fn latest_env_info(&self) -> EnvInfo {
|
fn latest_env_info(&self) -> EnvInfo {
|
||||||
let header_data = self.best_block_header();
|
let header = self.best_block_header();
|
||||||
let view = HeaderView::new(&header_data);
|
|
||||||
|
|
||||||
EnvInfo {
|
EnvInfo {
|
||||||
number: view.number(),
|
number: header.number(),
|
||||||
author: view.author(),
|
author: header.author(),
|
||||||
timestamp: view.timestamp(),
|
timestamp: header.timestamp(),
|
||||||
difficulty: view.difficulty(),
|
difficulty: header.difficulty(),
|
||||||
last_hashes: self.build_last_hashes(view.hash()),
|
last_hashes: self.build_last_hashes(header.hash()),
|
||||||
gas_used: U256::default(),
|
gas_used: U256::default(),
|
||||||
gas_limit: view.gas_limit(),
|
gas_limit: header.gas_limit(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -642,8 +642,7 @@ impl Client {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let root = HeaderView::new(&header).state_root();
|
let root = header.state_root();
|
||||||
|
|
||||||
State::from_existing(db, root, self.engine.account_start_nonce(), self.factories.clone()).ok()
|
State::from_existing(db, root, self.engine.account_start_nonce(), self.factories.clone()).ok()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -666,7 +665,6 @@ impl Client {
|
|||||||
/// Get a copy of the best block's state.
|
/// Get a copy of the best block's state.
|
||||||
pub fn state(&self) -> State {
|
pub fn state(&self) -> State {
|
||||||
let header = self.best_block_header();
|
let header = self.best_block_header();
|
||||||
let header = HeaderView::new(&header);
|
|
||||||
State::from_existing(
|
State::from_existing(
|
||||||
self.state_db.lock().boxed_clone_canon(&header.hash()),
|
self.state_db.lock().boxed_clone_canon(&header.hash()),
|
||||||
header.state_root(),
|
header.state_root(),
|
||||||
@ -843,13 +841,12 @@ impl snapshot::DatabaseRestore for Client {
|
|||||||
impl BlockChainClient for Client {
|
impl BlockChainClient for Client {
|
||||||
fn call(&self, t: &SignedTransaction, block: BlockId, analytics: CallAnalytics) -> Result<Executed, CallError> {
|
fn call(&self, t: &SignedTransaction, block: BlockId, analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||||
let header = self.block_header(block).ok_or(CallError::StatePruned)?;
|
let header = self.block_header(block).ok_or(CallError::StatePruned)?;
|
||||||
let view = HeaderView::new(&header);
|
let last_hashes = self.build_last_hashes(header.parent_hash());
|
||||||
let last_hashes = self.build_last_hashes(view.parent_hash());
|
|
||||||
let env_info = EnvInfo {
|
let env_info = EnvInfo {
|
||||||
number: view.number(),
|
number: header.number(),
|
||||||
author: view.author(),
|
author: header.author(),
|
||||||
timestamp: view.timestamp(),
|
timestamp: header.timestamp(),
|
||||||
difficulty: view.difficulty(),
|
difficulty: header.difficulty(),
|
||||||
last_hashes: last_hashes,
|
last_hashes: last_hashes,
|
||||||
gas_used: U256::zero(),
|
gas_used: U256::zero(),
|
||||||
gas_limit: U256::max_value(),
|
gas_limit: U256::max_value(),
|
||||||
@ -879,26 +876,25 @@ impl BlockChainClient for Client {
|
|||||||
|
|
||||||
fn replay(&self, id: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError> {
|
fn replay(&self, id: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||||
let address = self.transaction_address(id).ok_or(CallError::TransactionNotFound)?;
|
let address = self.transaction_address(id).ok_or(CallError::TransactionNotFound)?;
|
||||||
let header_data = self.block_header(BlockId::Hash(address.block_hash)).ok_or(CallError::StatePruned)?;
|
let header = self.block_header(BlockId::Hash(address.block_hash)).ok_or(CallError::StatePruned)?;
|
||||||
let body_data = self.block_body(BlockId::Hash(address.block_hash)).ok_or(CallError::StatePruned)?;
|
let body = self.block_body(BlockId::Hash(address.block_hash)).ok_or(CallError::StatePruned)?;
|
||||||
let mut state = self.state_at_beginning(BlockId::Hash(address.block_hash)).ok_or(CallError::StatePruned)?;
|
let mut state = self.state_at_beginning(BlockId::Hash(address.block_hash)).ok_or(CallError::StatePruned)?;
|
||||||
let txs = BodyView::new(&body_data).transactions();
|
let txs = body.transactions();
|
||||||
|
|
||||||
if address.index >= txs.len() {
|
if address.index >= txs.len() {
|
||||||
return Err(CallError::TransactionNotFound);
|
return Err(CallError::TransactionNotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||||
let view = HeaderView::new(&header_data);
|
let last_hashes = self.build_last_hashes(header.hash());
|
||||||
let last_hashes = self.build_last_hashes(view.hash());
|
|
||||||
let mut env_info = EnvInfo {
|
let mut env_info = EnvInfo {
|
||||||
number: view.number(),
|
number: header.number(),
|
||||||
author: view.author(),
|
author: header.author(),
|
||||||
timestamp: view.timestamp(),
|
timestamp: header.timestamp(),
|
||||||
difficulty: view.difficulty(),
|
difficulty: header.difficulty(),
|
||||||
last_hashes: last_hashes,
|
last_hashes: last_hashes,
|
||||||
gas_used: U256::default(),
|
gas_used: U256::default(),
|
||||||
gas_limit: view.gas_limit(),
|
gas_limit: header.gas_limit(),
|
||||||
};
|
};
|
||||||
for t in txs.iter().take(address.index) {
|
for t in txs.iter().take(address.index) {
|
||||||
match Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(t, Default::default()) {
|
match Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(t, Default::default()) {
|
||||||
@ -959,11 +955,11 @@ impl BlockChainClient for Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn best_block_header(&self) -> Bytes {
|
fn best_block_header(&self) -> encoded::Header {
|
||||||
self.chain.read().best_block_header()
|
self.chain.read().best_block_header()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_header(&self, id: BlockId) -> Option<Bytes> {
|
fn block_header(&self, id: BlockId) -> Option<::encoded::Header> {
|
||||||
let chain = self.chain.read();
|
let chain = self.chain.read();
|
||||||
Self::block_hash(&chain, id).and_then(|hash| chain.block_header_data(&hash))
|
Self::block_hash(&chain, id).and_then(|hash| chain.block_header_data(&hash))
|
||||||
}
|
}
|
||||||
@ -977,15 +973,15 @@ impl BlockChainClient for Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_body(&self, id: BlockId) -> Option<Bytes> {
|
fn block_body(&self, id: BlockId) -> Option<encoded::Body> {
|
||||||
let chain = self.chain.read();
|
let chain = self.chain.read();
|
||||||
Self::block_hash(&chain, id).and_then(|hash| chain.block_body(&hash))
|
Self::block_hash(&chain, id).and_then(|hash| chain.block_body(&hash))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block(&self, id: BlockId) -> Option<Bytes> {
|
fn block(&self, id: BlockId) -> Option<encoded::Block> {
|
||||||
if let BlockId::Pending = id {
|
if let BlockId::Pending = id {
|
||||||
if let Some(block) = self.miner.pending_block() {
|
if let Some(block) = self.miner.pending_block() {
|
||||||
return Some(block.rlp_bytes(Seal::Without));
|
return Some(encoded::Block::new(block.rlp_bytes(Seal::Without)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let chain = self.chain.read();
|
let chain = self.chain.read();
|
||||||
@ -1128,9 +1124,10 @@ impl BlockChainClient for Client {
|
|||||||
self.transaction_address(id).map(|addr| addr.block_hash)
|
self.transaction_address(id).map(|addr| addr.block_hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uncle(&self, id: UncleId) -> Option<Bytes> {
|
fn uncle(&self, id: UncleId) -> Option<encoded::Header> {
|
||||||
let index = id.position;
|
let index = id.position;
|
||||||
self.block_body(id.block).and_then(|body| BodyView::new(&body).uncle_rlp_at(index))
|
self.block_body(id.block).and_then(|body| body.view().uncle_rlp_at(index))
|
||||||
|
.map(encoded::Header::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt> {
|
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt> {
|
||||||
@ -1138,8 +1135,8 @@ impl BlockChainClient for Client {
|
|||||||
self.transaction_address(id)
|
self.transaction_address(id)
|
||||||
.and_then(|address| chain.block_number(&address.block_hash).and_then(|block_number| {
|
.and_then(|address| chain.block_number(&address.block_hash).and_then(|block_number| {
|
||||||
let t = chain.block_body(&address.block_hash)
|
let t = chain.block_body(&address.block_hash)
|
||||||
.and_then(|block| {
|
.and_then(|body| {
|
||||||
BodyView::new(&block).localized_transaction_at(&address.block_hash, block_number, address.index)
|
body.view().localized_transaction_at(&address.block_hash, block_number, address.index)
|
||||||
});
|
});
|
||||||
|
|
||||||
let tx_and_sender = t.and_then(|tx| tx.sender().ok().map(|sender| (tx, sender)));
|
let tx_and_sender = t.and_then(|tx| tx.sender().ok().map(|sender| (tx, sender)));
|
||||||
@ -1360,13 +1357,12 @@ impl BlockChainClient for Client {
|
|||||||
|
|
||||||
fn block_extra_info(&self, id: BlockId) -> Option<BTreeMap<String, String>> {
|
fn block_extra_info(&self, id: BlockId) -> Option<BTreeMap<String, String>> {
|
||||||
self.block_header(id)
|
self.block_header(id)
|
||||||
.map(|block| decode(&block))
|
.map(|header| self.engine.extra_info(&header.decode()))
|
||||||
.map(|header| self.engine.extra_info(&header))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uncle_extra_info(&self, id: UncleId) -> Option<BTreeMap<String, String>> {
|
fn uncle_extra_info(&self, id: UncleId) -> Option<BTreeMap<String, String>> {
|
||||||
self.uncle(id)
|
self.uncle(id)
|
||||||
.map(|header| self.engine.extra_info(&decode(&header)))
|
.map(|header| self.engine.extra_info(&header.decode()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pruning_info(&self) -> PruningInfo {
|
fn pruning_info(&self) -> PruningInfo {
|
||||||
|
@ -39,7 +39,6 @@ use miner::{Miner, MinerService, TransactionImportResult};
|
|||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use types::mode::Mode;
|
use types::mode::Mode;
|
||||||
use types::pruning_info::PruningInfo;
|
use types::pruning_info::PruningInfo;
|
||||||
use views::BlockView;
|
|
||||||
|
|
||||||
use verification::queue::QueueInfo;
|
use verification::queue::QueueInfo;
|
||||||
use block::{OpenBlock, SealedBlock};
|
use block::{OpenBlock, SealedBlock};
|
||||||
@ -47,6 +46,7 @@ use executive::Executed;
|
|||||||
use error::CallError;
|
use error::CallError;
|
||||||
use trace::LocalizedTrace;
|
use trace::LocalizedTrace;
|
||||||
use state_db::StateDB;
|
use state_db::StateDB;
|
||||||
|
use encoded;
|
||||||
|
|
||||||
/// Test client.
|
/// Test client.
|
||||||
pub struct TestBlockChainClient {
|
pub struct TestBlockChainClient {
|
||||||
@ -263,7 +263,7 @@ impl TestBlockChainClient {
|
|||||||
/// Make a bad block by setting invalid extra data.
|
/// Make a bad block by setting invalid extra data.
|
||||||
pub fn corrupt_block(&self, n: BlockNumber) {
|
pub fn corrupt_block(&self, n: BlockNumber) {
|
||||||
let hash = self.block_hash(BlockId::Number(n)).unwrap();
|
let hash = self.block_hash(BlockId::Number(n)).unwrap();
|
||||||
let mut header: BlockHeader = decode(&self.block_header(BlockId::Number(n)).unwrap());
|
let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode();
|
||||||
header.set_extra_data(b"This extra data is way too long to be considered valid".to_vec());
|
header.set_extra_data(b"This extra data is way too long to be considered valid".to_vec());
|
||||||
let mut rlp = RlpStream::new_list(3);
|
let mut rlp = RlpStream::new_list(3);
|
||||||
rlp.append(&header);
|
rlp.append(&header);
|
||||||
@ -275,7 +275,7 @@ impl TestBlockChainClient {
|
|||||||
/// Make a bad block by setting invalid parent hash.
|
/// Make a bad block by setting invalid parent hash.
|
||||||
pub fn corrupt_block_parent(&self, n: BlockNumber) {
|
pub fn corrupt_block_parent(&self, n: BlockNumber) {
|
||||||
let hash = self.block_hash(BlockId::Number(n)).unwrap();
|
let hash = self.block_hash(BlockId::Number(n)).unwrap();
|
||||||
let mut header: BlockHeader = decode(&self.block_header(BlockId::Number(n)).unwrap());
|
let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode();
|
||||||
header.set_parent_hash(H256::from(42));
|
header.set_parent_hash(H256::from(42));
|
||||||
let mut rlp = RlpStream::new_list(3);
|
let mut rlp = RlpStream::new_list(3);
|
||||||
rlp.append(&header);
|
rlp.append(&header);
|
||||||
@ -458,7 +458,7 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
None // Simple default.
|
None // Simple default.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uncle(&self, _id: UncleId) -> Option<Bytes> {
|
fn uncle(&self, _id: UncleId) -> Option<encoded::Header> {
|
||||||
None // Simple default.
|
None // Simple default.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,34 +487,39 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn best_block_header(&self) -> Bytes {
|
fn best_block_header(&self) -> encoded::Header {
|
||||||
self.block_header(BlockId::Hash(self.chain_info().best_block_hash)).expect("Best block always have header.")
|
self.block_header(BlockId::Hash(self.chain_info().best_block_hash))
|
||||||
|
.expect("Best block always has header.")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_header(&self, id: BlockId) -> Option<Bytes> {
|
fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
|
||||||
self.block_hash(id).and_then(|hash| self.blocks.read().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec()))
|
self.block_hash(id)
|
||||||
|
.and_then(|hash| self.blocks.read().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec()))
|
||||||
|
.map(encoded::Header::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_number(&self, _id: BlockId) -> Option<BlockNumber> {
|
fn block_number(&self, _id: BlockId) -> Option<BlockNumber> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_body(&self, id: BlockId) -> Option<Bytes> {
|
fn block_body(&self, id: BlockId) -> Option<encoded::Body> {
|
||||||
self.block_hash(id).and_then(|hash| self.blocks.read().get(&hash).map(|r| {
|
self.block_hash(id).and_then(|hash| self.blocks.read().get(&hash).map(|r| {
|
||||||
let mut stream = RlpStream::new_list(2);
|
let mut stream = RlpStream::new_list(2);
|
||||||
stream.append_raw(Rlp::new(r).at(1).as_raw(), 1);
|
stream.append_raw(Rlp::new(r).at(1).as_raw(), 1);
|
||||||
stream.append_raw(Rlp::new(r).at(2).as_raw(), 1);
|
stream.append_raw(Rlp::new(r).at(2).as_raw(), 1);
|
||||||
stream.out()
|
encoded::Body::new(stream.out())
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block(&self, id: BlockId) -> Option<Bytes> {
|
fn block(&self, id: BlockId) -> Option<encoded::Block> {
|
||||||
self.block_hash(id).and_then(|hash| self.blocks.read().get(&hash).cloned())
|
self.block_hash(id)
|
||||||
|
.and_then(|hash| self.blocks.read().get(&hash).cloned())
|
||||||
|
.map(encoded::Block::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_extra_info(&self, id: BlockId) -> Option<BTreeMap<String, String>> {
|
fn block_extra_info(&self, id: BlockId) -> Option<BTreeMap<String, String>> {
|
||||||
self.block(id)
|
self.block(id)
|
||||||
.map(|block| BlockView::new(&block).header())
|
.map(|block| block.view().header())
|
||||||
.map(|header| self.spec.engine.extra_info(&header))
|
.map(|header| self.spec.engine.extra_info(&header))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@ use header::{BlockNumber};
|
|||||||
use transaction::{LocalizedTransaction, SignedTransaction, PendingTransaction};
|
use transaction::{LocalizedTransaction, SignedTransaction, PendingTransaction};
|
||||||
use log_entry::LocalizedLogEntry;
|
use log_entry::LocalizedLogEntry;
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
use views::{BlockView};
|
|
||||||
use error::{ImportResult, CallError};
|
use error::{ImportResult, CallError};
|
||||||
use receipt::LocalizedReceipt;
|
use receipt::LocalizedReceipt;
|
||||||
use trace::LocalizedTrace;
|
use trace::LocalizedTrace;
|
||||||
@ -40,6 +39,7 @@ use types::blockchain_info::BlockChainInfo;
|
|||||||
use types::block_status::BlockStatus;
|
use types::block_status::BlockStatus;
|
||||||
use types::mode::Mode;
|
use types::mode::Mode;
|
||||||
use types::pruning_info::PruningInfo;
|
use types::pruning_info::PruningInfo;
|
||||||
|
use encoded;
|
||||||
|
|
||||||
#[ipc(client_ident="RemoteClient")]
|
#[ipc(client_ident="RemoteClient")]
|
||||||
/// Blockchain database client. Owns and manages a blockchain and a block queue.
|
/// Blockchain database client. Owns and manages a blockchain and a block queue.
|
||||||
@ -50,17 +50,17 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
fn keep_alive(&self) {}
|
fn keep_alive(&self) {}
|
||||||
|
|
||||||
/// Get raw block header data by block id.
|
/// Get raw block header data by block id.
|
||||||
fn block_header(&self, id: BlockId) -> Option<Bytes>;
|
fn block_header(&self, id: BlockId) -> Option<encoded::Header>;
|
||||||
|
|
||||||
/// Look up the block number for the given block ID.
|
/// Look up the block number for the given block ID.
|
||||||
fn block_number(&self, id: BlockId) -> Option<BlockNumber>;
|
fn block_number(&self, id: BlockId) -> Option<BlockNumber>;
|
||||||
|
|
||||||
/// Get raw block body data by block id.
|
/// Get raw block body data by block id.
|
||||||
/// Block body is an RLP list of two items: uncles and transactions.
|
/// Block body is an RLP list of two items: uncles and transactions.
|
||||||
fn block_body(&self, id: BlockId) -> Option<Bytes>;
|
fn block_body(&self, id: BlockId) -> Option<encoded::Body>;
|
||||||
|
|
||||||
/// Get raw block data by block header hash.
|
/// Get raw block data by block header hash.
|
||||||
fn block(&self, id: BlockId) -> Option<Bytes>;
|
fn block(&self, id: BlockId) -> Option<encoded::Block>;
|
||||||
|
|
||||||
/// Get block status by block header hash.
|
/// Get block status by block header hash.
|
||||||
fn block_status(&self, id: BlockId) -> BlockStatus;
|
fn block_status(&self, id: BlockId) -> BlockStatus;
|
||||||
@ -136,7 +136,7 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
fn transaction_block(&self, id: TransactionId) -> Option<H256>;
|
fn transaction_block(&self, id: TransactionId) -> Option<H256>;
|
||||||
|
|
||||||
/// Get uncle with given id.
|
/// Get uncle with given id.
|
||||||
fn uncle(&self, id: UncleId) -> Option<Bytes>;
|
fn uncle(&self, id: UncleId) -> Option<encoded::Header>;
|
||||||
|
|
||||||
/// Get transaction receipt with given hash.
|
/// Get transaction receipt with given hash.
|
||||||
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt>;
|
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt>;
|
||||||
@ -173,7 +173,7 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
fn additional_params(&self) -> BTreeMap<String, String>;
|
fn additional_params(&self) -> BTreeMap<String, String>;
|
||||||
|
|
||||||
/// Get the best block header.
|
/// Get the best block header.
|
||||||
fn best_block_header(&self) -> Bytes;
|
fn best_block_header(&self) -> encoded::Header;
|
||||||
|
|
||||||
/// Returns numbers of blocks containing given bloom.
|
/// Returns numbers of blocks containing given bloom.
|
||||||
fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option<Vec<BlockNumber>>;
|
fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option<Vec<BlockNumber>>;
|
||||||
@ -220,8 +220,7 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
let mut corpus = Vec::new();
|
let mut corpus = Vec::new();
|
||||||
while corpus.is_empty() {
|
while corpus.is_empty() {
|
||||||
for _ in 0..sample_size {
|
for _ in 0..sample_size {
|
||||||
let block_bytes = self.block(BlockId::Hash(h)).expect("h is either the best_block_hash or an ancestor; qed");
|
let block = self.block(BlockId::Hash(h)).expect("h is either the best_block_hash or an ancestor; qed");
|
||||||
let block = BlockView::new(&block_bytes);
|
|
||||||
let header = block.header_view();
|
let header = block.header_view();
|
||||||
if header.number() == 0 {
|
if header.number() == 0 {
|
||||||
return corpus;
|
return corpus;
|
||||||
|
@ -20,8 +20,6 @@ use std::time::{Instant, Duration};
|
|||||||
use util::*;
|
use util::*;
|
||||||
use util::using_queue::{UsingQueue, GetAction};
|
use util::using_queue::{UsingQueue, GetAction};
|
||||||
use account_provider::{AccountProvider, Error as AccountError};
|
use account_provider::{AccountProvider, Error as AccountError};
|
||||||
use views::{BlockView, HeaderView};
|
|
||||||
use header::Header;
|
|
||||||
use state::{State, CleanupMode};
|
use state::{State, CleanupMode};
|
||||||
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockId, CallAnalytics, TransactionId};
|
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockId, CallAnalytics, TransactionId};
|
||||||
use client::TransactionImportResult;
|
use client::TransactionImportResult;
|
||||||
@ -536,7 +534,7 @@ impl Miner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_gas_limit(&self, chain: &MiningBlockChainClient) {
|
fn update_gas_limit(&self, chain: &MiningBlockChainClient) {
|
||||||
let gas_limit = HeaderView::new(&chain.best_block_header()).gas_limit();
|
let gas_limit = chain.best_block_header().gas_limit();
|
||||||
let mut queue = self.transaction_queue.lock();
|
let mut queue = self.transaction_queue.lock();
|
||||||
queue.set_gas_limit(gas_limit);
|
queue.set_gas_limit(gas_limit);
|
||||||
if let GasLimit::Auto = self.options.tx_queue_gas_limit {
|
if let GasLimit::Auto = self.options.tx_queue_gas_limit {
|
||||||
@ -598,7 +596,7 @@ impl Miner {
|
|||||||
|
|
||||||
let schedule = chain.latest_schedule();
|
let schedule = chain.latest_schedule();
|
||||||
let gas_required = |tx: &SignedTransaction| tx.gas_required(&schedule).into();
|
let gas_required = |tx: &SignedTransaction| tx.gas_required(&schedule).into();
|
||||||
let best_block_header: Header = ::rlp::decode(&chain.best_block_header());
|
let best_block_header = chain.best_block_header().decode();
|
||||||
transactions.into_iter()
|
transactions.into_iter()
|
||||||
.map(|tx| {
|
.map(|tx| {
|
||||||
if chain.transaction_block(TransactionId::Hash(tx.hash())).is_some() {
|
if chain.transaction_block(TransactionId::Hash(tx.hash())).is_some() {
|
||||||
@ -1127,7 +1125,6 @@ impl MinerService for Miner {
|
|||||||
.map(|hash| {
|
.map(|hash| {
|
||||||
let block = chain.block(BlockId::Hash(*hash))
|
let block = chain.block(BlockId::Hash(*hash))
|
||||||
.expect("Client is sending message after commit to db and inserting to chain; the block is available; qed");
|
.expect("Client is sending message after commit to db and inserting to chain; the block is available; qed");
|
||||||
let block = BlockView::new(&block);
|
|
||||||
let txs = block.transactions();
|
let txs = block.transactions();
|
||||||
// populate sender
|
// populate sender
|
||||||
for tx in &txs {
|
for tx in &txs {
|
||||||
|
@ -190,8 +190,7 @@ impl<'a> BlockChunker<'a> {
|
|||||||
.and_then(|b| self.chain.block_receipts(&self.current_hash).map(|r| (b, r)))
|
.and_then(|b| self.chain.block_receipts(&self.current_hash).map(|r| (b, r)))
|
||||||
.ok_or(Error::BlockNotFound(self.current_hash))?;
|
.ok_or(Error::BlockNotFound(self.current_hash))?;
|
||||||
|
|
||||||
let view = BlockView::new(&block);
|
let abridged_rlp = AbridgedBlock::from_block_view(&block.view()).into_inner();
|
||||||
let abridged_rlp = AbridgedBlock::from_block_view(&view).into_inner();
|
|
||||||
|
|
||||||
let pair = {
|
let pair = {
|
||||||
let mut pair_stream = RlpStream::new_list(2);
|
let mut pair_stream = RlpStream::new_list(2);
|
||||||
@ -213,7 +212,7 @@ impl<'a> BlockChunker<'a> {
|
|||||||
self.rlps.push_front(pair);
|
self.rlps.push_front(pair);
|
||||||
|
|
||||||
last = self.current_hash;
|
last = self.current_hash;
|
||||||
self.current_hash = view.header_view().parent_hash();
|
self.current_hash = block.header_view().parent_hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
if loaded_size != 0 {
|
if loaded_size != 0 {
|
||||||
|
@ -20,7 +20,6 @@ use util::Mutex;
|
|||||||
use client::{BlockChainClient, Client, ChainNotify};
|
use client::{BlockChainClient, Client, ChainNotify};
|
||||||
use ids::BlockId;
|
use ids::BlockId;
|
||||||
use service::ClientIoMessage;
|
use service::ClientIoMessage;
|
||||||
use views::HeaderView;
|
|
||||||
|
|
||||||
use io::IoChannel;
|
use io::IoChannel;
|
||||||
use util::{H256, Bytes};
|
use util::{H256, Bytes};
|
||||||
@ -43,7 +42,7 @@ impl<F> Oracle for StandardOracle<F>
|
|||||||
where F: Send + Sync + Fn() -> bool
|
where F: Send + Sync + Fn() -> bool
|
||||||
{
|
{
|
||||||
fn to_number(&self, hash: H256) -> Option<u64> {
|
fn to_number(&self, hash: H256) -> Option<u64> {
|
||||||
self.client.block_header(BlockId::Hash(hash)).map(|h| HeaderView::new(&h).number())
|
self.client.block_header(BlockId::Hash(hash)).map(|h| h.number())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_major_importing(&self) -> bool {
|
fn is_major_importing(&self) -> bool {
|
||||||
|
@ -24,7 +24,7 @@ use types::filter::Filter;
|
|||||||
use util::*;
|
use util::*;
|
||||||
use devtools::*;
|
use devtools::*;
|
||||||
use miner::Miner;
|
use miner::Miner;
|
||||||
use rlp::{Rlp, View};
|
use rlp::View;
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use views::BlockView;
|
use views::BlockView;
|
||||||
use util::stats::Histogram;
|
use util::stats::Histogram;
|
||||||
@ -103,7 +103,7 @@ fn imports_good_block() {
|
|||||||
client.import_verified_blocks();
|
client.import_verified_blocks();
|
||||||
|
|
||||||
let block = client.block_header(BlockId::Number(1)).unwrap();
|
let block = client.block_header(BlockId::Number(1)).unwrap();
|
||||||
assert!(!block.is_empty());
|
assert!(!block.into_inner().is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -128,7 +128,7 @@ fn query_none_block() {
|
|||||||
fn query_bad_block() {
|
fn query_bad_block() {
|
||||||
let client_result = get_test_client_with_blocks(vec![get_bad_state_dummy_block()]);
|
let client_result = get_test_client_with_blocks(vec![get_bad_state_dummy_block()]);
|
||||||
let client = client_result.reference();
|
let client = client_result.reference();
|
||||||
let bad_block:Option<Bytes> = client.block_header(BlockId::Number(1));
|
let bad_block: Option<_> = client.block_header(BlockId::Number(1));
|
||||||
|
|
||||||
assert!(bad_block.is_none());
|
assert!(bad_block.is_none());
|
||||||
}
|
}
|
||||||
@ -180,7 +180,7 @@ fn returns_block_body() {
|
|||||||
let client = client_result.reference();
|
let client = client_result.reference();
|
||||||
let block = BlockView::new(&dummy_block);
|
let block = BlockView::new(&dummy_block);
|
||||||
let body = client.block_body(BlockId::Hash(block.header().hash())).unwrap();
|
let body = client.block_body(BlockId::Hash(block.header().hash())).unwrap();
|
||||||
let body = Rlp::new(&body);
|
let body = body.rlp();
|
||||||
assert_eq!(body.item_count(), 2);
|
assert_eq!(body.item_count(), 2);
|
||||||
assert_eq!(body.at(0).as_raw()[..], block.rlp().at(1).as_raw()[..]);
|
assert_eq!(body.at(0).as_raw()[..], block.rlp().at(1).as_raw()[..]);
|
||||||
assert_eq!(body.at(1).as_raw()[..], block.rlp().at(2).as_raw()[..]);
|
assert_eq!(body.at(1).as_raw()[..], block.rlp().at(2).as_raw()[..]);
|
||||||
@ -192,7 +192,7 @@ fn imports_block_sequence() {
|
|||||||
let client = client_result.reference();
|
let client = client_result.reference();
|
||||||
let block = client.block_header(BlockId::Number(5)).unwrap();
|
let block = client.block_header(BlockId::Number(5)).unwrap();
|
||||||
|
|
||||||
assert!(!block.is_empty());
|
assert!(!block.into_inner().is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
273
ethcore/src/types/encoded.rs
Normal file
273
ethcore/src/types/encoded.rs
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Lazily-decoded owning views of RLP-encoded blockchain objects.
|
||||||
|
//! These views are meant to contain _trusted_ data -- without encoding
|
||||||
|
//! errors or inconsistencies.
|
||||||
|
//!
|
||||||
|
//! In general these views are useful when only a few fields of an object
|
||||||
|
//! are relevant. In these cases it's more efficient to decode the object piecemeal.
|
||||||
|
//! When the entirety of the object is needed, it's better to upgrade it to a fully
|
||||||
|
//! decoded object where parts like the hash can be saved.
|
||||||
|
|
||||||
|
use block::Block as FullBlock;
|
||||||
|
use header::{BlockNumber, Header as FullHeader};
|
||||||
|
use transaction::SignedTransaction;
|
||||||
|
use views;
|
||||||
|
|
||||||
|
use util::{Address, Hashable, H256, H2048, U256};
|
||||||
|
use rlp::{Rlp, View};
|
||||||
|
|
||||||
|
/// Owning header view.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "ipc", binary)]
|
||||||
|
pub struct Header(Vec<u8>);
|
||||||
|
|
||||||
|
impl Header {
|
||||||
|
/// Create a new owning header view.
|
||||||
|
/// Expects the data to be an RLP-encoded header -- any other case will likely lead to
|
||||||
|
/// panics further down the line.
|
||||||
|
pub fn new(encoded: Vec<u8>) -> Self { Header(encoded) }
|
||||||
|
|
||||||
|
/// Upgrade this encoded view to a fully owned `Header` object.
|
||||||
|
pub fn decode(&self) -> FullHeader { ::rlp::decode(&self.0) }
|
||||||
|
|
||||||
|
/// Get a borrowed header view onto the data.
|
||||||
|
#[inline]
|
||||||
|
pub fn view(&self) -> views::HeaderView { views::HeaderView::new(&self.0) }
|
||||||
|
|
||||||
|
/// Get the rlp of the header.
|
||||||
|
#[inline]
|
||||||
|
pub fn rlp(&self) -> Rlp { Rlp::new(&self.0) }
|
||||||
|
|
||||||
|
/// Consume the view and return the raw bytes.
|
||||||
|
pub fn into_inner(self) -> Vec<u8> { self.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
// forwarders to borrowed view.
|
||||||
|
impl Header {
|
||||||
|
/// Returns the header hash.
|
||||||
|
pub fn hash(&self) -> H256 { self.sha3() }
|
||||||
|
|
||||||
|
/// Returns the parent hash.
|
||||||
|
pub fn parent_hash(&self) -> H256 { self.view().parent_hash() }
|
||||||
|
|
||||||
|
/// Returns the uncles hash.
|
||||||
|
pub fn uncles_hash(&self) -> H256 { self.view().uncles_hash() }
|
||||||
|
|
||||||
|
/// Returns the author.
|
||||||
|
pub fn author(&self) -> Address { self.view().author() }
|
||||||
|
|
||||||
|
/// Returns the state root.
|
||||||
|
pub fn state_root(&self) -> H256 { self.view().state_root() }
|
||||||
|
|
||||||
|
/// Returns the transaction trie root.
|
||||||
|
pub fn transactions_root(&self) -> H256 { self.view().transactions_root() }
|
||||||
|
|
||||||
|
/// Returns the receipts trie root
|
||||||
|
pub fn receipts_root(&self) -> H256 { self.view().receipts_root() }
|
||||||
|
|
||||||
|
/// Returns the block log bloom
|
||||||
|
pub fn log_bloom(&self) -> H2048 { self.view().log_bloom() }
|
||||||
|
|
||||||
|
/// Difficulty of this block
|
||||||
|
pub fn difficulty(&self) -> U256 { self.view().difficulty() }
|
||||||
|
|
||||||
|
/// Number of this block.
|
||||||
|
pub fn number(&self) -> BlockNumber { self.view().number() }
|
||||||
|
|
||||||
|
/// Time this block was produced.
|
||||||
|
pub fn timestamp(&self) -> u64 { self.view().timestamp() }
|
||||||
|
|
||||||
|
/// Gas limit of this block.
|
||||||
|
pub fn gas_limit(&self) -> U256 { self.view().gas_limit() }
|
||||||
|
|
||||||
|
/// Total gas used in this block.
|
||||||
|
pub fn gas_used(&self) -> U256 { self.view().gas_used() }
|
||||||
|
|
||||||
|
/// Block extra data.
|
||||||
|
pub fn extra_data(&self) -> Vec<u8> { self.view().extra_data() }
|
||||||
|
|
||||||
|
/// Engine-specific seal fields.
|
||||||
|
pub fn seal(&self) -> Vec<Vec<u8>> { self.view().seal() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hashable for Header {
|
||||||
|
fn sha3(&self) -> H256 {
|
||||||
|
self.0.sha3()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Owning block body view.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "ipc", binary)]
|
||||||
|
pub struct Body(Vec<u8>);
|
||||||
|
|
||||||
|
impl Body {
|
||||||
|
/// Create a new owning block body view. The raw bytes passed in must be an rlp-encoded block
|
||||||
|
/// body.
|
||||||
|
pub fn new(raw: Vec<u8>) -> Self { Body(raw) }
|
||||||
|
|
||||||
|
/// Get a borrowed view of the data within.
|
||||||
|
#[inline]
|
||||||
|
pub fn view(&self) -> views::BodyView { views::BodyView::new(&self.0) }
|
||||||
|
|
||||||
|
/// Fully decode this block body.
|
||||||
|
pub fn decode(&self) -> (Vec<SignedTransaction>, Vec<FullHeader>) {
|
||||||
|
(self.view().transactions(), self.view().uncles())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the RLP of this block body.
|
||||||
|
#[inline]
|
||||||
|
pub fn rlp(&self) -> Rlp {
|
||||||
|
Rlp::new(&self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume the view and return the raw bytes.
|
||||||
|
pub fn into_inner(self) -> Vec<u8> { self.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
// forwarders to borrowed view.
|
||||||
|
impl Body {
|
||||||
|
/// Get a vector of all transactions.
|
||||||
|
pub fn transactions(&self) -> Vec<SignedTransaction> { self.view().transactions() }
|
||||||
|
|
||||||
|
/// Number of transactions in the block.
|
||||||
|
pub fn transactions_count(&self) -> usize { self.view().transactions_count() }
|
||||||
|
|
||||||
|
/// A view over each transaction in the block.
|
||||||
|
pub fn transaction_views(&self) -> Vec<views::TransactionView> { self.view().transaction_views() }
|
||||||
|
|
||||||
|
/// The hash of each transaction in the block.
|
||||||
|
pub fn transaction_hashes(&self) -> Vec<H256> { self.view().transaction_hashes() }
|
||||||
|
|
||||||
|
/// Decode uncle headers.
|
||||||
|
pub fn uncles(&self) -> Vec<FullHeader> { self.view().uncles() }
|
||||||
|
|
||||||
|
/// Number of uncles.
|
||||||
|
pub fn uncles_count(&self) -> usize { self.view().uncles_count() }
|
||||||
|
|
||||||
|
/// Borrowed view over each uncle.
|
||||||
|
pub fn uncle_views(&self) -> Vec<views::HeaderView> { self.view().uncle_views() }
|
||||||
|
|
||||||
|
/// Hash of each uncle.
|
||||||
|
pub fn uncle_hashes(&self) -> Vec<H256> { self.view().uncle_hashes() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Owning block view.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "ipc", binary)]
|
||||||
|
pub struct Block(Vec<u8>);
|
||||||
|
|
||||||
|
impl Block {
|
||||||
|
/// Create a new owning block view. The raw bytes passed in must be an rlp-encoded block.
|
||||||
|
pub fn new(raw: Vec<u8>) -> Self { Block(raw) }
|
||||||
|
|
||||||
|
/// Get a borrowed view of the whole block.
|
||||||
|
#[inline]
|
||||||
|
pub fn view(&self) -> views::BlockView { views::BlockView::new(&self.0) }
|
||||||
|
|
||||||
|
/// Get a borrowed view of the block header.
|
||||||
|
#[inline]
|
||||||
|
pub fn header_view(&self) -> views::HeaderView { self.view().header_view() }
|
||||||
|
|
||||||
|
/// Decode to a full block.
|
||||||
|
pub fn decode(&self) -> FullBlock { ::rlp::decode(&self.0) }
|
||||||
|
|
||||||
|
/// Get the rlp of this block.
|
||||||
|
#[inline]
|
||||||
|
pub fn rlp(&self) -> Rlp {
|
||||||
|
Rlp::new(&self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume the view and return the raw bytes.
|
||||||
|
pub fn into_inner(self) -> Vec<u8> { self.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
// forwarders to borrowed header view.
|
||||||
|
impl Block {
|
||||||
|
/// Returns the header hash.
|
||||||
|
pub fn hash(&self) -> H256 { self.header_view().sha3() }
|
||||||
|
|
||||||
|
/// Returns the parent hash.
|
||||||
|
pub fn parent_hash(&self) -> H256 { self.header_view().parent_hash() }
|
||||||
|
|
||||||
|
/// Returns the uncles hash.
|
||||||
|
pub fn uncles_hash(&self) -> H256 { self.header_view().uncles_hash() }
|
||||||
|
|
||||||
|
/// Returns the author.
|
||||||
|
pub fn author(&self) -> Address { self.header_view().author() }
|
||||||
|
|
||||||
|
/// Returns the state root.
|
||||||
|
pub fn state_root(&self) -> H256 { self.header_view().state_root() }
|
||||||
|
|
||||||
|
/// Returns the transaction trie root.
|
||||||
|
pub fn transactions_root(&self) -> H256 { self.header_view().transactions_root() }
|
||||||
|
|
||||||
|
/// Returns the receipts trie root
|
||||||
|
pub fn receipts_root(&self) -> H256 { self.header_view().receipts_root() }
|
||||||
|
|
||||||
|
/// Returns the block log bloom
|
||||||
|
pub fn log_bloom(&self) -> H2048 { self.header_view().log_bloom() }
|
||||||
|
|
||||||
|
/// Difficulty of this block
|
||||||
|
pub fn difficulty(&self) -> U256 { self.header_view().difficulty() }
|
||||||
|
|
||||||
|
/// Number of this block.
|
||||||
|
pub fn number(&self) -> BlockNumber { self.header_view().number() }
|
||||||
|
|
||||||
|
/// Time this block was produced.
|
||||||
|
pub fn timestamp(&self) -> u64 { self.header_view().timestamp() }
|
||||||
|
|
||||||
|
/// Gas limit of this block.
|
||||||
|
pub fn gas_limit(&self) -> U256 { self.header_view().gas_limit() }
|
||||||
|
|
||||||
|
/// Total gas used in this block.
|
||||||
|
pub fn gas_used(&self) -> U256 { self.header_view().gas_used() }
|
||||||
|
|
||||||
|
/// Block extra data.
|
||||||
|
pub fn extra_data(&self) -> Vec<u8> { self.header_view().extra_data() }
|
||||||
|
|
||||||
|
/// Engine-specific seal fields.
|
||||||
|
pub fn seal(&self) -> Vec<Vec<u8>> { self.header_view().seal() }
|
||||||
|
}
|
||||||
|
|
||||||
|
// forwarders to body view.
|
||||||
|
impl Block {
|
||||||
|
/// Get a vector of all transactions.
|
||||||
|
pub fn transactions(&self) -> Vec<SignedTransaction> { self.view().transactions() }
|
||||||
|
|
||||||
|
/// Number of transactions in the block.
|
||||||
|
pub fn transactions_count(&self) -> usize { self.view().transactions_count() }
|
||||||
|
|
||||||
|
/// A view over each transaction in the block.
|
||||||
|
pub fn transaction_views(&self) -> Vec<views::TransactionView> { self.view().transaction_views() }
|
||||||
|
|
||||||
|
/// The hash of each transaction in the block.
|
||||||
|
pub fn transaction_hashes(&self) -> Vec<H256> { self.view().transaction_hashes() }
|
||||||
|
|
||||||
|
/// Decode uncle headers.
|
||||||
|
pub fn uncles(&self) -> Vec<FullHeader> { self.view().uncles() }
|
||||||
|
|
||||||
|
/// Number of uncles.
|
||||||
|
pub fn uncles_count(&self) -> usize { self.view().uncles_count() }
|
||||||
|
|
||||||
|
/// Borrowed view over each uncle.
|
||||||
|
pub fn uncle_views(&self) -> Vec<views::HeaderView> { self.view().uncle_views() }
|
||||||
|
|
||||||
|
/// Hash of each uncle.
|
||||||
|
pub fn uncle_hashes(&self) -> Vec<H256> { self.view().uncle_hashes() }
|
||||||
|
}
|
@ -36,3 +36,4 @@ pub mod snapshot_manifest;
|
|||||||
pub mod mode;
|
pub mod mode;
|
||||||
pub mod pruning_info;
|
pub mod pruning_info;
|
||||||
pub mod security_level;
|
pub mod security_level;
|
||||||
|
pub mod encoded;
|
||||||
|
@ -117,7 +117,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
|
|||||||
excluded.insert(details.parent.clone());
|
excluded.insert(details.parent.clone());
|
||||||
let b = bc.block(&hash)
|
let b = bc.block(&hash)
|
||||||
.expect("parent already known to be stored; qed");
|
.expect("parent already known to be stored; qed");
|
||||||
excluded.extend(BlockView::new(&b).uncle_hashes());
|
excluded.extend(b.uncle_hashes());
|
||||||
hash = details.parent;
|
hash = details.parent;
|
||||||
}
|
}
|
||||||
None => break
|
None => break
|
||||||
@ -264,6 +264,7 @@ mod tests {
|
|||||||
use types::log_entry::{LogEntry, LocalizedLogEntry};
|
use types::log_entry::{LogEntry, LocalizedLogEntry};
|
||||||
use rlp::View;
|
use rlp::View;
|
||||||
use time::get_time;
|
use time::get_time;
|
||||||
|
use encoded;
|
||||||
|
|
||||||
fn check_ok(result: Result<(), Error>) {
|
fn check_ok(result: Result<(), Error>) {
|
||||||
result.unwrap_or_else(|e| panic!("Block verification failed: {:?}", e));
|
result.unwrap_or_else(|e| panic!("Block verification failed: {:?}", e));
|
||||||
@ -322,16 +323,20 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get raw block data
|
/// Get raw block data
|
||||||
fn block(&self, hash: &H256) -> Option<Bytes> {
|
fn block(&self, hash: &H256) -> Option<encoded::Block> {
|
||||||
self.blocks.get(hash).cloned()
|
self.blocks.get(hash).cloned().map(encoded::Block::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_header_data(&self, hash: &H256) -> Option<Bytes> {
|
fn block_header_data(&self, hash: &H256) -> Option<encoded::Header> {
|
||||||
self.block(hash).map(|b| BlockView::new(&b).header_rlp().as_raw().to_vec())
|
self.block(hash)
|
||||||
|
.map(|b| b.header_view().rlp().as_raw().to_vec())
|
||||||
|
.map(encoded::Header::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_body(&self, hash: &H256) -> Option<Bytes> {
|
fn block_body(&self, hash: &H256) -> Option<encoded::Body> {
|
||||||
self.block(hash).map(|b| BlockChain::block_to_body(&b))
|
self.block(hash)
|
||||||
|
.map(|b| BlockChain::block_to_body(&b.into_inner()))
|
||||||
|
.map(encoded::Body::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn best_ancient_block(&self) -> Option<H256> {
|
fn best_ancient_block(&self) -> Option<H256> {
|
||||||
|
@ -94,7 +94,7 @@ impl<'a> BlockView<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return List of transactions in given block.
|
/// Return List of transactions in given block.
|
||||||
pub fn transaction_views(&self) -> Vec<TransactionView> {
|
pub fn transaction_views(&self) -> Vec<TransactionView<'a>> {
|
||||||
self.rlp.at(1).iter().map(TransactionView::new_from_rlp).collect()
|
self.rlp.at(1).iter().map(TransactionView::new_from_rlp).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ impl<'a> BlockView<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return List of transactions in given block.
|
/// Return List of transactions in given block.
|
||||||
pub fn uncle_views(&self) -> Vec<HeaderView> {
|
pub fn uncle_views(&self) -> Vec<HeaderView<'a>> {
|
||||||
self.rlp.at(2).iter().map(HeaderView::new_from_rlp).collect()
|
self.rlp.at(2).iter().map(HeaderView::new_from_rlp).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ impl<'a> BodyView<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return List of transactions in given block.
|
/// Return List of transactions in given block.
|
||||||
pub fn transaction_views(&self) -> Vec<TransactionView> {
|
pub fn transaction_views(&self) -> Vec<TransactionView<'a>> {
|
||||||
self.rlp.at(0).iter().map(TransactionView::new_from_rlp).collect()
|
self.rlp.at(0).iter().map(TransactionView::new_from_rlp).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ impl<'a> BodyView<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return List of transactions in given block.
|
/// Return List of transactions in given block.
|
||||||
pub fn uncle_views(&self) -> Vec<HeaderView> {
|
pub fn uncle_views(&self) -> Vec<HeaderView<'a>> {
|
||||||
self.rlp.at(1).iter().map(HeaderView::new_from_rlp).collect()
|
self.rlp.at(1).iter().map(HeaderView::new_from_rlp).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,7 +390,7 @@ fn execute_export(cmd: ExportBlockchain) -> Result<(), String> {
|
|||||||
if i % 10000 == 0 {
|
if i % 10000 == 0 {
|
||||||
info!("#{}", i);
|
info!("#{}", i);
|
||||||
}
|
}
|
||||||
let b = client.block(BlockId::Number(i)).ok_or("Error exporting incomplete chain")?;
|
let b = client.block(BlockId::Number(i)).ok_or("Error exporting incomplete chain")?.into_inner();
|
||||||
match format {
|
match format {
|
||||||
DataFormat::Binary => { out.write(&b).expect("Couldn't write to stream."); }
|
DataFormat::Binary => { out.write(&b).expect("Couldn't write to stream."); }
|
||||||
DataFormat::Hex => { out.write_fmt(format_args!("{}", b.pretty())).expect("Couldn't write to stream."); }
|
DataFormat::Hex => { out.write_fmt(format_args!("{}", b.pretty())).expect("Couldn't write to stream."); }
|
||||||
|
@ -27,11 +27,11 @@ use ethsync::{SyncProvider, ManageNetwork};
|
|||||||
use util::{Uint, RwLock, Mutex, H256, Colour, Bytes};
|
use util::{Uint, RwLock, Mutex, H256, Colour, Bytes};
|
||||||
use ethcore::client::*;
|
use ethcore::client::*;
|
||||||
use ethcore::service::ClientIoMessage;
|
use ethcore::service::ClientIoMessage;
|
||||||
use ethcore::views::BlockView;
|
|
||||||
use ethcore::snapshot::service::Service as SnapshotService;
|
use ethcore::snapshot::service::Service as SnapshotService;
|
||||||
use ethcore::snapshot::{RestorationStatus, SnapshotService as SS};
|
use ethcore::snapshot::{RestorationStatus, SnapshotService as SS};
|
||||||
use number_prefix::{binary_prefix, Standalone, Prefixed};
|
use number_prefix::{binary_prefix, Standalone, Prefixed};
|
||||||
use ethcore_rpc::is_major_importing;
|
use ethcore_rpc::is_major_importing;
|
||||||
|
use rlp::View;
|
||||||
|
|
||||||
pub struct Informant {
|
pub struct Informant {
|
||||||
report: RwLock<Option<ClientReport>>,
|
report: RwLock<Option<ClientReport>>,
|
||||||
@ -186,21 +186,19 @@ impl ChainNotify for Informant {
|
|||||||
let txs_imported = imported.iter()
|
let txs_imported = imported.iter()
|
||||||
.take(imported.len().saturating_sub(if ripe { 1 } else { 0 }))
|
.take(imported.len().saturating_sub(if ripe { 1 } else { 0 }))
|
||||||
.filter_map(|h| self.client.block(BlockId::Hash(*h)))
|
.filter_map(|h| self.client.block(BlockId::Hash(*h)))
|
||||||
.map(|b| BlockView::new(&b).transactions_count())
|
.map(|b| b.transactions_count())
|
||||||
.sum();
|
.sum();
|
||||||
|
|
||||||
if ripe {
|
if ripe {
|
||||||
if let Some(block) = imported.last().and_then(|h| self.client.block(BlockId::Hash(*h))) {
|
if let Some(block) = imported.last().and_then(|h| self.client.block(BlockId::Hash(*h))) {
|
||||||
let view = BlockView::new(&block);
|
let header_view = block.header_view();
|
||||||
let header = view.header();
|
let size = block.rlp().as_raw().len();
|
||||||
let tx_count = view.transactions_count();
|
|
||||||
let size = block.len();
|
|
||||||
let (skipped, skipped_txs) = (self.skipped.load(AtomicOrdering::Relaxed) + imported.len() - 1, self.skipped_txs.load(AtomicOrdering::Relaxed) + txs_imported);
|
let (skipped, skipped_txs) = (self.skipped.load(AtomicOrdering::Relaxed) + imported.len() - 1, self.skipped_txs.load(AtomicOrdering::Relaxed) + txs_imported);
|
||||||
info!(target: "import", "Imported {} {} ({} txs, {} Mgas, {} ms, {} KiB){}",
|
info!(target: "import", "Imported {} {} ({} txs, {} Mgas, {} ms, {} KiB){}",
|
||||||
Colour::White.bold().paint(format!("#{}", header.number())),
|
Colour::White.bold().paint(format!("#{}", header_view.number())),
|
||||||
Colour::White.bold().paint(format!("{}", header.hash())),
|
Colour::White.bold().paint(format!("{}", header_view.hash())),
|
||||||
Colour::Yellow.bold().paint(format!("{}", tx_count)),
|
Colour::Yellow.bold().paint(format!("{}", block.transactions_count())),
|
||||||
Colour::Yellow.bold().paint(format!("{:.2}", header.gas_used().low_u64() as f32 / 1000000f32)),
|
Colour::Yellow.bold().paint(format!("{:.2}", header_view.gas_used().low_u64() as f32 / 1000000f32)),
|
||||||
Colour::Purple.bold().paint(format!("{:.2}", duration as f32 / 1000000f32)),
|
Colour::Purple.bold().paint(format!("{:.2}", duration as f32 / 1000000f32)),
|
||||||
Colour::Blue.bold().paint(format!("{:.2}", size as f32 / 1024f32)),
|
Colour::Blue.bold().paint(format!("{:.2}", size as f32 / 1024f32)),
|
||||||
if skipped > 0 {
|
if skipped > 0 {
|
||||||
|
@ -36,7 +36,6 @@ use ethcore::account_provider::AccountProvider;
|
|||||||
use ethcore::client::{MiningBlockChainClient, BlockId, TransactionId, UncleId};
|
use ethcore::client::{MiningBlockChainClient, BlockId, TransactionId, UncleId};
|
||||||
use ethcore::header::{Header as BlockHeader, BlockNumber as EthBlockNumber};
|
use ethcore::header::{Header as BlockHeader, BlockNumber as EthBlockNumber};
|
||||||
use ethcore::block::IsBlock;
|
use ethcore::block::IsBlock;
|
||||||
use ethcore::views::*;
|
|
||||||
use ethcore::ethereum::Ethash;
|
use ethcore::ethereum::Ethash;
|
||||||
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, PendingTransaction, Action};
|
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, PendingTransaction, Action};
|
||||||
use ethcore::log_entry::LogEntry;
|
use ethcore::log_entry::LogEntry;
|
||||||
@ -122,13 +121,12 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
|
|||||||
fn block(&self, id: BlockId, include_txs: bool) -> Result<Option<RichBlock>, Error> {
|
fn block(&self, id: BlockId, include_txs: bool) -> Result<Option<RichBlock>, Error> {
|
||||||
let client = take_weak!(self.client);
|
let client = take_weak!(self.client);
|
||||||
match (client.block(id.clone()), client.block_total_difficulty(id)) {
|
match (client.block(id.clone()), client.block_total_difficulty(id)) {
|
||||||
(Some(bytes), Some(total_difficulty)) => {
|
(Some(block), Some(total_difficulty)) => {
|
||||||
let block_view = BlockView::new(&bytes);
|
let view = block.header_view();
|
||||||
let view = block_view.header_view();
|
Ok(Some(RichBlock {
|
||||||
let block = RichBlock {
|
|
||||||
block: Block {
|
block: Block {
|
||||||
hash: Some(view.sha3().into()),
|
hash: Some(view.sha3().into()),
|
||||||
size: Some(bytes.len().into()),
|
size: Some(block.rlp().as_raw().len().into()),
|
||||||
parent_hash: view.parent_hash().into(),
|
parent_hash: view.parent_hash().into(),
|
||||||
uncles_hash: view.uncles_hash().into(),
|
uncles_hash: view.uncles_hash().into(),
|
||||||
author: view.author().into(),
|
author: view.author().into(),
|
||||||
@ -144,16 +142,15 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
|
|||||||
difficulty: view.difficulty().into(),
|
difficulty: view.difficulty().into(),
|
||||||
total_difficulty: total_difficulty.into(),
|
total_difficulty: total_difficulty.into(),
|
||||||
seal_fields: view.seal().into_iter().map(|f| rlp::decode(&f)).map(Bytes::new).collect(),
|
seal_fields: view.seal().into_iter().map(|f| rlp::decode(&f)).map(Bytes::new).collect(),
|
||||||
uncles: block_view.uncle_hashes().into_iter().map(Into::into).collect(),
|
uncles: block.uncle_hashes().into_iter().map(Into::into).collect(),
|
||||||
transactions: match include_txs {
|
transactions: match include_txs {
|
||||||
true => BlockTransactions::Full(block_view.localized_transactions().into_iter().map(Into::into).collect()),
|
true => BlockTransactions::Full(block.view().localized_transactions().into_iter().map(Into::into).collect()),
|
||||||
false => BlockTransactions::Hashes(block_view.transaction_hashes().into_iter().map(Into::into).collect()),
|
false => BlockTransactions::Hashes(block.transaction_hashes().into_iter().map(Into::into).collect()),
|
||||||
},
|
},
|
||||||
extra_data: Bytes::new(view.extra_data()),
|
extra_data: Bytes::new(view.extra_data()),
|
||||||
},
|
},
|
||||||
extra_info: client.block_extra_info(id.clone()).expect(EXTRA_INFO_PROOF),
|
extra_info: client.block_extra_info(id.clone()).expect(EXTRA_INFO_PROOF),
|
||||||
};
|
}))
|
||||||
Ok(Some(block))
|
|
||||||
},
|
},
|
||||||
_ => Ok(None)
|
_ => Ok(None)
|
||||||
}
|
}
|
||||||
@ -169,7 +166,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
|
|||||||
fn uncle(&self, id: UncleId) -> Result<Option<RichBlock>, Error> {
|
fn uncle(&self, id: UncleId) -> Result<Option<RichBlock>, Error> {
|
||||||
let client = take_weak!(self.client);
|
let client = take_weak!(self.client);
|
||||||
let uncle: BlockHeader = match client.uncle(id) {
|
let uncle: BlockHeader = match client.uncle(id) {
|
||||||
Some(rlp) => rlp::decode(&rlp),
|
Some(hdr) => hdr.decode(),
|
||||||
None => { return Ok(None); }
|
None => { return Ok(None); }
|
||||||
};
|
};
|
||||||
let parent_difficulty = match client.block_total_difficulty(BlockId::Hash(uncle.parent_hash().clone())) {
|
let parent_difficulty = match client.block_total_difficulty(BlockId::Hash(uncle.parent_hash().clone())) {
|
||||||
@ -419,7 +416,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
|||||||
self.active()?;
|
self.active()?;
|
||||||
Ok(
|
Ok(
|
||||||
take_weak!(self.client).block(BlockId::Hash(hash.into()))
|
take_weak!(self.client).block(BlockId::Hash(hash.into()))
|
||||||
.map(|bytes| BlockView::new(&bytes).transactions_count().into())
|
.map(|block| block.transactions_count().into())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,7 +429,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
|||||||
)),
|
)),
|
||||||
_ => Ok(
|
_ => Ok(
|
||||||
take_weak!(self.client).block(num.into())
|
take_weak!(self.client).block(num.into())
|
||||||
.map(|bytes| BlockView::new(&bytes).transactions_count().into())
|
.map(|block| block.transactions_count().into())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -442,7 +439,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
|||||||
|
|
||||||
Ok(
|
Ok(
|
||||||
take_weak!(self.client).block(BlockId::Hash(hash.into()))
|
take_weak!(self.client).block(BlockId::Hash(hash.into()))
|
||||||
.map(|bytes| BlockView::new(&bytes).uncles_count().into())
|
.map(|block| block.uncles_count().into())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,7 +450,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
|||||||
BlockNumber::Pending => Ok(Some(0.into())),
|
BlockNumber::Pending => Ok(Some(0.into())),
|
||||||
_ => Ok(
|
_ => Ok(
|
||||||
take_weak!(self.client).block(num.into())
|
take_weak!(self.client).block(num.into())
|
||||||
.map(|bytes| BlockView::new(&bytes).uncles_count().into())
|
.map(|block| block.uncles_count().into())
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
use util::*;
|
use util::*;
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
use network::NetworkError;
|
use network::NetworkError;
|
||||||
use ethcore::header::{ Header as BlockHeader};
|
use ethcore::header::Header as BlockHeader;
|
||||||
|
|
||||||
known_heap_size!(0, HeaderId);
|
known_heap_size!(0, HeaderId);
|
||||||
|
|
||||||
@ -511,7 +511,9 @@ mod test {
|
|||||||
let client = TestBlockChainClient::new();
|
let client = TestBlockChainClient::new();
|
||||||
let nblocks = 200;
|
let nblocks = 200;
|
||||||
client.add_blocks(nblocks, EachBlockWith::Nothing);
|
client.add_blocks(nblocks, EachBlockWith::Nothing);
|
||||||
let blocks: Vec<_> = (0 .. nblocks).map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap()).collect();
|
let blocks: Vec<_> = (0..nblocks)
|
||||||
|
.map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap().into_inner())
|
||||||
|
.collect();
|
||||||
let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect();
|
let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect();
|
||||||
let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect();
|
let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect();
|
||||||
let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect();
|
let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect();
|
||||||
@ -564,7 +566,9 @@ mod test {
|
|||||||
let client = TestBlockChainClient::new();
|
let client = TestBlockChainClient::new();
|
||||||
let nblocks = 200;
|
let nblocks = 200;
|
||||||
client.add_blocks(nblocks, EachBlockWith::Nothing);
|
client.add_blocks(nblocks, EachBlockWith::Nothing);
|
||||||
let blocks: Vec<_> = (0 .. nblocks).map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap()).collect();
|
let blocks: Vec<_> = (0..nblocks)
|
||||||
|
.map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap().into_inner())
|
||||||
|
.collect();
|
||||||
let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect();
|
let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect();
|
||||||
let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect();
|
let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect();
|
||||||
let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect();
|
let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect();
|
||||||
@ -586,7 +590,9 @@ mod test {
|
|||||||
let client = TestBlockChainClient::new();
|
let client = TestBlockChainClient::new();
|
||||||
let nblocks = 200;
|
let nblocks = 200;
|
||||||
client.add_blocks(nblocks, EachBlockWith::Nothing);
|
client.add_blocks(nblocks, EachBlockWith::Nothing);
|
||||||
let blocks: Vec<_> = (0 .. nblocks).map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap()).collect();
|
let blocks: Vec<_> = (0..nblocks)
|
||||||
|
.map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap().into_inner())
|
||||||
|
.collect();
|
||||||
let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect();
|
let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect();
|
||||||
let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect();
|
let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect();
|
||||||
let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect();
|
let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect();
|
||||||
|
@ -92,7 +92,6 @@
|
|||||||
use util::*;
|
use util::*;
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
use network::*;
|
use network::*;
|
||||||
use ethcore::views::{HeaderView};
|
|
||||||
use ethcore::header::{BlockNumber, Header as BlockHeader};
|
use ethcore::header::{BlockNumber, Header as BlockHeader};
|
||||||
use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError, BlockQueueInfo};
|
use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError, BlockQueueInfo};
|
||||||
use ethcore::error::*;
|
use ethcore::error::*;
|
||||||
@ -1493,14 +1492,15 @@ impl ChainSync {
|
|||||||
trace!(target: "sync", "{} -> GetBlockHeaders (hash: {}, max: {}, skip: {}, reverse:{})", peer_id, hash, max_headers, skip, reverse);
|
trace!(target: "sync", "{} -> GetBlockHeaders (hash: {}, max: {}, skip: {}, reverse:{})", peer_id, hash, max_headers, skip, reverse);
|
||||||
match io.chain().block_header(BlockId::Hash(hash)) {
|
match io.chain().block_header(BlockId::Hash(hash)) {
|
||||||
Some(hdr) => {
|
Some(hdr) => {
|
||||||
let number = From::from(HeaderView::new(&hdr).number());
|
let number = hdr.number().into();
|
||||||
debug_assert_eq!(HeaderView::new(&hdr).sha3(), hash);
|
debug_assert_eq!(hdr.sha3(), hash);
|
||||||
|
|
||||||
if max_headers == 1 || io.chain().block_hash(BlockId::Number(number)) != Some(hash) {
|
if max_headers == 1 || io.chain().block_hash(BlockId::Number(number)) != Some(hash) {
|
||||||
// Non canonical header or single header requested
|
// Non canonical header or single header requested
|
||||||
// TODO: handle single-step reverse hashchains of non-canon hashes
|
// TODO: handle single-step reverse hashchains of non-canon hashes
|
||||||
trace!(target:"sync", "Returning single header: {:?}", hash);
|
trace!(target:"sync", "Returning single header: {:?}", hash);
|
||||||
let mut rlp = RlpStream::new_list(1);
|
let mut rlp = RlpStream::new_list(1);
|
||||||
rlp.append_raw(&hdr, 1);
|
rlp.append_raw(&hdr.into_inner(), 1);
|
||||||
return Ok(Some((BLOCK_HEADERS_PACKET, rlp)));
|
return Ok(Some((BLOCK_HEADERS_PACKET, rlp)));
|
||||||
}
|
}
|
||||||
number
|
number
|
||||||
@ -1528,8 +1528,8 @@ impl ChainSync {
|
|||||||
trace!(target: "sync", "{}: Returning cached fork header", peer_id);
|
trace!(target: "sync", "{}: Returning cached fork header", peer_id);
|
||||||
data.extend_from_slice(hdr);
|
data.extend_from_slice(hdr);
|
||||||
count += 1;
|
count += 1;
|
||||||
} else if let Some(mut hdr) = io.chain().block_header(BlockId::Number(number)) {
|
} else if let Some(hdr) = io.chain().block_header(BlockId::Number(number)) {
|
||||||
data.append(&mut hdr);
|
data.append(&mut hdr.into_inner());
|
||||||
count += 1;
|
count += 1;
|
||||||
} else {
|
} else {
|
||||||
// No required block.
|
// No required block.
|
||||||
@ -1562,8 +1562,8 @@ impl ChainSync {
|
|||||||
let mut added = 0usize;
|
let mut added = 0usize;
|
||||||
let mut data = Bytes::new();
|
let mut data = Bytes::new();
|
||||||
for i in 0..count {
|
for i in 0..count {
|
||||||
if let Some(mut hdr) = io.chain().block_body(BlockId::Hash(r.val_at::<H256>(i)?)) {
|
if let Some(body) = io.chain().block_body(BlockId::Hash(r.val_at::<H256>(i)?)) {
|
||||||
data.append(&mut hdr);
|
data.append(&mut body.into_inner());
|
||||||
added += 1;
|
added += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1585,8 +1585,8 @@ impl ChainSync {
|
|||||||
let mut added = 0usize;
|
let mut added = 0usize;
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
for i in 0..count {
|
for i in 0..count {
|
||||||
if let Some(hdr) = io.chain().state_data(&r.val_at::<H256>(i)?) {
|
if let Some(node) = io.chain().state_data(&r.val_at::<H256>(i)?) {
|
||||||
data.push(hdr);
|
data.push(node);
|
||||||
added += 1;
|
added += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1819,8 +1819,8 @@ impl ChainSync {
|
|||||||
let mut rlp_stream = RlpStream::new_list(blocks.len());
|
let mut rlp_stream = RlpStream::new_list(blocks.len());
|
||||||
for block_hash in blocks {
|
for block_hash in blocks {
|
||||||
let mut hash_rlp = RlpStream::new_list(2);
|
let mut hash_rlp = RlpStream::new_list(2);
|
||||||
let number = HeaderView::new(&chain.block_header(BlockId::Hash(block_hash.clone()))
|
let number = chain.block_header(BlockId::Hash(block_hash.clone()))
|
||||||
.expect("chain.tree_route and chain.find_uncles only return hahses of blocks that are in the blockchain. qed.")).number();
|
.expect("chain.tree_route and chain.find_uncles only return hahses of blocks that are in the blockchain. qed.").number();
|
||||||
hash_rlp.append(&block_hash);
|
hash_rlp.append(&block_hash);
|
||||||
hash_rlp.append(&number);
|
hash_rlp.append(&number);
|
||||||
rlp_stream.append_raw(hash_rlp.as_raw(), 1);
|
rlp_stream.append_raw(hash_rlp.as_raw(), 1);
|
||||||
@ -1844,7 +1844,8 @@ impl ChainSync {
|
|||||||
/// creates latest block rlp for the given client
|
/// creates latest block rlp for the given client
|
||||||
fn create_latest_block_rlp(chain: &BlockChainClient) -> Bytes {
|
fn create_latest_block_rlp(chain: &BlockChainClient) -> Bytes {
|
||||||
ChainSync::create_block_rlp(
|
ChainSync::create_block_rlp(
|
||||||
&chain.block(BlockId::Hash(chain.chain_info().best_block_hash)).expect("Best block always exists"),
|
&chain.block(BlockId::Hash(chain.chain_info().best_block_hash))
|
||||||
|
.expect("Best block always exists").into_inner(),
|
||||||
chain.chain_info().total_difficulty
|
chain.chain_info().total_difficulty
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1852,7 +1853,7 @@ impl ChainSync {
|
|||||||
/// creates given hash block rlp for the given client
|
/// creates given hash block rlp for the given client
|
||||||
fn create_new_block_rlp(chain: &BlockChainClient, hash: &H256) -> Bytes {
|
fn create_new_block_rlp(chain: &BlockChainClient, hash: &H256) -> Bytes {
|
||||||
ChainSync::create_block_rlp(
|
ChainSync::create_block_rlp(
|
||||||
&chain.block(BlockId::Hash(hash.clone())).expect("Block has just been sealed; qed"),
|
&chain.block(BlockId::Hash(hash.clone())).expect("Block has just been sealed; qed").into_inner(),
|
||||||
chain.block_total_difficulty(BlockId::Hash(hash.clone())).expect("Block has just been sealed; qed.")
|
chain.block_total_difficulty(BlockId::Hash(hash.clone())).expect("Block has just been sealed; qed.")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1915,8 +1916,7 @@ impl ChainSync {
|
|||||||
fn propagate_new_hashes(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo, peers: &[PeerId]) -> usize {
|
fn propagate_new_hashes(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo, peers: &[PeerId]) -> usize {
|
||||||
trace!(target: "sync", "Sending NewHashes to {:?}", peers);
|
trace!(target: "sync", "Sending NewHashes to {:?}", peers);
|
||||||
let mut sent = 0;
|
let mut sent = 0;
|
||||||
let last_parent = HeaderView::new(&io.chain().block_header(BlockId::Hash(chain_info.best_block_hash.clone()))
|
let last_parent = &io.chain().best_block_header().parent_hash();
|
||||||
.expect("Best block always exists")).parent_hash();
|
|
||||||
for peer_id in peers {
|
for peer_id in peers {
|
||||||
sent += match ChainSync::create_new_hashes_rlp(io.chain(), &last_parent, &chain_info.best_block_hash) {
|
sent += match ChainSync::create_new_hashes_rlp(io.chain(), &last_parent, &chain_info.best_block_hash) {
|
||||||
Some(rlp) => {
|
Some(rlp) => {
|
||||||
@ -2099,7 +2099,6 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use ::SyncConfig;
|
use ::SyncConfig;
|
||||||
use super::{PeerInfo, PeerAsking};
|
use super::{PeerInfo, PeerAsking};
|
||||||
use ethcore::views::BlockView;
|
|
||||||
use ethcore::header::*;
|
use ethcore::header::*;
|
||||||
use ethcore::client::*;
|
use ethcore::client::*;
|
||||||
use ethcore::miner::MinerService;
|
use ethcore::miner::MinerService;
|
||||||
@ -2253,7 +2252,8 @@ mod tests {
|
|||||||
|
|
||||||
let mut client = TestBlockChainClient::new();
|
let mut client = TestBlockChainClient::new();
|
||||||
client.add_blocks(100, EachBlockWith::Nothing);
|
client.add_blocks(100, EachBlockWith::Nothing);
|
||||||
let blocks: Vec<_> = (0 .. 100).map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap()).collect();
|
let blocks: Vec<_> = (0 .. 100)
|
||||||
|
.map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).map(|b| b.into_inner()).unwrap()).collect();
|
||||||
let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect();
|
let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect();
|
||||||
let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect();
|
let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect();
|
||||||
|
|
||||||
@ -2444,7 +2444,7 @@ mod tests {
|
|||||||
let mut client = TestBlockChainClient::new();
|
let mut client = TestBlockChainClient::new();
|
||||||
client.add_blocks(2, EachBlockWith::Uncle);
|
client.add_blocks(2, EachBlockWith::Uncle);
|
||||||
let queue = RwLock::new(VecDeque::new());
|
let queue = RwLock::new(VecDeque::new());
|
||||||
let block = client.block(BlockId::Latest).unwrap();
|
let block = client.block(BlockId::Latest).unwrap().into_inner();
|
||||||
let mut sync = ChainSync::new(SyncConfig::default(), &client);
|
let mut sync = ChainSync::new(SyncConfig::default(), &client);
|
||||||
sync.peers.insert(0,
|
sync.peers.insert(0,
|
||||||
PeerInfo {
|
PeerInfo {
|
||||||
@ -2722,9 +2722,8 @@ mod tests {
|
|||||||
// Add some balance to clients and reset nonces
|
// Add some balance to clients and reset nonces
|
||||||
for h in &[good_blocks[0], retracted_blocks[0]] {
|
for h in &[good_blocks[0], retracted_blocks[0]] {
|
||||||
let block = client.block(BlockId::Hash(*h)).unwrap();
|
let block = client.block(BlockId::Hash(*h)).unwrap();
|
||||||
let view = BlockView::new(&block);
|
client.set_balance(block.transactions()[0].sender().unwrap(), U256::from(1_000_000_000));
|
||||||
client.set_balance(view.transactions()[0].sender().unwrap(), U256::from(1_000_000_000));
|
client.set_nonce(block.transactions()[0].sender().unwrap(), U256::from(0));
|
||||||
client.set_nonce(view.transactions()[0].sender().unwrap(), U256::from(0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2741,8 +2740,7 @@ mod tests {
|
|||||||
// We need to update nonce status (because we say that the block has been imported)
|
// We need to update nonce status (because we say that the block has been imported)
|
||||||
for h in &[good_blocks[0]] {
|
for h in &[good_blocks[0]] {
|
||||||
let block = client.block(BlockId::Hash(*h)).unwrap();
|
let block = client.block(BlockId::Hash(*h)).unwrap();
|
||||||
let view = BlockView::new(&block);
|
client.set_nonce(block.transactions()[0].sender().unwrap(), U256::from(1));
|
||||||
client.set_nonce(view.transactions()[0].sender().unwrap(), U256::from(1));
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let queue = RwLock::new(VecDeque::new());
|
let queue = RwLock::new(VecDeque::new());
|
||||||
|
Loading…
Reference in New Issue
Block a user