Merge pull request #798 from ethcore/eth_rpc
another batch of rpc improvements
This commit is contained in:
commit
d7fb464fa9
@ -21,7 +21,7 @@ use util::*;
|
|||||||
use util::panics::*;
|
use util::panics::*;
|
||||||
use views::BlockView;
|
use views::BlockView;
|
||||||
use error::*;
|
use error::*;
|
||||||
use header::{BlockNumber};
|
use header::{BlockNumber, Header};
|
||||||
use state::State;
|
use state::State;
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use engine::Engine;
|
use engine::Engine;
|
||||||
@ -36,7 +36,7 @@ use filter::Filter;
|
|||||||
use log_entry::LocalizedLogEntry;
|
use log_entry::LocalizedLogEntry;
|
||||||
use block_queue::{BlockQueue, BlockQueueInfo};
|
use block_queue::{BlockQueue, BlockQueueInfo};
|
||||||
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
|
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
|
||||||
use client::{BlockId, TransactionId, ClientConfig, BlockChainClient};
|
use client::{BlockId, TransactionId, UncleId, ClientConfig, BlockChainClient};
|
||||||
use env_info::EnvInfo;
|
use env_info::EnvInfo;
|
||||||
use executive::{Executive, Executed};
|
use executive::{Executive, Executed};
|
||||||
use receipt::LocalizedReceipt;
|
use receipt::LocalizedReceipt;
|
||||||
@ -549,6 +549,11 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
|
|||||||
self.transaction_address(id).and_then(|address| self.chain.transaction(&address))
|
self.transaction_address(id).and_then(|address| self.chain.transaction(&address))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn uncle(&self, id: UncleId) -> Option<Header> {
|
||||||
|
let index = id.1;
|
||||||
|
self.block(id.0).and_then(|block| BlockView::new(&block).uncle_at(index))
|
||||||
|
}
|
||||||
|
|
||||||
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt> {
|
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt> {
|
||||||
self.transaction_address(id).and_then(|address| {
|
self.transaction_address(id).and_then(|address| {
|
||||||
let t = self.chain.block(&address.block_hash)
|
let t = self.chain.block(&address.block_hash)
|
||||||
|
@ -20,7 +20,7 @@ use util::hash::H256;
|
|||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
|
|
||||||
/// Uniquely identifies block.
|
/// Uniquely identifies block.
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone, Hash, Eq)]
|
||||||
pub enum BlockId {
|
pub enum BlockId {
|
||||||
/// Block's sha3.
|
/// Block's sha3.
|
||||||
/// Querying by hash is always faster.
|
/// Querying by hash is always faster.
|
||||||
@ -34,7 +34,7 @@ pub enum BlockId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Uniquely identifies transaction.
|
/// Uniquely identifies transaction.
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone, Hash, Eq)]
|
||||||
pub enum TransactionId {
|
pub enum TransactionId {
|
||||||
/// Transaction's sha3.
|
/// Transaction's sha3.
|
||||||
Hash(H256),
|
Hash(H256),
|
||||||
@ -42,3 +42,11 @@ pub enum TransactionId {
|
|||||||
/// Querying by block position is always faster.
|
/// Querying by block position is always faster.
|
||||||
Location(BlockId, usize)
|
Location(BlockId, usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Uniquely identifies Uncle.
|
||||||
|
pub struct UncleId (
|
||||||
|
/// Block id.
|
||||||
|
pub BlockId,
|
||||||
|
/// Position in block.
|
||||||
|
pub usize
|
||||||
|
);
|
||||||
|
@ -23,7 +23,7 @@ mod test_client;
|
|||||||
|
|
||||||
pub use self::client::*;
|
pub use self::client::*;
|
||||||
pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig};
|
pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig};
|
||||||
pub use self::ids::{BlockId, TransactionId};
|
pub use self::ids::{BlockId, TransactionId, UncleId};
|
||||||
pub use self::test_client::{TestBlockChainClient, EachBlockWith};
|
pub use self::test_client::{TestBlockChainClient, EachBlockWith};
|
||||||
pub use executive::Executed;
|
pub use executive::Executed;
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ use util::numbers::U256;
|
|||||||
use blockchain::TreeRoute;
|
use blockchain::TreeRoute;
|
||||||
use block_queue::BlockQueueInfo;
|
use block_queue::BlockQueueInfo;
|
||||||
use block::{ClosedBlock, SealedBlock};
|
use block::{ClosedBlock, SealedBlock};
|
||||||
use header::BlockNumber;
|
use header::{BlockNumber, Header};
|
||||||
use transaction::{LocalizedTransaction, SignedTransaction};
|
use transaction::{LocalizedTransaction, SignedTransaction};
|
||||||
use log_entry::LocalizedLogEntry;
|
use log_entry::LocalizedLogEntry;
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
@ -77,6 +77,9 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
/// Get transaction with given hash.
|
/// Get transaction with given hash.
|
||||||
fn transaction(&self, id: TransactionId) -> Option<LocalizedTransaction>;
|
fn transaction(&self, id: TransactionId) -> Option<LocalizedTransaction>;
|
||||||
|
|
||||||
|
/// Get uncle with given id.
|
||||||
|
fn uncle(&self, id: UncleId) -> Option<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>;
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
use util::*;
|
use util::*;
|
||||||
use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action};
|
use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action};
|
||||||
use blockchain::TreeRoute;
|
use blockchain::TreeRoute;
|
||||||
use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId};
|
use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId, UncleId};
|
||||||
use header::{Header as BlockHeader, BlockNumber};
|
use header::{Header as BlockHeader, BlockNumber};
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
use log_entry::LocalizedLogEntry;
|
use log_entry::LocalizedLogEntry;
|
||||||
@ -52,6 +52,8 @@ pub struct TestBlockChainClient {
|
|||||||
pub code: RwLock<HashMap<Address, Bytes>>,
|
pub code: RwLock<HashMap<Address, Bytes>>,
|
||||||
/// Execution result.
|
/// Execution result.
|
||||||
pub execution_result: RwLock<Option<Executed>>,
|
pub execution_result: RwLock<Option<Executed>>,
|
||||||
|
/// Transaction receipts.
|
||||||
|
pub receipts: RwLock<HashMap<TransactionId, LocalizedReceipt>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -87,12 +89,18 @@ impl TestBlockChainClient {
|
|||||||
storage: RwLock::new(HashMap::new()),
|
storage: RwLock::new(HashMap::new()),
|
||||||
code: RwLock::new(HashMap::new()),
|
code: RwLock::new(HashMap::new()),
|
||||||
execution_result: RwLock::new(None),
|
execution_result: RwLock::new(None),
|
||||||
|
receipts: RwLock::new(HashMap::new()),
|
||||||
};
|
};
|
||||||
client.add_blocks(1, EachBlockWith::Nothing); // add genesis block
|
client.add_blocks(1, EachBlockWith::Nothing); // add genesis block
|
||||||
client.genesis_hash = client.last_hash.read().unwrap().clone();
|
client.genesis_hash = client.last_hash.read().unwrap().clone();
|
||||||
client
|
client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the transaction receipt result
|
||||||
|
pub fn set_transaction_receipt(&self, id: TransactionId, receipt: LocalizedReceipt) {
|
||||||
|
self.receipts.write().unwrap().insert(id, receipt);
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the execution result.
|
/// Set the execution result.
|
||||||
pub fn set_execution_result(&self, result: Executed) {
|
pub fn set_execution_result(&self, result: Executed) {
|
||||||
*self.execution_result.write().unwrap() = Some(result);
|
*self.execution_result.write().unwrap() = Some(result);
|
||||||
@ -224,10 +232,14 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transaction_receipt(&self, _id: TransactionId) -> Option<LocalizedReceipt> {
|
fn uncle(&self, _id: UncleId) -> Option<BlockHeader> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt> {
|
||||||
|
self.receipts.read().unwrap().get(&id).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
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>> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ impl FromJson for LogEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Log localized in a blockchain.
|
/// Log localized in a blockchain.
|
||||||
#[derive(Default, Debug, PartialEq)]
|
#[derive(Default, Debug, PartialEq, Clone)]
|
||||||
pub struct LocalizedLogEntry {
|
pub struct LocalizedLogEntry {
|
||||||
/// Plain log entry.
|
/// Plain log entry.
|
||||||
pub entry: LogEntry,
|
pub entry: LogEntry,
|
||||||
|
@ -76,6 +76,7 @@ impl HeapSizeOf for Receipt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Receipt with additional info.
|
/// Receipt with additional info.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct LocalizedReceipt {
|
pub struct LocalizedReceipt {
|
||||||
/// Transaction hash.
|
/// Transaction hash.
|
||||||
pub transaction_hash: H256,
|
pub transaction_hash: H256,
|
||||||
|
@ -23,18 +23,27 @@ use ethminer::{MinerService, AccountDetails};
|
|||||||
use jsonrpc_core::*;
|
use jsonrpc_core::*;
|
||||||
use util::numbers::*;
|
use util::numbers::*;
|
||||||
use util::sha3::*;
|
use util::sha3::*;
|
||||||
use util::rlp::encode;
|
use util::rlp::{encode, UntrustedRlp, View};
|
||||||
|
use util::crypto::KeyPair;
|
||||||
use ethcore::client::*;
|
use ethcore::client::*;
|
||||||
use ethcore::block::IsBlock;
|
use ethcore::block::IsBlock;
|
||||||
use ethcore::views::*;
|
use ethcore::views::*;
|
||||||
use ethcore::ethereum::Ethash;
|
use ethcore::ethereum::Ethash;
|
||||||
use ethcore::ethereum::denominations::shannon;
|
use ethcore::ethereum::denominations::shannon;
|
||||||
use ethcore::transaction::Transaction as EthTransaction;
|
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action};
|
||||||
use v1::traits::{Eth, EthFilter};
|
use v1::traits::{Eth, EthFilter};
|
||||||
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log, Receipt};
|
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, CallRequest, OptionalValue, Index, Filter, Log, Receipt};
|
||||||
use v1::helpers::{PollFilter, PollManager, ExternalMinerService, ExternalMiner};
|
use v1::helpers::{PollFilter, PollManager, ExternalMinerService, ExternalMiner};
|
||||||
use util::keys::store::AccountProvider;
|
use util::keys::store::AccountProvider;
|
||||||
|
|
||||||
|
fn default_gas() -> U256 {
|
||||||
|
U256::from(21_000)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_gas_price() -> U256 {
|
||||||
|
shannon() * U256::from(50)
|
||||||
|
}
|
||||||
|
|
||||||
/// Eth rpc implementation.
|
/// Eth rpc implementation.
|
||||||
pub struct EthClient<C, S, A, M, EM = ExternalMiner>
|
pub struct EthClient<C, S, A, M, EM = ExternalMiner>
|
||||||
where C: BlockChainClient,
|
where C: BlockChainClient,
|
||||||
@ -61,7 +70,6 @@ impl<C, S, A, M> EthClient<C, S, A, M, ExternalMiner>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<C, S, A, M, EM> EthClient<C, S, A, M, EM>
|
impl<C, S, A, M, EM> EthClient<C, S, A, M, EM>
|
||||||
where C: BlockChainClient,
|
where C: BlockChainClient,
|
||||||
S: SyncProvider,
|
S: SyncProvider,
|
||||||
@ -127,9 +135,65 @@ impl<C, S, A, M, EM> EthClient<C, S, A, M, EM>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uncle(&self, _block: BlockId, _index: usize) -> Result<Value, Error> {
|
fn uncle(&self, id: UncleId) -> Result<Value, Error> {
|
||||||
// TODO: implement!
|
let client = take_weak!(self.client);
|
||||||
Ok(Value::Null)
|
match client.uncle(id).and_then(|u| client.block_total_difficulty(BlockId::Hash(u.hash())).map(|diff| (diff, u))) {
|
||||||
|
Some((difficulty, uncle)) => {
|
||||||
|
let block = Block {
|
||||||
|
hash: OptionalValue::Value(uncle.hash()),
|
||||||
|
parent_hash: uncle.parent_hash,
|
||||||
|
uncles_hash: uncle.uncles_hash,
|
||||||
|
author: uncle.author,
|
||||||
|
miner: uncle.author,
|
||||||
|
state_root: uncle.state_root,
|
||||||
|
transactions_root: uncle.transactions_root,
|
||||||
|
number: OptionalValue::Value(U256::from(uncle.number)),
|
||||||
|
gas_used: uncle.gas_used,
|
||||||
|
gas_limit: uncle.gas_limit,
|
||||||
|
logs_bloom: uncle.log_bloom,
|
||||||
|
timestamp: U256::from(uncle.timestamp),
|
||||||
|
difficulty: uncle.difficulty,
|
||||||
|
total_difficulty: difficulty,
|
||||||
|
receipts_root: uncle.receipts_root,
|
||||||
|
extra_data: Bytes::new(uncle.extra_data),
|
||||||
|
// todo:
|
||||||
|
nonce: H64::from(0),
|
||||||
|
uncles: vec![],
|
||||||
|
transactions: BlockTransactions::Hashes(vec![]),
|
||||||
|
};
|
||||||
|
to_value(&block)
|
||||||
|
},
|
||||||
|
None => Ok(Value::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign_call(client: &Arc<C>, accounts: &Arc<A>, request: CallRequest) -> Option<SignedTransaction> {
|
||||||
|
match request.from {
|
||||||
|
Some(ref from) => {
|
||||||
|
let transaction = EthTransaction {
|
||||||
|
nonce: request.nonce.unwrap_or_else(|| client.nonce(from)),
|
||||||
|
action: request.to.map_or(Action::Create, Action::Call),
|
||||||
|
gas: request.gas.unwrap_or_else(default_gas),
|
||||||
|
gas_price: request.gas_price.unwrap_or_else(default_gas_price),
|
||||||
|
value: request.value.unwrap_or_else(U256::zero),
|
||||||
|
data: request.data.map_or_else(Vec::new, |d| d.to_vec())
|
||||||
|
};
|
||||||
|
|
||||||
|
accounts.account_secret(from).ok().map(|secret| transaction.sign(&secret))
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
let transaction = EthTransaction {
|
||||||
|
nonce: request.nonce.unwrap_or_else(U256::zero),
|
||||||
|
action: request.to.map_or(Action::Create, Action::Call),
|
||||||
|
gas: request.gas.unwrap_or_else(default_gas),
|
||||||
|
gas_price: request.gas_price.unwrap_or_else(default_gas_price),
|
||||||
|
value: request.value.unwrap_or_else(U256::zero),
|
||||||
|
data: request.data.map_or_else(Vec::new, |d| d.to_vec())
|
||||||
|
};
|
||||||
|
|
||||||
|
KeyPair::create().ok().map(|kp| transaction.sign(kp.secret()))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +255,7 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
|
|
||||||
fn gas_price(&self, params: Params) -> Result<Value, Error> {
|
fn gas_price(&self, params: Params) -> Result<Value, Error> {
|
||||||
match params {
|
match params {
|
||||||
Params::None => to_value(&(shannon() * U256::from(50))),
|
Params::None => to_value(&default_gas_price()),
|
||||||
_ => Err(Error::invalid_params())
|
_ => Err(Error::invalid_params())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -304,12 +368,12 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
|
|
||||||
fn uncle_by_block_hash_and_index(&self, params: Params) -> Result<Value, Error> {
|
fn uncle_by_block_hash_and_index(&self, params: Params) -> Result<Value, Error> {
|
||||||
from_params::<(H256, Index)>(params)
|
from_params::<(H256, Index)>(params)
|
||||||
.and_then(|(hash, index)| self.uncle(BlockId::Hash(hash), index.value()))
|
.and_then(|(hash, index)| self.uncle(UncleId(BlockId::Hash(hash), index.value())))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uncle_by_block_number_and_index(&self, params: Params) -> Result<Value, Error> {
|
fn uncle_by_block_number_and_index(&self, params: Params) -> Result<Value, Error> {
|
||||||
from_params::<(BlockNumber, Index)>(params)
|
from_params::<(BlockNumber, Index)>(params)
|
||||||
.and_then(|(number, index)| self.uncle(number.into(), index.value()))
|
.and_then(|(number, index)| self.uncle(UncleId(number.into(), index.value())))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compilers(&self, params: Params) -> Result<Value, Error> {
|
fn compilers(&self, params: Params) -> Result<Value, Error> {
|
||||||
@ -371,7 +435,6 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn submit_hashrate(&self, params: Params) -> Result<Value, Error> {
|
fn submit_hashrate(&self, params: Params) -> Result<Value, Error> {
|
||||||
// TODO: Index should be U256.
|
|
||||||
from_params::<(U256, H256)>(params).and_then(|(rate, id)| {
|
from_params::<(U256, H256)>(params).and_then(|(rate, id)| {
|
||||||
self.external_miner.submit_hashrate(rate, id);
|
self.external_miner.submit_hashrate(rate, id);
|
||||||
to_value(&true)
|
to_value(&true)
|
||||||
@ -380,14 +443,22 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
|
|
||||||
fn send_transaction(&self, params: Params) -> Result<Value, Error> {
|
fn send_transaction(&self, params: Params) -> Result<Value, Error> {
|
||||||
from_params::<(TransactionRequest, )>(params)
|
from_params::<(TransactionRequest, )>(params)
|
||||||
.and_then(|(transaction_request, )| {
|
.and_then(|(request, )| {
|
||||||
let accounts = take_weak!(self.accounts);
|
let accounts = take_weak!(self.accounts);
|
||||||
match accounts.account_secret(&transaction_request.from) {
|
match accounts.account_secret(&request.from) {
|
||||||
Ok(secret) => {
|
Ok(secret) => {
|
||||||
let miner = take_weak!(self.miner);
|
let miner = take_weak!(self.miner);
|
||||||
let client = take_weak!(self.client);
|
let client = take_weak!(self.client);
|
||||||
|
|
||||||
let transaction: EthTransaction = transaction_request.into();
|
let transaction = EthTransaction {
|
||||||
|
nonce: request.nonce.unwrap_or_else(|| client.nonce(&request.from)),
|
||||||
|
action: request.to.map_or(Action::Create, Action::Call),
|
||||||
|
gas: request.gas.unwrap_or_else(default_gas),
|
||||||
|
gas_price: request.gas_price.unwrap_or_else(default_gas_price),
|
||||||
|
value: request.value.unwrap_or_else(U256::zero),
|
||||||
|
data: request.data.map_or_else(Vec::new, |d| d.to_vec())
|
||||||
|
};
|
||||||
|
|
||||||
let signed_transaction = transaction.sign(&secret);
|
let signed_transaction = transaction.sign(&secret);
|
||||||
let hash = signed_transaction.hash();
|
let hash = signed_transaction.hash();
|
||||||
|
|
||||||
@ -408,47 +479,58 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&self, params: Params) -> Result<Value, Error> {
|
fn send_raw_transaction(&self, params: Params) -> Result<Value, Error> {
|
||||||
from_params::<(TransactionRequest, BlockNumber)>(params)
|
from_params::<(Bytes, )>(params)
|
||||||
.and_then(|(transaction_request, _block_number)| {
|
.and_then(|(raw_transaction, )| {
|
||||||
let accounts = take_weak!(self.accounts);
|
let decoded: Result<SignedTransaction, _> = UntrustedRlp::new(&raw_transaction.to_vec()).as_val();
|
||||||
match accounts.account_secret(&transaction_request.from) {
|
match decoded {
|
||||||
Ok(secret) => {
|
Ok(signed_tx) => {
|
||||||
|
let miner = take_weak!(self.miner);
|
||||||
let client = take_weak!(self.client);
|
let client = take_weak!(self.client);
|
||||||
|
|
||||||
let transaction: EthTransaction = transaction_request.into();
|
let hash = signed_tx.hash();
|
||||||
let signed_transaction = transaction.sign(&secret);
|
let import = miner.import_transactions(vec![signed_tx], |a: &Address| AccountDetails {
|
||||||
|
nonce: client.nonce(a),
|
||||||
let output = client.call(&signed_transaction)
|
balance: client.balance(a),
|
||||||
.map(|e| Bytes::new(e.output))
|
});
|
||||||
.unwrap_or(Bytes::default());
|
match import.into_iter().collect::<Result<Vec<_>, _>>() {
|
||||||
|
Ok(_) => to_value(&hash),
|
||||||
to_value(&output)
|
Err(e) => {
|
||||||
|
warn!("Error sending transaction: {:?}", e);
|
||||||
|
to_value(&U256::zero())
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Err(_) => { to_value(&Bytes::default()) }
|
Err(_) => { to_value(&U256::zero()) }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn estimate_gas(&self, params: Params) -> Result<Value, Error> {
|
fn call(&self, params: Params) -> Result<Value, Error> {
|
||||||
from_params::<(TransactionRequest, BlockNumber)>(params)
|
from_params::<(CallRequest, BlockNumber)>(params)
|
||||||
.and_then(|(transaction_request, _block_number)| {
|
.and_then(|(request, _block_number)| {
|
||||||
let accounts = take_weak!(self.accounts);
|
|
||||||
match accounts.account_secret(&transaction_request.from) {
|
|
||||||
Ok(secret) => {
|
|
||||||
let client = take_weak!(self.client);
|
let client = take_weak!(self.client);
|
||||||
|
let accounts = take_weak!(self.accounts);
|
||||||
|
let signed = Self::sign_call(&client, &accounts, request);
|
||||||
|
let output = signed.map(|tx| client.call(&tx)
|
||||||
|
.map(|e| Bytes::new(e.output))
|
||||||
|
.unwrap_or(Bytes::default()));
|
||||||
|
|
||||||
let transaction: EthTransaction = transaction_request.into();
|
to_value(&output)
|
||||||
let signed_transaction = transaction.sign(&secret);
|
})
|
||||||
|
|
||||||
let gas_used = client.call(&signed_transaction)
|
|
||||||
.map(|e| e.gas_used + e.refunded)
|
|
||||||
.unwrap_or(U256::zero());
|
|
||||||
|
|
||||||
to_value(&gas_used)
|
|
||||||
},
|
|
||||||
Err(_) => { to_value(&U256::zero()) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn estimate_gas(&self, params: Params) -> Result<Value, Error> {
|
||||||
|
from_params::<(CallRequest, BlockNumber)>(params)
|
||||||
|
.and_then(|(request, _block_number)| {
|
||||||
|
let client = take_weak!(self.client);
|
||||||
|
let accounts = take_weak!(self.accounts);
|
||||||
|
let signed = Self::sign_call(&client, &accounts, request);
|
||||||
|
let output = signed.map(|tx| client.call(&tx)
|
||||||
|
.map(|e| e.gas_used + e.refunded)
|
||||||
|
.unwrap_or(U256::zero()));
|
||||||
|
|
||||||
|
to_value(&output)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,12 +14,15 @@
|
|||||||
// 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::str::FromStr;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use jsonrpc_core::IoHandler;
|
use jsonrpc_core::IoHandler;
|
||||||
use util::hash::{Address, H256};
|
use util::hash::{Address, H256, FixedHash};
|
||||||
use util::numbers::{Uint, U256};
|
use util::numbers::{Uint, U256};
|
||||||
use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed};
|
use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, TransactionId};
|
||||||
|
use ethcore::log_entry::{LocalizedLogEntry, LogEntry};
|
||||||
|
use ethcore::receipt::LocalizedReceipt;
|
||||||
use v1::{Eth, EthClient};
|
use v1::{Eth, EthClient};
|
||||||
use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config, TestMinerService, TestExternalMiner};
|
use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config, TestMinerService, TestExternalMiner};
|
||||||
|
|
||||||
@ -382,6 +385,63 @@ fn rpc_eth_sign() {
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rpc_eth_transaction_receipt() {
|
||||||
|
let receipt = LocalizedReceipt {
|
||||||
|
transaction_hash: H256::zero(),
|
||||||
|
transaction_index: 0,
|
||||||
|
block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(),
|
||||||
|
block_number: 0x4510c,
|
||||||
|
cumulative_gas_used: U256::from(0x20),
|
||||||
|
gas_used: U256::from(0x10),
|
||||||
|
contract_address: None,
|
||||||
|
logs: vec![LocalizedLogEntry {
|
||||||
|
entry: LogEntry {
|
||||||
|
address: Address::from_str("33990122638b9132ca29c723bdf037f1a891a70c").unwrap(),
|
||||||
|
topics: vec![
|
||||||
|
H256::from_str("a6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc").unwrap(),
|
||||||
|
H256::from_str("4861736852656700000000000000000000000000000000000000000000000000").unwrap()
|
||||||
|
],
|
||||||
|
data: vec![],
|
||||||
|
},
|
||||||
|
block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(),
|
||||||
|
block_number: 0x4510c,
|
||||||
|
transaction_hash: H256::new(),
|
||||||
|
transaction_index: 0,
|
||||||
|
log_index: 1,
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
let hash = H256::from_str("b903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238").unwrap();
|
||||||
|
let tester = EthTester::default();
|
||||||
|
tester.client.set_transaction_receipt(TransactionId::Hash(hash), receipt);
|
||||||
|
|
||||||
|
let request = r#"{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "eth_getTransactionReceipt",
|
||||||
|
"params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],
|
||||||
|
"id": 1
|
||||||
|
}"#;
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","contractAddress":null,"cumulativeGasUsed":"0x20","gasUsed":"0x10","logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","data":"0x","logIndex":"0x01","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00"}],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00"},"id":1}"#;
|
||||||
|
|
||||||
|
assert_eq!(tester.io.handle_request(request), Some(response.to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rpc_eth_transaction_receipt_null() {
|
||||||
|
let tester = EthTester::default();
|
||||||
|
|
||||||
|
let request = r#"{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "eth_getTransactionReceipt",
|
||||||
|
"params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],
|
||||||
|
"id": 1
|
||||||
|
}"#;
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#;
|
||||||
|
|
||||||
|
assert_eq!(tester.io.handle_request(request), Some(response.to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rpc_eth_compilers() {
|
fn rpc_eth_compilers() {
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "eth_getCompilers", "params": [], "id": 1}"#;
|
let request = r#"{"jsonrpc": "2.0", "method": "eth_getCompilers", "params": [], "id": 1}"#;
|
||||||
|
106
rpc/src/v1/types/call_request.rs
Normal file
106
rpc/src/v1/types/call_request.rs
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// 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::Address;
|
||||||
|
use util::numbers::U256;
|
||||||
|
use v1::types::Bytes;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, PartialEq, Deserialize)]
|
||||||
|
pub struct CallRequest {
|
||||||
|
pub from: Option<Address>,
|
||||||
|
pub to: Option<Address>,
|
||||||
|
#[serde(rename="gasPrice")]
|
||||||
|
pub gas_price: Option<U256>,
|
||||||
|
pub gas: Option<U256>,
|
||||||
|
pub value: Option<U256>,
|
||||||
|
pub data: Option<Bytes>,
|
||||||
|
pub nonce: Option<U256>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::str::FromStr;
|
||||||
|
use rustc_serialize::hex::FromHex;
|
||||||
|
use serde_json;
|
||||||
|
use util::numbers::{Uint, U256};
|
||||||
|
use util::hash::Address;
|
||||||
|
use ethcore::transaction::{Transaction, Action};
|
||||||
|
use v1::types::Bytes;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transaction_request_deserialize() {
|
||||||
|
let s = r#"{
|
||||||
|
"from":"0x0000000000000000000000000000000000000001",
|
||||||
|
"to":"0x0000000000000000000000000000000000000002",
|
||||||
|
"gasPrice":"0x1",
|
||||||
|
"gas":"0x2",
|
||||||
|
"value":"0x3",
|
||||||
|
"data":"0x123456",
|
||||||
|
"nonce":"0x4"
|
||||||
|
}"#;
|
||||||
|
let deserialized: CallRequest = serde_json::from_str(s).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(deserialized, CallRequest {
|
||||||
|
from: Some(Address::from(1)),
|
||||||
|
to: Some(Address::from(2)),
|
||||||
|
gas_price: Some(U256::from(1)),
|
||||||
|
gas: Some(U256::from(2)),
|
||||||
|
value: Some(U256::from(3)),
|
||||||
|
data: Some(Bytes::new(vec![0x12, 0x34, 0x56])),
|
||||||
|
nonce: Some(U256::from(4)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transaction_request_deserialize2() {
|
||||||
|
let s = r#"{
|
||||||
|
"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
|
||||||
|
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
|
||||||
|
"gas": "0x76c0",
|
||||||
|
"gasPrice": "0x9184e72a000",
|
||||||
|
"value": "0x9184e72a",
|
||||||
|
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
|
||||||
|
}"#;
|
||||||
|
let deserialized: CallRequest = serde_json::from_str(s).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(deserialized, CallRequest {
|
||||||
|
from: Some(Address::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap()),
|
||||||
|
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
|
gas_price: Some(U256::from_str("9184e72a000").unwrap()),
|
||||||
|
gas: Some(U256::from_str("76c0").unwrap()),
|
||||||
|
value: Some(U256::from_str("9184e72a").unwrap()),
|
||||||
|
data: Some(Bytes::new("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap())),
|
||||||
|
nonce: None
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transaction_request_deserialize_empty() {
|
||||||
|
let s = r#"{"from":"0x0000000000000000000000000000000000000001"}"#;
|
||||||
|
let deserialized: CallRequest = serde_json::from_str(s).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(deserialized, CallRequest {
|
||||||
|
from: Some(Address::from(1)),
|
||||||
|
to: None,
|
||||||
|
gas_price: None,
|
||||||
|
gas: None,
|
||||||
|
value: None,
|
||||||
|
data: None,
|
||||||
|
nonce: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -20,19 +20,19 @@ use v1::types::Bytes;
|
|||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct Log {
|
pub struct Log {
|
||||||
address: Address,
|
pub address: Address,
|
||||||
topics: Vec<H256>,
|
pub topics: Vec<H256>,
|
||||||
data: Bytes,
|
pub data: Bytes,
|
||||||
#[serde(rename="blockHash")]
|
#[serde(rename="blockHash")]
|
||||||
block_hash: H256,
|
pub block_hash: H256,
|
||||||
#[serde(rename="blockNumber")]
|
#[serde(rename="blockNumber")]
|
||||||
block_number: U256,
|
pub block_number: U256,
|
||||||
#[serde(rename="transactionHash")]
|
#[serde(rename="transactionHash")]
|
||||||
transaction_hash: H256,
|
pub transaction_hash: H256,
|
||||||
#[serde(rename="transactionIndex")]
|
#[serde(rename="transactionIndex")]
|
||||||
transaction_index: U256,
|
pub transaction_index: U256,
|
||||||
#[serde(rename="logIndex")]
|
#[serde(rename="logIndex")]
|
||||||
log_index: U256,
|
pub log_index: U256,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<LocalizedLogEntry> for Log {
|
impl From<LocalizedLogEntry> for Log {
|
||||||
|
@ -24,6 +24,7 @@ mod optionals;
|
|||||||
mod sync;
|
mod sync;
|
||||||
mod transaction;
|
mod transaction;
|
||||||
mod transaction_request;
|
mod transaction_request;
|
||||||
|
mod call_request;
|
||||||
mod receipt;
|
mod receipt;
|
||||||
|
|
||||||
pub use self::block::{Block, BlockTransactions};
|
pub use self::block::{Block, BlockTransactions};
|
||||||
@ -36,5 +37,6 @@ pub use self::optionals::OptionalValue;
|
|||||||
pub use self::sync::{SyncStatus, SyncInfo};
|
pub use self::sync::{SyncStatus, SyncInfo};
|
||||||
pub use self::transaction::Transaction;
|
pub use self::transaction::Transaction;
|
||||||
pub use self::transaction_request::TransactionRequest;
|
pub use self::transaction_request::TransactionRequest;
|
||||||
|
pub use self::call_request::CallRequest;
|
||||||
pub use self::receipt::Receipt;
|
pub use self::receipt::Receipt;
|
||||||
|
|
||||||
|
@ -53,4 +53,42 @@ impl From<LocalizedReceipt> for Receipt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use serde_json;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use util::numbers::*;
|
||||||
|
use v1::types::{Bytes, Log, Receipt};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn receipt_serialization() {
|
||||||
|
let s = r#"{"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","cumulativeGasUsed":"0x20","gasUsed":"0x10","contractAddress":null,"logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00","logIndex":"0x01"}]}"#;
|
||||||
|
|
||||||
|
let receipt = Receipt {
|
||||||
|
transaction_hash: H256::zero(),
|
||||||
|
transaction_index: U256::zero(),
|
||||||
|
block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(),
|
||||||
|
block_number: U256::from(0x4510c),
|
||||||
|
cumulative_gas_used: U256::from(0x20),
|
||||||
|
gas_used: U256::from(0x10),
|
||||||
|
contract_address: None,
|
||||||
|
logs: vec![Log {
|
||||||
|
address: Address::from_str("33990122638b9132ca29c723bdf037f1a891a70c").unwrap(),
|
||||||
|
topics: vec![
|
||||||
|
H256::from_str("a6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc").unwrap(),
|
||||||
|
H256::from_str("4861736852656700000000000000000000000000000000000000000000000000").unwrap()
|
||||||
|
],
|
||||||
|
data: Bytes::new(vec![]),
|
||||||
|
block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(),
|
||||||
|
block_number: U256::from(0x4510c),
|
||||||
|
transaction_hash: H256::new(),
|
||||||
|
transaction_index: U256::zero(),
|
||||||
|
log_index: U256::one()
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
let serialized = serde_json::to_string(&receipt).unwrap();
|
||||||
|
assert_eq!(serialized, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -15,8 +15,7 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use util::hash::Address;
|
use util::hash::Address;
|
||||||
use util::numbers::{Uint, U256};
|
use util::numbers::U256;
|
||||||
use ethcore::transaction::{Action, Transaction};
|
|
||||||
use v1::types::Bytes;
|
use v1::types::Bytes;
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq, Deserialize)]
|
#[derive(Debug, Default, PartialEq, Deserialize)]
|
||||||
@ -31,19 +30,6 @@ pub struct TransactionRequest {
|
|||||||
pub nonce: Option<U256>,
|
pub nonce: Option<U256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<Transaction> for TransactionRequest {
|
|
||||||
fn into(self) -> Transaction {
|
|
||||||
Transaction {
|
|
||||||
nonce: self.nonce.unwrap_or_else(U256::zero),
|
|
||||||
action: self.to.map_or(Action::Create, Action::Call),
|
|
||||||
gas: self.gas.unwrap_or_else(U256::zero),
|
|
||||||
gas_price: self.gas_price.unwrap_or_else(U256::zero),
|
|
||||||
value: self.value.unwrap_or_else(U256::zero),
|
|
||||||
data: self.data.map_or_else(Vec::new, |d| d.to_vec()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
@ -55,50 +41,6 @@ mod tests {
|
|||||||
use v1::types::Bytes;
|
use v1::types::Bytes;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn transaction_request_into_transaction() {
|
|
||||||
let tr = TransactionRequest {
|
|
||||||
from: Address::default(),
|
|
||||||
to: Some(Address::from(10)),
|
|
||||||
gas_price: Some(U256::from(20)),
|
|
||||||
gas: Some(U256::from(10_000)),
|
|
||||||
value: Some(U256::from(1)),
|
|
||||||
data: Some(Bytes::new(vec![10, 20])),
|
|
||||||
nonce: Some(U256::from(12)),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(Transaction {
|
|
||||||
nonce: U256::from(12),
|
|
||||||
action: Action::Call(Address::from(10)),
|
|
||||||
gas: U256::from(10_000),
|
|
||||||
gas_price: U256::from(20),
|
|
||||||
value: U256::from(1),
|
|
||||||
data: vec![10, 20],
|
|
||||||
}, tr.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn empty_transaction_request_into_transaction() {
|
|
||||||
let tr = TransactionRequest {
|
|
||||||
from: Address::default(),
|
|
||||||
to: None,
|
|
||||||
gas_price: None,
|
|
||||||
gas: None,
|
|
||||||
value: None,
|
|
||||||
data: None,
|
|
||||||
nonce: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(Transaction {
|
|
||||||
nonce: U256::zero(),
|
|
||||||
action: Action::Create,
|
|
||||||
gas: U256::zero(),
|
|
||||||
gas_price: U256::zero(),
|
|
||||||
value: U256::zero(),
|
|
||||||
data: vec![],
|
|
||||||
}, tr.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn transaction_request_deserialize() {
|
fn transaction_request_deserialize() {
|
||||||
let s = r#"{
|
let s = r#"{
|
||||||
|
@ -20,6 +20,7 @@ use numbers::*;
|
|||||||
use bytes::*;
|
use bytes::*;
|
||||||
use secp256k1::{key, Secp256k1};
|
use secp256k1::{key, Secp256k1};
|
||||||
use rand::os::OsRng;
|
use rand::os::OsRng;
|
||||||
|
use sha3::Hashable;
|
||||||
|
|
||||||
/// Secret key for secp256k1 EC operations. 256 bit generic "hash" data.
|
/// Secret key for secp256k1 EC operations. 256 bit generic "hash" data.
|
||||||
pub type Secret = H256;
|
pub type Secret = H256;
|
||||||
@ -135,15 +136,22 @@ impl KeyPair {
|
|||||||
public: p,
|
public: p,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns public key
|
/// Returns public key
|
||||||
pub fn public(&self) -> &Public {
|
pub fn public(&self) -> &Public {
|
||||||
&self.public
|
&self.public
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns private key
|
/// Returns private key
|
||||||
pub fn secret(&self) -> &Secret {
|
pub fn secret(&self) -> &Secret {
|
||||||
&self.secret
|
&self.secret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns address.
|
||||||
|
pub fn address(&self) -> Address {
|
||||||
|
Address::from(self.public.sha3())
|
||||||
|
}
|
||||||
|
|
||||||
/// Sign a message with our secret key.
|
/// Sign a message with our secret key.
|
||||||
pub fn sign(&self, message: &H256) -> Result<Signature, CryptoError> { ec::sign(&self.secret, message) }
|
pub fn sign(&self, message: &H256) -> Result<Signature, CryptoError> { ec::sign(&self.secret, message) }
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user