Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

jsonrpc #391

Merged
merged 19 commits into from
Feb 10, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 34 additions & 11 deletions ethcore/src/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@ use extras::*;
use transaction::*;
use views::*;

/// Uniquely identifies block.
pub enum BlockId {
/// Block's sha3.
/// Querying by hash is always faster.
Hash(H256),
/// Block number within canon blockchain.
Number(BlockNumber)
}

/// Uniquely identifies transaction.
pub enum TransactionId {
/// Transaction's sha3.
Hash(H256),
/// Block id and transaction index within this block.
/// Querying by block position is always faster.
Location(BlockId, usize)
}

/// Represents a tree route between `from` block and `to` block:
pub struct TreeRoute {
/// A vector of hashes of all blocks, ordered from `from` to `to`.
Expand Down Expand Up @@ -111,19 +129,24 @@ pub trait BlockProvider {
}

/// 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))
fn transaction(&self, id: TransactionId) -> Option<LocalizedTransaction> {
match id {
TransactionId::Hash(ref hash) => self.transaction_address(hash),
TransactionId::Location(BlockId::Hash(hash), index) => Some(TransactionAddress {
block_hash: hash,
index: index
}),
TransactionId::Location(BlockId::Number(number), index) => self.block_hash(number).map(|hash| TransactionAddress {
block_hash: hash,
index: index
})
}.and_then(|address| self.block(&address.block_hash).and_then(|bytes| BlockView::new(&bytes).localized_transaction_at(address.index)))
}

/// Get a list of transactions for a given block.
/// Returns None if block deos not exist.
fn transactions(&self, hash: &H256) -> Option<Vec<SignedTransaction>> {
self.block(hash).map(|bytes| BlockView::new(&bytes).transactions())
/// Returns None if block does not exist.
fn transactions(&self, hash: &H256) -> Option<Vec<LocalizedTransaction>> {
self.block(hash).map(|bytes| BlockView::new(&bytes).localized_transactions())
}

/// Returns reference to genesis hash.
Expand Down Expand Up @@ -864,7 +887,7 @@ mod tests {
let transactions = bc.transactions(&b1_hash).unwrap();
assert_eq!(transactions.len(), 7);
for t in transactions {
assert_eq!(bc.transaction(&t.hash()).unwrap(), t);
assert_eq!(bc.transaction(TransactionId::Hash(t.hash())).unwrap(), t);
}
}
}
10 changes: 9 additions & 1 deletion ethcore/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

use util::*;
use rocksdb::{Options, DB, DBCompactionStyle};
use blockchain::{BlockChain, BlockProvider, CacheSize};
use blockchain::{BlockChain, BlockProvider, CacheSize, TransactionId};
use views::BlockView;
use error::*;
use header::BlockNumber;
Expand All @@ -31,6 +31,7 @@ use service::{NetSyncMessage, SyncMessage};
use env_info::LastHashes;
use verification::*;
use block::*;
use transaction::LocalizedTransaction;
pub use blockchain::TreeRoute;

/// General block status
Expand Down Expand Up @@ -104,6 +105,9 @@ pub trait BlockChainClient : Sync + Send {
/// Get block total difficulty.
fn block_total_difficulty_at(&self, n: BlockNumber) -> Option<U256>;

/// Get transaction with given hash.
fn transaction(&self, id: TransactionId) -> Option<LocalizedTransaction>;

/// Get a tree route between `from` and `to`.
/// See `BlockChain::tree_route`.
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute>;
Expand Down Expand Up @@ -388,6 +392,10 @@ impl BlockChainClient for Client {
self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_total_difficulty(&h))
}

fn transaction(&self, id: TransactionId) -> Option<LocalizedTransaction> {
self.chain.read().unwrap().transaction(id)
}

fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute> {
self.chain.read().unwrap().tree_route(from.clone(), to.clone())
}
Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ pub mod ethereum;
pub mod header;
pub mod service;
pub mod spec;
pub mod transaction;
pub mod views;
pub mod receipt;

Expand All @@ -115,7 +116,6 @@ mod state;
mod account;
mod account_db;
mod action_params;
mod transaction;
mod null_engine;
mod builtin;
mod extras;
Expand Down
25 changes: 23 additions & 2 deletions ethcore/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use util::*;
use error::*;
use evm::Schedule;
use header::BlockNumber;

#[derive(Debug, Clone, PartialEq, Eq)]
/// Transaction action type.
Expand Down Expand Up @@ -156,8 +157,7 @@ impl Transaction {
}
}



/// Signed transaction information.
#[derive(Debug, Clone, Eq)]
pub struct SignedTransaction {
/// Plain Transaction.
Expand Down Expand Up @@ -290,6 +290,27 @@ impl SignedTransaction {
}
}

/// Signed Transaction that is a part of canon blockchain.
#[derive(Debug, PartialEq, Eq)]
pub struct LocalizedTransaction {
/// Signed part.
pub signed: SignedTransaction,
/// Block number.
pub block_number: BlockNumber,
/// Block hash.
pub block_hash: H256,
/// Transaction index within block.
pub transaction_index: usize
}

impl Deref for LocalizedTransaction {
type Target = SignedTransaction;

fn deref(&self) -> &Self::Target {
&self.signed
}
}

#[test]
fn sender_test() {
let t: SignedTransaction = decode(&FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap());
Expand Down
34 changes: 34 additions & 0 deletions ethcore/src/views.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,22 @@ impl<'a> BlockView<'a> {
self.rlp.val_at(1)
}

/// Return List of transactions with additional localization info.
pub fn localized_transactions(&self) -> Vec<LocalizedTransaction> {
let header = self.header_view();
let block_hash = header.sha3();
let block_number = header.number();
self.transactions()
.into_iter()
.enumerate()
.map(|(i, t)| LocalizedTransaction {
signed: t,
block_hash: block_hash.clone(),
block_number: block_number,
transaction_index: i
}).collect()
}

/// Return number of transactions in given block, without deserializing them.
pub fn transactions_count(&self) -> usize {
self.rlp.at(1).iter().count()
Expand All @@ -170,6 +186,24 @@ impl<'a> BlockView<'a> {
self.rlp.at(1).iter().map(|rlp| rlp.as_raw().sha3()).collect()
}

/// Returns transaction at given index without deserializing unnecessary data.
pub fn transaction_at(&self, index: usize) -> Option<SignedTransaction> {
self.rlp.at(1).iter().nth(index).map(|rlp| rlp.as_val())
}

/// Returns localized transaction at given index.
pub fn localized_transaction_at(&self, index: usize) -> Option<LocalizedTransaction> {
let header = self.header_view();
let block_hash = header.sha3();
let block_number = header.number();
self.transaction_at(index).map(|t| LocalizedTransaction {
signed: t,
block_hash: block_hash,
block_number: block_number,
transaction_index: index
})
}

/// Return list of uncles of given block.
pub fn uncles(&self) -> Vec<Header> {
self.rlp.val_at(2)
Expand Down
65 changes: 40 additions & 25 deletions rpc/src/v1/impls/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ use util::uint::*;
use util::sha3::*;
use ethcore::client::*;
use ethcore::views::*;
use ethcore::blockchain::{BlockId, TransactionId};
use v1::traits::{Eth, EthFilter};
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus};
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, Transaction, OptionalValue, Index};

/// Eth rpc implementation.
pub struct EthClient {
Expand Down Expand Up @@ -96,48 +97,43 @@ impl Eth for EthClient {
}

fn block_transaction_count(&self, params: Params) -> Result<Value, Error> {
match from_params::<H256>(params) {
Ok(hash) => match self.client.block(&hash) {
from_params::<(H256,)>(params)
.and_then(|(hash,)| match self.client.block(&hash) {
Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()),
None => Ok(Value::Null)
},
Err(err) => Err(err)
}
})
}

fn block_uncles_count(&self, params: Params) -> Result<Value, Error> {
match from_params::<H256>(params) {
Ok(hash) => match self.client.block(&hash) {
from_params::<(H256,)>(params)
.and_then(|(hash,)| match self.client.block(&hash) {
Some(bytes) => to_value(&BlockView::new(&bytes).uncles_count()),
None => Ok(Value::Null)
},
Err(err) => Err(err)
}
})
}

// TODO: do not ignore block number param
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)
}
from_params::<(Address, BlockNumber)>(params)
.and_then(|(address, _block_number)| to_value(&self.client.code(&address).map_or_else(Bytes::default, Bytes::new)))
}

fn block(&self, params: Params) -> Result<Value, Error> {
match from_params::<(H256, bool)>(params) {
Ok((hash, include_txs)) => match (self.client.block_header(&hash), self.client.block_total_difficulty(&hash)) {
from_params::<(H256, bool)>(params)
.and_then(|(hash, include_txs)| match (self.client.block(&hash), self.client.block_total_difficulty(&hash)) {
(Some(bytes), Some(total_difficulty)) => {
let view = HeaderView::new(&bytes);
let block_view = BlockView::new(&bytes);
let view = block_view.header_view();
let block = Block {
hash: view.sha3(),
hash: OptionalValue::Value(view.sha3()),
parent_hash: view.parent_hash(),
uncles_hash: view.uncles_hash(),
author: view.author(),
miner: view.author(),
state_root: view.state_root(),
transactions_root: view.transactions_root(),
receipts_root: view.receipts_root(),
number: U256::from(view.number()),
number: OptionalValue::Value(U256::from(view.number())),
gas_used: view.gas_used(),
gas_limit: view.gas_limit(),
logs_bloom: view.log_bloom(),
Expand All @@ -147,22 +143,41 @@ impl Eth for EthClient {
uncles: vec![],
transactions: {
if include_txs {
BlockTransactions::Hashes(vec![])
BlockTransactions::Full(block_view.localized_transactions().into_iter().map(From::from).collect())
} else {
BlockTransactions::Full(vec![])
BlockTransactions::Hashes(block_view.transaction_hashes())
}
},
extra_data: Bytes::default()
};
to_value(&block)
},
_ => Ok(Value::Null)
},
Err(err) => Err(err)
}
})
}

fn transaction_by_hash(&self, params: Params) -> Result<Value, Error> {
from_params::<(H256,)>(params)
.and_then(|(hash,)| match self.client.transaction(TransactionId::Hash(hash)) {
Some(t) => to_value(&Transaction::from(t)),
None => Ok(Value::Null)
})
}

fn transaction_by_block_hash_and_index(&self, params: Params) -> Result<Value, Error> {
from_params::<(H256, Index)>(params)
.and_then(|(hash, index)| match self.client.transaction(TransactionId::Location(BlockId::Hash(hash), index.value())) {
Some(t) => to_value(&Transaction::from(t)),
None => Ok(Value::Null)
})
}

fn transaction_by_block_number_and_index(&self, _params: Params) -> Result<Value, Error> {
unimplemented!()
}
}


/// Eth filter rpc implementation.
pub struct EthFilterClient {
client: Arc<Client>
Expand Down
15 changes: 11 additions & 4 deletions rpc/src/v1/traits/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,14 @@ pub trait Eth: Sized + Send + Sync + 'static {
/// Estimate gas needed for execution of given contract.
fn estimate_gas(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }

/// Returns transaction at given block and index.
fn transaction_at(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
/// Get transaction by it's hash.
fn transaction_by_hash(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }

/// Returns transaction at given block hash and index.
fn transaction_by_block_hash_and_index(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }

/// Returns transaction by given block number and index.
fn transaction_by_block_number_and_index(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }

/// Returns transaction receipt.
fn transaction_receipt(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
Expand Down Expand Up @@ -131,8 +137,9 @@ pub trait Eth: Sized + Send + Sync + 'static {
delegate.add_method("eth_estimateGas", Eth::estimate_gas);
delegate.add_method("eth_getBlockByHash", Eth::block);
delegate.add_method("eth_getBlockByNumber", Eth::block);
delegate.add_method("eth_getTransactionByBlockHashAndIndex", Eth::transaction_at);
delegate.add_method("eth_getTransactionByBlockNumberAndIndex", Eth::transaction_at);
delegate.add_method("eth_getTransactionByHash", Eth::transaction_by_hash);
delegate.add_method("eth_getTransactionByBlockHashAndIndex", Eth::transaction_by_block_hash_and_index);
delegate.add_method("eth_getTransactionByBlockNumberAndIndex", Eth::transaction_by_block_number_and_index);
delegate.add_method("eth_getTransactionReceipt", Eth::transaction_receipt);
delegate.add_method("eth_getUncleByBlockHashAndIndex", Eth::uncle_at);
delegate.add_method("eth_getUncleByBlockNumberAndIndex", Eth::uncle_at);
Expand Down