commit
97789cbab7
@ -85,6 +85,9 @@ pub trait BlockProvider {
|
|||||||
/// Get the hash of given block's number.
|
/// Get the hash of given block's number.
|
||||||
fn block_hash(&self, index: BlockNumber) -> Option<H256>;
|
fn block_hash(&self, index: BlockNumber) -> Option<H256>;
|
||||||
|
|
||||||
|
/// Get the address of transaction with given hash.
|
||||||
|
fn transaction_address(&self, hash: &H256) -> Option<TransactionAddress>;
|
||||||
|
|
||||||
/// 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(hash).map(|bytes| BlockView::new(&bytes).header())
|
self.block(hash).map(|bytes| BlockView::new(&bytes).header())
|
||||||
@ -107,6 +110,16 @@ pub trait BlockProvider {
|
|||||||
self.block(hash).map(|bytes| BlockView::new(&bytes).header_view().number())
|
self.block(hash).map(|bytes| BlockView::new(&bytes).header_view().number())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get transaction with given transaction hash.
|
||||||
|
fn transaction(&self, hash: &H256) -> Option<SignedTransaction> {
|
||||||
|
self.transaction_address(hash).and_then(|address| self.transaction_at(&address))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get transaction at given address.
|
||||||
|
fn transaction_at(&self, address: &TransactionAddress) -> Option<SignedTransaction> {
|
||||||
|
self.block(&address.block_hash).map(|bytes| BlockView::new(&bytes).transactions()).and_then(|t| t.into_iter().nth(address.index))
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a list of transactions for a given block.
|
/// Get a list of transactions for a given block.
|
||||||
/// Returns None if block deos not exist.
|
/// Returns None if block deos not exist.
|
||||||
fn transactions(&self, hash: &H256) -> Option<Vec<SignedTransaction>> {
|
fn transactions(&self, hash: &H256) -> Option<Vec<SignedTransaction>> {
|
||||||
@ -201,6 +214,11 @@ impl BlockProvider for BlockChain {
|
|||||||
fn block_hash(&self, index: BlockNumber) -> Option<H256> {
|
fn block_hash(&self, index: BlockNumber) -> Option<H256> {
|
||||||
self.query_extras(&index, &self.block_hashes)
|
self.query_extras(&index, &self.block_hashes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the address of transaction with given hash.
|
||||||
|
fn transaction_address(&self, hash: &H256) -> Option<TransactionAddress> {
|
||||||
|
self.query_extras(hash, &self.transaction_addresses)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const COLLECTION_QUEUE_SIZE: usize = 8;
|
const COLLECTION_QUEUE_SIZE: usize = 8;
|
||||||
@ -474,6 +492,14 @@ impl BlockChain {
|
|||||||
parent_details.children.push(hash.clone());
|
parent_details.children.push(hash.clone());
|
||||||
batch.put_extras(&parent_hash, &parent_details);
|
batch.put_extras(&parent_hash, &parent_details);
|
||||||
|
|
||||||
|
// update transaction addresses
|
||||||
|
for (i, tx_hash) in block.transaction_hashes().iter().enumerate() {
|
||||||
|
batch.put_extras(tx_hash, &TransactionAddress {
|
||||||
|
block_hash: hash.clone(),
|
||||||
|
index: i
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// if it's not new best block, just return
|
// if it's not new best block, just return
|
||||||
if !is_new_best {
|
if !is_new_best {
|
||||||
return (batch, None, details);
|
return (batch, None, details);
|
||||||
@ -824,4 +850,21 @@ mod tests {
|
|||||||
let bc = bc_result.reference();
|
let bc = bc_result.reference();
|
||||||
assert_eq!(bc.best_block_number(), 0);
|
assert_eq!(bc.best_block_number(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn find_transaction_by_hash() {
|
||||||
|
let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083023e38808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0".from_hex().unwrap();
|
||||||
|
let b1 = "f904a8f901faa0ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0a65c2364cd0f1542d761823dc0109c6b072f14c20459598c5455c274601438f4a070616ebd7ad2ed6fb7860cf7e9df00163842351c38a87cac2c1cb193895035a2a05c5b4fc43c2d45787f54e1ae7d27afdb4ad16dfc567c5692070d5c4556e0b1d7b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000183023ec683021536845685109780a029f07836e4e59229b3a065913afc27702642c683bba689910b2b2fd45db310d3888957e6d004a31802f902a7f85f800a8255f094aaaf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca0575da4e21b66fa764be5f74da9389e67693d066fb0d1312e19e17e501da00ecda06baf5a5327595f6619dfc2fcb3f2e6fb410b5810af3cb52d0e7508038e91a188f85f010a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba04fa966bf34b93abc1bcd665554b7f316b50f928477b50be0f3285ead29d18c5ba017bba0eeec1625ab433746955e125d46d80b7fdc97386c51266f842d8e02192ef85f020a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca004377418ae981cc32b1312b4a427a1d69a821b28db8584f5f2bd8c6d42458adaa053a1dba1af177fac92f3b6af0a9fa46a22adf56e686c93794b6a012bf254abf5f85f030a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca04fe13febd28a05f4fcb2f451d7ddc2dda56486d9f8c79a62b0ba4da775122615a0651b2382dd402df9ebc27f8cb4b2e0f3cea68dda2dca0ee9603608f0b6f51668f85f040a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba078e6a0ba086a08f8450e208a399bb2f2d2a0d984acd2517c7c7df66ccfab567da013254002cd45a97fac049ae00afbc43ed0d9961d0c56a3b2382c80ce41c198ddf85f050a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0a7174d8f43ea71c8e3ca9477691add8d80ac8e0ed89d8d8b572041eef81f4a54a0534ea2e28ec4da3b5b944b18c51ec84a5cf35f5b3343c5fb86521fd2d388f506f85f060a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba034bd04065833536a10c77ee2a43a5371bc6d34837088b861dd9d4b7f44074b59a078807715786a13876d3455716a6b9cb2186b7a4887a5c31160fc877454958616c0".from_hex().unwrap();
|
||||||
|
let b1_hash = H256::from_str("f53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3").unwrap();
|
||||||
|
|
||||||
|
let temp = RandomTempPath::new();
|
||||||
|
let bc = BlockChain::new(&genesis, temp.as_path());
|
||||||
|
bc.insert_block(&b1);
|
||||||
|
|
||||||
|
let transactions = bc.transactions(&b1_hash).unwrap();
|
||||||
|
assert_eq!(transactions.len(), 7);
|
||||||
|
for t in transactions {
|
||||||
|
assert_eq!(bc.transaction(&t.hash()).unwrap(), t);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,6 +85,9 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
/// Get block total difficulty.
|
/// Get block total difficulty.
|
||||||
fn block_total_difficulty(&self, hash: &H256) -> Option<U256>;
|
fn block_total_difficulty(&self, hash: &H256) -> Option<U256>;
|
||||||
|
|
||||||
|
/// Get address code.
|
||||||
|
fn code(&self, address: &Address) -> Option<Bytes>;
|
||||||
|
|
||||||
/// Get raw block header data by block number.
|
/// Get raw block header data by block number.
|
||||||
fn block_header_at(&self, n: BlockNumber) -> Option<Bytes>;
|
fn block_header_at(&self, n: BlockNumber) -> Option<Bytes>;
|
||||||
|
|
||||||
@ -161,7 +164,7 @@ pub struct Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const HISTORY: u64 = 1000;
|
const HISTORY: u64 = 1000;
|
||||||
const CLIENT_DB_VER_STR: &'static str = "1.0";
|
const CLIENT_DB_VER_STR: &'static str = "2.0";
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
/// Create a new client with given spec and DB path.
|
/// Create a new client with given spec and DB path.
|
||||||
@ -358,6 +361,10 @@ impl BlockChainClient for Client {
|
|||||||
self.chain.read().unwrap().block_details(hash).map(|d| d.total_difficulty)
|
self.chain.read().unwrap().block_details(hash).map(|d| d.total_difficulty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn code(&self, address: &Address) -> Option<Bytes> {
|
||||||
|
self.state().code(address)
|
||||||
|
}
|
||||||
|
|
||||||
fn block_header_at(&self, n: BlockNumber) -> Option<Bytes> {
|
fn block_header_at(&self, n: BlockNumber) -> Option<Bytes> {
|
||||||
self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_header(&h))
|
self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_header(&h))
|
||||||
}
|
}
|
||||||
|
@ -260,7 +260,7 @@ pub struct TransactionAddress {
|
|||||||
/// Block hash
|
/// Block hash
|
||||||
pub block_hash: H256,
|
pub block_hash: H256,
|
||||||
/// Transaction index within the block
|
/// Transaction index within the block
|
||||||
pub index: u64
|
pub index: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtrasIndexable for TransactionAddress {
|
impl ExtrasIndexable for TransactionAddress {
|
||||||
|
@ -20,7 +20,7 @@ use util::*;
|
|||||||
use error::*;
|
use error::*;
|
||||||
use evm::Schedule;
|
use evm::Schedule;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
/// Transaction action type.
|
/// Transaction action type.
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
/// Create creates new contract.
|
/// Create creates new contract.
|
||||||
@ -45,7 +45,7 @@ impl Decodable for Action {
|
|||||||
|
|
||||||
/// A set of information describing an externally-originating message call
|
/// A set of information describing an externally-originating message call
|
||||||
/// or contract creation operation.
|
/// or contract creation operation.
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Transaction {
|
pub struct Transaction {
|
||||||
/// Nonce.
|
/// Nonce.
|
||||||
pub nonce: U256,
|
pub nonce: U256,
|
||||||
@ -158,7 +158,7 @@ impl Transaction {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Eq)]
|
||||||
pub struct SignedTransaction {
|
pub struct SignedTransaction {
|
||||||
/// Plain Transaction.
|
/// Plain Transaction.
|
||||||
unsigned: Transaction,
|
unsigned: Transaction,
|
||||||
@ -174,6 +174,12 @@ pub struct SignedTransaction {
|
|||||||
sender: RefCell<Option<Address>>
|
sender: RefCell<Option<Address>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for SignedTransaction {
|
||||||
|
fn eq(&self, other: &SignedTransaction) -> bool {
|
||||||
|
self.unsigned == other.unsigned && self.v == other.v && self.r == other.r && self.s == other.s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Deref for SignedTransaction {
|
impl Deref for SignedTransaction {
|
||||||
type Target = Transaction;
|
type Target = Transaction;
|
||||||
|
|
||||||
|
@ -294,6 +294,10 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn transaction_address(&self, _hash: &H256) -> Option<TransactionAddress> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the hash of given block's number.
|
/// Get the hash of given block's number.
|
||||||
fn block_hash(&self, index: BlockNumber) -> Option<H256> {
|
fn block_hash(&self, index: BlockNumber) -> Option<H256> {
|
||||||
self.numbers.get(&index).cloned()
|
self.numbers.get(&index).cloned()
|
||||||
|
@ -155,6 +155,11 @@ impl<'a> BlockView<'a> {
|
|||||||
self.rlp.val_at(1)
|
self.rlp.val_at(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return number of transactions in given block, without deserializing them.
|
||||||
|
pub fn transactions_count(&self) -> usize {
|
||||||
|
self.rlp.at(1).iter().count()
|
||||||
|
}
|
||||||
|
|
||||||
/// 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> {
|
||||||
self.rlp.at(1).iter().map(TransactionView::new_from_rlp).collect()
|
self.rlp.at(1).iter().map(TransactionView::new_from_rlp).collect()
|
||||||
@ -170,6 +175,11 @@ impl<'a> BlockView<'a> {
|
|||||||
self.rlp.val_at(2)
|
self.rlp.val_at(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return number of uncles in given block, without deserializing them.
|
||||||
|
pub fn uncles_count(&self) -> usize {
|
||||||
|
self.rlp.at(2).iter().count()
|
||||||
|
}
|
||||||
|
|
||||||
/// 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> {
|
||||||
self.rlp.at(2).iter().map(HeaderView::new_from_rlp).collect()
|
self.rlp.at(2).iter().map(HeaderView::new_from_rlp).collect()
|
||||||
|
@ -18,4 +18,4 @@ ethcore = { path = "../ethcore" }
|
|||||||
ethsync = { path = "../sync" }
|
ethsync = { path = "../sync" }
|
||||||
clippy = "0.0.37"
|
clippy = "0.0.37"
|
||||||
target_info = "0.1.0"
|
target_info = "0.1.0"
|
||||||
|
rustc-serialize = "0.3"
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#![plugin(serde_macros)]
|
#![plugin(serde_macros)]
|
||||||
#![plugin(clippy)]
|
#![plugin(clippy)]
|
||||||
|
|
||||||
|
extern crate rustc_serialize;
|
||||||
extern crate target_info;
|
extern crate target_info;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
@ -23,7 +23,7 @@ use util::sha3::*;
|
|||||||
use ethcore::client::*;
|
use ethcore::client::*;
|
||||||
use ethcore::views::*;
|
use ethcore::views::*;
|
||||||
use v1::traits::{Eth, EthFilter};
|
use v1::traits::{Eth, EthFilter};
|
||||||
use v1::types::Block;
|
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus};
|
||||||
|
|
||||||
/// Eth rpc implementation.
|
/// Eth rpc implementation.
|
||||||
pub struct EthClient {
|
pub struct EthClient {
|
||||||
@ -40,6 +40,7 @@ impl EthClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Eth for EthClient {
|
impl Eth for EthClient {
|
||||||
|
// TODO: do not hardcode protocol version
|
||||||
fn protocol_version(&self, params: Params) -> Result<Value, Error> {
|
fn protocol_version(&self, params: Params) -> Result<Value, Error> {
|
||||||
match params {
|
match params {
|
||||||
Params::None => Ok(Value::U64(63)),
|
Params::None => Ok(Value::U64(63)),
|
||||||
@ -47,6 +48,15 @@ impl Eth for EthClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: do no hardcode default sync status
|
||||||
|
fn syncing(&self, params: Params) -> Result<Value, Error> {
|
||||||
|
match params {
|
||||||
|
Params::None => to_value(&SyncStatus::default()),
|
||||||
|
_ => Err(Error::invalid_params())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: do not hardcode author.
|
||||||
fn author(&self, params: Params) -> Result<Value, Error> {
|
fn author(&self, params: Params) -> Result<Value, Error> {
|
||||||
match params {
|
match params {
|
||||||
Params::None => to_value(&Address::new()),
|
Params::None => to_value(&Address::new()),
|
||||||
@ -54,6 +64,23 @@ impl Eth for EthClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: return real value of mining once it's implemented.
|
||||||
|
fn is_mining(&self, params: Params) -> Result<Value, Error> {
|
||||||
|
match params {
|
||||||
|
Params::None => Ok(Value::Bool(false)),
|
||||||
|
_ => Err(Error::invalid_params())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: return real hashrate once we have mining
|
||||||
|
fn hashrate(&self, params: Params) -> Result<Value, Error> {
|
||||||
|
match params {
|
||||||
|
Params::None => Ok(Value::U64(0)),
|
||||||
|
_ => Err(Error::invalid_params())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: do not hardode gas_price
|
||||||
fn gas_price(&self, params: Params) -> Result<Value, Error> {
|
fn gas_price(&self, params: Params) -> Result<Value, Error> {
|
||||||
match params {
|
match params {
|
||||||
Params::None => Ok(Value::U64(0)),
|
Params::None => Ok(Value::U64(0)),
|
||||||
@ -68,27 +95,37 @@ impl Eth for EthClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_mining(&self, params: Params) -> Result<Value, Error> {
|
fn block_transaction_count(&self, params: Params) -> Result<Value, Error> {
|
||||||
match params {
|
match from_params::<H256>(params) {
|
||||||
Params::None => Ok(Value::Bool(false)),
|
Ok(hash) => match self.client.block(&hash) {
|
||||||
_ => Err(Error::invalid_params())
|
Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()),
|
||||||
|
None => Ok(Value::Null)
|
||||||
|
},
|
||||||
|
Err(err) => Err(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hashrate(&self, params: Params) -> Result<Value, Error> {
|
fn block_uncles_count(&self, params: Params) -> Result<Value, Error> {
|
||||||
match params {
|
match from_params::<H256>(params) {
|
||||||
Params::None => Ok(Value::U64(0)),
|
Ok(hash) => match self.client.block(&hash) {
|
||||||
_ => Err(Error::invalid_params())
|
Some(bytes) => to_value(&BlockView::new(&bytes).uncles_count()),
|
||||||
|
None => Ok(Value::Null)
|
||||||
|
},
|
||||||
|
Err(err) => Err(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_transaction_count(&self, _: Params) -> Result<Value, Error> {
|
// TODO: do not ignore block number param
|
||||||
Ok(Value::U64(0))
|
fn code_at(&self, params: Params) -> Result<Value, Error> {
|
||||||
|
match from_params::<(Address, BlockNumber)>(params) {
|
||||||
|
Ok((address, _block_number)) => to_value(&self.client.code(&address).map_or_else(Bytes::default, Bytes::new)),
|
||||||
|
Err(err) => Err(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block(&self, params: Params) -> Result<Value, Error> {
|
fn block(&self, params: Params) -> Result<Value, Error> {
|
||||||
match from_params::<(H256, bool)>(params) {
|
match from_params::<(H256, bool)>(params) {
|
||||||
Ok((hash, _include_txs)) => match (self.client.block_header(&hash), self.client.block_total_difficulty(&hash)) {
|
Ok((hash, include_txs)) => match (self.client.block_header(&hash), self.client.block_total_difficulty(&hash)) {
|
||||||
(Some(bytes), Some(total_difficulty)) => {
|
(Some(bytes), Some(total_difficulty)) => {
|
||||||
let view = HeaderView::new(&bytes);
|
let view = HeaderView::new(&bytes);
|
||||||
let block = Block {
|
let block = Block {
|
||||||
@ -108,7 +145,14 @@ impl Eth for EthClient {
|
|||||||
difficulty: view.difficulty(),
|
difficulty: view.difficulty(),
|
||||||
total_difficulty: total_difficulty,
|
total_difficulty: total_difficulty,
|
||||||
uncles: vec![],
|
uncles: vec![],
|
||||||
transactions: vec![]
|
transactions: {
|
||||||
|
if include_txs {
|
||||||
|
BlockTransactions::Hashes(vec![])
|
||||||
|
} else {
|
||||||
|
BlockTransactions::Full(vec![])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
extra_data: Bytes::default()
|
||||||
};
|
};
|
||||||
to_value(&block)
|
to_value(&block)
|
||||||
},
|
},
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
pub mod traits;
|
pub mod traits;
|
||||||
mod impls;
|
mod impls;
|
||||||
mod types;
|
mod types;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
pub use self::traits::{Web3, Eth, EthFilter, Net};
|
pub use self::traits::{Web3, Eth, EthFilter, Net};
|
||||||
pub use self::impls::*;
|
pub use self::impls::*;
|
||||||
|
1
rpc/src/v1/tests/mod.rs
Normal file
1
rpc/src/v1/tests/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
//TODO: load custom blockchain state and test
|
@ -23,6 +23,9 @@ pub trait Eth: Sized + Send + Sync + 'static {
|
|||||||
/// Returns protocol version.
|
/// Returns protocol version.
|
||||||
fn protocol_version(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
fn protocol_version(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
|
/// Returns an object with data about the sync status or false. (wtf?)
|
||||||
|
fn syncing(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
/// Returns the number of hashes per second that the node is mining with.
|
/// Returns the number of hashes per second that the node is mining with.
|
||||||
fn hashrate(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
fn hashrate(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
@ -108,6 +111,7 @@ pub trait Eth: Sized + Send + Sync + 'static {
|
|||||||
fn to_delegate(self) -> IoDelegate<Self> {
|
fn to_delegate(self) -> IoDelegate<Self> {
|
||||||
let mut delegate = IoDelegate::new(Arc::new(self));
|
let mut delegate = IoDelegate::new(Arc::new(self));
|
||||||
delegate.add_method("eth_protocolVersion", Eth::protocol_version);
|
delegate.add_method("eth_protocolVersion", Eth::protocol_version);
|
||||||
|
delegate.add_method("eth_syncing", Eth::syncing);
|
||||||
delegate.add_method("eth_hashrate", Eth::hashrate);
|
delegate.add_method("eth_hashrate", Eth::hashrate);
|
||||||
delegate.add_method("eth_coinbase", Eth::author);
|
delegate.add_method("eth_coinbase", Eth::author);
|
||||||
delegate.add_method("eth_mining", Eth::is_mining);
|
delegate.add_method("eth_mining", Eth::is_mining);
|
||||||
|
@ -14,10 +14,28 @@
|
|||||||
// 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 serde::{Serialize, Serializer};
|
||||||
use util::hash::*;
|
use util::hash::*;
|
||||||
use util::uint::*;
|
use util::uint::*;
|
||||||
|
use v1::types::{Bytes, Transaction};
|
||||||
|
|
||||||
#[derive(Default, Debug, Serialize)]
|
#[derive(Debug)]
|
||||||
|
pub enum BlockTransactions {
|
||||||
|
Hashes(Vec<H256>),
|
||||||
|
Full(Vec<Transaction>)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for BlockTransactions {
|
||||||
|
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||||
|
where S: Serializer {
|
||||||
|
match *self {
|
||||||
|
BlockTransactions::Hashes(ref hashes) => hashes.serialize(serializer),
|
||||||
|
BlockTransactions::Full(ref ts) => ts.serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
pub hash: H256,
|
pub hash: H256,
|
||||||
#[serde(rename="parentHash")]
|
#[serde(rename="parentHash")]
|
||||||
@ -38,9 +56,8 @@ pub struct Block {
|
|||||||
pub gas_used: U256,
|
pub gas_used: U256,
|
||||||
#[serde(rename="gasLimit")]
|
#[serde(rename="gasLimit")]
|
||||||
pub gas_limit: U256,
|
pub gas_limit: U256,
|
||||||
// TODO: figure out how to properly serialize bytes
|
#[serde(rename="extraData")]
|
||||||
//#[serde(rename="extraData")]
|
pub extra_data: Bytes,
|
||||||
//extra_data: Vec<u8>,
|
|
||||||
#[serde(rename="logsBloom")]
|
#[serde(rename="logsBloom")]
|
||||||
pub logs_bloom: H2048,
|
pub logs_bloom: H2048,
|
||||||
pub timestamp: U256,
|
pub timestamp: U256,
|
||||||
@ -48,5 +65,52 @@ pub struct Block {
|
|||||||
#[serde(rename="totalDifficulty")]
|
#[serde(rename="totalDifficulty")]
|
||||||
pub total_difficulty: U256,
|
pub total_difficulty: U256,
|
||||||
pub uncles: Vec<U256>,
|
pub uncles: Vec<U256>,
|
||||||
pub transactions: Vec<U256>
|
pub transactions: BlockTransactions
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use serde_json;
|
||||||
|
use util::hash::*;
|
||||||
|
use util::uint::*;
|
||||||
|
use v1::types::{Transaction, Bytes};
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialize_block_transactions() {
|
||||||
|
let t = BlockTransactions::Full(vec![Transaction::default()]);
|
||||||
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
|
assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x00","transactionIndex":"0x00","from":"0x0000000000000000000000000000000000000000","to":"0x0000000000000000000000000000000000000000","value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}]"#);
|
||||||
|
|
||||||
|
let t = BlockTransactions::Hashes(vec![H256::default()]);
|
||||||
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
|
assert_eq!(serialized, r#"["0x0000000000000000000000000000000000000000000000000000000000000000"]"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialize_block() {
|
||||||
|
let block = Block {
|
||||||
|
hash: H256::default(),
|
||||||
|
parent_hash: H256::default(),
|
||||||
|
uncles_hash: H256::default(),
|
||||||
|
author: Address::default(),
|
||||||
|
miner: Address::default(),
|
||||||
|
state_root: H256::default(),
|
||||||
|
transactions_root: H256::default(),
|
||||||
|
receipts_root: H256::default(),
|
||||||
|
number: U256::default(),
|
||||||
|
gas_used: U256::default(),
|
||||||
|
gas_limit: U256::default(),
|
||||||
|
extra_data: Bytes::default(),
|
||||||
|
logs_bloom: H2048::default(),
|
||||||
|
timestamp: U256::default(),
|
||||||
|
difficulty: U256::default(),
|
||||||
|
total_difficulty: U256::default(),
|
||||||
|
uncles: vec![],
|
||||||
|
transactions: BlockTransactions::Hashes(vec![])
|
||||||
|
};
|
||||||
|
|
||||||
|
let serialized = serde_json::to_string(&block).unwrap();
|
||||||
|
assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","author":"0x0000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","number":"0x00","gasUsed":"0x00","gasLimit":"0x00","extraData":"0x00","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x00","difficulty":"0x00","totalDifficulty":"0x00","uncles":[],"transactions":[]}"#);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
68
rpc/src/v1/types/block_number.rs
Normal file
68
rpc/src/v1/types/block_number.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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/>.
|
||||||
|
|
||||||
|
use serde::{Deserialize, Deserializer, Error};
|
||||||
|
use serde::de::Visitor;
|
||||||
|
|
||||||
|
/// Represents rpc api block number param.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum BlockNumber {
|
||||||
|
Num(u64),
|
||||||
|
Latest,
|
||||||
|
Earliest,
|
||||||
|
Pending
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserialize for BlockNumber {
|
||||||
|
fn deserialize<D>(deserializer: &mut D) -> Result<BlockNumber, D::Error>
|
||||||
|
where D: Deserializer {
|
||||||
|
deserializer.visit(BlockNumberVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BlockNumberVisitor;
|
||||||
|
|
||||||
|
impl Visitor for BlockNumberVisitor {
|
||||||
|
type Value = BlockNumber;
|
||||||
|
|
||||||
|
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: Error {
|
||||||
|
match value {
|
||||||
|
"latest" => Ok(BlockNumber::Latest),
|
||||||
|
"earliest" => Ok(BlockNumber::Earliest),
|
||||||
|
"pending" => Ok(BlockNumber::Pending),
|
||||||
|
_ if value.starts_with("0x") => u64::from_str_radix(&value[2..], 16).map(BlockNumber::Num).map_err(|_| Error::syntax("invalid block number")),
|
||||||
|
_ => value.parse::<u64>().map(BlockNumber::Num).map_err(|_| Error::syntax("invalid block number"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: Error {
|
||||||
|
self.visit_str(value.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use serde_json;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_number_deserialization() {
|
||||||
|
let s = r#"["0xa", "10", "latest", "earliest", "pending"]"#;
|
||||||
|
let deserialized: Vec<BlockNumber> = serde_json::from_str(s).unwrap();
|
||||||
|
assert_eq!(deserialized, vec![BlockNumber::Num(10), BlockNumber::Num(10), BlockNumber::Latest, BlockNumber::Earliest, BlockNumber::Pending])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
61
rpc/src/v1/types/bytes.rs
Normal file
61
rpc/src/v1/types/bytes.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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/>.
|
||||||
|
|
||||||
|
use rustc_serialize::hex::ToHex;
|
||||||
|
use serde::{Serialize, Serializer};
|
||||||
|
|
||||||
|
/// Wrapper structure around vector of bytes.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Bytes(Vec<u8>);
|
||||||
|
|
||||||
|
impl Bytes {
|
||||||
|
/// Simple constructor.
|
||||||
|
pub fn new(bytes: Vec<u8>) -> Bytes {
|
||||||
|
Bytes(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Bytes {
|
||||||
|
fn default() -> Self {
|
||||||
|
// default serialized value is 0x00
|
||||||
|
Bytes(vec![0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for Bytes {
|
||||||
|
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||||
|
where S: Serializer {
|
||||||
|
let mut serialized = "0x".to_owned();
|
||||||
|
serialized.push_str(self.0.to_hex().as_ref());
|
||||||
|
serializer.visit_str(serialized.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use serde_json;
|
||||||
|
use rustc_serialize::hex::FromHex;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bytes_serialize() {
|
||||||
|
let bytes = Bytes("0123456789abcdef".from_hex().unwrap());
|
||||||
|
let serialized = serde_json::to_string(&bytes).unwrap();
|
||||||
|
assert_eq!(serialized, r#""0x0123456789abcdef""#);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -15,5 +15,13 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
mod block;
|
mod block;
|
||||||
|
mod block_number;
|
||||||
|
mod bytes;
|
||||||
|
mod sync;
|
||||||
|
mod transaction;
|
||||||
|
|
||||||
pub use self::block::Block;
|
pub use self::block::{Block, BlockTransactions};
|
||||||
|
pub use self::block_number::BlockNumber;
|
||||||
|
pub use self::bytes::Bytes;
|
||||||
|
pub use self::sync::SyncStatus;
|
||||||
|
pub use self::transaction::Transaction;
|
||||||
|
27
rpc/src/v1/types/sync.rs
Normal file
27
rpc/src/v1/types/sync.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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/>.
|
||||||
|
|
||||||
|
use util::hash::*;
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Serialize)]
|
||||||
|
pub struct SyncStatus {
|
||||||
|
#[serde(rename="startingBlock")]
|
||||||
|
pub starting_block: H256,
|
||||||
|
#[serde(rename="currentBlock")]
|
||||||
|
pub current_block: H256,
|
||||||
|
#[serde(rename="highestBlock")]
|
||||||
|
pub highest_block: H256,
|
||||||
|
}
|
52
rpc/src/v1/types/transaction.rs
Normal file
52
rpc/src/v1/types/transaction.rs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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/>.
|
||||||
|
|
||||||
|
use util::hash::*;
|
||||||
|
use util::uint::*;
|
||||||
|
use v1::types::Bytes;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Serialize)]
|
||||||
|
pub struct Transaction {
|
||||||
|
hash: H256,
|
||||||
|
nonce: U256,
|
||||||
|
#[serde(rename="blockHash")]
|
||||||
|
block_hash: H256,
|
||||||
|
#[serde(rename="blockNumber")]
|
||||||
|
block_number: U256,
|
||||||
|
#[serde(rename="transactionIndex")]
|
||||||
|
transaction_index: U256,
|
||||||
|
from: Address,
|
||||||
|
to: Address,
|
||||||
|
value: U256,
|
||||||
|
#[serde(rename="gasPrice")]
|
||||||
|
gas_price: U256,
|
||||||
|
gas: U256,
|
||||||
|
input: Bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use serde_json;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_transaction_serialize() {
|
||||||
|
let t = Transaction::default();
|
||||||
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
|
assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x00","transactionIndex":"0x00","from":"0x0000000000000000000000000000000000000000","to":"0x0000000000000000000000000000000000000000","value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}"#);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -82,6 +82,10 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
Some(U256::zero())
|
Some(U256::zero())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn code(&self, _address: &Address) -> Option<Bytes> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
fn block_header(&self, h: &H256) -> Option<Bytes> {
|
fn block_header(&self, h: &H256) -> Option<Bytes> {
|
||||||
self.blocks.read().unwrap().get(h).map(|r| Rlp::new(r).at(0).as_raw().to_vec())
|
self.blocks.read().unwrap().get(h).map(|r| Rlp::new(r).at(0).as_raw().to_vec())
|
||||||
}
|
}
|
||||||
|
@ -458,7 +458,8 @@ macro_rules! construct_uint {
|
|||||||
let mut hex = "0x".to_owned();
|
let mut hex = "0x".to_owned();
|
||||||
let mut bytes = [0u8; 8 * $n_words];
|
let mut bytes = [0u8; 8 * $n_words];
|
||||||
self.to_bytes(&mut bytes);
|
self.to_bytes(&mut bytes);
|
||||||
hex.push_str(bytes.to_hex().as_ref());
|
let len = cmp::max((self.bits() + 7) / 8, 1);
|
||||||
|
hex.push_str(bytes[bytes.len() - len..].to_hex().as_ref());
|
||||||
serializer.visit_str(hex.as_ref())
|
serializer.visit_str(hex.as_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user