Exposing engine extra info in block RPC (#3169)
* Exposing extra info in RPC * Proper serialization and client trait API
This commit is contained in:
parent
d37f4cc82f
commit
f31d42d0c5
@ -65,7 +65,7 @@ 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::{View, UntrustedRlp};
|
use rlp::{decode, View, UntrustedRlp};
|
||||||
use state_db::StateDB;
|
use state_db::StateDB;
|
||||||
use rand::OsRng;
|
use rand::OsRng;
|
||||||
|
|
||||||
@ -1189,6 +1189,18 @@ impl BlockChainClient for Client {
|
|||||||
fn signing_network_id(&self) -> Option<u8> {
|
fn signing_network_id(&self) -> Option<u8> {
|
||||||
self.engine.signing_network_id(&self.latest_env_info())
|
self.engine.signing_network_id(&self.latest_env_info())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn block_extra_info(&self, id: BlockID) -> Option<BTreeMap<String, String>> {
|
||||||
|
self.block_header(id)
|
||||||
|
.map(|block| decode(&block))
|
||||||
|
.map(|header| self.engine.extra_info(&header))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uncle_extra_info(&self, id: UncleID) -> Option<BTreeMap<String, String>> {
|
||||||
|
self.uncle(id)
|
||||||
|
.map(|block| BlockView::new(&block).header())
|
||||||
|
.map(|header| self.engine.extra_info(&header))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MiningBlockChainClient for Client {
|
impl MiningBlockChainClient for Client {
|
||||||
|
@ -38,6 +38,7 @@ use evm::{Factory as EvmFactory, VMType, Schedule};
|
|||||||
use miner::{Miner, MinerService, TransactionImportResult};
|
use miner::{Miner, MinerService, TransactionImportResult};
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use types::mode::Mode;
|
use types::mode::Mode;
|
||||||
|
use views::BlockView;
|
||||||
|
|
||||||
use verification::queue::QueueInfo;
|
use verification::queue::QueueInfo;
|
||||||
use block::{OpenBlock, SealedBlock};
|
use block::{OpenBlock, SealedBlock};
|
||||||
@ -417,6 +418,10 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
None // Simple default.
|
None // Simple default.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn uncle_extra_info(&self, _id: UncleID) -> Option<BTreeMap<String, String>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn transaction_receipt(&self, id: TransactionID) -> Option<LocalizedReceipt> {
|
fn transaction_receipt(&self, id: TransactionID) -> Option<LocalizedReceipt> {
|
||||||
self.receipts.read().get(&id).cloned()
|
self.receipts.read().get(&id).cloned()
|
||||||
}
|
}
|
||||||
@ -459,6 +464,13 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn block_extra_info(&self, id: BlockID) -> Option<BTreeMap<String, String>> {
|
||||||
|
self.block(id)
|
||||||
|
.map(|block| BlockView::new(&block).header())
|
||||||
|
.map(|header| self.spec.engine.extra_info(&header))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn block_status(&self, id: BlockID) -> BlockStatus {
|
fn block_status(&self, id: BlockID) -> BlockStatus {
|
||||||
match id {
|
match id {
|
||||||
BlockID::Number(number) if (number as usize) < self.blocks.read().len() => BlockStatus::InChain,
|
BlockID::Number(number) if (number as usize) < self.blocks.read().len() => BlockStatus::InChain,
|
||||||
|
@ -29,13 +29,13 @@ use error::{ImportResult, CallError};
|
|||||||
use receipt::LocalizedReceipt;
|
use receipt::LocalizedReceipt;
|
||||||
use trace::LocalizedTrace;
|
use trace::LocalizedTrace;
|
||||||
use evm::{Factory as EvmFactory, Schedule};
|
use evm::{Factory as EvmFactory, Schedule};
|
||||||
use types::ids::*;
|
|
||||||
use types::trace_filter::Filter as TraceFilter;
|
|
||||||
use executive::Executed;
|
use executive::Executed;
|
||||||
use env_info::LastHashes;
|
use env_info::LastHashes;
|
||||||
use types::call_analytics::CallAnalytics;
|
|
||||||
use block_import_error::BlockImportError;
|
use block_import_error::BlockImportError;
|
||||||
use ipc::IpcConfig;
|
use ipc::IpcConfig;
|
||||||
|
use types::ids::*;
|
||||||
|
use types::trace_filter::Filter as TraceFilter;
|
||||||
|
use types::call_analytics::CallAnalytics;
|
||||||
use types::blockchain_info::BlockChainInfo;
|
use types::blockchain_info::BlockChainInfo;
|
||||||
use types::block_status::BlockStatus;
|
use types::block_status::BlockStatus;
|
||||||
use types::mode::Mode;
|
use types::mode::Mode;
|
||||||
@ -235,6 +235,12 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
|
|
||||||
/// Set the mode.
|
/// Set the mode.
|
||||||
fn set_mode(&self, mode: Mode);
|
fn set_mode(&self, mode: Mode);
|
||||||
|
|
||||||
|
/// Returns engine-related extra info for `BlockID`.
|
||||||
|
fn block_extra_info(&self, id: BlockID) -> Option<BTreeMap<String, String>>;
|
||||||
|
|
||||||
|
/// Returns engine-related extra info for `UncleID`.
|
||||||
|
fn uncle_extra_info(&self, id: UncleID) -> Option<BTreeMap<String, String>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extended client interface used for mining
|
/// Extended client interface used for mining
|
||||||
|
@ -81,7 +81,7 @@ impl Engine for BasicAuthority {
|
|||||||
fn builtins(&self) -> &BTreeMap<Address, Builtin> { &self.builtins }
|
fn builtins(&self) -> &BTreeMap<Address, Builtin> { &self.builtins }
|
||||||
|
|
||||||
/// Additional engine-specific information for the user/developer concerning `header`.
|
/// Additional engine-specific information for the user/developer concerning `header`.
|
||||||
fn extra_info(&self, _header: &Header) -> HashMap<String, String> { hash_map!["signature".to_owned() => "TODO".to_owned()] }
|
fn extra_info(&self, _header: &Header) -> BTreeMap<String, String> { map!["signature".to_owned() => "TODO".to_owned()] }
|
||||||
|
|
||||||
fn schedule(&self, _env_info: &EnvInfo) -> Schedule {
|
fn schedule(&self, _env_info: &EnvInfo) -> Schedule {
|
||||||
Schedule::new_homestead()
|
Schedule::new_homestead()
|
||||||
|
@ -47,7 +47,7 @@ pub trait Engine : Sync + Send {
|
|||||||
fn seal_fields(&self) -> usize { 0 }
|
fn seal_fields(&self) -> usize { 0 }
|
||||||
|
|
||||||
/// Additional engine-specific information for the user/developer concerning `header`.
|
/// Additional engine-specific information for the user/developer concerning `header`.
|
||||||
fn extra_info(&self, _header: &Header) -> HashMap<String, String> { HashMap::new() }
|
fn extra_info(&self, _header: &Header) -> BTreeMap<String, String> { BTreeMap::new() }
|
||||||
|
|
||||||
/// Additional information.
|
/// Additional information.
|
||||||
fn additional_params(&self) -> HashMap<String, String> { HashMap::new() }
|
fn additional_params(&self) -> HashMap<String, String> { HashMap::new() }
|
||||||
|
@ -133,8 +133,8 @@ impl Engine for Ethash {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Additional engine-specific information for the user/developer concerning `header`.
|
/// Additional engine-specific information for the user/developer concerning `header`.
|
||||||
fn extra_info(&self, header: &Header) -> HashMap<String, String> {
|
fn extra_info(&self, header: &Header) -> BTreeMap<String, String> {
|
||||||
hash_map!["nonce".to_owned() => format!("0x{}", header.nonce().hex()), "mixHash".to_owned() => format!("0x{}", header.mix_hash().hex())]
|
map!["nonce".to_owned() => format!("0x{}", header.nonce().hex()), "mixHash".to_owned() => format!("0x{}", header.mix_hash().hex())]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schedule(&self, env_info: &EnvInfo) -> Schedule {
|
fn schedule(&self, env_info: &EnvInfo) -> Schedule {
|
||||||
|
@ -55,7 +55,7 @@ pub struct TraceId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Uniquely identifies Uncle.
|
/// Uniquely identifies Uncle.
|
||||||
#[derive(Debug, Binary)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone, Binary)]
|
||||||
pub struct UncleID {
|
pub struct UncleID {
|
||||||
/// Block id.
|
/// Block id.
|
||||||
pub block: BlockID,
|
pub block: BlockID,
|
||||||
|
@ -44,7 +44,7 @@ use ethcore::snapshot::SnapshotService;
|
|||||||
use self::ethash::SeedHashCompute;
|
use self::ethash::SeedHashCompute;
|
||||||
use v1::traits::Eth;
|
use v1::traits::Eth;
|
||||||
use v1::types::{
|
use v1::types::{
|
||||||
Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo,
|
RichBlock, Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo,
|
||||||
Transaction, CallRequest, Index, Filter, Log, Receipt, Work,
|
Transaction, CallRequest, Index, Filter, Log, Receipt, Work,
|
||||||
H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256,
|
H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256,
|
||||||
};
|
};
|
||||||
@ -53,6 +53,8 @@ use v1::helpers::dispatch::{default_gas_price, dispatch_transaction};
|
|||||||
use v1::helpers::block_import::is_major_importing;
|
use v1::helpers::block_import::is_major_importing;
|
||||||
use v1::helpers::auto_args::Trailing;
|
use v1::helpers::auto_args::Trailing;
|
||||||
|
|
||||||
|
const EXTRA_INFO_PROOF: &'static str = "Object exists in in blockchain (fetched earlier), extra_info is always available if object exists; qed";
|
||||||
|
|
||||||
/// Eth RPC options
|
/// Eth RPC options
|
||||||
pub struct EthClientOptions {
|
pub struct EthClientOptions {
|
||||||
/// Returns receipt from pending blocks
|
/// Returns receipt from pending blocks
|
||||||
@ -117,36 +119,39 @@ 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<Block>, 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(bytes), Some(total_difficulty)) => {
|
||||||
let block_view = BlockView::new(&bytes);
|
let block_view = BlockView::new(&bytes);
|
||||||
let view = block_view.header_view();
|
let view = block_view.header_view();
|
||||||
let block = Block {
|
let block = RichBlock {
|
||||||
hash: Some(view.sha3().into()),
|
block: Block {
|
||||||
size: Some(bytes.len().into()),
|
hash: Some(view.sha3().into()),
|
||||||
parent_hash: view.parent_hash().into(),
|
size: Some(bytes.len().into()),
|
||||||
uncles_hash: view.uncles_hash().into(),
|
parent_hash: view.parent_hash().into(),
|
||||||
author: view.author().into(),
|
uncles_hash: view.uncles_hash().into(),
|
||||||
miner: view.author().into(),
|
author: view.author().into(),
|
||||||
state_root: view.state_root().into(),
|
miner: view.author().into(),
|
||||||
transactions_root: view.transactions_root().into(),
|
state_root: view.state_root().into(),
|
||||||
receipts_root: view.receipts_root().into(),
|
transactions_root: view.transactions_root().into(),
|
||||||
number: Some(view.number().into()),
|
receipts_root: view.receipts_root().into(),
|
||||||
gas_used: view.gas_used().into(),
|
number: Some(view.number().into()),
|
||||||
gas_limit: view.gas_limit().into(),
|
gas_used: view.gas_used().into(),
|
||||||
logs_bloom: view.log_bloom().into(),
|
gas_limit: view.gas_limit().into(),
|
||||||
timestamp: view.timestamp().into(),
|
logs_bloom: view.log_bloom().into(),
|
||||||
difficulty: view.difficulty().into(),
|
timestamp: view.timestamp().into(),
|
||||||
total_difficulty: total_difficulty.into(),
|
difficulty: view.difficulty().into(),
|
||||||
seal_fields: view.seal().into_iter().map(|f| rlp::decode(&f)).map(Bytes::new).collect(),
|
total_difficulty: total_difficulty.into(),
|
||||||
uncles: block_view.uncle_hashes().into_iter().map(Into::into).collect(),
|
seal_fields: view.seal().into_iter().map(|f| rlp::decode(&f)).map(Bytes::new).collect(),
|
||||||
transactions: match include_txs {
|
uncles: block_view.uncle_hashes().into_iter().map(Into::into).collect(),
|
||||||
true => BlockTransactions::Full(block_view.localized_transactions().into_iter().map(Into::into).collect()),
|
transactions: match include_txs {
|
||||||
false => BlockTransactions::Hashes(block_view.transaction_hashes().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()),
|
||||||
|
},
|
||||||
|
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),
|
||||||
};
|
};
|
||||||
Ok(Some(block))
|
Ok(Some(block))
|
||||||
},
|
},
|
||||||
@ -161,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<Block>, 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(rlp) => rlp::decode(&rlp),
|
||||||
@ -172,27 +177,30 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
|
|||||||
None => { return Ok(None); }
|
None => { return Ok(None); }
|
||||||
};
|
};
|
||||||
|
|
||||||
let block = Block {
|
let block = RichBlock {
|
||||||
hash: Some(uncle.hash().into()),
|
block: Block {
|
||||||
size: None,
|
hash: Some(uncle.hash().into()),
|
||||||
parent_hash: uncle.parent_hash().clone().into(),
|
size: None,
|
||||||
uncles_hash: uncle.uncles_hash().clone().into(),
|
parent_hash: uncle.parent_hash().clone().into(),
|
||||||
author: uncle.author().clone().into(),
|
uncles_hash: uncle.uncles_hash().clone().into(),
|
||||||
miner: uncle.author().clone().into(),
|
author: uncle.author().clone().into(),
|
||||||
state_root: uncle.state_root().clone().into(),
|
miner: uncle.author().clone().into(),
|
||||||
transactions_root: uncle.transactions_root().clone().into(),
|
state_root: uncle.state_root().clone().into(),
|
||||||
number: Some(uncle.number().into()),
|
transactions_root: uncle.transactions_root().clone().into(),
|
||||||
gas_used: uncle.gas_used().clone().into(),
|
number: Some(uncle.number().into()),
|
||||||
gas_limit: uncle.gas_limit().clone().into(),
|
gas_used: uncle.gas_used().clone().into(),
|
||||||
logs_bloom: uncle.log_bloom().clone().into(),
|
gas_limit: uncle.gas_limit().clone().into(),
|
||||||
timestamp: uncle.timestamp().into(),
|
logs_bloom: uncle.log_bloom().clone().into(),
|
||||||
difficulty: uncle.difficulty().clone().into(),
|
timestamp: uncle.timestamp().into(),
|
||||||
total_difficulty: (uncle.difficulty().clone() + parent_difficulty).into(),
|
difficulty: uncle.difficulty().clone().into(),
|
||||||
receipts_root: uncle.receipts_root().clone().into(),
|
total_difficulty: (uncle.difficulty().clone() + parent_difficulty).into(),
|
||||||
extra_data: uncle.extra_data().clone().into(),
|
receipts_root: uncle.receipts_root().clone().into(),
|
||||||
seal_fields: uncle.seal().clone().into_iter().map(|f| rlp::decode(&f)).map(Bytes::new).collect(),
|
extra_data: uncle.extra_data().clone().into(),
|
||||||
uncles: vec![],
|
seal_fields: uncle.seal().clone().into_iter().map(|f| rlp::decode(&f)).map(Bytes::new).collect(),
|
||||||
transactions: BlockTransactions::Hashes(vec![]),
|
uncles: vec![],
|
||||||
|
transactions: BlockTransactions::Hashes(vec![]),
|
||||||
|
},
|
||||||
|
extra_info: client.uncle_extra_info(id).expect(EXTRA_INFO_PROOF),
|
||||||
};
|
};
|
||||||
Ok(Some(block))
|
Ok(Some(block))
|
||||||
}
|
}
|
||||||
@ -435,13 +443,13 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_by_hash(&self, hash: RpcH256, include_txs: bool) -> Result<Option<Block>, Error> {
|
fn block_by_hash(&self, hash: RpcH256, include_txs: bool) -> Result<Option<RichBlock>, Error> {
|
||||||
try!(self.active());
|
try!(self.active());
|
||||||
|
|
||||||
self.block(BlockID::Hash(hash.into()), include_txs)
|
self.block(BlockID::Hash(hash.into()), include_txs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> Result<Option<Block>, Error> {
|
fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> Result<Option<RichBlock>, Error> {
|
||||||
try!(self.active());
|
try!(self.active());
|
||||||
|
|
||||||
self.block(num.into(), include_txs)
|
self.block(num.into(), include_txs)
|
||||||
@ -483,13 +491,13 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uncle_by_block_hash_and_index(&self, hash: RpcH256, index: Index) -> Result<Option<Block>, Error> {
|
fn uncle_by_block_hash_and_index(&self, hash: RpcH256, index: Index) -> Result<Option<RichBlock>, Error> {
|
||||||
try!(self.active());
|
try!(self.active());
|
||||||
|
|
||||||
self.uncle(UncleID { block: BlockID::Hash(hash.into()), position: index.value() })
|
self.uncle(UncleID { block: BlockID::Hash(hash.into()), position: index.value() })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uncle_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> Result<Option<Block>, Error> {
|
fn uncle_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> Result<Option<RichBlock>, Error> {
|
||||||
try!(self.active());
|
try!(self.active());
|
||||||
|
|
||||||
self.uncle(UncleID { block: num.into(), position: index.value() })
|
self.uncle(UncleID { block: num.into(), position: index.value() })
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Eth rpc interface.
|
//! Eth rpc interface.
|
||||||
use jsonrpc_core::*;
|
use jsonrpc_core::*;
|
||||||
|
|
||||||
use v1::types::{Block, BlockNumber, Bytes, CallRequest, Filter, FilterChanges, Index};
|
use v1::types::{RichBlock, BlockNumber, Bytes, CallRequest, Filter, FilterChanges, Index};
|
||||||
use v1::types::{Log, Receipt, SyncStatus, Transaction, Work};
|
use v1::types::{Log, Receipt, SyncStatus, Transaction, Work};
|
||||||
use v1::types::{H64, H160, H256, U256};
|
use v1::types::{H64, H160, H256, U256};
|
||||||
|
|
||||||
@ -68,11 +68,11 @@ build_rpc_trait! {
|
|||||||
|
|
||||||
/// Returns block with given hash.
|
/// Returns block with given hash.
|
||||||
#[rpc(name = "eth_getBlockByHash")]
|
#[rpc(name = "eth_getBlockByHash")]
|
||||||
fn block_by_hash(&self, H256, bool) -> Result<Option<Block>, Error>;
|
fn block_by_hash(&self, H256, bool) -> Result<Option<RichBlock>, Error>;
|
||||||
|
|
||||||
/// Returns block with given number.
|
/// Returns block with given number.
|
||||||
#[rpc(name = "eth_getBlockByNumber")]
|
#[rpc(name = "eth_getBlockByNumber")]
|
||||||
fn block_by_number(&self, BlockNumber, bool) -> Result<Option<Block>, Error>;
|
fn block_by_number(&self, BlockNumber, bool) -> Result<Option<RichBlock>, Error>;
|
||||||
|
|
||||||
/// Returns the number of transactions sent from given address at given time (block number).
|
/// Returns the number of transactions sent from given address at given time (block number).
|
||||||
#[rpc(name = "eth_getTransactionCount")]
|
#[rpc(name = "eth_getTransactionCount")]
|
||||||
@ -128,11 +128,11 @@ build_rpc_trait! {
|
|||||||
|
|
||||||
/// Returns an uncles at given block and index.
|
/// Returns an uncles at given block and index.
|
||||||
#[rpc(name = "eth_getUncleByBlockHashAndIndex")]
|
#[rpc(name = "eth_getUncleByBlockHashAndIndex")]
|
||||||
fn uncle_by_block_hash_and_index(&self, H256, Index) -> Result<Option<Block>, Error>;
|
fn uncle_by_block_hash_and_index(&self, H256, Index) -> Result<Option<RichBlock>, Error>;
|
||||||
|
|
||||||
/// Returns an uncles at given block and index.
|
/// Returns an uncles at given block and index.
|
||||||
#[rpc(name = "eth_getUncleByBlockNumberAndIndex")]
|
#[rpc(name = "eth_getUncleByBlockNumberAndIndex")]
|
||||||
fn uncle_by_block_number_and_index(&self, BlockNumber, Index) -> Result<Option<Block>, Error>;
|
fn uncle_by_block_number_and_index(&self, BlockNumber, Index) -> Result<Option<RichBlock>, Error>;
|
||||||
|
|
||||||
/// Returns available compilers.
|
/// Returns available compilers.
|
||||||
#[rpc(name = "eth_getCompilers")]
|
#[rpc(name = "eth_getCompilers")]
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
use v1::types::{Bytes, Transaction, H160, H256, H2048, U256};
|
use v1::types::{Bytes, Transaction, H160, H256, H2048, U256};
|
||||||
|
|
||||||
@ -93,11 +95,45 @@ pub struct Block {
|
|||||||
pub size: Option<U256>,
|
pub size: Option<U256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Block representation with additional info
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RichBlock {
|
||||||
|
/// Standard block
|
||||||
|
pub block: Block,
|
||||||
|
/// Engine-specific fields with additional description.
|
||||||
|
/// Should be included directly to serialized block object.
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
pub extra_info: BTreeMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for RichBlock {
|
||||||
|
type Target = Block;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for RichBlock {
|
||||||
|
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
|
||||||
|
use serde_json::{to_value, Value};
|
||||||
|
|
||||||
|
let serialized = (to_value(&self.block), to_value(&self.extra_info));
|
||||||
|
if let (Value::Object(mut block), Value::Object(extras)) = serialized {
|
||||||
|
// join two objects
|
||||||
|
block.extend(extras);
|
||||||
|
// and serialize
|
||||||
|
try!(block.serialize(serializer));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use v1::types::{Transaction, H160, H256, H2048, Bytes, U256};
|
use v1::types::{Transaction, H64, H160, H256, H2048, Bytes, U256};
|
||||||
use super::{Block, BlockTransactions};
|
use super::{Block, RichBlock, BlockTransactions};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialize_block_transactions() {
|
fn test_serialize_block_transactions() {
|
||||||
@ -134,8 +170,17 @@ mod tests {
|
|||||||
transactions: BlockTransactions::Hashes(vec![].into()),
|
transactions: BlockTransactions::Hashes(vec![].into()),
|
||||||
size: Some(69.into()),
|
size: Some(69.into()),
|
||||||
};
|
};
|
||||||
|
let serialized_block = serde_json::to_string(&block).unwrap();
|
||||||
|
let rich_block = RichBlock {
|
||||||
|
block: block,
|
||||||
|
extra_info: map![
|
||||||
|
"mixHash".into() => format!("0x{:?}", H256::default()),
|
||||||
|
"nonce".into() => format!("0x{:?}", H64::default())
|
||||||
|
],
|
||||||
|
};
|
||||||
|
let serialized_rich_block = serde_json::to_string(&rich_block).unwrap();
|
||||||
|
|
||||||
let serialized = serde_json::to_string(&block).unwrap();
|
assert_eq!(serialized_block, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","author":"0x0000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","number":"0x0","gasUsed":"0x0","gasLimit":"0x0","extraData":"0x","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x0","difficulty":"0x0","totalDifficulty":"0x0","sealFields":["0x","0x"],"uncles":[],"transactions":[],"size":"0x45"}"#);
|
||||||
assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","author":"0x0000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","number":"0x0","gasUsed":"0x0","gasLimit":"0x0","extraData":"0x","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x0","difficulty":"0x0","totalDifficulty":"0x0","sealFields":["0x","0x"],"uncles":[],"transactions":[],"size":"0x45"}"#);
|
assert_eq!(serialized_rich_block, r#"{"author":"0x0000000000000000000000000000000000000000","difficulty":"0x0","extraData":"0x","gasLimit":"0x0","gasUsed":"0x0","hash":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","number":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","sealFields":["0x","0x"],"sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","size":"0x45","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x0","totalDifficulty":"0x0","transactions":[],"transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","uncles":[]}"#);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ mod work;
|
|||||||
mod histogram;
|
mod histogram;
|
||||||
|
|
||||||
pub use self::bytes::Bytes;
|
pub use self::bytes::Bytes;
|
||||||
pub use self::block::{Block, BlockTransactions};
|
pub use self::block::{RichBlock, Block, BlockTransactions};
|
||||||
pub use self::block_number::BlockNumber;
|
pub use self::block_number::BlockNumber;
|
||||||
pub use self::call_request::CallRequest;
|
pub use self::call_request::CallRequest;
|
||||||
pub use self::confirmations::{ConfirmationPayload, ConfirmationRequest, TransactionModification};
|
pub use self::confirmations::{ConfirmationPayload, ConfirmationRequest, TransactionModification};
|
||||||
|
Loading…
Reference in New Issue
Block a user