2020-09-22 14:53:52 +02:00
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
2019-02-07 14:34:24 +01:00
2020-09-22 14:53:52 +02:00
// OpenEthereum is free software: you can redistribute it and/or modify
2019-02-07 14:34:24 +01:00
// 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.
2020-09-22 14:53:52 +02:00
// OpenEthereum is distributed in the hope that it will be useful,
2019-02-07 14:34:24 +01:00
// 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
2020-09-22 14:53:52 +02:00
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
2019-02-07 14:34:24 +01:00
use std ::{ str ::FromStr , sync ::Arc } ;
use accounts ::AccountProvider ;
use ethcore ::client ::TestBlockChainClient ;
use ethereum_types ::{ Address , U256 } ;
use parity_runtime ::Runtime ;
use parking_lot ::Mutex ;
2020-12-10 16:42:05 +01:00
use types ::transaction ::{ Action , Transaction , TypedTransaction } ;
2019-02-07 14:34:24 +01:00
use jsonrpc_core ::IoHandler ;
use v1 ::{
2020-08-05 06:08:03 +02:00
helpers ::{
2019-02-07 14:34:24 +01:00
dispatch ::{ self , FullDispatcher } ,
2020-08-05 06:08:03 +02:00
nonce ,
} ,
2019-02-07 14:34:24 +01:00
metadata ::Metadata ,
tests ::helpers ::TestMinerService ,
EthClientOptions , EthSigning , SigningUnsafeClient ,
} ;
fn blockchain_client ( ) -> Arc < TestBlockChainClient > {
let client = TestBlockChainClient ::new ( ) ;
Arc ::new ( client )
}
fn accounts_provider ( ) -> Arc < AccountProvider > {
Arc ::new ( AccountProvider ::transient_provider ( ) )
}
fn miner_service ( ) -> Arc < TestMinerService > {
Arc ::new ( TestMinerService ::default ( ) )
}
struct EthTester {
pub runtime : Runtime ,
pub client : Arc < TestBlockChainClient > ,
pub accounts_provider : Arc < AccountProvider > ,
pub miner : Arc < TestMinerService > ,
pub io : IoHandler < Metadata > ,
}
impl Default for EthTester {
fn default ( ) -> Self {
Self ::new_with_options ( Default ::default ( ) )
}
}
impl EthTester {
pub fn new_with_options ( options : EthClientOptions ) -> Self {
let runtime = Runtime ::with_thread_count ( 1 ) ;
let client = blockchain_client ( ) ;
let accounts_provider = accounts_provider ( ) ;
let ap = Arc ::new ( dispatch ::Signer ::new ( accounts_provider . clone ( ) ) ) as _ ;
let miner = miner_service ( ) ;
let gas_price_percentile = options . gas_price_percentile ;
let reservations = Arc ::new ( Mutex ::new ( nonce ::Reservations ::new ( runtime . executor ( ) ) ) ) ;
2020-08-05 06:08:03 +02:00
2019-02-07 14:34:24 +01:00
let dispatcher = FullDispatcher ::new (
client . clone ( ) ,
miner . clone ( ) ,
reservations ,
gas_price_percentile ,
) ;
let sign = SigningUnsafeClient ::new ( & ap , dispatcher ) . to_delegate ( ) ;
let mut io : IoHandler < Metadata > = IoHandler ::default ( ) ;
io . extend_with ( sign ) ;
2020-08-05 06:08:03 +02:00
2019-02-07 14:34:24 +01:00
EthTester {
runtime ,
client ,
miner ,
io ,
accounts_provider ,
}
}
}
#[ test ]
fn rpc_eth_send_transaction ( ) {
let tester = EthTester ::default ( ) ;
let address = tester . accounts_provider . new_account ( & " " . into ( ) ) . unwrap ( ) ;
tester
. accounts_provider
. unlock_account_permanently ( address , " " . into ( ) )
. unwrap ( ) ;
let request = r #" {
" jsonrpc " : " 2.0 " ,
" method " : " eth_sendTransaction " ,
" params " : [ {
" from " : " " #
. to_owned ( )
+ format! ( " 0x {:x} " , address ) . as_ref ( )
+ r #" " ,
" to " : " 0xd46e8dd67c5d32be8058bb8eb970870f07244567 " ,
" gas " : " 0x76c0 " ,
" gasPrice " : " 0x9184e72a000 " ,
" value " : " 0x9184e72a "
} ] ,
" id " : 1
} " #;
2020-12-10 16:42:05 +01:00
let t = TypedTransaction ::Legacy ( Transaction {
2019-02-07 14:34:24 +01:00
nonce : U256 ::zero ( ) ,
gas_price : U256 ::from ( 0x9184e72a000 u64 ) ,
gas : U256 ::from ( 0x76c0 ) ,
action : Action ::Call (
Address ::from_str ( " d46e8dd67c5d32be8058bb8eb970870f07244567 " ) . unwrap ( ) ,
2020-08-05 06:08:03 +02:00
) ,
2019-02-07 14:34:24 +01:00
value : U256 ::from ( 0x9184e72a u64 ) ,
data : vec ! [ ] ,
2020-12-10 16:42:05 +01:00
} ) ;
2019-02-07 14:34:24 +01:00
let signature = tester
. accounts_provider
2020-12-10 16:42:05 +01:00
. sign ( address , None , t . signature_hash ( None ) )
2019-02-07 14:34:24 +01:00
. unwrap ( ) ;
let t = t . with_signature ( signature , None ) ;
2020-08-05 06:08:03 +02:00
2019-02-07 14:34:24 +01:00
let response = r # "{"jsonrpc":"2.0","result":""# . to_owned ( )
+ format! ( " 0x {:x} " , t . hash ( ) ) . as_ref ( )
+ r # "","id":1}"# ;
2020-08-05 06:08:03 +02:00
2019-02-07 14:34:24 +01:00
assert_eq! ( tester . io . handle_request_sync ( & request ) , Some ( response ) ) ;
2020-08-05 06:08:03 +02:00
2019-02-07 14:34:24 +01:00
tester . miner . increment_nonce ( & address ) ;
2020-08-05 06:08:03 +02:00
2020-12-10 16:42:05 +01:00
let t = TypedTransaction ::Legacy ( Transaction {
2019-02-07 14:34:24 +01:00
nonce : U256 ::one ( ) ,
gas_price : U256 ::from ( 0x9184e72a000 u64 ) ,
gas : U256 ::from ( 0x76c0 ) ,
action : Action ::Call (
Address ::from_str ( " d46e8dd67c5d32be8058bb8eb970870f07244567 " ) . unwrap ( ) ,
2020-08-05 06:08:03 +02:00
) ,
2019-02-07 14:34:24 +01:00
value : U256 ::from ( 0x9184e72a u64 ) ,
data : vec ! [ ] ,
2020-12-10 16:42:05 +01:00
} ) ;
2019-02-07 14:34:24 +01:00
let signature = tester
. accounts_provider
2020-12-10 16:42:05 +01:00
. sign ( address , None , t . signature_hash ( None ) )
2019-02-07 14:34:24 +01:00
. unwrap ( ) ;
let t = t . with_signature ( signature , None ) ;
2020-08-05 06:08:03 +02:00
2019-02-07 14:34:24 +01:00
let response = r # "{"jsonrpc":"2.0","result":""# . to_owned ( )
+ format! ( " 0x {:x} " , t . hash ( ) ) . as_ref ( )
+ r # "","id":1}"# ;
2020-08-05 06:08:03 +02:00
2019-02-07 14:34:24 +01:00
assert_eq! ( tester . io . handle_request_sync ( & request ) , Some ( response ) ) ;
}
#[ test ]
fn rpc_eth_sign_transaction ( ) {
2020-12-10 16:42:05 +01:00
use rustc_hex ::ToHex ;
2019-02-07 14:34:24 +01:00
let tester = EthTester ::default ( ) ;
let address = tester . accounts_provider . new_account ( & " " . into ( ) ) . unwrap ( ) ;
tester
. accounts_provider
. unlock_account_permanently ( address , " " . into ( ) )
. unwrap ( ) ;
let request = r #" {
" jsonrpc " : " 2.0 " ,
" method " : " eth_signTransaction " ,
" params " : [ {
" from " : " " #
. to_owned ( )
+ format! ( " 0x {:x} " , address ) . as_ref ( )
+ r #" " ,
" to " : " 0xd46e8dd67c5d32be8058bb8eb970870f07244567 " ,
" gas " : " 0x76c0 " ,
" gasPrice " : " 0x9184e72a000 " ,
" value " : " 0x9184e72a "
} ] ,
" id " : 1
} " #;
2020-12-10 16:42:05 +01:00
let t = TypedTransaction ::Legacy ( Transaction {
2019-02-07 14:34:24 +01:00
nonce : U256 ::one ( ) ,
gas_price : U256 ::from ( 0x9184e72a000 u64 ) ,
gas : U256 ::from ( 0x76c0 ) ,
action : Action ::Call (
Address ::from_str ( " d46e8dd67c5d32be8058bb8eb970870f07244567 " ) . unwrap ( ) ,
2020-08-05 06:08:03 +02:00
) ,
2019-02-07 14:34:24 +01:00
value : U256 ::from ( 0x9184e72a u64 ) ,
data : vec ! [ ] ,
2020-12-10 16:42:05 +01:00
} ) ;
2019-02-07 14:34:24 +01:00
let signature = tester
. accounts_provider
2020-12-10 16:42:05 +01:00
. sign ( address , None , t . signature_hash ( None ) )
2019-02-07 14:34:24 +01:00
. unwrap ( ) ;
let t = t . with_signature ( signature , None ) ;
let signature = t . signature ( ) ;
2020-12-10 16:42:05 +01:00
let rlp = t . encode ( ) ;
2020-08-05 06:08:03 +02:00
2019-02-07 14:34:24 +01:00
let response = r # "{"jsonrpc":"2.0","result":{"# . to_owned ( )
+ r # ""raw":"0x"#
+ & rlp . to_hex ( )
+ r # "","#
+ r # ""tx":{"#
+ r # ""blockHash":null,"blockNumber":null,"#
+ & format! (
" \" chainId \" :{}, " ,
t . chain_id ( ) . map_or ( " null " . to_owned ( ) , | n | format! ( " {} " , n ) )
2020-08-05 06:08:03 +02:00
)
2019-02-07 14:34:24 +01:00
+ r # ""condition":null,"creates":null,"#
+ & format! ( " \" from \" : \" 0x {:x} \" , " , & address )
+ r # ""gas":"0x76c0","gasPrice":"0x9184e72a000","#
+ & format! ( " \" hash \" : \" 0x {:x} \" , " , t . hash ( ) )
+ r # ""input":"0x","#
+ r # ""nonce":"0x1","#
+ & format! ( " \" publicKey \" : \" 0x {:x} \" , " , t . recover_public ( ) . unwrap ( ) )
+ & format! ( " \" r \" : \" 0x {:x} \" , " , U256 ::from ( signature . r ( ) ) )
+ & format! ( " \" raw \" : \" 0x {} \" , " , rlp . to_hex ( ) )
+ & format! ( " \" s \" : \" 0x {:x} \" , " , U256 ::from ( signature . s ( ) ) )
+ & format! ( " \" standardV \" : \" 0x {:x} \" , " , U256 ::from ( t . standard_v ( ) ) )
2021-02-17 16:52:51 +01:00
+ r # ""to":"0xd46e8dd67c5d32be8058bb8eb970870f07244567","transactionIndex":null,"#
2021-12-09 09:17:42 +01:00
+ r # ""type":"0x0","#
2021-02-23 13:46:08 +01:00
+ & format! ( " \" v \" : \" 0x {:x} \" , " , U256 ::from ( t . v ( ) ) )
2019-02-07 14:34:24 +01:00
+ r # ""value":"0x9184e72a""#
+ r # "}},"id":1}"# ;
2020-08-05 06:08:03 +02:00
2019-02-07 14:34:24 +01:00
tester . miner . increment_nonce ( & address ) ;
2020-08-05 06:08:03 +02:00
2019-02-07 14:34:24 +01:00
assert_eq! ( tester . io . handle_request_sync ( & request ) , Some ( response ) ) ;
}
#[ test ]
fn rpc_eth_send_transaction_with_bad_to ( ) {
let tester = EthTester ::default ( ) ;
let address = tester . accounts_provider . new_account ( & " " . into ( ) ) . unwrap ( ) ;
let request = r #" {
" jsonrpc " : " 2.0 " ,
" method " : " eth_sendTransaction " ,
" params " : [ {
" from " : " " #
. to_owned ( )
+ format! ( " 0x {:x} " , address ) . as_ref ( )
+ r #" " ,
" to " : " " ,
" gas " : " 0x76c0 " ,
" gasPrice " : " 0x9184e72a000 " ,
" value " : " 0x9184e72a "
} ] ,
" id " : 1
} " #;
2021-03-12 10:12:42 +01:00
let response = r # "{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid params: 0x prefix is missing."},"id":1}"# ;
2019-02-07 14:34:24 +01:00
assert_eq! (
tester . io . handle_request_sync ( & request ) ,
Some ( response . into ( ) )
) ;
}
#[ test ]
fn rpc_eth_send_transaction_error ( ) {
let tester = EthTester ::default ( ) ;
let address = tester . accounts_provider . new_account ( & " " . into ( ) ) . unwrap ( ) ;
let request = r #" {
" jsonrpc " : " 2.0 " ,
" method " : " eth_sendTransaction " ,
" params " : [ {
" from " : " " #
. to_owned ( )
+ format! ( " 0x {:x} " , address ) . as_ref ( )
+ r #" " ,
" to " : " 0xd46e8dd67c5d32be8058bb8eb970870f07244567 " ,
" gas " : " 0x76c0 " ,
" gasPrice " : " 0x9184e72a000 " ,
" value " : " 0x9184e72a "
} ] ,
" id " : 1
} " #;
let response = r # "{"jsonrpc":"2.0","error":{"code":-32020,"message":"Your account is locked. Unlock the account via CLI, personal_unlockAccount or use Trusted Signer.","data":"NotUnlocked"},"id":1}"# ;
assert_eq! (
tester . io . handle_request_sync ( & request ) ,
Some ( response . into ( ) )
) ;
}